【Spring源码解析】Spring XML方式获取bean源码初步解析

 2023-01-10
原文作者:燃尽余火 原文地址:https://juejin.cn/post/7121741699780444167

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

1、前言

上文 Spring XML方式获取bean过程概览 讲解了XML方式获取bean的大概流程,这篇文章说下真正获取bean的前置操作。

2、从doGetBean开始

继续查看 现在User1 user = context.getBean(“user”, User1.class); 解析获取bean的过程。

  1. 获取通过name获取bean真实的beanName
  2. 使用beanName尝试从缓存中获取bean
  3. 如果从缓存中获取到,那么返回对应的实例。
  4. 如果没有从缓存中获取,判断是否是原型模式,如果存在循环依赖,直接报错
  5. 获取parentBeanFactory
  6. 如果parentBeanFactory不为空,尝试从parentBeanFactory 递归获取bean
  7. 如果为空,那么判断是否只对类型检测,那么会记录
  8. 将配置Xml 配置文件的GenericBeanDefination 转换成RootBeanDefination,如果指定beanName 那么会合并到父类的相关属性
  9. 之后判断是否存在依赖的bean,如果存在先对依赖对象进行注册并获取
  10. 判断定义bean是否是单例模式,如果是获取作用域是单例模式的情况bean
  11. 判断定义bean是否是原型模式,如果是获取作用域是原型模式的情况bean
  12. 如果不是单例和原型模式,那么获取作用域,并获取作用域下bean
  13. 检测最终获取的bean是否和需要的bean类型一致,如果一致那么返回或的bean

2.1、获取真正的beanName

    final String beanName = transformedBeanName(name);

进入查看:

其实一共就两个步骤,第一处理特殊字符&,然后从aliasMap中获取真实beanName。

    protected String transformedBeanName(String name) {
       return canonicalName(BeanFactoryUtils.transformedBeanName(name));
    }
    // 处理特殊字符
    public static String transformedBeanName(String name) {
       Assert.notNull(name, "'name' must not be null");
       if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
          return name;
       }
       return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
          do {
             beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
          }
          while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
          return beanName;
       });
    }
    
    public String canonicalName(String name) {
        String canonicalName = name;
    
        String resolvedName;
        do {
            resolvedName = (String)this.aliasMap.get(canonicalName);
            if (resolvedName != null) {
                canonicalName = resolvedName;
            }
        } while(resolvedName != null);
    
        return canonicalName;
    }

2.2、从缓存中获取bean

    Object sharedInstance = getSingleton(beanName);

进入查看具体实现:

    @Override
    @Nullable
    public Object getSingleton(String beanName) {
       return getSingleton(beanName, true);
    }
    
    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
       Object singletonObject = this.singletonObjects.get(beanName);
       if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
          synchronized (this.singletonObjects) {
             singletonObject = this.earlySingletonObjects.get(beanName);
             if (singletonObject == null && allowEarlyReference) {
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                   singletonObject = singletonFactory.getObject();
                   this.earlySingletonObjects.put(beanName, singletonObject);
                   this.singletonFactories.remove(beanName);
                }
             }
          }
       }
       return singletonObject;
    }

这里主要是从缓存中获取bean实例。先从singletonObjects中获取,如果未获取到从earlySingletonObject获取,再未获取到那么从singletonFactories中获取。这也是获取bean的三级缓存。

其中 singletonObjects 是已经完成实例化的对象,earlySingletonObject 是经过代理但是没有对属性赋值的对象,singletonFactories 是缓存当前实例的工厂bean。

2.3、获取bean实例

这里其实不仅仅应用于从缓存获取成功后处理,而且未成功处理最后也是通过此方法获取实例bean。

    bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);

进入此方法实现:

    protected Object getObjectForBeanInstance(
          Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
    
       // Don't let calling code try to dereference the factory if the bean isn't a factory.
       if (BeanFactoryUtils.isFactoryDereference(name)) {
          if (beanInstance instanceof NullBean) {
             return beanInstance;
          }
          if (!(beanInstance instanceof FactoryBean)) {
             throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
          }
       }
    
       // Now we have the bean instance, which may be a normal bean or a FactoryBean.
       // If it's a FactoryBean, we use it to create a bean instance, unless the
       // caller actually wants a reference to the factory.
       if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
          return beanInstance;
       }
    
       Object object = null;
       if (mbd == null) {
          object = getCachedObjectForFactoryBean(beanName);
       }
       if (object == null) {
          // Return bean instance from factory.
          FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
          // Caches object obtained from FactoryBean if it is a singleton.
          if (mbd == null && containsBeanDefinition(beanName)) {
             mbd = getMergedLocalBeanDefinition(beanName);
          }
          boolean synthetic = (mbd != null && mbd.isSynthetic());
          object = getObjectFromFactoryBean(factory, beanName, !synthetic);
       }
       return object;
    }

