【1】Spring源码-Bean的加载(BeanFactory)

2019-10-12  本文已影响0人  小毛1221

1. Spring Framework架构图

image.png

后面主要涉及到Beans、Context、AOP、Transactions、MVC等方面的内容。

2. Beans

2.1 BeanFactory的初始化

2.1.1 加载配置文件

2.1.2 创建BeanFactory

创建BeanFactory就更简单了,有时直接new一个出来。

protected DefaultListableBeanFactory createBeanFactory() {
   return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}

2.1.3 加载BeanDefinitions

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
      throws BeanDefinitionStoreException {
   try {
      Document doc = doLoadDocument(inputSource, resource);
      return registerBeanDefinitions(doc, resource);
   }
   catch (BeanDefinitionStoreException ex) {
      throw ex;
   }
   catch (SAXParseException ex) {
      throw new XmlBeanDefinitionStoreException(resource.getDescription(),
            "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
   }
   catch (SAXException ex) {
      throw new XmlBeanDefinitionStoreException(resource.getDescription(),
            "XML document from " + resource + " is invalid", ex);
   }
   catch (ParserConfigurationException ex) {
      throw new BeanDefinitionStoreException(resource.getDescription(),
            "Parser configuration exception parsing XML from " + resource, ex);
   }
   catch (IOException ex) {
      throw new BeanDefinitionStoreException(resource.getDescription(),
            "IOException parsing XML document from " + resource, ex);
   }
   catch (Throwable ex) {
      throw new BeanDefinitionStoreException(resource.getDescription(),
            "Unexpected exception parsing XML document from " + resource, ex);
   }
}
  1. 利用之前配置文件封装好的Resource对象加载XML文件,并得到对应的Document;
  2. 根据返回的Document注册Bean信息:doRegisterBeanDefinitions( );
        a. 获取Document的root节点,递归变量Document中的每一个节点;
        b. 解析每一个节点,注册BeanDefinition(在后续bean的加载中会用到);
            i. parseBeanDefinitions中会解析xml文件的各种标签,如<import>,<bean>,而<beans>该标签又会递归调用doRegisterBeanDefinitions。
// public static final String BEAN_ELEMENT = "bean";
public static final String BEAN_ELEMENT = BeanDefinitionParserDelegate.BEAN_ELEMENT;


public static final String NESTED_BEANS_ELEMENT = "beans";

public static final String ALIAS_ELEMENT = "alias";

public static final String IMPORT_ELEMENT = "import";


private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
   if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
      importBeanDefinitionResource(ele);
   }
   else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
      processAliasRegistration(ele);
   }
   else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
      processBeanDefinition(ele, delegate);
   }
   else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
      // recurse
      doRegisterBeanDefinitions(ele);
   }
}

        ii. 解析xml的各项标签完成后,还需要注册BeanDefinition(如processBeanDefinition()方法),包括通过beanName注册和通过别名alias注册(如果对某个bean配置了一个或多个别名,还需要将别名注册):
                 * 注册BeanDefinition就是将BeanDefinition放入map(BeanDefinitionMap,concurrentHashMap)中,key为beanName,value为BeanDefinition;
                 * this.beanDefinitionMap.put(beanName, beanDefinition);
                 * 通过alias注册(processAliasRegistration()方法): 将alias放入map(aliasMap,concurrentHashMap)中,key为alias,value为beanName;
        iii. 当每个bean被解析并注册完成后,会发出响应事件(fireComponentRegistered),通知相关的监听器。这里的实现只是为了扩展,当开发者需要对注册BeanDefinition事件进行监听时,可以通过注册监听器的方式并将处理逻辑写入监听器中,目前在spring中并没有对此事件做任何逻辑处理。
这些步骤其实也都是包含在ApplicationContext的初始化中哦,也就是ApplicationContext几乎包含BeanFactory的所有功能。

2.2 Bean的加载

加载Bean的开始,BeanFactory#getBean(String beanName)。

