Spring bean的加载过程

本文详细探讨了Spring Bean的加载过程,从doGetBean方法的解析开始,涉及bean的缓存检查、父容器查找、bean定义处理和依赖管理。讨论了循环依赖问题,包括构造器循环依赖和setter循环依赖的解决机制。深入分析了doCreateBean方法中的bean生命周期,包括Bean的建立、属性注入、初始化回调方法以及BeanPostProcessor的作用。最后,文章提到了Bean生命周期的应用,以自定义注解实现Logger为例。
摘要由CSDN通过智能技术生成

一、问题引入:

ctx.getBean方法是如何运作的 ?

public  static  void  main(String[] args) {
     ApplicationContext ctx =  new  ClassPathXmlApplicationContext( "spring.xml" ); // 读取bean.xml中的内容
     TestBean testBean = ctx.getBean( "testBean" ,TestBean. class );
     System.out.println(testBean.getA());
}

二、doGetBean加载概述:

 

 

 

AbstractBeanFactory.doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)

 doGetBean()

1. 首先这里会将传入的beanName进行转化。代码如下所示:

final  String beanName = transformedBeanName(name):
protected  String transformedBeanName(String name) {
    return  canonicalName(BeanFactoryUtils.transformedBeanName(name));
}

转化有两个步骤,首先处理beanName为&XXX的格式,这里表示要取指定name的factoryBean。在这里先把&符号取消,先获取bean再处理。然后,针对bean的alias机制,这里传入的参数可能是一个bean别名,那么我们先获取这个bean的主要id,只需要根据id值取bean就可以了。

2.判断这个beanName的bean是否已经创建了【缓存获取】,代码如下:

/** Cache of singleton objects: bean name --> bean instance */
private  final  Map<String, Object> singletonObjects =  new  ConcurrentHashMap<String, Object>( 64 );
 
/** 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 */
private  final  Map<String, Object> earlySingletonObjects =  new  HashMap<String, Object>( 16 );
protected  Object getSingleton(String beanName,  boolean  allowEarlyReference) { 
         //检查缓存中是否存在实例 
         Object singletonObject =  this .singletonObjects.get(beanName); 
         if  (singletonObject ==  null ) { 
             //如果为空,则锁定全局变量并进行处理 
             synchronized  ( this .singletonObjects) { 
                 //如果此bean正在加载则不处理 
                 singletonObject =  this .earlySingletonObjects.get(beanName); 
                 if  (singletonObject ==  null  && allowEarlyReference) { 
                     //当某些方法需要提前初始化的时候则会调用addSingletonFactory方法将对应的ObjectFactory初始化策略存储在singletonFactories 
                     ObjectFactory singletonFactory =  this .singletonFactories.get (beanName); 
                     if  (singletonFactory !=  null ) { 
                         //调用预先设定的getObject方法 
                         singletonObject = singletonFactory.getObject(); 
                         //记录在缓存中,earlySingletonObjects和singletonFactories互斥 
                         this .earlySingletonObjects.put(beanName, singletonObject); 
                         this .singletonFactories.remove(beanName); 
                    
                
            
        
         return  (singletonObject != NULL_OBJECT ? singletonObject :  null ); 
     }


3.尝试从父容器中寻找,这一点和classLoader的父子加载机制相同。代码如下所示

BeanFactory parentBeanFactory = getParentBeanFactory();
if  (parentBeanFactory !=  null  && !containsBeanDefinition(beanName)) {
     // Not found -> check parent.
     String nameToLookup = originalBeanName(name);
     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);
     }
}

4.获取bean定义信息

final  RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);

这里会对bean信息进行一个封装,主要是处理parent信息和scope信息。将这些信息进行一次定义融合,同时接下来对bean进行检查。

5. 处理依赖信息,这里会针对xml定义中的depends-on进行处理。如下面代码所示:

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

6.调用getSingleton(String beanName, ObjectFactory singletonFactory),最终会触发objectFactory的getObject方法,即调用createBean(beanName, mbd, args)方法进行bean创建。代码如下所示:

// Create bean instance.
if  (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName,  new  ObjectFactory<Object>() {
     @Override
     public  Object getObject()  throws  BeansException {
         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);
}

三、循环依赖

       循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方,比如CircleA引用CircleB,CircleB引用CircleC,CircleC引用CircleA,则它们最终反映为一个环。此处不是循环调用,循环调用是方法之间的环调用。

 Spring容器循环依赖包括构造器循环依赖和setter循环依赖,那Spring容器如何解决循环依赖呢?

 

  • 构造器循环依赖:表示通过构造器注入构成的循环依赖,此依赖是无法解决的,只能抛出BeanCurrentlyInCreationException异常表示循环依赖。

 

如在创建CircleA类时,构造器需要CircleB类,那将去创建CircleB,在创建CircleB类时又发现需要CircleC类,则又去创建CircleC,最终在创建CircleC时发现又需要CircleA;从而形成一个环,没办法创建。

 

Spring容器将每一个正在创建的Bean 标识符放在一个“当前创建Bean池”中,Bean标识符在创建过程中将一直保持在这个池中,因此如果在创建Bean过程中发现自己已经在“当前创建Bean池”里时将抛出BeanCurrentlyInCreationException异常表示循环依赖;而对于创建完毕的Bean将从“当前创建Bean池”中清除掉。

 

  • setter循环依赖:表示通过setter注入方式构成的循环依赖。

 

对于setter注入造成的依赖是通过Spring容器提前暴露刚完成构造器注入但未完成其他步骤(如setter注入)的Bean来完成的,而且只能解决单例作用域的Bean循环依赖。

四、doCreateBean()-bean生命周期

AbstractAutowireCapableBeanFactory.createBean(String, RootBeanDefinition, Object[])

在进入doCreateBean()之前,执行一次如下的操作:

// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbd
if  (bean !=  null ) {
     return  bean;
}

我的理解:主要是处理实现了InstantiationAwareBeanPostProcessor的后置处理器,相当于给我们开发者一个在bean真正创建的的机会进行代理逃逸或者对配置做一些修改。

bean真正执行的函数:doCreateBean:

1:Bean的建立:

容器寻找Bean的定义信息并将其实例化。

(1)基于FactoryBean实例化

(2)基于构造器的实例化。

  • 默认构造器或者是不带lookup或者replace配置方法时实例化使用java反射直接实现
  • 否则使用动态代理将配置特性加入bean中

插一个过程,处理循环依赖的提前曝光策略:

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,  new  ObjectFactory<Object>() {
                 @Override
                 public  Object getObject()  throws  BeansException {
                     return  getEarlyBeanReference(beanName, mbd, bean);
                 }
             });
         }