这里其实主要是对普通bean和FactoryBean的区分,普通bean直接返回,作为FactoryBean需要特殊处理。

getCachedObjectForFactoryBean的作用是从factoryBeanObjectCache缓存中获取FactoryBean。

再后通过 getMergedLocalBeanDefinition 查看 是否存在继承关系bean并也存在实例化的情况,如果存在则进行合并。

示例: bean Person 和 继承了Person的bean PersonExt。 在XML配置文件中:

    <bean class="com.fankf.spring.Person" name="p,p1" init-method="myInit" destroy-method="myDestory">
        <property name="name" value="lisi"/>
    </bean>
    
    <bean class="com.fankf.spring.PersonExt" name="person,person1" init-method="myInit" destroy-method="myDestory" parent="p">
        <property name="name" value="zhangsan"/>
    </bean>

其中 parent="p" 指向了Person对象。进入方法查看源码:

    protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
       // Quick check on the concurrent map first, with minimal locking.
       RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
       if (mbd != null) {
          return mbd;
       }
       return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
    }
    
    protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
          throws BeanDefinitionStoreException {
    
       return getMergedBeanDefinition(beanName, bd, null);
    }
    
    protected RootBeanDefinition getMergedBeanDefinition(
          String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
          throws BeanDefinitionStoreException {
    
       synchronized (this.mergedBeanDefinitions) {
          RootBeanDefinition mbd = null;
    
          // Check with full lock now in order to enforce the same merged instance.
          if (containingBd == null) {
             mbd = this.mergedBeanDefinitions.get(beanName);
          }
    
          if (mbd == null) {
             if (bd.getParentName() == null) {
                // Use copy of given root bean definition.
                if (bd instanceof RootBeanDefinition) {
                   mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
                }
                else {
                   mbd = new RootBeanDefinition(bd);
                }
             }
             else {
                // Child bean definition: needs to be merged with parent.
                BeanDefinition pbd;
                try {
                   String parentBeanName = transformedBeanName(bd.getParentName());
                   if (!beanName.equals(parentBeanName)) {
                      pbd = getMergedBeanDefinition(parentBeanName);
                   }
                   else {
                      BeanFactory parent = getParentBeanFactory();
                      if (parent instanceof ConfigurableBeanFactory) {
                         pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
                      }
                      else {
                         throw new NoSuchBeanDefinitionException(parentBeanName,
                               "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
                               "': cannot be resolved without an AbstractBeanFactory parent");
                      }
                   }
                }
                catch (NoSuchBeanDefinitionException ex) {
                   throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
                         "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
                }
                // Deep copy with overridden values.
                mbd = new RootBeanDefinition(pbd);
                mbd.overrideFrom(bd);
             }
    
             // Set default singleton scope, if not configured before.
             if (!StringUtils.hasLength(mbd.getScope())) {
                mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
             }
    
             // A bean contained in a non-singleton bean cannot be a singleton itself.
             // Let's correct this on the fly here, since this might be the result of
             // parent-child merging for the outer bean, in which case the original inner bean
             // definition will not have inherited the merged outer bean's singleton status.
             if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
                mbd.setScope(containingBd.getScope());
             }
    
             // Cache the merged bean definition for the time being
             // (it might still get re-merged later on in order to pick up metadata changes)
             if (containingBd == null && isCacheBeanMetadata()) {
                this.mergedBeanDefinitions.put(beanName, mbd);
             }
          }
    
          return mbd;
       }
    }

获取bean语句修改成 :

    PersonExt person = (PersonExt) context.getBean("person");