对于加载过程中所涉及的步骤大致如下:

  1. 转换对应beanName。
  1. 尝试从缓存中加载单例。
  1. bean的实例化。
  1. 原型模式的依赖检查。
  1. 检测parentBeanFactory。
  1. 将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition。
  1. 寻找依赖。
  1. 针对不同的scope进行bean的创建。

    * 利用反射创建Bean,BeanUtils.instantiateClass(constructorToUse),如果有动态代理则创建

    * 属性注入populateBean()方法注入属性,循环查找Bean所需注入的属性(分为autowiredByName和autowiredByType),使用getBean()方法获取并注入

    * 调用initializeBean方法完成用户自定义的初始化方法,该方法会先调用postProcessBeforeInitialization再调用InitializingBean.afterPropertiesSet(需要实现InitializingBean接口,实现用户自定义afterPropertiesSet方法)再调用postProcessAfterInitialization

  1. 类型转换。

以AbstractBeanFactory为例:

public Object getBean(String name) throws BeansException {
   return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
      @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
   /**
    * 1. 转换BeanName
    */
   final String beanName = transformedBeanName(name);
   Object bean;

   /**
    * 2. 尝试从缓存中加载单例
    * 首先尝试从缓存中加载,如果加载不成功则再次尝试从singletonFactories中加载。
    * 因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,
    * 在Spring中创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光加入到缓存中,
    * 一旦下一个bean创建时候需要依赖上一个bean则直接使用ObjectFactory
    */
   Object sharedInstance = getSingleton(beanName);
   if (sharedInstance != null && args == null) {
      if (logger.isDebugEnabled()) {
         if (isSingletonCurrentlyInCreation(beanName)) {
            logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                  "' that is not fully initialized yet - a consequence of a circular reference");
         }
         else {
            logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
         }
      }
      /**
       * 3. Bean的实例化
       * 判断得到的Bean是否为FactoryBean,如果是则从FactoryBean中获取bean实例(FactoryBean#getObject())
       *
       */
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }
   /**
    * 2.1 如果缓存中没有
    */
   else {
      /**
       * 4. 原型模式的依赖检查,如果原型模式有循环依赖则抛出异常
       */
      if (isPrototypeCurrentlyInCreation(beanName)) {
         throw new BeanCurrentlyInCreationException(beanName);
      }

      /**
       * 5. 当父工厂不为空,且BeanDefinition在父工厂中,则从父工厂中获取Bean
       */
      BeanFactory parentBeanFactory = getParentBeanFactory();
      if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
         // Not found -> check parent.
         String nameToLookup = originalBeanName(name);
         if (parentBeanFactory instanceof AbstractBeanFactory) {
            return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                  nameToLookup, requiredType, args, typeCheckOnly);
         }
         else if (args != null) {
            // Delegation to parent with explicit args.
            return (T) parentBeanFactory.getBean(nameToLookup, args);
         }
         else {
            // No args -> delegate to standard getBean method.
            return parentBeanFactory.getBean(nameToLookup, requiredType);
         }
      }

      if (!typeCheckOnly) {
         markBeanAsCreated(beanName);
      }

      try {
         /**
          * 6. 转换得到RootBeanDefinition
          * 在Spring中可以定义父子Bean,子类Bean可以继承父类Bean的属性,这里就是"递归向上"合并父子Bean的属性
          */
         final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
         checkMergedBeanDefinition(mbd, beanName, args);

         /**
          * 7. 寻找Bean的依赖
          */
         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 {
                  /**
                   * 7.1 实例化所有依赖Bean
                   */
                  getBean(dep);
               }
               catch (NoSuchBeanDefinitionException ex) {
                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
               }
            }
         }

         /**
          * 8. 根据不同的scope创建Bean
          */
         if (mbd.isSingleton()) {
            /**
             * 8.1 创建Bean,并加入缓存
             */
            sharedInstance = getSingleton(beanName, () -> {
               try {
                  /**
                   * 8.2 创建Bean
                   * 利用反射创建Bean,BeanUtils.instantiateClass(constructorToUse),如果有动态代理则创建
                   * 属性注入populateBean(),循环查找Bean所需注入的属性(分为autowiredByName和autowiredByType),使用getBean()方法获取并注入
                   * 调用initializeBean方法完成用户自定义的初始化方法,该方法会先调用postProcessBeforeInitialization再调用InitializingBean.afterPropertiesSet(需要实现InitializingBean接口,实现用户自定义afterPropertiesSet方法)再调用postProcessAfterInitialization
                   */
                  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;
               }
            });
            /**
             * 8.2 Bean的实例化
             */
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
         }

         else 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);
         }

         else {
            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);
            }
         }
      }
      catch (BeansException ex) {
         cleanupAfterBeanCreationFailure(beanName);
         throw ex;
      }
   }

   /**
    * 9. 类型转换
    */
   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.isDebugEnabled()) {
            logger.debug("Failed to convert bean '" + name + "' to required type '" +
                  ClassUtils.getQualifiedName(requiredType) + "'", ex);
         }
         throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
      }
   }
   return (T) bean;
}

