14.spring系列- bean生命周期-2

阶段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实例化阶段

分两个小阶段

  1. bean实例化前操作
  2. 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个小的阶段

  1. 实例化后阶段
  2. Bean属性赋值前阶段
  3. 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方法设置的值。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值