这里 getMergedLocalBeanDefinition(String beanName) 作用获取beanName 对应Bean实例,getMergedBeanDefinition(String beanName, BeanDefinition bd) 只做跳转使用,具体查看 getMergedBeanDefinition( String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd) 方法:

  1. containingBd == null 必定为 true ,从 mergedBeanDefinitions.get(beanName) 获取 beanDefination,此处也刚开始执行必定为空。
  2. 如果不存在parent='p' 那么就执行 mbd = new RootBeanDefinition(bd); 直接返回。
  3. 这里存在那么就 transformedBeanName(bd.getParentName()) 获取p,beanName.equals(parentBeanName) 则判断 "person".equals("p") 返回false,从而获取 p 别买对应的实例,其实就是对parent对应的Person类进行加载。
  4. mbd = new RootBeanDefinition(pbd) 从而对Person类进行GenericBeanDefination 转换成RootBeanDefination, mbd.overrideFrom(bd) 这里使用子类的方法覆盖同名的父类方法 。 这个才是主要的。对比原GenericBeanDefination内容还要多,多的内容是父类的未重写的属性和方法。

2.4、检测是否是抽象

checkMergedBeanDefinition 检测是否是抽象类,如果是直接报错。

    protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName, @Nullable Object[] args)
          throws BeanDefinitionStoreException {
    
       if (mbd.isAbstract()) {
          throw new BeanIsAbstractException(beanName);
       }
    }

2.5、处理依赖的bean

获取所有依赖的bean,对依赖的bean进行注册 registerDependentBean 和 获取 getBean 。

    String[] dependsOn = mbd.getDependsOn();
    if (dependsOn != null) {
       for (String dep : dependsOn) {
          if (isDependent(beanName, dep)) {
             throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                   "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
          }
          registerDependentBean(dep, beanName);
          try {
             getBean(dep);
          }
          catch (NoSuchBeanDefinitionException ex) {
             throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                   "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
          }
       }
    }

2.6、判断是否是单例

单例情况下创建bean实例,这里 getObjectForBeanInstance 和 2.3 的内容是相同的。 而getSingleton 是获取bean,在此之前进行了createBean的过程。这里内容比较多,下篇讲解。

    if (mbd.isSingleton()) {
       sharedInstance = getSingleton(beanName, () -> {
          try {
             return createBean(beanName, mbd, args);
          }
          catch (BeansException ex) {
             // Explicitly remove instance from singleton cache: It might have been put there
             // eagerly by the creation process, to allow for circular reference resolution.
             // Also remove any beans that received a temporary reference to the bean.
             destroySingleton(beanName);
             throw ex;
          }
       });
       bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }

2.7、判断是否是原型

如果是原型模式,getObjectForBeanInstance 仍然是相同的。 不同在于在createBean 之前分别执行了beforePrototypeCreation 和 之后 afterPrototypeCreation 操作,都是对循环依赖的处理。

    if (mbd.isPrototype()) {
       // It's a prototype -> create a new instance.
       Object prototypeInstance = null;
       try {
          beforePrototypeCreation(beanName);
          prototypeInstance = createBean(beanName, mbd, args);
       }
       finally {
          afterPrototypeCreation(beanName);
       }
       bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
    }

2.8、非单例和原型的作用域统一处理

其他的作用域,先获取作用域,然后进行的操作和原型模式类似。最后 getObjectForBeanInstance 获取实例bean,之前进行的 createBean 前后分别处理循环依赖问题。

    String scopeName = mbd.getScope();
    final Scope scope = this.scopes.get(scopeName);
    if (scope == null) {
      throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
    }
    try {
      Object scopedInstance = scope.get(beanName, () -> {
         beforePrototypeCreation(beanName);
         try {
            return createBean(beanName, mbd, args);
         }
         finally {
            afterPrototypeCreation(beanName);
         }
      });
      bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
    }
    catch (IllegalStateException ex) {
      throw new BeanCreationException(beanName,
            "Scope '" + scopeName + "' is not active for the current thread; consider " +
            "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
            ex);
    }

2.9、对获取bean的类型和需要的类型进行校验

这里主要是 getTypeConverter().convertIfNecessary(bean, requiredType); 这一句,我们这里没有对 requiredType 传值,所以就不仔细看了,有兴趣可以往里看,还是比较简单的。

    if (requiredType != null && !requiredType.isInstance(bean)) {
       try {
          T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
          if (convertedBean == null) {
             throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
          }
          return convertedBean;
       }
       catch (TypeMismatchException ex) {
          if (logger.isTraceEnabled()) {
             logger.trace("Failed to convert bean '" + name + "' to required type '" +
                   ClassUtils.getQualifiedName(requiredType) + "'", ex);
          }
          throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
       }
    }
    return (T) bean;

3、总结

以上不是完全按照上面文章的顺序进行的讲解,有几个比较简单的就没有提到。其他三种实例化的情况因为内容比较多,就放到下篇再讲解,也是希望看到文章的朋友有新收获!

加油!共勉!