2.2.1 FactoryBean

2.3 解决循环依赖

循环依赖的产生可能有很多种情况,例如:

当然,Spring对于循环依赖的解决不是无条件的,首先前提条件是针对scope单例并且没有显式指明不需要解决循环依赖的对象,而且要求该对象没有被代理过。同时Spring解决循环依赖也不是万能,以上三种情况只能解决两种,第一种在构造方法中相互依赖的情况Spring也无法解决。
而第二种情况下,需要保证先初始化B,可以使用@DependsOn

2.3.1 单例模式(Singleton)的循环依赖

Spring循环依赖的理论依据其实是Java基于引用传递,当我们获取到对象的引用时,对象的field或者或属性是可以延后设置的。
Spring单例对象的初始化其实可以分为三步(就是上文中的createBean()方法):

会发生循环依赖的步骤集中在第一步和第二步。

三级缓存
对于单例对象来说,在Spring的整个容器的生命周期内,有且只存在一个对象,很容易想到这个对象应该存在Cache中,Spring大量运用了Cache的手段,在循环依赖问题的解决过程中甚至使用了“三级缓存”。

“三级缓存”主要是指


/** Cache of singleton objects: bean name --> bean instance 已经初始化完成的实例*/

private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

/** Cache of singleton factories: bean name --> ObjectFactory */

private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

/** Cache of early singleton objects: bean name --> bean instance 只完成构造方法,还没有注入属性的bean*/

private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16); 

从字面意思来说:singletonObjects指单例对象的cache,singletonFactories指单例对象工厂的cache,earlySingletonObjects指提前曝光的单例对象的cache。以上三个cache构成了三级缓存,Spring就用这三级缓存巧妙的解决了循环依赖问题。


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;
}

为什么用到三级缓存

//截取自AbstractAutowireCapableBeanFactory#doCreateBean()
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
      isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
   if (logger.isDebugEnabled()) {
      logger.debug("Eagerly caching bean '" + beanName +
            "' to allow for resolving potential circular references");
   }
   addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

而ObjectFactory的getObject方法主要是通过以下方法实现(getEarlyBeanReference( )):

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
   Object exposedObject = bean;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
            SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
            exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
         }
      }
   }
   return exposedObject;
}

bean被加入缓存的时间

2.3.2 原型模式(Prototye)的循环依赖

在Spring中,@Controller默认都是单例的(singleton)。所谓单例,就是Spring的IOC机制只创建该类的一个实例,每次请求,都会用这同一个实例进行处理,因此若存在全局变量(成员变量),本次请求的值肯定会影响下一次请求时该变量的值。

使用成员变量后,若不想影响下次请求,就需要用到原型模式,即在Controller上加@Scope(“prototype”)

原型模式,指的是每次调用时,会重新创建该类的一个实例,比较类似于我们自己自己new的对象实例。

Spring对原型模式循环依赖的处理策略:

在原型模式下,如果存在A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生A还未创建完的时候因为对于B的创建再次返回创建A,造成循环依赖,所以在加载bean时,原型模式需要判断当前bean的所有依赖是否已被创建,如果创建了(即发生循环依赖)会抛出异常。只有在单例情况下才会尝试解决循环依赖。
在spring中解决循环依赖只对单例有效,而对于prototype的bean,spring没有好的解决办法,唯一要做的就是抛出异常

在单例模式中Spring通过缓存来解决循环依赖,而在原型模式中,由于每次调用都会创建一个对象,所以对象数量是不可控的,且每一个prototype都需要是全新的,因而无法进行缓存,所以Spring没有处理原型模式下的循环依赖。

仔细思考一下,其实prototype的循环引用其实不一定是有意义的。

参考:https://blog.csdn.net/f641385712/article/details/92801300

上一篇 下一篇

猜你喜欢

热点阅读