2:属性注入:

使用依赖注入,Spring按照Bean定义信息配置Bean所有属性。

populateBean(beanName, mbd, instanceWrapper);

插一个过程:initializeBean():

后面的3-8的步骤均在此方法中调用:

protected  Object initializeBean( final  String beanName,  final  Object bean, RootBeanDefinition mbd) {
     if  (System.getSecurityManager() !=  null ) {
         AccessController.doPrivileged( new  PrivilegedAction<Object>() {
             @Override
             public  Object run() {
                 invokeAwareMethods(beanName, bean);
                 return  null ;
             }
         }, getAccessControlContext());
     }
     else  {
         invokeAwareMethods(beanName, bean);
     }
 
     Object wrappedBean = bean;
     if  (mbd ==  null  || !mbd.isSynthetic()) {
         wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
     }
 
     try  {
         invokeInitMethods(beanName, wrappedBean, mbd);
     }
     catch  (Throwable ex) {
         throw  new  BeanCreationException(
                 (mbd !=  null  ? mbd.getResourceDescription() :  null ),
                 beanName,  "Invocation of init method failed" , ex);
     }
 
     if  (mbd ==  null  || !mbd.isSynthetic()) {
         wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
     }
     return  wrappedBean;
}


3:BeanNameAware的setBeanName():

如果Bean类有实现org.springframework.beans.BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。

4:BeanFactoryAware的setBeanFactory():

如果Bean类有实现org.springframework.beans.factory.BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身。

5:BeanPostProcessors的ProcessBeforeInitialization()

如果有org.springframework.beans.factory.config.BeanPostProcessors和Bean关联,那么其postProcessBeforeInitialization()方法将被将被调用。

6:initializingBean的afterPropertiesSet():

如果Bean类已实现org.springframework.beans.factory.InitializingBean接口,则执行他的afterProPertiesSet()方法

7:Bean定义文件中定义init-method:

可以在Bean定义文件中使用"init-method"属性设定方法名称例如:

如果有以上设置的话,则执行到这个阶段,就会执行initBean()方法

8:BeanPostProcessors的ProcessaAfterInitialization()

如果有任何的BeanPostProcessors实例与Bean实例关联,则执行BeanPostProcessors实例的ProcessaAfterInitialization()方法

五、Bean生命周期应用

自定义注解实现Logger

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值