在执行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实例;如果sharedInstance是FactoryBean类型的,则需调用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 > <property name="id" value="test"></property> <property name="name" value="parent"></property> </bean> <bean > <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(java.lang.String, org.springframework.beans.factory.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(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
这里会调用resolveBeforeInstantiation方法,在注释中的意思是给后置处理器返回一个代理对象,但一般情况下在此次是不会返回代理对象的,不论是使用JDK代理还是Cglib代理,前提条件需要有一个Bean实例,而此时的Bean实例并没有创建,代理对象并不会生成,这里只是将用户定义的切面信息进行缓存;
之后执行doCreateBean方法,创建Bean实例的流程在这里;
AbstractAutowireCapableBeanFactory#doCreateBean
调用createBeanInstance方法,使用合适的实例化策略创建实例;
AbstractAutowireCapableBeanFactory#createBeanInstance根据@Autowried自动注入/调用无参构造器创建,进行相应的处理;
- instantiateBean 调用无参数的构造器进行创建对象;
- autowireConstructor @Autowired自动注入,调用构造器注入;
注:bean的实例是是通过反射创建;
Spring中有三级缓存,用于解决属性赋值的循环依赖;
此时创建出来的Bean没有进行属性赋值的,属于早期对象,isSingleton表示是否为单例,allowCircularReferences默认为true,isSingletonCurrentlyInCreation表示当前beanName的Bean正在创建;
符合条件则调用addSingletonFactory方法,该方法把早期对象包装成一个ObjectFactory暴露到三级缓存中;
调用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进行对象初始化;
AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
invokeAwareMethods会将实现了XXXAware接口进行方法的回调,invokeInitMethods方法会将实现InitializingBean接口方法进行回调,applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization则会对BeanPostProcessor接口申明的方法进行回调;
xxxAware接口的调用;
调用registerDisposableBeanIfNecessary方法,注册销毁Bean的接口DisposableBean,当Bean生命周期结束时会对该接口的destroy方法进行回调;
AbstractBeanFactory#getBean(java.lang.String)的大致流程图
单例Bean创建大致流程图
Bean生命周期大致流程图
根据BeanFactory的注释可以看到一个标准bean的生命周期,如下: