Loading

Spring执行Bean创建流程分析

在执行DefaultListableBeanFactory#preInstantiateSingletons方法时会创建非懒加载的单例Bean,这个创建过程是通过调用AbstractBeanFactory#getBean(java.lang.String)创建的;

下面分析AbstractBeanFactory#getBean(java.lang.String)的执行流程;

 

AbstractBeanFactory#getBean(java.lang.String)

该方法是一个空壳方法,没有任何的实现逻辑 真正的逻辑调用在doGetBean()中,该接口是实现了BeanFactory的getBean(String name)接口;

 

AbstractBeanFactory#doGetBean

通过调用transformedBeanName获取beanName这里传入进来的name可能是别名alias,也有可能是工厂bean的name,所以在这里需要统一转换成beanName

通过调用getSingleton尝试从缓存中获取对象sharedInstance 

判断条件(sharedInstance ! = null && args == null)是否成立,如果成立,则调用getObjectForBeanInstance返回Bean实例;如果sharedInstance是普通的单例bean,getObjectForBeanInstance方法会直接返回bean实例;如果sharedInstanceFactoryBean类型的,则需调用getObject工厂方法获取真正的bean实例

注:Spring会为FactoryBean接口的实例创建两种对象,一种是FactoryBean实例本身的对象,FactoryBean实例本身的对象是存储在一级缓存中,而另一种是FactoryBean#getObject创建的对象,该对象是存在factoryBeanObjectCache中; 

 

条件(sharedInstance ! = null && args == null)不成立,则走下面的逻辑;

调用isPrototypeCurrentlyInCreation(beanName)判断是否存在多例对象(prototype:多例对象,IOC容器启动的时候,IOC容器启动并不会去调用方法创建对象, 而是每次获取的时候才会调用方法创建对象)的循环依赖,存在则抛出BeanCurrentlyInCreationException异常;

注:Spring解决了单例对象的属性注入的循环依赖,而构造器注入的循环依赖没有解决; 

 

创建两个循环依赖的多例Bean,如下:

查看代码

@Scope ( "prototype" )
@Component
public class InstanceC {
    private final static Log LOG = LogFactory.getLog(InstanceC. class );

    @Autowired
    private InstanceD instanceD;

//  @Autowired
//  public InstanceC(InstanceD instanceD) {
//      this.instanceD = instanceD;
//  }

    public InstanceC() {
        LOG.info( "InstanceC constructor" );
    }

    public void invoke() {
        LOG.info( "C invoke..." );
    }

    public InstanceD getInstanceD() {
        return instanceD;
    }
}

  

查看代码
 @Scope ( "prototype" )
@Component
public class InstanceD {
    private final static Log LOG = LogFactory.getLog(InstanceD. class );

    @Autowired
    private InstanceC instanceC;

//  @Autowired
//  public InstanceD(InstanceC instanceC) {
//      this.instanceC = instanceC;
//  }

    public void invoke() {
        LOG.info( "D invoke..." );
    }

    public InstanceC getInstanceC() {
        return instanceC;
    }
}

  

异常如下:

getParentBeanFactory()判断AbstractBeanFacotry工厂是否有父工厂(一般情况下是没有父工厂因为AbstractBeanFactory直接是抽象类,不存在父工厂),存在则根据父工厂调用getBean,一般情况下,只有Spring 和SpringMvc整合的时才会有父子容器的概念;

调用getMergedLocalBeanDefinition(beanName)会合并父BeanDefinition和子BeanDefinition,子BeanDefinition会覆盖父BeanDefintion;

测试如下:

查看代码
 public class ComponentC {
    private String name;
    private String id;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this .name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this .id = id;
    }

    @Override
    public String toString() {
        return "ComponentC{" +
                "name='" + name + '\ '' +
                ", id='" + id + '\ '' +
                '}' ;
    }
}

 

查看代码
 public class ComponentD {
    private String name;
    private String id;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this .name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this .id = id;
    }

    @Override
    public String toString() {
        return "ComponentC{" +
                "name='" + name + '\ '' +
                ", id='" + id + '\ '' +
                '}' ;
    }
}

  

