Spring系列三之Bean实例化流程

2024-09-05 20:03:52 浏览数 (2)

1 Bean实例化

紧接着上文,Spring的Bean实例化发生在刷新IOC容器阶段的倒数第二步finishBeanFactoryInitialization(beanFactory),最终在该方法中调用DefaultListable.preInstantiateSingletons()方法实例化所有非懒加载的Bean实例,代码如下

代码语言:javascript复制
public void preInstantiateSingletons() throws BeansException {
    ......
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

    // 加载所有非懒加载的Bean
    for (String beanName : beanNames) {
       RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
       if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
          if (isFactoryBean(beanName)) {
             Object bean = getBean(FACTORY_BEAN_PREFIX   beanName);
             if (bean instanceof FactoryBean) {
                // 如果是FactoryBean,先判断是不是需要在此处实例化,需要才实例化
                FactoryBean<?> factory = (FactoryBean<?>) bean;
                boolean isEagerInit;
                if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                   isEagerInit = AccessController.doPrivileged(
                         (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
                         getAccessControlContext());
                }
                else {
                   isEagerInit = (factory instanceof SmartFactoryBean &&
                         ((SmartFactoryBean<?>) factory).isEagerInit());
                }
                if (isEagerInit) {
                   getBean(beanName);
                }
             }
          }
          else {
             getBean(beanName);
          }
       }
    }

    // 所有非懒加载Bean实例加载完成之后,Bean如果实现了SmartInitializingSingleton,调用其回调方法
    // afterSingletonsInstantiated(),这个特性在xxl-job执行器的初始化中有使用过
    for (String beanName : beanNames) {
       Object singletonInstance = getSingleton(beanName);
       if (singletonInstance instanceof SmartInitializingSingleton) {
          StartupStep smartInitialize = getApplicationStartup().start("spring.beans.smart-initialize")
                .tag("beanName", beanName);
          SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
          if (System.getSecurityManager() != null) {
             AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                smartSingleton.afterSingletonsInstantiated();
                return null;
             }, getAccessControlContext());
          }
          else {
             smartSingleton.afterSingletonsInstantiated();
          }
          smartInitialize.end();
       }
    }
}

代码也比较清晰,第一步实例化所有非懒加载的实例,其核心就是调用getBean(beanName)方法,第二步如果Bean实现了SmartInitializingSingleton接口,调用其回调方法afterSingletonsInstantiated(),而getBean方法是调用AbstractBeanFactory.doGetBean方法,doGetBean方法的代码比较复杂,以一个循环依赖且是单例模式的例子来梳理代码的流程(A依赖B,B依赖A,A,B都是单例模式),如下只保留了核心代码的流程

代码语言:javascript复制
protected <T> T doGetBean(
       String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
       throws BeansException {

    String beanName = transformedBeanName(name);
    Object beanInstance;
   
    // 第一步,先从缓存中获取Bean实例
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
       ......
       beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    } else {
       ......
       StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
             .tag("beanName", name);
       try {
          ......
          RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
          checkMergedBeanDefinition(mbd, beanName, args);

          // 第二步,检查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 {
                   getBean(dep);
                }
                catch (NoSuchBeanDefinitionException ex) {
                   throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                         "'"   beanName   "' depends on missing bean '"   dep   "'", ex);
                }
             }
          }
          // 第三步,创建Bean
          if (mbd.isSingleton()) {
             sharedInstance = getSingleton(beanName, () -> {
                try {
                   return createBean(beanName, mbd, args);
                } catch (BeansException ex) {
                   destroySingleton(beanName);
                   throw ex;
                }
             });
             beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
          } else if (mbd.isPrototype()) {
             ......
          } else {
             ......
          }
       } catch (BeansException ex) {
          ......
       } finally {
          beanCreation.end();
       }
    }
    return adaptBeanInstance(name, beanInstance, requiredType);
}

下面就一步一步来分析

第一步:首先调用getSingleton(beanName)从缓存中获取A实例,如下

