在SpringBean的生命周期中,Bean的实例化阶段就是Spring将Bean给生产出来的这个过程,本文将对Bean的实例化过程进行概述。
简要来说,Spring首先通过输入流读取了Xml配置文件的信息,而后通过反射的方式将Bean实例化,但在这过程中,Spring是怎么做的,又做了什么,才是重点内容,接下来将展开描述该部分。
Bean实例化过程概览
- 读取Xml文件
- Spring将配置好的Bean的信息先封装为BeanDefinition
- 将其存储在Map集合BeanDefinitionMap中
- Bean工厂后处理器(BeanFactoryPostProcessor)
- 循环遍历Map集合
- 获取到Bean的信息,通过反射的方式实例化Bean并注入属性
- Bean后处理器(BeanPostProcessor)
- 实例化阶段完成
BeanDefinition
BeanDefinition中封装了Bean的配置信息,包含类名、别名、作用域等Bean的属性。Spring将从配置文件中读取到的信息封装为BeanDefinition,将这些封装后的内容存放入BeanDefinitionMap集合中。这样在后续就可以通过遍历该集合,获取到各个Bean的信息,从而进行实例化、配置装配等操作。
后处理器
后处理器是Spring提供的,可以对IoC容器实现扩展的接口,这种接口分为两种,分别是Bean后处理器与Bean工厂后处理器,它们各自的执行时机不同,操作对象也不同。后处理器是一种特殊的Bean,只需要将其写入配置,即可在既定的时机执行操作。
BeanFactoryPostProcessor
该接口是Spring提供的可以对BeanFactory进行操作的后处理器,实现该接口并将其配置为Bean,即可在BeanDefinitionMap装配完成后,Bean实例化之前,执行其下的postProcessorBeanFactory方法。在该方法中,可以对容器进行操作,例如注册新的Bean等。
示例:
创建两个类,添加构造方法方便观察。
public class BeanA {
//构造方法
public BeanA() {
System.out.println("beanA实例化");
}
}
public class BeanB {
//构造方法
public BeanB() {
System.out.println("beanB实例化");
}
}
创建类实现BeanFactoryPostProcessor接口并重写方法。
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
/*
* 观察是否可以获取BeanDefinition
* 如果可以获取,则说明此时BeanDefinitionMap已装配完毕
*/
String beanA = beanFactory.getBeanDefinition("beanA").getBeanClassName();
String beanB = beanFactory.getBeanDefinition("beanB").getBeanClassName();
System.out.println(beanA);
System.out.println(beanB);
//为方便观察,输出语句
System.out.println("Bean工厂后处理器");
}
}
将这些类在Xml文件中配置为Bean。
<?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工厂后处理器配置为Bean -->
<bean class="com.stlg.MyBeanFactoryPostProcessor"/>
<bean id="beanA" class="com.stlg.bean.BeanA"/>
<bean id="beanB" class="com.stlg.bean.BeanB"/>
</beans>
在测试类中加载容器,观察执行结果。
可以观察到,在后处理器执行时,已经可以正常获取到BeanDefinition了,这说明BeanDefinition已经装配进BeanDefinitionMap集合中了,而Bean工厂后处理器结束后beanA与beanB逐个被实例化。这说明Bean工厂后处理器是在BeanDefinition装配完毕后,Bean实例化之前执行的。
该接口下还有一个值得注意的子接口BeanDefinitionRegistryPostProcessor,这个接口的实现类下的postProcessBeanDefinitionRegistry方法会在postProcessorBeanFactory方法前执行,在该方法中可以直接进行Bean的注册。
示例:
创建类BeanC,同样添加构造方法。
创建类并实现BeanDefinitionRegistryPostProcessor接口,重写方法。
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
//注册BeanC
registry.registerBeanDefinition("beanC", new RootBeanDefinition("com.stlg.bean.BeanC"));
System.out.println("注册BeanC");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("Bean工厂后处理器(注册)");
}
}
将其配置为Bean。
<?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工厂后处理器配置为Bean -->
<bean class="com.stlg.MyBeanFactoryPostProcessor"/>
<bean class="com.stlg.MyBeanDefinitionRegistryPostProcessor"/>
<bean id="beanA" class="com.stlg.bean.BeanA"/>
<bean id="beanB" class="com.stlg.bean.BeanB"/>
</beans>
再次查看运行结果,观察BeanFactoryPostProcessor与BeanDefinitionRegistryPostProcessor的执行时机。
可以清楚地看到,BeanC虽然没有被配置到Xml文件中,但在后处理器中仍然注册且能够获取到。
观察可以发现,BeanDefinitionRegistryPostProcessor下的方法与BeanFactoryPostProcessor下的方法执行顺序为:
- postProcessBeanDefinitionRegistry
- postProcessBeanFactory---BeanDefinitionRegistryPostProcessor
- postProcessBeanFactory---BeanFactoryPostProcessor
Bean实例化阶段
在Bean工厂后处理器的操作结束后,也就代表着Bean的初始配置信息已经确定,接下来就要进行实例化阶段了。在这时候Spring会对BeanDefinitionMap容器进行遍历,获取到每个BeanDefinition并抽取出Bean的信息,依次通过反射进行实例化并进行属性注入,但此时的Bean仅仅是一个半成品,要进入下一个阶段对Bean进行完善和强化。
BeanPostProcessor
该接口是Spring提供的可以对实例化后的Bean进行操作的后处理器,实现该接口并将其配置为Bean,即可在Bean被实例化后,放入容器前,进行一系列操作。该接口下有两个方法:postProcessBeforeInitialization与postProcessAfterInitialization,顾名思义,两个方法执行时机分别为初始化操作前后。
在循环遍历BeanDefinitionMap中,每将一个Bean实例化后,都会执行这个后处理器对Bean进行强化等操作。在后处理器期间会执行Bean自定义初始化操作。这一系列操作完成后,才算一个完整的Bean,可以放入容器中。
示例:
为BeanA与BeanB添加初始化方法。
public class BeanA {
private String desc;
//构造方法
public BeanA() {
System.out.println("beanA实例化");
}
//初始化方法
public void init() {
System.out.println("beanA初始化");
}
}
public class BeanB {
//构造方法
public BeanB() {
System.out.println("beanB实例化");
}
//初始化方法
public void init() {
System.out.println("beanB初始化");
}
}
创建类并实现BeanPostProcessor接口,重写方法。
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//输出语句方便观察执行时机
System.out.println("beforeInitialization...");
//暂时不做操作直接返回,下同
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("afterInitialization...");
return 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后处理器配置为Bean -->
<bean class="com.stlg.MyBeanPostProcessor"/>
<bean id="beanA" class="com.stlg.bean.BeanA" init-method="init"/>
<bean id="beanB" class="com.stlg.bean.BeanB" init-method="init"/>
</beans>
运行并查看结果,观察各方法运行时机。
可以发现一个Bean在实例化后会执行后处理器的beforeInitialization方法,而后进行初始化操作,最后执行afterInitialization方法。执行完成后才会进行下一个Bean的流程。
总结
首先我们写在Xml文件中的配置会被Spring使用输入流读取,Spring将读取到的Bean的配置信息封装为BeanDefinition并放入Map集合BeanDefinitionMap中。
而后Bean工厂后处理器开始执行,此阶段可对BeanFactory进行强化或注册新的Bean等其他操作(如果实现BeanDefinitionRegistryPostProcessor接口会优先执行)。
接着Spring将循环从BeanDefinitionMap中获取BeanDefinition,提取配置信息并进行实例化。
在每个Bean被实例化后,均开始执行Bean后处理器,此阶段可以对Bean进行强化修改等操作。且在Bean初始化前后均可进行操作。
在执行完毕后,一个完整的Bean被放入容器,继续进行下一个Bean的完善,直到所有的Bean均执行完毕。