bean.xml

查看代码
 <?xml version= "1.0" encoding= "UTF-8" ?>
<beans xmlns= "http://www.springframework.org/schema/beans"
       xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation= "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" >

    <bean  id = "componentC" class= "org.example.component.ComponentC" abstract= "true" >
        <property name= "id" value= "test" >< /property >
        <property name= "name" value= "parent" >< /property >
    < /bean >

    <bean  id = "componentD" class= "org.example.component.ComponentD" parent= "componentC" >
        <property name= "name" value= "son" >< /property >
<!--     <property name= "id" value= "componentD" >< /property >-->
    < /bean >
< /beans >

  

查看代码
 @Test
public void xmlConfigTest() {
    ApplicationContext context =  new ClassPathXmlApplicationContext( "bean.xml" );
    System.out.println(context.getBean( "componentD" ));
}

 

执行结果如下:

 

将bean.xml中注释打开,执行结果如下:

 

处理Bean加载依赖顺序,如果dependsOn不为空,则调用registerDependentBean(dep, beanName)注册该Bean的依赖项,getBean(dep)优先创建依赖的对象;

 

测试如下:

查看代码
 public class DependsA {
    private final static Log LOG = LogFactory.getLog(DependsA. class );

    public DependsA() {
        LOG.info( "DependsA" );
    }
}

  

查看代码
 public class DependsB {
    private final static Log LOG = LogFactory.getLog(DependsB. class );

    public DependsB() {
        LOG.info( "DependsB" );
    }
}

  

查看代码
 @Configuration
public class DependOnConfig {

    @Bean
    public DependsA dependsA() {
        return new DependsA();
    }

    @Bean
    @DependsOn (value = { "dependsA" })
    public DependsB dependsB() {
        return new DependsB();
    }
}

 

查看代码
 @Test
public void dependsOnTest() {
    AnnotationConfigApplicationContext context =  new AnnotationConfigApplicationContext(DependOnConfig. class );
}

  

执行结果如下:

 

之后根据BeanDefinition的scope类型创建Bean实例,下面分析scope为singleton类型的Bean实例创建;

调用getSingleton(beanName, new ObjectFactory<Object>(){})获取单例对象;只有sharedInstance是FactoryBean类型的,getObjectForBeanInstance才需要调用getObject获取对象的实例,否则是直接返回的;

 

DefaultSingletonBeanRegistry#getSingleton(String, ObjectFactory<?>)

首先从单例缓存池中获取Bean实例,如果Bean实例存在,则将对象返回,否则执行创建对象的逻辑;

调用beforeSingletonCreation方法标记当前bean要被创建,该方法在Bean创建前调用的;

singletonsCurrentlyInCreation 在这里会把beanName加入进来,标记该Bean正在创建,当第二次进入时,如果出现singletonsCurrentlyInCreation 添加失败,这个时候出现了循环依赖(构造器注入);

ObjectFactory类型的入参singletonFactory调用getObject方法,用于返回一个Bean的实例;

在最后会调用afterSingletonCreation将singletonsCurrentlyInCreation标记正在创建的bean从集合中移除,addSingleton将创建的单实例Bean加入到缓存中;

至此,单实例Bean被Spring缓存起来了;

 

需要注意的是,在Spring中,只有单例对象才会被缓存起来,而多例对象(scope为prototype类型的实例)是不会执行getSingle的逻辑,也就是执行完创建后的实例不会被缓存起来,每对scope为prototype类型的实例调用一次getBean,实例都会被创建; 

而getSingleton方法的其中一个入参是一个函数接口,执行创建的逻辑在createBean方法;

 

AbstractAutowireCapableBeanFactory#createBean

这里会调用resolveBeforeInstantiation方法,在注释中的意思是给后置处理器返回一个代理对象,但一般情况下在此次是不会返回代理对象的,不论是使用JDK代理还是Cglib代理,前提条件需要有一个Bean实例,而此时的Bean实例并没有创建,代理对象并不会生成,这里只是将用户定义的切面信息进行缓存;

 之后执行doCreateBean方法,创建Bean实例的流程在这里;

 