代码语言:javascript复制
public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // Quick check for existing instance without full singleton lock
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
       singletonObject = this.earlySingletonObjects.get(beanName);
       if (singletonObject == null && allowEarlyReference) {
          synchronized (this.singletonObjects) {
             // Consistent creation of early reference within full singleton lock
             singletonObject = this.singletonObjects.get(beanName);
             if (singletonObject == null) {
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null) {
                   ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                   if (singletonFactory != null) {
                      singletonObject = singletonFactory.getObject();
                      this.earlySingletonObjects.put(beanName, singletonObject);
                      this.singletonFactories.remove(beanName);
                   }
                }
             }
          }
       }
    }
    return singletonObject;
}

从上面的代码中可以看出,Spring用了三级缓存来处理

第一级缓存singletonObjects,是一个Map<String, Object>结构,key是BeanName,value是Instance,先从singletonObjects中获取实例,如果实例不为空,直接返回,所以这里先实例化A的时候,A为空且不在创建当中(创建中的实例用singletonsCurrentlyInCreation这个Set结构来保存),直接返回null

第二步:检查依赖,第一步返回null,则走到创建Bean的流程,创建Bean之前,首先要检查Bean依赖于哪些Bean,这里的依赖并不是指@Autowired这类属性注入的依赖关系,而是@DependsOn这类注解配置的依赖,如果有依赖,则先实例化DependsOn的Bean,如果没有就开始第三步创建Bean

第三步:创建Bean,调用了getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法,代码如下

代码语言:javascript复制
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    ......
    synchronized (this.singletonObjects) {
       // 还是先从第一级缓存singletonObjects中获取实例,不为null直接返回
       Object singletonObject = this.singletonObjects.get(beanName);
       if (singletonObject == null) {
          // 在创建的过程当中,如果Bean正处于销毁中,则抛出异常
          if (this.singletonsCurrentlyInDestruction) {
             throw new BeanCreationNotAllowedException(beanName,
                   "Singleton bean creation not allowed while singletons of this factory are in destruction "  
                   "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
          }
          ......
          // 执行创建之前的操作,其实就是将该Bean标记为创建中的状态,也就是将BeanName放入到上面提到过的
          // singletonsCurrentlyInCreation这个Set结构中
          beforeSingletonCreation(beanName);
          boolean newSingleton = false;
          boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
          if (recordSuppressedExceptions) {
             this.suppressedExceptions = new LinkedHashSet<>();
          }
          try {
             // 通过singletonFactory创建Bean
             singletonObject = singletonFactory.getObject();
             newSingleton = true;
          }
          catch (IllegalStateException ex) {
             ......
          } catch (BeanCreationException ex) {
             ......
          } finally {
             ......
             // 执行创建之后的操作,即将BeanName从singletonsCurrentlyInCreation这个Set结构中删除
             afterSingletonCreation(beanName);
          }
          if (newSingleton) {
             // 将生成的Bean放入到第一级缓存singletonObjects当中,并且删除第二级和第三级缓存
             addSingleton(beanName, singletonObject);
          }
       }
       return singletonObject;
    }
}

说明都放在了上面的代码注释中,下面再来看看singletonFactory创建Bean的过程,是通过调用createBean(beanName, mbd, args)方法创建,代码如下

代码语言:javascript复制
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
       throws BeanCreationException {
    ......
    RootBeanDefinition mbdToUse = mbd;
    ......
    try {
       // 执行Bean实例化之前的操作,即依次执行InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法
       Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
       // 如果在postProcessBeforeInstantiation方法中返回了实例,直接返回
       if (bean != null) {
          return bean;
       }
    } catch (Throwable ex) {
       ......
    }
    try {
       // 创建实例
       Object beanInstance = doCreateBean(beanName, mbdToUse, args);
       if (logger.isTraceEnabled()) {
          logger.trace("Finished creating instance of bean '"   beanName   "'");
       }
       return beanInstance;
    }
    catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
       ......
    } catch (Throwable ex) {
       ......
    }
}

