阶段4:BeanDefinition合并阶段
合并阶段是做什么的?
可能我们定义bean的时候有父子bean关系,此时子BeanDefinition中的信息是不完整的,比如设置属性的时候配置在父BeanDefinition中,此时子BeanDefinition中是没有这些信息的,需要将子bean的BeanDefinition和父bean的BeanDefinition进行合并,得到最终的一个RootBeanDefinition,合并之后得到的RootBeanDefinition包含bean定义的所有信息,包含了从父bean中继继承过来的所有信息,后续bean的所有创建工作就是依靠合并之后BeanDefinition来进行的。
合并BeanDefinition会使用下面这个方法:
org.springframework.beans.factory.support.AbstractBeanFactory#getMergedBeanDefinition
bean定义可能存在多级父子关系,合并的时候进进行递归合并,最终得到一个包含完整信息的RootBeanDefinition
案例
类:
public class LessonModel {
//课程名称
private String name;
//课时
private int lessonCount;
//描述信息
private String description;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLessonCount() {
return lessonCount;
}
public void setLessonCount(int lessonCount) {
this.lessonCount = lessonCount;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "LessonModel{" +
"name='" + name + '\'' +
", lessonCount=" + lessonCount +
", description='" + description + '\'' +
'}';
}
}
xml配置:
<bean id="lesson1" class="com.spring.beanLife1.LessonModel"/>
<bean id="lesson2" parent="lesson1">
<property name="name" value="spring高手系列"/>
<property name="lessonCount" value="100"/>
</bean>
<bean id="lesson3" parent="lesson2">
<property name="description" value="一起学spring"/>
</bean>
测试:
@Test
public void testBeanMerge(){
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
String path = "classpath:/bean/beans1.xml";
xmlBeanDefinitionReader.loadBeanDefinitions(path);
//遍历容器中注册的所有bean信息
for (String beanName : beanFactory.getBeanDefinitionNames()) {
//通过bean名称获取原始的注册的BeanDefinition信息
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
//获取合并之后的BeanDefinition信息
BeanDefinition mergedBeanDefinition = beanFactory.getMergedBeanDefinition(beanName);
System.out.println(beanName);
System.out.println("解析xml过程中注册的beanDefinition:" + beanDefinition);
System.out.println("beanDefinition中的属性信息" + beanDefinition.getPropertyValues());
System.out.println("合并之后得到的mergedBeanDefinition:" + mergedBeanDefinition);
System.out.println("mergedBeanDefinition中的属性信息" + mergedBeanDefinition.getPropertyValues());
System.out.println("---------------------------");
}
}
结果:
lesson1
解析xml过程中注册的beanDefinition:Generic bean: class [com.spring.beanLife1.LessonModel]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [bean/beans1.xml]
beanDefinition中的属性信息PropertyValues: length=0
合并之后得到的mergedBeanDefinition:Root bean: class [com.spring.beanLife1.LessonModel]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [bean/beans1.xml]
mergedBeanDefinition中的属性信息PropertyValues: length=0
---------------------------
lesson2
解析xml过程中注册的beanDefinition:Generic bean with parent 'lesson1': class [null]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [bean/beans1.xml]
beanDefinition中的属性信息PropertyValues: length=2; bean property 'name'; bean property 'lessonCount'
合并之后得到的mergedBeanDefinition:Root bean: class [com.spring.beanLife1.LessonModel]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [bean/beans1.xml]
mergedBeanDefinition中的属性信息PropertyValues: length=2; bean property 'name'; bean property 'lessonCount'
---------------------------
lesson3
解析xml过程中注册的beanDefinition:Generic bean with parent 'lesson2': class [null]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [bean/beans1.xml]
beanDefinition中的属性信息PropertyValues: length=1; bean property 'description'
合并之后得到的mergedBeanDefinition:Root bean: class [com.spring.beanLife1.LessonModel]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [bean/beans1.xml]
mergedBeanDefinition中的属性信息PropertyValues: length=3; bean property 'name'; bean property 'lessonCount'; bean property 'description'
---------------------------
从输出的结果中可以看到,合并之前,BeanDefinition是不完整的,比lesson2和lesson3中的class是null,属性信息也不完整,但是合并之后这些信息都完整了。
合并之前是GenericBeanDefinition类型的,合并之后得到的是RootBeanDefinition类型的。
获取lesson3合并的BeanDefinition时,内部会递归进行合并,先将lesson1和lesson2合并,然后将lesson2再和lesson3合并,最后得到合并之后的BeanDefinition。
后面的阶段将使用合并产生的RootBeanDefinition。
阶段5:Bean Class加载阶段
这个阶段就是将bean的class名称转换为Class类型的对象。
BeanDefinition中有个Object类型的字段:beanClass
private volatile Object beanClass;
用来表示bean的class对象,通常这个字段的值有2种类型,一种是bean对应的Class类型的对象,另一种是bean对应的Class的完整类名,第一种情况不需要解析,第二种情况:即这个字段是bean的类名的时候,就需要通过类加载器将其转换为一个Class对象。
此时会对阶段4中合并产生的RootBeanDefinition中的beanClass进行解析,将bean的类名转换为Class对象,然后赋值给beanClass字段。
源码位置:
org.springframework.beans.factory.support.AbstractBeanFactory#resolveBeanClass
上面得到了Bean Class对象以及合并之后的BeanDefinition,下面就开始进入实例化这个对象的阶段了。
阶段6:Bean实例化阶段
分两个小阶段
- bean实例化前操作
- bean实例化操作
Bean实例化前操作
先来看一下DefaultListableBeanFactory,这个类中有个非常非常重要的字段:
private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();
是一个BeanPostProcessor类型的集合
BeanPostProcessor是一个接口,还有很多子接口,这些接口中提供了很多方法,spring在bean生命周期的不同阶段,会调用上面这个列表中的BeanPostProcessor中的一些方法,来对生命周期进行扩展,bean生命周期中的所有扩展点都是依靠这个集合中的BeanPostProcessor来实现的,所以如果大家想对bean的生命周期进行干预,这块一定要掌握好。
注意:本文中很多以BeanPostProcessor结尾的,都实现了BeanPostProcessor接口,有些是直接实现的,有些是实现了它的子接口。
bean实例化之前会调用一段代码:
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
这段代码在bean实例化之前给开发者留了个口子,开发者自己可以在这个地方直接去创建一个对象作为bean实例,而跳过spring内部实例化bean的过程。
上面代码中轮询beanPostProcessors列表,如果类型是InstantiationAwareBeanPostProcessor, 尝试调用InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation获取bean的实例对象,如果能够获取到,那么将返回值作为当前bean的实例,那么spring自带的实例化bean的过程就被跳过了。
postProcessBeforeInstantiation方法如下:
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
案例
@Test
public void testBeforeInstantiation(){
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
//添加一个BeanPostProcessor:InstantiationAwareBeanPostProcessor
factory.addBeanPostProcessor(new InstantiationAwareBeanPostProcessor() {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("调用postProcessBeforeInstantiation()");
//发现类型是Car类型的时候,硬编码创建一个Car对象返回
if (beanClass == Car.class) {
Car car = new Car();
car.setName("保时捷");
return car;
}
return null;
}
});
//定义一个car bean,车名为:奥迪
AbstractBeanDefinition carBeanDefinition = BeanDefinitionBuilder.
genericBeanDefinition(Car.class).
addPropertyValue("name", "奥迪"). //@2
getBeanDefinition();
factory.registerBeanDefinition("car", carBeanDefinition);
//从容器中获取car这个bean的实例,输出
System.out.println(factory.getBean("car"));
}
运行输出:
调用postProcessBeforeInstantiation()
Car{name='保时捷'}
bean定义的时候,名称为:奥迪,最后输出的为:保时捷
定义和输出不一致的原因是因为我们在InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation方法中手动创建了一个实例直接返回了,而不是依靠spring内部去创建这个实例。
Bean实例化操作
这个过程是干什么?
这个过程会通过反射来调用bean的构造器来创建bean的实例。
具体需要使用哪个构造器,spring为开发者提供了一个接口,允许开发者自己来判断用哪个构造器。
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
if (ctors != null) {
return ctors;
}
}
}
会调用SmartInstantiationAwareBeanPostProcessor接口的determineCandidateConstructors方法,这个方法会返回候选的构造器列表,也可以返回空
这个方法有个比较重要的实现类:AutowiredAnnotationBeanPostProcessor。
可以将@Autowired标注的方法作为候选构造器返回
案例
下面我们来个案例,自定义一个注解,当构造器被这个注解标注的时候,让spring自动选择使用这个构造器创建对象。
自定义一个注解:
@Target(ElementType.CONSTRUCTOR)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAutowried {
}
public class Person {
private String name;
private Integer age;
public Person() {
System.out.println("调用 Person()");
}
@MyAutowried
public Person(String name) {
System.out.println("调用 Person(String name)");
this.name = name;
}
public Person(String name, Integer age) {
System.out.println("调用 Person(String name, int age)");
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class MySmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
@Override
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
if (declaredConstructors != null) {
//获取有@MyAutowried注解的构造器列表
List<Constructor<?>> collect = Arrays.stream(declaredConstructors).
filter(constructor -> constructor.isAnnotationPresent(MyAutowried.class)).
collect(toList());
Constructor[] constructors = collect.toArray(new Constructor[collect.size()]);
return constructors.length != 0 ? constructors : null;
} else {
return null;
}
}
}
测试方法:
@Test
public void testAutoConstructors() {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
MySmartInstantiationAwareBeanPostProcessor postProcessor = new MySmartInstantiationAwareBeanPostProcessor();
factory.addBeanPostProcessor(postProcessor);
factory.registerBeanDefinition("name",
BeanDefinitionBuilder.
genericBeanDefinition(String.class).
addConstructorArgValue("spring").
getBeanDefinition());
factory.registerBeanDefinition("age",
BeanDefinitionBuilder.
genericBeanDefinition(Integer.class).
addConstructorArgValue(30).
getBeanDefinition());
factory.registerBeanDefinition("person",
BeanDefinitionBuilder.
genericBeanDefinition(Person.class)
.getBeanDefinition());
Person person = factory.getBean("person", Person.class);
System.out.println(person);
}
运行结果:
调用 Person(String name)
Person{name='spring', age=null}
到目前为止bean实例化阶段结束了,继续进入后面的阶段。
阶段7:合并后的BeanDefinition处理
这块的源码如下:
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
}
会调用MergedBeanDefinitionPostProcessor接口的postProcessMergedBeanDefinition方法
void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);
第一个参数为beanDefinition,表示合并之后的RootBeanDefinition,我们可以在这个方法内部对合并之后的BeanDefinition进行再次处理
postProcessMergedBeanDefinition有2个实现类:
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
在 postProcessMergedBeanDefinition 方法中对 @Autowired、@Value 标注的方法、字段进行缓存
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
在 postProcessMergedBeanDefinition 方法中对 @Resource 标注的字段、@Resource 标注的方法、 @PostConstruct 标注的字段、 @PreDestroy标注的方法进行缓存
阶段8:Bean属性设置阶段
属性设置阶段分为3个小的阶段
- 实例化后阶段
- Bean属性赋值前阶段
- bean属性赋值
实例化后阶段
会调用InstantiationAwareBeanPostProcessor接口的postProcessAfterInstantiation这个方法,调用逻辑如下:
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
postProcessAfterInstantiation方法返回false的时候,Bean属性赋值,后续的Bean属性赋值前处理都会被跳过了。
来看个案例,案例中返回false,跳过属性的赋值操作。
public class UserModel {
private String name;
private int age;
@Override
public String toString() {
return "UserModel{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return false;
}
}
测试:
@Test
public void testAssignment() {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
MyInstantiationAwareBeanPostProcessor postProcessor = new MyInstantiationAwareBeanPostProcessor();
factory.addBeanPostProcessor(postProcessor);
factory.registerBeanDefinition("userModel",
BeanDefinitionBuilder.genericBeanDefinition(com.spring.beanLife3.UserModel.class)
.addPropertyValue("name", "spring")
.addPropertyValue("age", "5")
.getBeanDefinition()
);
com.spring.beanLife3.UserModel userModel = factory.getBean("userModel", com.spring.beanLife3.UserModel.class);
System.out.println(userModel);
}
输出结果:
UserModel{name='null', age=0}
Bean属性赋值前阶段
这个阶段会调用InstantiationAwareBeanPostProcessor接口的postProcessProperties方法,调用逻辑:
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
从上面可以看出,如果InstantiationAwareBeanPostProcessor中的postProcessProperties和postProcessPropertyValues都返回空的时候,表示这个bean不需要设置属性,直接返回了,直接进入下一个阶段。
postProcessProperties有两个比较重要的实现类:
AutowiredAnnotationBeanPostProcessor在这个方法中对@Autowired、@Value标注的字段、方法注入值。
CommonAnnotationBeanPostProcessor在这个方法中对@Resource标注的字段和方法注入值。
来个案例,我们在案例中对pvs进行修改。
@Test
public void testPvs(){
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
factory.addBeanPostProcessor(new InstantiationAwareBeanPostProcessor() {
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if("userModel1".equals(beanName)){
if(null == pvs){
pvs = new MutablePropertyValues();
}
MutablePropertyValues mutablePropertyValues = (MutablePropertyValues) pvs;
mutablePropertyValues.addPropertyValue("name","spring");
mutablePropertyValues.addPropertyValue("age","5");
}
return null;
}
});
factory.registerBeanDefinition("userModel1",
BeanDefinitionBuilder.genericBeanDefinition(com.spring.beanLife3.UserModel.class)
.addPropertyValue("name", "audi")
.addPropertyValue("age", "10")
.getBeanDefinition()
);
factory.registerBeanDefinition("userModel2",
BeanDefinitionBuilder.genericBeanDefinition(com.spring.beanLife3.UserModel.class)
.addPropertyValue("name", "BMW")
.addPropertyValue("age", "20")
.getBeanDefinition()
);
for (String beanName : factory.getBeanDefinitionNames()) {
System.out.println(String.format("%s->%s", beanName, factory.getBean(beanName)));
}
}
运行结果:
userModel1->UserModel{name='spring', age=5}
16:37:39.190 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'userModel2'
userModel2->UserModel{name='BMW', age=20}
Bean属性赋值阶段
这个过程比较简单了,循环处理PropertyValues中的属性值信息,通过反射调用set方法将属性的值设置到bean实例中。
PropertyValues中的值是通过bean xml中property元素配置的,或者调用MutablePropertyValues中add方法设置的值。