AbstractAutowireCapableBeanFactory#doCreateBean

调用createBeanInstance方法

调用createBeanInstance方法,使用合适的实例化策略创建实例;

AbstractAutowireCapableBeanFactory#createBeanInstance根据@Autowried自动注入/调用无参构造器创建,进行相应的处理;

  • instantiateBean 调用无参数的构造器进行创建对象;
  • autowireConstructor @Autowired自动注入,调用构造器注入;

注:bean的实例是是通过反射创建;

 

Spring中有三级缓存

Spring中有三级缓存,用于解决属性赋值的循环依赖;

此时创建出来的Bean没有进行属性赋值的,属于早期对象,isSingleton表示是否为单例,allowCircularReferences默认为true,isSingletonCurrentlyInCreation表示当前beanName的Bean正在创建;

符合条件则调用addSingletonFactory方法,该方法把早期对象包装成一个ObjectFactory暴露到三级缓存中;

调用populateBean进行属性赋值

调用populateBean进行属性赋值,对象的属性注入是通过后置处理器处理的;

如@Autowired的属性注入是通过AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues处理的;

伪代码如下:

查看代码
 @Component
public class ComponentA {
    private final static Log LOG = LogFactory.getLog(ComponentA. class );

    @Autowired
    private ComponentB componentB;

    public ComponentA() {
        LOG.info( "ComponentA constructor" );
    }
}

@Component
public class ComponentB {
    private final static Log LOG = LogFactory.getLog(ComponentB. class );

    public ComponentB() {
        LOG.info( "ComponentB constructor" );
    }
}

上面的伪代码ComponentB是ComponentA的字段值,需要自动注入;

后置处理器最终会根据注入的类型执行下面的注入逻辑,如字段的注入,执行AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject方法;

最终通过org.springframework.beans.factory.config.DependencyDescriptor#resolveCandidate获取需要依赖的Bean的实例对象,其实该方法是通过BeanFactory#getBean获取Bean的实例对象;

调用initializeBean进行对象初始化

调用initializeBean进行对象初始化;

AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)

invokeAwareMethods会将实现了xxxAware接口(非忽略的自动自动装配接口)进行方法的回调,invokeInitMethods方法会将实现InitializingBean接口方法进行回调,applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization则会对BeanPostProcessor接口申明的方法进行回调;

 

xxxAware接口的调用

AbstractApplicationContext#prepareBeanFactory

这些接口是Spring框架提供的一种机制,用于在bean实例化之后,自动将一些特定的依赖注入到bean中;这些接口提供了访问Environment,EmbeddedValueResolver,ResourceLoader, ApplicationEventPublisher,MessageSource和ApplicationContext等Spring的核心组件的能力;然而,在prepareBeanFactory方法中,Spring容器尚未完全初始化,因此无法提供这些依赖的实例;因此,为了避免在不完全初始化的情况下注入依赖,Spring选择忽略这些自动装配的依赖接口;

BeanNameAware, BeanClassLoaderAware和BeanFactoryAware这些接口的实现不依赖于其他Spring核心组件的完全初始化,因此可以在prepareBeanFactory方法中处理,与其他依赖接口不同,它们的注入不会受到未完全初始化的影响;
 

非忽略自动装配xxxAware接口的调用;

其中ApplicationContextAwareProcessor#applyBeanPostProcessorsBeforeInitialization执行会执行被忽略的自动装配xxxAware接口的方法;

调用registerDisposableBeanIfNecessary方法

调用registerDisposableBeanIfNecessary方法,注册销毁Bean的接口DisposableBean,当Bean生命周期结束时会对该接口的destroy方法进行回调; 

 

AbstractBeanFactory#getBean(java.lang.String)的大致流程图

 

单例Bean创建大致流程图

 

Bean生命周期大致流程图

根据BeanFactory的注释可以看到一个标准bean的生命周期,如下:

 

posted @ 2021-10-03 18:00  街头卖艺的肖邦  阅读(288)  评论(0)    收藏  举报