从上面的代码中可以看出createBean的方法比较简单,就是在创建实例之前先依次执行InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法,然后再调用doCreateBean(beanName, mbdToUse, args)方法创建实例,看看doCreateBean方法

代码语言:javascript复制
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
       throws BeanCreationException {

    // 1.实例化bean.
    BeanWrapper instanceWrapper = null;
    ......
    if (instanceWrapper == null) {
       instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    ......

    // 2.封装一个Bean创建工厂放入第三级缓存singletonFactories
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
          isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
       if (logger.isTraceEnabled()) {
          logger.trace("Eagerly caching bean '"   beanName  
                "' to allow for resolving potential circular references");
       }
       addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    Object exposedObject = bean;
    try {
       // 3.设置Bean属性
       populateBean(beanName, mbd, instanceWrapper);
       // 4.初始化Bean
       exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    catch (Throwable ex) {
       if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
          throw (BeanCreationException) ex;
       }
       else {
          throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
       }
    }
    // 5.设置exposedObject 
    if (earlySingletonExposure) {
		Object earlySingletonReference = getSingleton(beanName, false);
		if (earlySingletonReference != null) {
			if (exposedObject == bean) {
				exposedObject = earlySingletonReference;
			}
		    ......
		}
	}
    return exposedObject;
}

doCreateBean方法的逻辑也比较清晰,主要有以下的步骤,依次来看看

1.实例化bean,这一步没啥好说的,主要就是创建一个Bean实例

2.如果允许循环依赖并且是在创建中的状态,就封装一个Bean创建工厂放入第三级缓存singletonFactories,singletonFactories也是一个Map结构,这个创建工厂并不是创建Bean的实例(第一步已经做了),而是在第一步创建的Bean的基础上做一层或者多层封装

3.设置Bean属性,主要通过populateBean(beanName, mbd, instanceWrapper)方法来执行,代码如下

代码语言:javascript复制
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    ......
    // 首先执行InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation方法
    // 即在Bean实例化之后需要执行的方法
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
       for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
          if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
             return;
          }
       }
    }

    ......

    // 再次执行InstantiationAwareBeanPostProcessor的各种后置处理方法
    // @AutoWire注解就是在此处通过AutowiredAnnotationBeanPostProcessor这个类处理的
    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
    PropertyDescriptor[] filteredPds = null;
    if (hasInstAwareBpps) {
       if (pvs == null) {
          pvs = mbd.getPropertyValues();
       }
       for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
          PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
          if (pvsToUse == null) {
             if (filteredPds == null) {
                filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
             }
             pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
             if (pvsToUse == null) {
                return;
             }
          }
          pvs = pvsToUse;
       }
    }
    ......
}

由于A依赖B,所以在populateBean方法中又会重新调用doGetBean方法获取B的实例,在B实例的实例化过程中同样的逻辑重新执行一遍又到populateBean方法,由于B又依赖于A,所以在populateBean方法中又会去获取A实例,所有这里我们再来看看getSingleton(beanName,true)方法,如下

代码语言:javascript复制
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // Quick check for existing instance without full singleton lock
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
       singletonObject = this.earlySingletonObjects.get(beanName);
       if (singletonObject == null && allowEarlyReference) {
          synchronized (this.singletonObjects) {
             // Consistent creation of early reference within full singleton lock
             singletonObject = this.singletonObjects.get(beanName);
             if (singletonObject == null) {
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null) {
                   ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                   if (singletonFactory != null) {
                      singletonObject = singletonFactory.getObject();
                      this.earlySingletonObjects.put(beanName, singletonObject);
                      this.singletonFactories.remove(beanName);
                   }
                }
             }
          }
       }
    }
    return singletonObject;
}

这里和第一次获取A的逻辑不同,这依次会走到第三级缓存singletonFactories这里,通过之前创建的工厂来生成A的实例,即通过getEarlyBeanReference(beanName, mbd, bean)方法来生成最终的A实例,如下

代码语言:javascript复制
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    Object exposedObject = bean;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
       for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
          exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
       }
    }
    return exposedObject;
}

这里就不得不提到AnnotationAwareAspectJAutoProxyCreator这个BeanPostProcessor了,如果我们的类有切面,就是通过AnnotationAwareAspectJAutoProxyCreator来生成的代理类,这样最终A的实例就生成了,最后再将A的创建工厂从第三级缓存singletonFactories中删除,再放入到第二级缓存earlySingletonObjects中,这样就完成了B实例中的A的依赖注入

4.初始化Bean

最后一步通过initializeBean(beanName, exposedObject, mbd)方法进行初始化,如下

代码语言:javascript复制
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    // 执行各种Aware接口的注入,这一步处理的Aware主要有BeanNameAware、BeanClassLoaderAware、
    // BeanFactoryAware
    if (System.getSecurityManager() != null) {
       AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
          invokeAwareMethods(beanName, bean);
          return null;
       }, getAccessControlContext());
    }
    else {
       invokeAwareMethods(beanName, bean);
    }
    // 执行BeanPostProcessor的postProcessBeforeInitialization方法
    // 即在初始化之前要执行的方法
    // 其中像@PostConstruct注解的方法就是在此处执行
    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
       wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
       // 执行初始化的方法,先执行InitializingBean的接口方法afterPropertiesSet,再执行配置的init方法
       invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
       throw new BeanCreationException(
             (mbd != null ? mbd.getResourceDescription() : null),
             beanName, "Invocation of init method failed", ex);
    }
    // 执行BeanPostProcessor的postProcessAfterInitialization
    // 即在初始化之后要执行的方法
    // 如果有切面,生成代理类也是在这个步骤处理
    if (mbd == null || !mbd.isSynthetic()) {
       wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

初始化完了之后,将BeanName从singletonsCurrentlyInCreation这个Set结构中删除,再将生成的Bean放入到第一级缓存singletonObjects当中,并且删除第二级和第三级缓存,这样B的实例就生成好了,B生成好了之后又回到A的populateBean方法就完成了A实例中的B的依赖注入

5.设置exposedObject

在B通过initializeBean方法完成初始化后返回的wrappedBean,如果有切面的话,其实返回的是代理对象,但是A对象的代理对象已经在B的实例化过程当中放到了earlySingletonObjects中,那么A在执行initializeBean方法时就不应该再去重新生成一个代理对象,而是应该从earlySingletonObjects中去取,然后直接赋值给exposedObject即可,这一步非常重要,不然会导致B中引用的A对象和singletonObjects中的A对象不是同一个对象,代码如下

代码语言:javascript复制
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
       Object cacheKey = getCacheKey(bean.getClass(), beanName);
       if (this.earlyProxyReferences.remove(cacheKey) != bean) {
          return wrapIfNecessary(bean, beanName, cacheKey);
       }
    }
    return bean;AnnotationAwareAspectJAutoProxyCreator
}

在initializeBean方法中的applyBeanPostProcessorsAfterInitialization方法中会调用AnnotationAwareAspectJAutoProxyCreator的父类AbstractAutoProxyCreator的postProcessAfterInitialization方法,在此方法中如果earlyProxyReferences中包含了该Bean,说明已经通过getEarlyBeanReference方法生成了代理类,这里就不会再执行wrapIfNecessary方法

文末尾记录一个常见的面试题,为什么Spring解决循环依赖是三级缓存,而不是二级缓存?

个人理解:二级缓存也能解决问题,但是要使用二级缓存解决循环依赖,意味着所有Bean在实例化后就要完成AOP代理(因为在Spring中如果有AOP,注入的都是代理对象)这样违背了Spring设计的原则,Spring在设计的时候就是使用AnnotationAwareAspectJAutoProxyCreator这个BeanPostProcessor在initializeBean的最后一步来完成AOP代理,而不是在实例化后就立马进行AOP代理,只有当确实有循环依赖时,才会提前生成代理对象

0 人点赞