Spring Bean生命周期详解

Spring bean生命周期13个环节

阶段1:Bean元信息配置阶段

阶段2:Bean元信息解析阶段

阶段3:将Bean注册到容器中

阶段4:BeanDefinition合并阶段

阶段5:Bean Class加载阶段

阶段6:Bean实例化阶段(2个小阶段)

  • Bean实例化前阶段

  • Bean实例化阶段

阶段7:合并后的BeanDefinition处理

阶段8:属性赋值阶段(3个小阶段)

  • Bean实例化后阶段

  • Bean属性赋值前阶段

  • Bean属性赋值阶段

阶段9:Bean初始化阶段(5个小阶段)

  • Bean Aware接口回调阶段

  • Bean初始化前阶段

  • Bean初始化阶段

  • Bean初始化后阶段

阶段10:所有单例bean初始化完成后阶段

阶段11:Bean的使用阶段

阶段12:Bean销毁前阶段

阶段13:Bean销毁阶段

阶段1:Bean元信息配置阶段

这个阶段主要是bean信息的定义阶段。

Bean信息定义4种方式
  • API的方式

  • Xml文件方式

  • properties文件的方式

  • 注解的方式

API的方式

先来说这种方式,因为其他几种方式最终都会采用这种方式来定义bean配置信息。

Spring容器启动的过程中,会将Bean解析成Spring内部的BeanDefinition结构。

不管是是通过xml配置文件的<Bean>标签,还是通过注解配置的@Bean,还是@Compontent标注的类,还是扫描得到的类,它最终都会被解析成一个BeanDefinition对象,最后我们的Bean工厂就会根据这份Bean的定义信息,对bean进行实例化、初始化等等操作。

你可以把BeanDefinition丢给Bean工厂,然后Bean工厂就会根据这个信息帮你生产一个Bean实例,拿去使用。

BeanDefinition里面里面包含了bean定义的各种信息,如:bean对应的class、scope、lazy信息、dependOn信息、autowireCandidate(是否是候选对象)、primary(是否是主要的候选者)等信息。

BeanDefinition是个接口,有几个实现类,看一下类图

BeanDefinition接口:bean定义信息接口

java 复制代码
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
 
    /**
     * 设置此bean的父bean名称(对应xml中bean元素的parent属性)
     */
    void setParentName(@Nullable String parentName);
 
    /**
     * 返回此bean定义时指定的父bean的名称
     */
    @Nullable
    String getParentName();
 
    /**
     * 指定此bean定义的bean类名(对应xml中bean元素的class属性)
     */
    void setBeanClassName(@Nullable String beanClassName);
 
    /**
     * 返回此bean定义的当前bean类名
     * 注意,如果子定义重写/继承其父类的类名,则这不一定是运行时使用的实际类名。此外,这可能只是调用工厂方法的类,或者在调用方法的工厂bean引用的情况下,它甚至可能是空的。因此,不要认为这是运行时的最终bean类型,而只将其用于单个bean定义级别的解析目的。
     */
    @Nullable
    String getBeanClassName();
 
    /**
     * 设置此bean的生命周期,如:singleton、prototype(对应xml中bean元素的scope属性)
     */
    void setScope(@Nullable String scope);
 
    /**
     * 返回此bean的生命周期,如:singleton、prototype
     */
    @Nullable
    String getScope();
 
    /**
     * 设置是否应延迟初始化此bean(对应xml中bean元素的lazy属性)
     */
    void setLazyInit(boolean lazyInit);
 
    /**
     * 返回是否应延迟初始化此bean,只对单例bean有效
     */
    boolean isLazyInit();
 
    /**
     * 设置此bean依赖于初始化的bean的名称,bean工厂将保证dependsOn指定的bean会在当前bean初始化之前先初始化好
     */
    void setDependsOn(@Nullable String... dependsOn);
 
    /**
     * 返回此bean所依赖的bean名称
     */
    @Nullable
    String[] getDependsOn();
 
    /**
     * 设置此bean是否作为其他bean自动注入时的候选者
     * autowireCandidate
     */
    void setAutowireCandidate(boolean autowireCandidate);
 
    /**
     * 返回此bean是否作为其他bean自动注入时的候选者
     */
    boolean isAutowireCandidate();
 
    /**
     * 设置此bean是否为自动注入的主要候选者
     * primary:是否为主要候选者
     */
    void setPrimary(boolean primary);
 
    /**
     * 返回此bean是否作为自动注入的主要候选者
     */
    boolean isPrimary();
 
    /**
     * 指定要使用的工厂bean(如果有)。这是要对其调用指定工厂方法的bean的名称。
     * factoryBeanName:工厂bean名称
     */
    void setFactoryBeanName(@Nullable String factoryBeanName);
 
    /**
     * 返回工厂bean名称(如果有)(对应xml中bean元素的factory-bean属性)
     */
    @Nullable
    String getFactoryBeanName();
 
    /**
     * 指定工厂方法(如果有)。此方法将使用构造函数参数调用,如果未指定任何参数,则不使用任何参数调用。该方法将在指定的工厂bean(如果有的话)上调用,或者作为本地bean类上的静态方法调用。
     * factoryMethodName:工厂方法名称
     */
    void setFactoryMethodName(@Nullable String factoryMethodName);
 
    /**
     * 返回工厂方法名称(对应xml中bean的factory-method属性)
     */
    @Nullable
    String getFactoryMethodName();
 
    /**
     * 返回此bean的构造函数参数值
     */
    ConstructorArgumentValues getConstructorArgumentValues();
 
    /**
     * 是否有构造器参数值设置信息(对应xml中bean元素的<constructor-arg />子元素)
     */
    default boolean hasConstructorArgumentValues() {
        return !getConstructorArgumentValues().isEmpty();
    }
 
    /**
     * 获取bean定义是配置的属性值设置信息
     */
    MutablePropertyValues getPropertyValues();
 
    /**
     * 这个bean定义中是否有属性设置信息(对应xml中bean元素的<property />子元素)
     */
    default boolean hasPropertyValues() {
        return !getPropertyValues().isEmpty();
    }
 
    /**
     * 设置bean初始化方法名称
     */
    void setInitMethodName(@Nullable String initMethodName);
 
    /**
     * bean初始化方法名称
     */
    @Nullable
    String getInitMethodName();
 
    /**
     * 设置bean销毁方法的名称
     */
    void setDestroyMethodName(@Nullable String destroyMethodName);
 
    /**
     * bean销毁的方法名称
     */
    @Nullable
    String getDestroyMethodName();
 
    /**
     * 设置bean的role信息
     */
    void setRole(int role);
 
    /**
     * bean定义的role信息
     */
    int getRole();
 
    /**
     * 设置bean描述信息
     */
    void setDescription(@Nullable String description);
 
    /**
     * bean描述信息
     */
    @Nullable
    String getDescription();
 
    /**
     * bean类型解析器
     */
    ResolvableType getResolvableType();
 
    /**
     * 是否是单例的bean
     */
    boolean isSingleton();
 
    /**
     * 是否是多列的bean
     */
    boolean isPrototype();
 
    /**
     * 对应xml中bean元素的abstract属性,用来指定是否是抽象的
     */
    boolean isAbstract();
 
    /**
     * 返回此bean定义来自的资源的描述(以便在出现错误时显示上下文)
     */
    @Nullable
    String getResourceDescription();
 
    @Nullable
    BeanDefinition getOriginatingBeanDefinition();
 
}

BeanDefinition接口上面还继承了2个接口:

  • AttributeAccessor

  • BeanMetadataElement

AttributeAccessor接口:属性访问接口

java 复制代码
public interface AttributeAccessor {
 
    /**
     * 设置属性->值
     */
    void setAttribute(String name, @Nullable Object value);
 
    /**
     * 获取某个属性对应的值
     */
    @Nullable
    Object getAttribute(String name);
 
    /**
     * 移除某个属性
     */
    @Nullable
    Object removeAttribute(String name);
 
    /**
     * 是否包含某个属性
     */
    boolean hasAttribute(String name);
 
    /**
     * 返回所有的属性名称
     */
    String[] attributeNames();
 
}

这个接口相当于key->value数据结构的一种操作,BeanDefinition继承这个,内部实际上是使用了LinkedHashMap来实现这个接口中的所有方法,通常我们通过这些方法来保存BeanDefinition定义过程中产生的一些附加信息。

BeanMetadataElement接口

java 复制代码
public interface BeanMetadataElement {
 
    @Nullable
    default Object getSource() {
        return null;
    }
 
}

BeanDefinition继承这个接口,getSource返回BeanDefinition定义的来源,比如我们通过xml定义BeanDefinition的,此时getSource就表示定义bean的xml资源;若我们通过api的方式定义BeanDefinition,我们可以将source设置为定义BeanDefinition时所在的类,出错时,可以根据这个来源方便排错。

RootBeanDefinition类:表示根bean定义信息

通常bean中没有父bean的就使用这种表示 或者合并后的bean定义

ChildBeanDefinition类:表示子bean定义信息

如果需要指定父bean的,可以使用ChildBeanDefinition来定义子bean的配置信息,里面有个parentName属性,用来指定父bean的名称。

GenericBeanDefinition类:通用的bean定义信息

既可以表示没有父bean的bean配置信息,也可以表示有父bean的子bean配置信息,这个类里面也有parentName属性,用来指定父bean的名称。

ConfigurationClassBeanDefinition类:表示通过配置类中@Bean方法定义bean信息

可以通过配置类中使用@Bean来标注一些方法,通过这些方法来定义bean,这些方法配置的bean信息最后会转换为ConfigurationClassBeanDefinition类型的对象

AnnotatedBeanDefinition接口:表示通过注解的方式定义的bean信息

里面有个方法

复制代码
AnnotationMetadata getMetadata();

用来获取定义这个bean的类上的所有注解信息。

BeanDefinitionBuilder:构建BeanDefinition的工具类

spring中为了方便操作BeanDefinition,提供了一个类:BeanDefinitionBuilder,内部提供了很多静态方法,通过这些方法可以非常方便的组装BeanDefinition对象,下面我们通过案例来感受一下。

案例1:组装一个简单的bean

java 复制代码
package bean.lifeCycle.phase1;

public class Car {
    private String name;

    public String getName() {
        return name;
    }

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

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

}

测试用例

java 复制代码
package bean.lifeCycle.phase1;

import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;

public class Test1 {
    // 组装一个简单的bean
    public static void main(String[] args) {
        //指定class
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(Car.class.getName());
        //获取BeanDefinition
        AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        System.out.println(beanDefinition);
        // 等效 <bean class="bean.lifeCycle.phase1.Car" />
    }
}

等效于

java 复制代码
<bean class="bean.lifeCycle.phase1.Car" />

运行输出

复制代码
Root bean: class [bean.lifeCycle.phase1.Car]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null

案例1:组装一个有属性的bean

java 复制代码
package bean.lifeCycle.phase1;

import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

public class Test2 {
    // 案例2:组装一个有属性的bean
    public static void main(String[] args) {
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(Car.class.getName());
        //设置普通类型属性
        beanDefinitionBuilder.addPropertyValue("name","audio");
        //获取BeanDefinition
        AbstractBeanDefinition carBeanDefinition = beanDefinitionBuilder.getBeanDefinition();
        System.out.println(carBeanDefinition);
        
        //创建spring容器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        //调用registerBeanDefinition向容器中注册bean 将carBeanDefinition这个bean配置信息注册到spring容器中,bean的名称为car
        factory.registerBeanDefinition("car",carBeanDefinition);
        Car bean = factory.getBean("car", Car.class); //@4
        System.out.println(bean);
    }
}

运行输出

Root bean: class bean.lifeCycle.phase1.Car; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null

13:58:31.137 main DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'car'
Car{name='audio'}

案例3:组装一个有依赖关系的bean

java 复制代码
package bean.lifeCycle.phase1;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

public class Test3 {
    // 组装一个有依赖关系的bean
    public static void main(String[] args) {
        // 先创建car这个BeanDefinition
        BeanDefinition carBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Car.class.getName())
                                                                .addPropertyValue("name", "奥迪").getBeanDefinition();
        //创建User这个BeanDefinition
        BeanDefinitionBuilder userDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(User.class.getName());
        userDefinitionBuilder.addPropertyValue("name","李二牛").addPropertyReference("myCar","car");
        AbstractBeanDefinition userDefinition = userDefinitionBuilder.getBeanDefinition();

        //创建spring容器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        //调用registerBeanDefinition向容器中注册bean
        factory.registerBeanDefinition("car",carBeanDefinition);
        factory.registerBeanDefinition("user",userDefinition);
        System.out.println(factory.getBean("car"));
        System.out.println(factory.getBean("user"));


        /*
        上面代码等效于
        <bean id="car" class="bean.lifeCycle.phase1.Car">
            <property name="name" value="奥迪"/>
        </bean>

        <bean id="user" class="bean.lifeCycle.phase1.User">
            <property name="name" value="李少斌"/>
            <property name="myCar" ref="car"/>
        </bean>
        */
    }
}

运行输出

14:02:13.882 main DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'car'

Car{name='奥迪'}

14:02:13.982 main DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'user'

User{name='李二牛', myCar=Car{name='奥迪'}}

案例4:来2个有父子关系的bean

java 复制代码
package bean.lifeCycle.phase1;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

public class Test4 {
    // 来2个有父子关系的bean
    public static void main(String[] args) {
        //先创建car这个BeanDefinition
        BeanDefinition carBeanDefinition1 = BeanDefinitionBuilder.
                genericBeanDefinition(Car.class).
                addPropertyValue("name", "保时捷").
                getBeanDefinition();

        BeanDefinition carBeanDefinition2 = BeanDefinitionBuilder.
                genericBeanDefinition(). //内部生成一个GenericBeanDefinition对象
                        setParentName("car1"). //@1:设置父bean的名称为car1
                        getBeanDefinition();


        //创建spring容器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        //调用registerBeanDefinition向容器中注册bean
        //注册car1->carBeanDefinition1
        factory.registerBeanDefinition("car1", carBeanDefinition1);
        //注册car2->carBeanDefinition2
        factory.registerBeanDefinition("car2", carBeanDefinition2);
        //从容器中获取car1
        System.out.println(String.format("car1->%s", factory.getBean("car1")));
        //从容器中获取car2
        System.out.println(String.format("car2->%s", factory.getBean("car2")));

    }

    /**
     * 等效于
     * <bean id="car1" class="bean.lifeCycle.phase1.Car">
     *     <property name="name" value="保时捷"/>
     * </bean>
     * <bean id="car2" parent="car1" />
     */
}

运行输出

14:03:33.335 main DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'car1'

car1->Car{name='保时捷'}

14:03:33.426 main DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'car2'

car2->Car{name='保时捷'}

案例5:通过api设置(Map、Set、List)属性

java 复制代码
package bean.lifeCycle.phase1;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.*;

import java.util.Arrays;

public class Test5 {
    // 下面我们采用纯api的方式实现,如下

    /**
     * 有几点需要说一下:
     * RuntimeBeanReference:用来表示bean引用类型,类似于xml中的ref
     * ManagedList:属性如果是List类型的,t需要用到这个类进行操作,这个类继承了ArrayList
     * ManagedSet:属性如果是Set类型的,t需要用到这个类进行操作,这个类继承了LinkedHashSet
     * ManagedMap:属性如果是Map类型的,t需要用到这个类进行操作,这个类继承了LinkedHashMap
     * 上面也就是这几个类结合的结果。
     *
     */

    public static void main(String[] args) {
        //定义car1
        BeanDefinition car1 = BeanDefinitionBuilder.
                genericBeanDefinition(Car.class).
                addPropertyValue("name", "奥迪").
                getBeanDefinition();
        //定义car2
        BeanDefinition car2 = BeanDefinitionBuilder.
                genericBeanDefinition(Car.class).
                addPropertyValue("name", "保时捷").
                getBeanDefinition();

        //定义CompositeObj这个bean
        //创建stringList这个属性对应的值
        ManagedList<String> stringList = new ManagedList<>();
        stringList.addAll(Arrays.asList("java高并发系列", "mysql系列", "maven高手系列"));

        //创建carList这个属性对应的值,内部引用其他两个bean的名称[car1,car2]
        ManagedList<RuntimeBeanReference> carList = new ManagedList<>();
        carList.add(new RuntimeBeanReference("car1"));
        carList.add(new RuntimeBeanReference("car2"));

        //创建stringList这个属性对应的值
        ManagedSet<String> stringSet = new ManagedSet<>();
        stringSet.addAll(Arrays.asList("java高并发系列", "mysql系列", "maven高手系列"));

        //创建carSet这个属性对应的值,内部引用其他两个bean的名称[car1,car2]
        ManagedList<RuntimeBeanReference> carSet = new ManagedList<>();
        carSet.add(new RuntimeBeanReference("car1"));
        carSet.add(new RuntimeBeanReference("car2"));

        //创建stringMap这个属性对应的值
        ManagedMap<String, String> stringMap = new ManagedMap<>();
        stringMap.put("系列1", "java高并发系列");
        stringMap.put("系列2", "Maven高手系列");
        stringMap.put("系列3", "mysql系列");

        ManagedMap<String, RuntimeBeanReference> stringCarMap = new ManagedMap<>();
        stringCarMap.put("car1", new RuntimeBeanReference("car1"));
        stringCarMap.put("car2", new RuntimeBeanReference("car2"));


        //下面我们使用原生的api来创建BeanDefinition
        GenericBeanDefinition compositeObj = new GenericBeanDefinition();
        compositeObj.setBeanClassName(CompositeObj.class.getName());
        compositeObj.getPropertyValues().add("name", "路人甲Java").
                add("salary", 50000).
                add("car1", new RuntimeBeanReference("car1")).
                add("stringList", stringList).
                add("carList", carList).
                add("stringSet", stringSet).
                add("carSet", carSet).
                add("stringMap", stringMap).
                add("stringCarMap", stringCarMap);

        //将上面bean 注册到容器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        factory.registerBeanDefinition("car1", car1);
        factory.registerBeanDefinition("car2", car2);
        factory.registerBeanDefinition("compositeObj", compositeObj);

        //下面我们将容器中所有的bean输出
        for (String beanName : factory.getBeanDefinitionNames()) {
            System.out.println(String.format("%s->%s", beanName, factory.getBean(beanName)));
        }

    }
}

先用xml来定义一个CompositeObj的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="car1" class="bean.lifeCycle.phase1.Car">
        <property name="name" value="奥迪"/>
    </bean>

    <bean id="car2" class="bean.lifeCycle.phase1.Car">
        <property name="name" value="保时捷"/>
    </bean>

    <bean id="compositeObj" class="bean.lifeCycle.phase1.CompositeObj">
    <property name="name" value="路人甲Java"/>
    <property name="salary" value="50000"/>
    <property name="car1" ref="car1"/>
    <property name="stringList">
        <list>
            <value>java高并发系列</value>
            <value>mysql系列</value>
            <value>maven高手系列</value>
        </list>
    </property>
    <property name="carList">
        <list>
            <ref bean="car1"/>
            <ref bean="car2"/>
        </list>
    </property>
    <property name="stringSet">
        <set>
            <value>java高并发系列</value>
            <value>mysql系列</value>
            <value>maven高手系列</value>
        </set>
    </property>
    <property name="carSet">
        <set>
            <ref bean="car1"/>
            <ref bean="car2"/>
        </set>
    </property>
    <property name="stringMap">
        <map>
            <entry key="系列1" value="java高并发系列"/>
            <entry key="系列2" value="Maven高手系列"/>
            <entry key="系列3" value="mysql系列"/>
        </map>
    </property>
    <property name="stringCarMap">
        <map>
            <entry key="car1" value-ref="car1"/>
            <entry key="car2" value-ref="car2"/>
        </map>
    </property>
    </bean>

</beans>

运行结果:

14:09:12.679 main DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'car1'

car1->Car{name='奥迪'}

14:09:12.774 main DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'car2'

car2->Car{name='保时捷'}

14:09:12.775 main DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'compositeObj'

compositeObj->CompositeObj{name='路人甲Java', salary=50000, car1=Car{name='奥迪'}, stringList=java高并发系列, mysql系列, maven高手系列, carList=Car{name='奥迪'}, Car{name='保时捷'}, stringSet=java高并发系列, mysql系列, maven高手系列, carSet=Car{name='奥迪'}, Car{name='保时捷'}, stringMap={系列1=java高并发系列, 系列2=Maven高手系列, 系列3=mysql系列}, stringCarMap={car1=Car{name='奥迪'}, car2=Car{name='保时捷'}}}

Process finished with exit code 0

Xml文件方式

这种方式大家也比较熟悉,即通过xml的方式来定义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-4.3.xsd">
 
    <bean id="bean名称" class="bean完整类名"/>
 
</beans>
properties文件的方式
XML 复制代码
employee.(class)=MyClass       // 等同于:<bean class="MyClass" />
employee.(abstract)=true       // 等同于:<bean abstract="true" />
employee.group=Insurance       // 为属性设置值,等同于:<property name="group" value="Insurance" />
employee.usesDialUp=false      // 为employee这个bean中的usesDialUp属性设置值,等同于:等同于:<property name="usesDialUp" value="false" />
 
salesrep.(parent)=employee     // 定义了一个id为salesrep的bean,指定父bean为employee,等同于:<bean id="salesrep" parent="employee" />
salesrep.(lazy-init)=true      // 设置延迟初始化,等同于:<bean lazy-init="true" />
salesrep.manager(ref)=tony     // 设置这个bean的manager属性值,是另外一个bean,名称为tony,等同于:<property name="manager" ref="tony" />
salesrep.department=Sales      // 等同于:<property name="department" value="Sales" />
 
techie.(parent)=employee       // 定义了一个id为techie的bean,指定父bean为employee,等同于:<bean id="techie" parent="employee" />
techie.(scope)=prototype       // 设置bean的作用域,等同于<bean scope="prototype" />
techie.manager(ref)=jeff       // 等同于:<property name="manager" ref="jeff" />
techie.department=Engineering  // <property name="department" value="Engineering" />
techie.usesDialUp=true         // <property name="usesDialUp" value="true" />
 
ceo.$0(ref)=secretary          // 设置构造函数第1个参数值,等同于:<constructor-arg index="0" ref="secretary" />
ceo.$1=1000000                 // 设置构造函数第2个参数值,等同于:<constructor-arg index="1" value="1000000" />
注解的方式

常见的2种:

  1. 类上标注@Compontent注解来定义一个bean

  2. 配置类中使用@Bean注解来定义bean

小结

Bean注册者只识别BeanDefinition对象,不管什么方式最后都会将这些bean定义的信息转换为BeanDefinition对象,然后注册到spring容器中。

阶段2:Bean元信息解析阶段

Bean元信息的解析就是将各种方式定义的bean配置信息解析为BeanDefinition对象。

Bean元信息的解析主要有3种方式
  1. xml文件定义bean的解析

  2. properties文件定义bean的解析

  3. 注解方式定义bean的解

XML方式解析:XmlBeanDefinitionReader

Spring中提供了一个类XmlBeanDefinitionReader,将xml中定义的bean解析为BeanDefinition对象。

直接来看案例代码

来一个bean xml配置文件

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="car" class="bean.lifeCycle.phase2.Car">
        <property name="name" value="奥迪"/>
    </bean>

    <bean id="car1" class="bean.lifeCycle.phase2.Car">
        <property name="name" value="保时捷"/>
    </bean>

    <bean id="car2" parent="car1"/>

    <bean id="user" class="bean.lifeCycle.phase2.User">
        <property name="name" value="路人甲Java"/>
        <property name="car" ref="car1"/>
    </bean>

</beans>

将bean xml解析为BeanDefinition对象

java 复制代码
public class Test1 {
     //  * xml方式bean配置信息解析
    public static void main(String[] args) {
        //定义一个spring容器,这个容器默认实现了BeanDefinitionRegistry,所以本身就是一个bean注册器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        //定义一个xml的BeanDefinition读取器,需要传递一个BeanDefinitionRegistry(bean注册器)对象
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(factory);
        //指定bean xml配置文件的位置
        String location = "classpath:carDefinition.xml";
        //通过XmlBeanDefinitionReader加载bean xml文件,然后将解析产生的BeanDefinition注册到容器容器中
        int countBean = xmlBeanDefinitionReader.loadBeanDefinitions(location);
        System.out.println(String.format("共注册了 %s 个bean", countBean));
        //打印出注册的bean的配置信息
        for (String beanName : factory.getBeanDefinitionNames()) {
            //通过名称从容器中获取对应的BeanDefinition信息
            BeanDefinition beanDefinition = factory.getBeanDefinition(beanName);
            //获取BeanDefinition具体使用的是哪个类
            String beanDefinitionClassName = beanDefinition.getClass().getName();
            //通过名称获取bean对象
            Object bean = factory.getBean(beanName);
            //打印输出
            System.out.println(beanName + ":");
            System.out.println("    beanDefinitionClassName:" + beanDefinitionClassName);
            System.out.println("    beanDefinition:" + beanDefinition);
            System.out.println("    bean:" + bean);
        }

    }
}

上面注释比较详细,这里就不解释了。

注意一点:创建XmlBeanDefinitionReader的时候需要传递一个bean注册器(BeanDefinitionRegistry),解析过程中生成的BeanDefinition会丢到bean注册器中。

运行输出:

上面的输出认真看一下,这几个BeanDefinition都是GenericBeanDefinition这种类型的,也就是说xml中定义的bean被解析之后都是通过GenericBeanDefinition这种类型表示的。

Properties文件定义bean的解析:PropertiesBeanDefinitionReader

spring中提供了一个类PropertiesBeanDefinitionReader,将xml中定义的bean解析为BeanDefinition对象,过程和xml的方式类似。

下面通过properties文件的方式实现上面xml方式定义的bean。

来个properties文件:beans.properties

java 复制代码
car.(class)=bean.lifeCycle.phase2.Car
car.name= ??

car1.(class)=bean.lifeCycle.phase2.Car
car1.name= ???
car2.(parent)=car1

user.(class)=bean.lifeCycle.phase2.User
user.name= ???Java
user.car(ref)=car

将bean properties文件解析为BeanDefinition对象

java 复制代码
public class Test2 {
    // 将bean properties文件解析为BeanDefinition对象
    public static void main(String[] args) {
        //定义一个spring容器,这个容器默认实现了BeanDefinitionRegistry,所以本身就是一个bean注册器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

        //定义一个properties的BeanDefinition读取器,需要传递一个BeanDefinitionRegistry(bean注册器)对象
        PropertiesBeanDefinitionReader propertiesBeanDefinitionReader = new PropertiesBeanDefinitionReader(factory);

        //指定bean xml配置文件的位置
        String location = "classpath:beans.properties";
        //通过PropertiesBeanDefinitionReader加载bean properties文件,然后将解析产生的BeanDefinition注册到容器容器中
        int countBean = propertiesBeanDefinitionReader.loadBeanDefinitions(location);
        System.out.println(String.format("共注册了 %s 个bean", countBean));

        //打印出注册的bean的配置信息
        for (String beanName : factory.getBeanDefinitionNames()) {
            //通过名称从容器中获取对应的BeanDefinition信息
            BeanDefinition beanDefinition = factory.getBeanDefinition(beanName);
            //获取BeanDefinition具体使用的是哪个类
            String beanDefinitionClassName = beanDefinition.getClass().getName();
            //通过名称获取bean对象
            Object bean = factory.getBean(beanName);
            //打印输出
            System.out.println(beanName + ":");
            System.out.println("    beanDefinitionClassName:" + beanDefinitionClassName);
            System.out.println("    beanDefinition:" + beanDefinition);
            System.out.println("    bean:" + bean);
        }

    }
}

运行输出:

输出和xml方式输出基本上一致。

properties方式使用起来并不是太方便,所以平时我们很少看到有人使用。

注解方式:PropertiesBeanDefinitionReader

注解的方式定义的bean,需要使用AnnotatedBeanDefinitionReader 这个类来进行解析,方式也和上面2种方式类似,直接来看案例。

通过注解来标注2个类

Sevice1

java 复制代码
package bean.lifeCycle.phase2;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Primary
@Lazy
public class Service1 {
}

这个类上面使用了3个注解,这些注解前面都介绍过,可以用来配置bean的信息

上面这个bean是个多例的。

Service2

java 复制代码
package bean.lifeCycle.phase2;

import org.springframework.beans.factory.annotation.Autowired;

public class Service2 {

    @Autowired
    private Service1 service1; //@1   @1:标注了@Autowired,说明需要注入这个对象

    @Override
    public String toString() {
        return "Service2{" +
                "service1=" + service1 +
                '}';
    }
}

注解定义的bean解析为BeanDefinition,如下:

java 复制代码
public class Test3 {
    // 注解方式:AnnotatedBeanDefinitionReader
    public static void main(String[] args) {
        //定义一个spring容器,这个容器默认实现了BeanDefinitionRegistry,所以本身就是一个bean注册器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

        //定义一个注解方式的BeanDefinition读取器,需要传递一个BeanDefinitionRegistry(bean注册器)对象
        AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(factory);
        annotatedBeanDefinitionReader.register(Service1.class, Service2.class);
        //打印出注册的bean的配置信息

//        factory.getBeansOfType(BeanPostProcessor.class).values().forEach(factory::addBeanPostProcessor); // @1


        for (String beanName : new String[]{"service1", "service2"}) {
            //通过名称从容器中获取对应的BeanDefinition信息
            BeanDefinition beanDefinition = factory.getBeanDefinition(beanName);
            //获取BeanDefinition具体使用的是哪个类
            String beanDefinitionClassName = beanDefinition.getClass().getName();
            //通过名称获取bean对象
            Object bean = factory.getBean(beanName);
            //打印输出
            System.out.println(beanName + ":");
            System.out.println("    beanDefinitionClassName:" + beanDefinitionClassName);
            System.out.println("    beanDefinition:" + beanDefinition);
            System.out.println("    bean:" + bean);
        }
    }

    /**
     * 输出中可以看出service1这个bean的beanDefinition中lazyInit确实为true,
     * primary也为true,scope为prototype,说明类Service1注解上标注3个注解信息被解析之后放在了beanDefinition中。
     * 注意下:最后一行中的service1为什么为null,不是标注了@Autowired么?
     * 这个地方提前剧透一下,看不懂的没关系,这篇文章都结束之后,就明白了。
     * 调整一下上面的代码,加上下面@1这行代码,如下:
     */

运行输出

输出中可以看出service1这个bean的beanDefinition中lazyInit确实为true,primary也为true,scope为prototype,说明类Service1注解上标注3个注解信息被解析之后放在了beanDefinition中。

注意下:最后一行中的service1为什么为null,不是标注了@Autowired么?

这个地方提前剧透一下,看不懂的没关系,这篇文章都结束之后,就明白了。

调整一下上面的代码,加上下面@1这行代码,如下:

java 复制代码
public class Test3 {
    // 注解方式:AnnotatedBeanDefinitionReader
    public static void main(String[] args) {
        //定义一个spring容器,这个容器默认实现了BeanDefinitionRegistry,所以本身就是一个bean注册器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

        //定义一个注解方式的BeanDefinition读取器,需要传递一个BeanDefinitionRegistry(bean注册器)对象
        AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(factory);
        annotatedBeanDefinitionReader.register(Service1.class, Service2.class);
        //打印出注册的bean的配置信息

        factory.getBeansOfType(BeanPostProcessor.class).values().forEach(factory::addBeanPostProcessor); // @1

        for (String beanName : new String[]{"service1", "service2"}) {
            //通过名称从容器中获取对应的BeanDefinition信息
            BeanDefinition beanDefinition = factory.getBeanDefinition(beanName);
            //获取BeanDefinition具体使用的是哪个类
            String beanDefinitionClassName = beanDefinition.getClass().getName();
            //通过名称获取bean对象
            Object bean = factory.getBean(beanName);
            //打印输出
            System.out.println(beanName + ":");
            System.out.println("    beanDefinitionClassName:" + beanDefinitionClassName);
            System.out.println("    beanDefinition:" + beanDefinition);
            System.out.println("    bean:" + bean);
        }
    }

    /**
     * 输出中可以看出service1这个bean的beanDefinition中lazyInit确实为true,
     * primary也为true,scope为prototype,说明类Service1注解上标注3个注解信息被解析之后放在了beanDefinition中。
     * 注意下:最后一行中的service1为什么为null,不是标注了@Autowired么?
     * 这个地方提前剧透一下,看不懂的没关系,这篇文章都结束之后,就明白了。
     * 调整一下上面的代码,加上下面@1这行代码,如下:
     */

再次运行一下,最后一行有值了:

阶段3:Spring Bean注册阶段

bean注册阶段需要用到一个非常重要的接口:BeanDefinitionRegistry

Bean注册接口:BeanDefinitionRegistry

这个接口中定义了注册bean常用到的一些方法,源码如下:

java 复制代码
public interface BeanDefinitionRegistry extends AliasRegistry {
 
    /**
     * 注册一个新的bean定义
     * beanName:bean的名称
     * beanDefinition:bean定义信息
     */
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException;
 
    /**
     * 通过bean名称移除已注册的bean
     * beanName:bean名称
     */
    void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
 
    /**
     * 通过名称获取bean的定义信息
     * beanName:bean名称
     */
    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
 
    /**
     * 查看beanName是否注册过
     */
    boolean containsBeanDefinition(String beanName);
 
    /**
     * 获取已经定义(注册)的bean名称列表
     */
    String[] getBeanDefinitionNames();
 
    /**
     * 返回注册器中已注册的bean数量
     */
    int getBeanDefinitionCount();
 
    /**
     * 确定给定的bean名称或者别名是否已在此注册表中使用
     * beanName:可以是bean名称或者bean的别名
     */
    boolean isBeanNameInUse(String beanName);
 
}
别名注册接口:AliasRegistry

BeanDefinitionRegistry接口继承了AliasRegistry接口,这个接口中定义了操作bean别名的一些方法,看一下其源码:

java 复制代码
public interface AliasRegistry {
 
    /**
     * 给name指定别名alias
     */
    void registerAlias(String name, String alias);
 
    /**
     * 从此注册表中删除指定的别名
     */
    void removeAlias(String alias);
 
    /**
     * 判断name是否作为别名已经被使用了
     */
    boolean isAlias(String name);
 
    /**
     * 返回name对应的所有别名
     */
    String[] getAliases(String name);
 
}
BeanDefinitionRegistry唯一实现:DefaultListableBeanFactory
复制代码
org.springframework.beans.factory.support.DefaultListableBeanFactory

大家可能看到有很多类也实现了BeanDefinitionRegistry接口,比如我们经常用到的AnnotationConfigApplicationContext,但实际上其内部是转发给了DefaultListableBeanFactory进行处理的,所以真正实现这个接口的类是DefaultListableBeanFactory。

大家再回头看一下开头的几个案例,都使用的是DefaultListableBeanFactory作为bean注册器,此时你们应该可以理解为什么了

下面我们来个案例演示一下上面常用的一些方法。

java 复制代码
package bean.lifeCycle.phase3;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;

import java.util.Arrays;

public class Test1 {
    public static void main(String[] args) {
        //创建一个bean工厂,这个默认实现了BeanDefinitionRegistry接口,所以也是一个bean注册器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        //定义一个bean
        GenericBeanDefinition nameBdf = new GenericBeanDefinition();
        nameBdf.setBeanClass(String.class);
        nameBdf.getConstructorArgumentValues().addIndexedArgumentValue(0, "路人甲Java");
        //将bean注册到容器中
        factory.registerBeanDefinition("name", nameBdf);
        //通过名称获取BeanDefinition
        System.out.println(factory.getBeanDefinition("name"));
        //通过名称判断是否注册过BeanDefinition
        System.out.println(factory.containsBeanDefinition("name"));
        //获取所有注册的名称
        System.out.println(Arrays.asList(factory.getBeanDefinitionNames()));
        //获取已注册的BeanDefinition的数量
        System.out.println(factory.getBeanDefinitionCount());
        //判断指定的name是否使用过
        System.out.println(factory.isBeanNameInUse("name"));


        //别名相关方法

        //为name注册2个别名
        factory.registerAlias("name", "alias-name-1");
        factory.registerAlias("name", "alias-name-2");

        //判断alias-name-1是否已被作为别名使用
        System.out.println(factory.isAlias("alias-name-1"));

        //通过名称获取对应的所有别名
        System.out.println(Arrays.asList(factory.getAliases("name")));

        //最后我们再来获取一下这个bean
        System.out.println(factory.getBean("name"));


    }
}

运行:

下面要介绍的从阶段4到阶段14,也就是从:BeanDefinition合并阶段Bean初始化完成阶段,都是在调用getBean从容器中获取bean对象的过程中发送的操作,要注意细看了,大家下去了建议去看getBean这个方法的源码,以下过程均来自于这个方法

复制代码
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

阶段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

来一个普通的类

java 复制代码
package bean.lifeCycle.phase4;

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定义3个具有父子关系的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="lesson1" class="bean.lifeCycle.phase4.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="路人甲Java带你学spring,超越90%开发者!"/>
    </bean>

</beans>

lesson2相当于lesson1的儿子,lesson3相当于lesson1的孙子。

解析xml注册bean

下面将解析xml,进行bean注册,然后遍历输出bean的名称,解析过程中注册的原始的BeanDefinition,合并之后的BeanDefinition,以及合并前后BeanDefinition中的属性信息

java 复制代码
package bean.lifeCycle.phase4;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;

public class MergedBeanDefinitionTest {
      //  * BeanDefinition 合并
    public static void main(String[] args) {
        //创建bean容器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

        //创建一个bean xml解析器
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(factory);
        //解析bean xml,将解析过程中产生的BeanDefinition注册到DefaultListableBeanFactory中
        beanDefinitionReader.loadBeanDefinitions("beanDefinition2.xml");
        //遍历容器中注册的所有bean信息
        String[] beanDefinitionNames = factory.getBeanDefinitionNames();
        for (String beanName : beanDefinitionNames) {
            //通过bean名称获取原始的注册的BeanDefinition信息
            BeanDefinition beanDefinition = factory.getBeanDefinition(beanName);
            //获取合并之后的BeanDefinition信息
            BeanDefinition mergedBeanDefinition = factory.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("---------------------------");
            
        }
    }

    /**
     * 从输出的结果中可以看到,合并之前,BeanDefinition是不完整的,比lesson2和lesson3中的class是null,属性信息也不完整,但是合并之后这些信息都完整了。
     * 合并之前是GenericBeanDefinition类型的,合并之后得到的是RootBeanDefinition类型的。
     * 获取lesson3合并的BeanDefinition时,内部会递归进行合并,先将lesson1和lesson2合并,然后将lesson2再和lesson3合并,最后得到合并之后的BeanDefinition。
     * 后面的阶段将使用合并产生的RootBeanDefinition。
     */
}

运行:

java 复制代码
D:\jdk-17\install\bin\java.exe -javaagent:D:\idea202303\install\lib\idea_rt.jar=60179:D:\idea202303\install\bin -Dfile.encoding=UTF-8 -classpath E:\my-springboot-test\target\classes;E:\repository\org\springframework\boot\spring-boot-starter-web\2.7.6\spring-boot-starter-web-2.7.6.jar;E:\repository\org\springframework\boot\spring-boot-starter\2.7.6\spring-boot-starter-2.7.6.jar;E:\repository\org\springframework\boot\spring-boot\2.7.6\spring-boot-2.7.6.jar;E:\repository\org\springframework\boot\spring-boot-autoconfigure\2.7.6\spring-boot-autoconfigure-2.7.6.jar;E:\repository\org\springframework\boot\spring-boot-starter-logging\2.7.6\spring-boot-starter-logging-2.7.6.jar;E:\repository\ch\qos\logback\logback-classic\1.2.11\logback-classic-1.2.11.jar;E:\repository\ch\qos\logback\logback-core\1.2.11\logback-core-1.2.11.jar;E:\repository\org\apache\logging\log4j\log4j-to-slf4j\2.17.2\log4j-to-slf4j-2.17.2.jar;E:\repository\org\apache\logging\log4j\log4j-api\2.17.2\log4j-api-2.17.2.jar;E:\repository\org\slf4j\jul-to-slf4j\1.7.36\jul-to-slf4j-1.7.36.jar;E:\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;E:\repository\org\yaml\snakeyaml\1.30\snakeyaml-1.30.jar;E:\repository\org\springframework\boot\spring-boot-starter-json\2.7.6\spring-boot-starter-json-2.7.6.jar;E:\repository\com\fasterxml\jackson\core\jackson-databind\2.13.4.2\jackson-databind-2.13.4.2.jar;E:\repository\com\fasterxml\jackson\core\jackson-annotations\2.13.4\jackson-annotations-2.13.4.jar;E:\repository\com\fasterxml\jackson\core\jackson-core\2.13.4\jackson-core-2.13.4.jar;E:\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.13.4\jackson-datatype-jdk8-2.13.4.jar;E:\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.13.4\jackson-datatype-jsr310-2.13.4.jar;E:\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.13.4\jackson-module-parameter-names-2.13.4.jar;E:\repository\org\springframework\boot\spring-boot-starter-tomcat\2.7.6\spring-boot-starter-tomcat-2.7.6.jar;E:\repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.69\tomcat-embed-core-9.0.69.jar;E:\repository\org\apache\tomcat\embed\tomcat-embed-el\9.0.69\tomcat-embed-el-9.0.69.jar;E:\repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.69\tomcat-embed-websocket-9.0.69.jar;E:\repository\org\springframework\spring-web\5.3.24\spring-web-5.3.24.jar;E:\repository\org\springframework\spring-beans\5.3.24\spring-beans-5.3.24.jar;E:\repository\org\springframework\spring-webmvc\5.3.24\spring-webmvc-5.3.24.jar;E:\repository\org\springframework\spring-aop\5.3.24\spring-aop-5.3.24.jar;E:\repository\org\springframework\spring-context\5.3.24\spring-context-5.3.24.jar;E:\repository\org\springframework\spring-expression\5.3.24\spring-expression-5.3.24.jar;E:\repository\org\slf4j\slf4j-api\1.7.36\slf4j-api-1.7.36.jar;E:\repository\org\springframework\spring-core\5.3.24\spring-core-5.3.24.jar;E:\repository\org\springframework\spring-jcl\5.3.24\spring-jcl-5.3.24.jar bean.lifeCycle.phase4.MergedBeanDefinitionTest
10:21:48.736 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 3 bean definitions from class path resource [beanDefinition2.xml]
lesson1
解析xml过程中注册的beanDefinition:Generic bean: class [bean.lifeCycle.phase4.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 [beanDefinition2.xml]
beanDefinition中的属性信息PropertyValues: length=0
合并之后得到的mergedBeanDefinition:Root bean: class [bean.lifeCycle.phase4.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 [beanDefinition2.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 [beanDefinition2.xml]
beanDefinition中的属性信息PropertyValues: length=2; bean property 'name'; bean property 'lessonCount'
合并之后得到的mergedBeanDefinition:Root bean: class [bean.lifeCycle.phase4.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 [beanDefinition2.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 [beanDefinition2.xml]
beanDefinition中的属性信息PropertyValues: length=1; bean property 'description'
合并之后得到的mergedBeanDefinition:Root bean: class [bean.lifeCycle.phase4.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 [beanDefinition2.xml]
mergedBeanDefinition中的属性信息PropertyValues: length=3; bean property 'name'; bean property 'lessonCount'; bean property 'description'
---------------------------

Process finished with exit code 0

从输出的结果中可以看到,合并之前,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,下面就开始进入实例化这个对象的阶段了。

Bean实例化分为3个阶段:前阶段、实例化阶段、后阶段;下面详解介绍。

阶段6:Bean实例化阶段

分2个小的阶段
  1. Bean实例化前操作

  2. Bean的实例化操作

Bean实例化前操作

先来看一下DefaultListableBeanFactory,这个类中有个非常非常重要的字段:

复制代码
private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();

是一个BeanPostProcessor类型的集合

BeanPostProcessor是一个接口,还有很多子接口,这些接口中提供了很多方法,spring在bean生命周期的不同阶段,会调用上面这个列表中的BeanPostProcessor中的一些方法,来对生命周期进行扩展,bean生命周期中的所有扩展点都是依靠这个集合中的BeanPostProcessor来实现的,所以如果大家想对bean的生命周期进行干预,这块一定要掌握好。

注意:本文中很多以BeanPostProcessor结尾的,都实现了BeanPostProcessor接口,有些是直接实现的,有些是实现了它的子接口。

Bean实例化之前会调用一段代码:

java 复制代码
	/**
	 * Apply InstantiationAwareBeanPostProcessors to the specified bean definition
	 * (by class and name), invoking their {@code postProcessBeforeInstantiation} methods.
	 * <p>Any returned object will be used as the bean instead of actually instantiating
	 * the target bean. A {@code null} return value from the post-processor will
	 * result in the target bean being instantiated.
	 * @param beanClass the class of the bean to be instantiated
	 * @param beanName the name of the bean
	 * @return the bean object to use instead of a default instance of the target bean, or {@code null}
	 * @see InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
	 */
	@Nullable
	protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
		for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
			Object result = bp.postProcessBeforeInstantiation(beanClass, beanName);
			if (result != null) {
				return result;
			}
		}
		return null;
	}

这段代码在bean实例化之前给开发者留了个口子,开发者自己可以在这个地方直接去创建一个对象作为bean实例,而跳过spring内部实例化bean的过程

上面代码中轮询BeanPostProcessorCache中的InstantiationAwareBeanPostProcessor列表, 尝试调用InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation获取bean的实例对象,如果能够获取到,那么将返回值作为当前bean的实例,那么spring自带的实例化bean的过程就被跳过了。

postProcessBeforeInstantiation方法如下

这个地方给开发者提供了一个扩展点,允许开发者在这个方法中直接返回bean的一个实例。

下面我们来个案例看一下。

java 复制代码
package bean.lifeCycle.phase6;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.lang.Nullable;

public class InstantiationAwareBeanPostProcessorTest {

    /** bean 实例化前阶段,
     * #postProcessBeforeInitialization(Object, String)}
    */
    public static void main(String[] args) {

        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        //添加一个BeanPostProcessor:InstantiationAwareBeanPostProcessor
        factory.addBeanPostProcessor(new InstantiationAwareBeanPostProcessor() { //@1
            @Nullable
            @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"));

    }

    /**
     * bean定义的时候,名称为:奥迪,最后输出的为:保时捷
     * 定义和输出不一致的原因是因为我们在InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation方法中手动创建了一个实例直接返回了,而不是依靠spring内部去创建这个实例。
     * 小结
     * 实际上,在实例化前阶段对bean的创建进行干预的情况,用的非常少,所以大部分bean的创建还会继续走下面的阶段。
     */


}

@1:创建了一个InstantiationAwareBeanPostProcessor,丢到了容器中的BeanPostProcessor列表中

@2:创建了一个car bean,name为奥迪

运行输出

bean定义的时候,名称为:奥迪,最后输出的为:保时捷

定义和输出不一致的原因是因为我们在InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation方法中手动创建了一个实例直接返回了,而不是依靠spring内部去创建这个实例。

实际上,在实例化前阶段对bean的创建进行干预的情况,用的非常少,所以大部分bean的创建还会继续走下面的阶段。

Bean实例化操作

这个过程可以干什么?

这个过程会通过反射来调用bean的构造器来创建bean的实例。

具体需要使用哪个构造器,spring为开发者提供了一个接口,允许开发者自己来判断用哪个构造器。

看一下这块的代码逻辑

java 复制代码
	/**
	 * Determine candidate constructors to use for the given bean, checking all registered
	 * {@link SmartInstantiationAwareBeanPostProcessor SmartInstantiationAwareBeanPostProcessors}.
	 * @param beanClass the raw class of the bean
	 * @param beanName the name of the bean
	 * @return the candidate constructors, or {@code null} if none specified
	 * @throws org.springframework.beans.BeansException in case of errors
	 * @see org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors
	 */
	@Nullable
	protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
			throws BeansException {

		if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
			for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
				Constructor<?>[] ctors = bp.determineCandidateConstructors(beanClass, beanName);
				if (ctors != null) {
					return ctors;
				}
			}
		}
		return null;
	}

会调用SmartInstantiationAwareBeanPostProcessor接口的determineCandidateConstructors方法确定候选构造方法(),这个方法会返回候选的构造器列表,也可以返回空,看一下这个方法的源码:

这个方法有个比较重要的实现类

复制代码
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor

可以将@Autowired标注的方法作为候选构造器返回,有兴趣的可以去看一下代码。

案例

下面我们来个案例,自定义一个注解,当构造器被这个注解标注的时候,让spring自动选择使用这个构造器创建对象。

自定义一个注解

下面这个注解可以标注在构造器上面,使用这个标注之后,创建bean的时候将使用这个构造器

java 复制代码
package bean.lifeCycle.phase6;


import java.lang.annotation.*;

@Target(ElementType.CONSTRUCTOR)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAutowried {
}

来个普通的类

java 复制代码
package bean.lifeCycle.phase6;

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;
    }

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

这个类定义了三个构造方法

自定义一个SmartInstantiationAwareBeanPostProcessor

代码的逻辑:将@MyAutowried标注的构造器列表返回

java 复制代码
package bean.lifeCycle.phase6;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
import org.springframework.lang.Nullable;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class MySmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
    @Nullable
    @Override
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println(beanClass);
        System.out.println("调用 MySmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors 方法");
        Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
        if (declaredConstructors != null) {
            //获取有@MyAutowried注解的构造器列表
            List<Constructor<?>> collect = Arrays.stream(declaredConstructors).
                    filter(constructor -> constructor.isAnnotationPresent(MyAutowried.class)).
                    collect(Collectors.toList());
            Constructor[] constructors = collect.toArray(new Constructor[collect.size()]);
            return constructors.length != 0 ? constructors : null;
        } else {
            return null;
        }
    }

}

来个测试用例

java 复制代码
package bean.lifeCycle.phase6;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

public class SmartInstantiationAwareBeanPostProcessorTest {
    //  * 通过{@link org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors(Class, String)}
    //  来确定使用哪个构造器来创建bean实例
    //原文链接:https://blog.csdn.net/weixin_46228112/article/details/124602418


    public static void main(String[] args) {
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        //创建一个SmartInstantiationAwareBeanPostProcessor,将其添加到容器中
        factory.addBeanPostProcessor(new MySmartInstantiationAwareBeanPostProcessor());
        factory.registerBeanDefinition("name",
                BeanDefinitionBuilder.
                        genericBeanDefinition(String.class).
                        addConstructorArgValue("路人甲Java").
                        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中标注@MyAutowired标注的构造器。

}

运行输出

从输出中可以看出调用了Person中标注@MyAutowired标注的构造器。

到目前为止bean实例化阶段结束了,继续进入后面的阶段。

阶段7:合并后的BeanDefinition处理

这块的源码如下

java 复制代码
	/**
	 * Apply MergedBeanDefinitionPostProcessors to the specified bean definition,
	 * invoking their {@code postProcessMergedBeanDefinition} methods.
	 * @param mbd the merged bean definition for the bean
	 * @param beanType the actual type of the managed bean instance
	 * @param beanName the name of the bean
	 * @see MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
	 */
	protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
		for (MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) {
			processor.postProcessMergedBeanDefinition(mbd, beanType, beanName);
		}
	}

会调用MergedBeanDefinitionPostProcessor接口的postProcessMergedBeanDefinition方法,看一下这个方法的源码:

复制代码

Spring会轮询BeanPostProcessorCache中的mergedDefinition

,依次调用MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition

第一个参数为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这个方法,调用逻辑如下:

postProcessAfterInstantiation方法返回false的时候,后续的Bean属性赋值前处理、Bean属性赋值都会被跳过了。

来看一下postProcessAfterInstantiation这个方法的定义

来看个案例,案例中返回false,跳过属性的赋值操作。

案例

java 复制代码
package bean.lifeCycle.phase8;

public class UserModel {
    private String name;
    private Integer 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 "UserModel{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

测试用例

下面很简单,来注册一个UserModel的bean

java 复制代码
package bean.lifeCycle.phase8;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

public class Test1 {
    // InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
    // 实例化后阶段
    public static void main(String[] args) {

        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        factory.registerBeanDefinition("user1", BeanDefinitionBuilder.
                genericBeanDefinition(UserModel.class).
                addPropertyValue("name", "路人甲Java").
                addPropertyValue("age", 30).
                getBeanDefinition());

        factory.registerBeanDefinition("user2", BeanDefinitionBuilder.
                genericBeanDefinition(UserModel.class).
                addPropertyValue("name", "刘德华").
                addPropertyValue("age", 50).
                getBeanDefinition());

        for (String beanName : factory.getBeanDefinitionNames()) {
            System.out.println(String.format("%s->%s", beanName, factory.getBean(beanName)));
        }

    }
}

上面定义了2个bean:user1,user2,获取之后输出

运行输出

此时UserModel中2个属性都是有值的。

下面来阻止user1的赋值,对代码进行改造,加入下面代码:

java 复制代码
package bean.lifeCycle.phase8;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

public class Test2 {
    // 下面来阻止user1的赋值,对代码进行改造,加入下
    public static void main(String[] args) {

        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        factory.registerBeanDefinition("user1", BeanDefinitionBuilder.
                genericBeanDefinition(UserModel.class).
                addPropertyValue("name", "路人甲Java").
                addPropertyValue("age", 30).
                getBeanDefinition());

        factory.registerBeanDefinition("user2", BeanDefinitionBuilder.
                genericBeanDefinition(UserModel.class).
                addPropertyValue("name", "刘德华").
                addPropertyValue("age", 50).
                getBeanDefinition());

        factory.addBeanPostProcessor(new InstantiationAwareBeanPostProcessor() {
            @Override
            public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
                if ("user1".equals(beanName)) {
                    return false;
                } else {
                    return true;
                }
            }
        });

        for (String beanName : factory.getBeanDefinitionNames()) {
            System.out.println(String.format("%s->%s", beanName, factory.getBean(beanName)));
        }

    }
}

再次运行测试输出:

user1的属性赋值被跳过了。

Bean属性赋值前阶段

这个阶段会调用InstantiationAwareBeanPostProcessor接口的postProcessProperties方法,调用逻辑:

java 复制代码
	PropertyDescriptor[] filteredPds = null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
				if (pvsToUse == null) {
					if (filteredPds == null) {
						filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
					}
					pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						return;
					}
				}
				pvs = pvsToUse;
			}
		}

从上面可以看出,如果InstantiationAwareBeanPostProcessor中的postProcessPropertiespostProcessPropertyValues都返回空的时候,表示这个bean不需要设置属性,直接返回了,直接进入下一个阶段。

来看一下postProcessProperties这个方法的定义:

PropertyValues中保存了bean实例对象中所有属性值的设置,所以我们可以在这个这个方法中对PropertyValues值进行修改。

这个方法有2个比较重要的实现类

AutowiredAnnotationBeanPostProcessor在这个方法中对@Autowired、@Value标注的字段、方法注入值。

CommonAnnotationBeanPostProcessor在这个方法中对@Resource标注的字段和方法注入值

来个案例,我们在案例中对pvs进行修改。

案例

java 复制代码
package bean.lifeCycle.phase8;

import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.lang.Nullable;

public class Test3 {
    // Bean属性赋值前阶段
    public static void main(String[] args) {

        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

        factory.addBeanPostProcessor(new InstantiationAwareBeanPostProcessor() { // @0
            @Nullable
            @Override
            public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
                if ("user1".equals(beanName)) {
                    if (pvs == null) {
                        pvs = new MutablePropertyValues();
                    }
                    if (pvs instanceof MutablePropertyValues) {
                        MutablePropertyValues mpvs = (MutablePropertyValues) pvs;
                        //将姓名设置为:路人
                        mpvs.add("name", "路人");
                        //将年龄属性的值修改为18
                        mpvs.add("age", 18);
                    }
                }
                return null;
            }
        });

        //注意 user1 这个没有给属性设置值
        factory.registerBeanDefinition("user1", BeanDefinitionBuilder.
                genericBeanDefinition(UserModel.class).
                getBeanDefinition()); //@1

        factory.registerBeanDefinition("user2", BeanDefinitionBuilder.
                genericBeanDefinition(UserModel.class).
                addPropertyValue("name", "刘德华").
                addPropertyValue("age", 50).
                getBeanDefinition());

        for (String beanName : factory.getBeanDefinitionNames()) {
            System.out.println(String.format("%s->%s", beanName, factory.getBean(beanName)));
        }

        /**
         * @1:user1这个bean没有设置属性的值
         *
         * @0:这个实现 org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor#postProcessProperties
         * 方法,在其内部对 user1 这个bean进行属性值信息进行修改
         *
         */

    }
}

@1:user1这个bean没有设置属性的值

@0:这个实现 org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor#postProcessProperties 方法,在其内部对 user1 这个bean进行属性值信息进行修改

运行输出

上面过程都ok,进入bean赋值操作

Bean属性赋值阶段

这个过程比较简单了,循环处理PropertyValues中的属性值信息,通过反射调用set方法将属性的值设置到bean实例中。

PropertyValues中的值是通过bean xml中property元素配置的,或者调用MutablePropertyValues中add方法设置的值。

阶段9:Bean初始化阶段

这个阶段分为5个小的阶段
  • Bean Aware接口回调

  • Bean初始化前操作

  • Bean初始化操作

  • Bean初始化后操作

  • Bean初始化完成操作

Bean Aware接口回调

源码

java 复制代码
private void invokeAwareMethods(String beanName, Object bean) {
		if (bean instanceof Aware) {
			if (bean instanceof BeanNameAware) {
				((BeanNameAware) bean).setBeanName(beanName);
			}
			if (bean instanceof BeanClassLoaderAware) {
				ClassLoader bcl = getBeanClassLoader();
				if (bcl != null) {
					((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
				}
			}
			if (bean instanceof BeanFactoryAware) {
				((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
			}
		}
	}

如果我们的bean实例实现了上面的接口,会按照下面的顺序依次进行调用:

BeanNameAware:将bean的名称注入进去

BeanClassLoaderAware:将BeanClassLoader注入进去

BeanFactoryAware:将BeanFactory注入进去

来个案例感受一下,来个类,实现上面3个接口。

java 复制代码
package bean.lifeCycle.phase9;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;

public class AwareBean implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware {

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("setBeanClassLoader:" + classLoader);

    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("setBeanFactory:" + beanFactory);

    }

    @Override
    public void setBeanName(String name) {
        System.out.println("setBeanName:" + name);

    }
}

来个测试类,创建上面这个对象的的bean

java 复制代码
package bean.lifeCycle.phase9;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;

public class InvokeAwareTest {
    // Bean Aware接口回调
    public static void main(String[] args) {
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        factory.registerBeanDefinition("awareBean", BeanDefinitionBuilder.genericBeanDefinition(AwareBean.class).getBeanDefinition());
        //调用getBean方法获取bean,将触发bean的初始化
        factory.getBean("awareBean");

       /* AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(AwareBean.class);
        context.refresh();
        context.getBean(AwareBean.class);*/
    }
}

运行输出

Bean初始化前操作

这个阶段的源码:

java 复制代码
@Override
	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessBeforeInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

会调用BeanPostProcessor的postProcessBeforeInitialization方法,若返回null,当前方法将结束。

通常称postProcessBeforeInitialization这个方法为:bean初始化前操作。

这个接口有2个实现类,比较重要:

org.springframework.context.support.ApplicationContextAwareProcessor

org.springframework.context.annotation.CommonAnnotationBeanPostProcessor

ApplicationContextAwareProcessor注入6个Aware接口对象

如果bean实现了下面的接口,在ApplicationContextAwareProcessor#postProcessBeforeInitialization中会依次调用下面接口中的方法,将Aware前缀对应的对象注入到bean实例中。

EnvironmentAware:注入Environment对象

EmbeddedValueResolverAware:注入EmbeddedValueResolver对象

ResourceLoaderAware:注入ResourceLoader对象

ApplicationEventPublisherAware:注入ApplicationEventPublisher对象

MessageSourceAware:注入MessageSource对象

ApplicationContextAware:注入ApplicationContext对象

从名称上可以看出这个类以ApplicationContext开头的,说明这个类只能在ApplicationContext环境中使用。

CommonAnnotationBeanPostProcessor调用@PostConstruct标注的方法

CommonAnnotationBeanPostProcessor#postProcessBeforeInitialization中会调用bean中所有标注@PostConstruct注解的方法

来个案例,感受一下。

java 复制代码
package bean.lifeCycle.phase9;

import org.springframework.beans.BeansException;
import org.springframework.context.*;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.StringValueResolver;

import javax.annotation.PostConstruct;

public class Bean1 implements
        EnvironmentAware,
        EmbeddedValueResolverAware,
        ResourceLoaderAware,
        ApplicationEventPublisherAware,
        MessageSourceAware,
        ApplicationContextAware {
    @PostConstruct
    public void postConstruct1() { //@1
        System.out.println("postConstruct1()");
    }

    @PostConstruct
    public void postConstruct2() { //@2
        System.out.println("postConstruct2()");
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            System.out.println("setApplicationContext:" + applicationContext);

    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
            System.out.println("setApplicationEventPublisher:" + applicationEventPublisher);

    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
            System.out.println("setEmbeddedValueResolver:" + resolver);

    }

    @Override
    public void setEnvironment(Environment environment) {
            System.out.println("setEnvironment:" + environment.getClass());

    }

    @Override
    public void setMessageSource(MessageSource messageSource) {
            System.out.println("setMessageSource:" + messageSource);

    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
            System.out.println("setResourceLoader:" + resourceLoader);

    }
}

来个测试案例

java 复制代码
package bean.lifeCycle.phase9;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.Observable;

public class Test1 {
    // Bean初始化前操作
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(Bean1.class);
        context.refresh();
    }

    /**
     * CommonAnnotationBeanPostProcessor调用@PostConstruct标注的方法
     *CommonAnnotationBeanPostProcessor#postProcessBeforeInitialization中会调用bean中所有标注@PostConstruct注解的方法
     *
     * 通常称postProcessBeforeInitialization这个方法为:bean初始化前操作。
     * 这个接口有2个实现类,比较重要:
     * org.springframework.context.support.ApplicationContextAwareProcessor
     * org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
     * ApplicationContextAwareProcessor注入6个Aware接口对象
     * 如果bean实现了下面的接口,在ApplicationContextAwareProcessor#postProcessBeforeInitialization中会依次调用下面接口中的方法,
     * 将Aware前缀对应的对象注入到bean实例中。
     * EnvironmentAware:注入Environment对象
     * EmbeddedValueResolverAware:注入EmbeddedValueResolver对象
     * ResourceLoaderAware:注入ResourceLoader对象
     * ApplicationEventPublisherAware:注入ApplicationEventPublisher对象
     * MessageSourceAware:注入MessageSource对象
     * ApplicationContextAware:注入ApplicationContext对象
     * 从名称上可以看出这个类以ApplicationContext开头的,说明这个类只能在ApplicationContext环境中使用。
     *
     */
}

运行输出

大家可以去看一下AnnotationConfigApplicationContext的源码,其内部会添加很多BeanPostProcessorDefaultListableBeanFactory中。

Bean初始化阶段

2个步骤

  1. 调用InitializingBean接口的afterPropertiesSet方法

  2. 调用定义bean的时候指定的初始化方法。

调用InitializingBean接口的afterPropertiesSet方法

来看一下InitializingBean这个接口

当我们的bean实现了这个接口的时候,会在这个阶段被调用

调用bean定义的时候指定的初始化方法

先来看一下如何指定bean的初始化方法,3种方式

复制代码
<bean init-method="bean中方法名称"/>

方式2:@Bean的方式指定初始化方法

复制代码
@Bean(initMethod = "初始化的方法")

方式3:api的方式指定初始化方法

复制代码
this.beanDefinition.setInitMethodName(methodName);

初始化方法最终会赋值给下面这个字段

复制代码
org.springframework.beans.factory.support.AbstractBeanDefinition#initMethodName

案例

java 复制代码
package bean.lifeCycle.phase9;

import org.springframework.beans.factory.InitializingBean;

public class Service implements InitializingBean {
    public void myInit() {
        System.out.println("自定义的初始化的化的方法 调用init()方法");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("调用afterPropertiesSet()");

    }
}

下面我们定义Service这个bean,指定init方法为初始化方法

java 复制代码
package bean.lifeCycle.phase9;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

public class Test2 {
    // Bean初始化阶段  2个步骤
    //
    //调用InitializingBean接口的afterPropertiesSet方法
    //
    //调用定义bean的时候指定的初始化方法

     // 初始化方法测试

    public static void main(String[] args) {
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        BeanDefinition service = BeanDefinitionBuilder.genericBeanDefinition(Service.class).
                setInitMethodName("myInit"). //@1:指定初始化方法
                        getBeanDefinition();
        factory.registerBeanDefinition("myService", service);
        System.out.println(factory.getBean("myService"));


    }
}

运行输出

调用顺序:InitializingBean中的afterPropertiesSet、 然后在调用自定义的初始化方法

Bean初始化后阶段

这块的源码:

java 复制代码
@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

调用BeanPostProcessor接口的postProcessAfterInitialization方法,返回null的时候,会中断上面的操作。

通常称postProcessAfterInitialization这个方法为:bean初始化后置操作。

来个案例

java 复制代码
package bean.lifeCycle.phase9;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.lang.Nullable;

public class Test3 {
    // bean 初始化后的方法
    public static void main(String[] args) {
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        //加入bean初始化后置处理器方法实现
        factory.addBeanPostProcessor(new BeanPostProcessor() {
            @Nullable
            @Override
            public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                System.out.println("postProcessAfterInitialization:" + beanName);
                System.out.println("初始化后的方法执行:" + beanName);
                return bean;
            }
        });

        //下面注册2个String类型的bean

        factory.registerBeanDefinition("name",
                BeanDefinitionBuilder.
                        genericBeanDefinition(String.class).
                        addConstructorArgValue("公众号:【路人甲Java】").
                        getBeanDefinition());

        factory.registerBeanDefinition("personInformation",
                BeanDefinitionBuilder.genericBeanDefinition(String.class).
                        addConstructorArgValue("带领大家成为java高手!").
                        getBeanDefinition());


        System.out.println("-------输出bean信息---------");
        for (String beanDefinitionName : factory.getBeanDefinitionNames()) {
            System.out.println(String.format("%s==%s",beanDefinitionName,factory.getBean(beanDefinitionName)));
        }


    }
}

运行输出

阶段10:所有单例bean初始化完成后阶段

所有单例bean实例化完成之后,spring会回调下面这个接口:

java 复制代码
public interface SmartInitializingSingleton {
    void afterSingletonsInstantiated();
}

调用逻辑在下面这个方法中

/**

* 确保所有非lazy的单例都被实例化,同时考虑到FactoryBeans。如果需要,通常在工厂设置结束时调用。

*/

org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

这个方法内部会先触发所有非延迟加载的单例bean初始化,然后从容器中找到类型是SmartInitializingSingleton的bean,调用他们的afterSingletonsInstantiated方法。

有兴趣的可以去看一下带有ApplicationContext的容器,内部最终都会调用上面这个方法触发所有单例bean的初始化。

来个2个案例演示一下SmartInitializingSingleton的使用。

案例1:ApplicationContext自动回调SmartInitializingSingleton接口

Service1:

java 复制代码
package bean.lifeCycle.phase10;

import org.springframework.stereotype.Component;

@Component
public class MyService1 {
    public MyService1() {
        System.out.println("创建  "+ this.getClass());
    }
}

Service2:

java 复制代码
package bean.lifeCycle.phase10;

import org.springframework.stereotype.Component;

@Component
public class MyService2 {
    public MyService2() {
        System.out.println("创建  "+ this.getClass());
    }
}

自定义一个SmartInitializingSingleton

java 复制代码
package bean.lifeCycle.phase10;

import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.stereotype.Component;


/**
 * 自定义一个SmartInitializingSingleton
 */
@Component
public class MySmartInitializingSingleton implements SmartInitializingSingleton {
    @Override
    public void afterSingletonsInstantiated() {
        System.out.println("所有bean初始化完毕!");
    }

}

来个测试类,通过包扫描的方式注册上面3个bean

java 复制代码
package bean.lifeCycle.phase10;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

/**
 * 所有bean初始化完毕,
 * 容器会回调{@link SmartInitializingSingleton#afterSingletonsInstantiated()}
 */
@ComponentScan
public class Test1 {
    // ApplicationContext自动回调SmartInitializingSingleton接口
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context  = new AnnotationConfigApplicationContext();
        context.register(Test1.class);
        System.out.println("开始启动容器!");
        context.refresh();
        System.out.println("容器启动完毕!");
    }

}

运行输出

案例2:通过api的方式让DefaultListableBeanFactory去回调SmartInitializingSingleton
java 复制代码
package bean.lifeCycle.phase10;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

public class Test2 {
    // 案例2:通过api的方式让DefaultListableBeanFactory去回调SmartInitializingSingleton
    public static void main(String[] args) {
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        factory.registerBeanDefinition("myService1", BeanDefinitionBuilder.genericBeanDefinition(MyService1.class).getBeanDefinition());
        factory.registerBeanDefinition("myService2", BeanDefinitionBuilder.genericBeanDefinition(MyService2.class).getBeanDefinition());
        factory.registerBeanDefinition("mySmartInitializingSingleton", BeanDefinitionBuilder.genericBeanDefinition(MySmartInitializingSingleton.class).getBeanDefinition());
        System.out.println("准备触发所有单例bean初始化");
        //触发所有bean初始化,并且回调 SmartInitializingSingleton#afterSingletonsInstantiated 方法
        factory.preInstantiateSingletons();
    }
}

上面通过api的方式注册bean

最后调用factory.preInstantiateSingletons触发所有非lazy单例bean初始化,所有bean装配完毕之后,会回调SmartInitializingSingleton接口。

阶段11:Bean使用阶段

这个阶段就不说了,调用getBean方法得到了bean之后,大家可以随意使用,任意发挥。

阶段12:Bean销毁阶段

触发bean销毁的几种方式
  1. 调用org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#destroyBean

  2. 调用org.springframework.beans.factory.config.ConfigurableBeanFactory#destroySingletons

  3. 调用ApplicationContext中的close方法

Bean销毁阶段会依次执行
  1. 轮询beanPostProcessors列表,如果是DestructionAwareBeanPostProcessor这种类型的,会调用其内部的postProcessBeforeDestruction方法

  2. 如果bean实现了org.springframework.beans.factory.DisposableBean接口,会调用这个接口中的destroy方法

  3. 调用bean自定义的销毁方法

DestructionAwareBeanPostProcessor接口

看下源码

这个接口有个关键的实现类:

复制代码
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor

CommonAnnotationBeanPostProcessor#postProcessBeforeDestruction方法中会调用bean中所有标注了@PreDestroy的方法。

再来说一下自定义销毁方法有3种方式

方式1:xml中指定销毁方法

复制代码
<bean destroy-method="bean中方法名称"/>

方式2:@Bean中指定销毁方法

java 复制代码
@Bean(destroyMethod = "销毁的方法")

方式3:api的方式指定销毁方法

复制代码
this.beanDefinition.setDestroyMethodName(methodName);

销毁方法最终会赋值给下面这个字段

复制代码
org.springframework.beans.factory.support.AbstractBeanDefinition#destroyMethodName

下面来看销毁的案例

来个类

java 复制代码
package bean.lifeCycle.phase12;

import org.springframework.context.support.AbstractApplicationContext;

public class MyServiceA {
    public MyServiceA() {
        System.out.println("创建 " + this.getClass());
    }
}

自定义一个DestructionAwareBeanPostProcessor

java 复制代码
package bean.lifeCycle.phase12;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;

public class MyDestructionAwareBeanPostProcessor implements DestructionAwareBeanPostProcessor {
    @Override
    public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
        System.out.println("准备销毁bean:" + beanName);

    }
}

来个测试类

java 复制代码
package bean.lifeCycle.phase12;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class Test1 {
    // 案例1:自定义DestructionAwareBeanPostProcessor
    public static void main(String[] args) {
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        //添加自定义的DestructionAwareBeanPostProcessor
        factory.addBeanPostProcessor(new MyDestructionAwareBeanPostProcessor());
        //向容器中注入3个单例bean
        factory.registerBeanDefinition("myServiceA1", BeanDefinitionBuilder.genericBeanDefinition(MyServiceA.class).getBeanDefinition());
        factory.registerBeanDefinition("myServiceA2", BeanDefinitionBuilder.genericBeanDefinition(MyServiceA.class).getBeanDefinition());
        factory.registerBeanDefinition("myServiceA3", BeanDefinitionBuilder.genericBeanDefinition(MyServiceA.class).getBeanDefinition());
        //触发所有单例bean初始化
        factory.preInstantiateSingletons();
        System.out.println("销毁serviceA1");
        //销毁指定的bean
        factory.destroySingleton("myServiceA1");//@2
        System.out.println("触发所有单例bean的销毁");
        factory.destroySingletons();

    }

    // 可以看到postProcessBeforeDestruction被调用了3次,依次销毁3个自定义的bean

}

上面使用了2种方式来触发bean的销毁@1和@2

运行输出

可以看到postProcessBeforeDestruction被调用了3次,依次销毁3个自定义的bean

案例2:触发@PreDestroy标注的方法被调用

上面说了这个注解是在CommonAnnotationBeanPostProcessor#postProcessBeforeDestruction中被处理的,所以只需要将这个加入BeanPostProcessor列表就可以了。

再来个类

java 复制代码
package bean.lifeCycle.phase12;

import javax.annotation.PreDestroy;

public class MyServiceB {
    public MyServiceB() {
        System.out.println("创建 " + this.getClass());
    }

    @PreDestroy
    public void preDestroy() { //@1
        System.out.println("preDestroy()");
        System.out.println("准备销毁bean");
    }

}

@1:标注了@PreDestroy注解

测试用例

java 复制代码
package bean.lifeCycle.phase12;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;

public class Test2 {
    // 案例2:触发@PreDestroy标注的方法被调用
    // 上面说了这个注解是在CommonAnnotationBeanPostProcessor#postProcessBeforeDestruction中被处理的,
    // 所以只需要将这个加入BeanPostProcessor列表就可以了。
    public static void main(String[] args) {
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        //添加自定义的DestructionAwareBeanPostProcessor
        factory.addBeanPostProcessor(new MyDestructionAwareBeanPostProcessor()); //@1
        //将CommonAnnotationBeanPostProcessor加入
        factory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor()); //@2
        //向容器中注入bean
        factory.registerBeanDefinition("myServiceB", BeanDefinitionBuilder.genericBeanDefinition(MyServiceB.class).getBeanDefinition());
        //触发所有单例bean初始化
        factory.preInstantiateSingletons();
        System.out.println("销毁myServiceB");
        //销毁指定的bean
        factory.destroySingleton("myServiceB");


        // @1:放入了一个自定义的DestructionAwareBeanPostProcessor

        // @2:放入了CommonAnnotationBeanPostProcessor,这个会处理bean中标注@PreDestroy注解的方法

    }

}

@1:放入了一个自定义的DestructionAwareBeanPostProcessor

@2:放入了CommonAnnotationBeanPostProcessor,这个会处理bean中标注@PreDestroy注解的方法

看效果运行输出

案例3:看一下销毁阶段的执行顺序

实际上ApplicationContext内部已经将spring内部一些常见的必须的BeannPostProcessor自动装配到beanPostProcessors列表中,比如我们熟悉的下面的几个:

1.org.springframework.context.annotation.CommonAnnotationBeanPostProcessor

用来处理@Resource、@PostConstruct、@PreDestroy的

2.org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor

用来处理@Autowired、@Value注解

3.org.springframework.context.support.ApplicationContextAwareProcessor

用来回调Bean实现的各种Aware接口

所以通过ApplicationContext来销毁bean,会触发3中方式的执行。

下面我们就以AnnotationConfigApplicationContext来演示一下销毁操作。

来一个类

java 复制代码
package bean.lifeCycle.phase12;

import org.springframework.beans.factory.DisposableBean;

import javax.annotation.PreDestroy;

public class MyServiceC implements DisposableBean {

    public MyServiceC() {
        System.out.println("创建MyServiceC实例");

    }
    @PreDestroy
    public void preDestroy1() {
        System.out.println("preDestroy1()");
    }

    @PreDestroy
    public void preDestroy2() {
        System.out.println("preDestroy2()");
    }


    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean接口中的destroy()");

    }


    //自定义的销毁方法
    public void customDestroyMethod() { //@1
        System.out.println("我是自定义的销毁方法:customDestroyMethod()");
    }
}

上面的类中有2个方法标注了@PreDestroy

这个类实现了DisposableBean接口,重写了接口的中的destroy方法

@1:这个destroyMethod我们一会通过@Bean注解的方式,将其指定为自定义方法。

来看测试用例

java 复制代码
package bean.lifeCycle.phase12;

import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;

@Configurable
public class Test3 {
    // 案例3:看一下销毁阶段的执行顺序


    @Bean(destroyMethod = "customDestroyMethod") //@1
    public MyServiceC myServiceC() {
        return new MyServiceC();
    }

    public static void main(String[] args) {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(Test3.class);

        //启动容器
        System.out.println("准备启动容器");
        context.refresh();
        System.out.println("容器启动完毕");
        System.out.println("myServiceC:" + context.getBean(MyServiceC.class));
        //关闭容器
        System.out.println("准备关闭容器");
        //调用容器的close方法,会触发bean的销毁操作
        context.close(); //@2
        System.out.println("容器关闭完毕");
    }

    /**
     * 上面这个类标注了@Configuration,表示是一个配置类,内部有个@Bean标注的方法,表示使用这个方法来定义一个bean。
     *
     * @1:通过destroyMethod属性将customDestroyMethod指定为自定义销毁方法
     *
     * @2:关闭容器,
     *
     * 可以看出销毁方法调用的顺序:
     *
     * @PreDestroy标注的所有方法
     *
     * DisposableBean接口中的destroy()
     *
     * 自定义的销毁方法
     *
     *
     */
}

上面这个类标注了@Configuration,表示是一个配置类,内部有个@Bean标注的方法,表示使用这个方法来定义一个bean。

@1:通过destroyMethod属性将customDestroyMethod指定为自定义销毁方法

@2:关闭容器,触发bean销毁操作

来运行test3,输出

复制代码

可以看出销毁方法调用的顺序:

  1. @PreDestroy标注的所有方法

  2. DisposableBean接口中的destroy()

  3. 自定义的销毁方法

下面来说一个非常非常重要的类,打起精神,一定要注意看。

AbstractApplicationContext类(非常重要的类)

来看一下UML图:

BeanFactory接口

这个我们已经很熟悉了,Bean工厂的顶层接口

DefaultListableBeanFactory类

实现了BeanFactory接口,可以说这个可以是BeanFactory接口真正的唯一实现,内部真正实现了bean生命周期中的所有代码。

其他的一些类都是依赖于DefaultListableBeanFactory类,将请求转发给DefaultListableBeanFactory进行bean的处理的。

其他3个类

我们经常用到的就是这3个类:AnnotationConfigApplicationContext/ClassPathXmlApplicationContext/FileSystemXmlApplicationContext这3个类,他们的主要内部的功能是依赖他的父类AbstractApplicationContext来实现的,所以大家主要看AbstractApplicationContext这个类。

AbstractApplicationContext类

这个类中有2个比较重要的方法

public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory

大家是否注意过我们使用AnnotationConfigApplicationContext的时候,经常调用reflush方法,这个方法内部就会调用上面这2个方法。

第一个方法:getBeanFactory()

返回当前应用上下文中的ConfigurableListableBeanFactory,这也是个接口类型的,这个接口有一个唯一的实现类:DefaultListableBeanFactory

有没有很熟悉,上面说过:DefaultListableBeanFactory是BeanFactory真正的唯一实现。

应用上线文中就会使用这个ConfigurableListableBeanFactory来操作spring容器。

refresh 调用 obtainFreshBeanFactory() 方法

复制代码
复制代码
obtainFreshBeanFactory()调用getBeanFactory()

第二个方法:registerBeanPostProcessors

说的通俗点:这个方法就是向ConfigurableListableBeanFactory中注册BeanPostProcessor,内容会从spring容器中获取所有类型的BeanPostProcessor,将其添加到DefaultListableBeanFactory#beanPostProcessors列表中

看一下这个方法的源码:

java 复制代码
	/**
	 * Instantiate and register all BeanPostProcessor beans,
	 * respecting explicit order if given.
	 * <p>Must be called before any instantiation of application beans.
	 */
	protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
	}

会将请求转发给PostProcessorRegistrationDelegate#registerBeanPostProcessors

内部比较长,大家可以去看一下源码,这个方法内部主要用到了4个BeanPostProcessor类型的List集合。

List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();

List<BeanPostProcessor> orderedPostProcessors

List<BeanPostProcessor> nonOrderedPostProcessors;

List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();

先说一下:当到方法的时候,spring容器中已经完成了所有Bean的注册

Spring会从容器中找出所有类型的BeanPostProcessor列表,然后按照下面的规则将其分别放到上面的4个集合中,上面4个集合中的BeanPostProcessor会被依次添加到DefaultListableBeanFactory#beanPostProcessors列表中,来看一下4个集合的分别放的是那些BeanPostProcessor:

priorityOrderedPostProcessors(指定优先级的BeanPostProcessor)

实现org.springframework.core.PriorityOrdered接口的BeanPostProcessor,但是不包含MergedBeanDefinitionPostProcessor类型的

orderedPostProcessors(指定了顺序的BeanPostProcessor)

标注有@Order注解,或者实现了org.springframework.core.annotation.Order接口的BeanPostProcessor,但是不包含MergedBeanDefinitionPostProcessor类型的

nonOrderedPostProcessors(未指定顺序的BeanPostProcessor)

上面2中类型置为以及MergedBeanDefinitionPostProcessor之外的

internalPostProcessors

MergedBeanDefinitionPostProcessor类型的BeanPostProcessor列表。

大家可以去看一下CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor,这两个类都实现了PriorityOrdered接口,但是他们也实现了MergedBeanDefinitionPostProcessor接口,所以最终他们会被丢到internalPostProcessors这个集合中,会被放入BeanPostProcessor的最后面

Bean生命周期流程图

参考:

https://blog.csdn.net/weixin_46228112/article/details/124602418?spm=1001.2014.3001.5506

相关推荐
曹牧20 分钟前
文档格式:OFD
java
豆角焖肉1 小时前
Maven进阶与搭建私服
java·maven
空中湖1 小时前
Spring AI Agent 编排:ReAct 模式 + 多 Agent 协作实战
人工智能·spring·react.js
大不点wow1 小时前
Java序列化与反序列化:让对象走出JVM
java·开发语言·jvm
止语Lab1 小时前
好的 DX 不等于少写代码——三种语言的摩擦力设计课
后端
吃饱了得干活1 小时前
别再手动解析 LLM 输出了!LangChain 四种结构化输出方案对比
后端·python·langchain
噢,我明白了1 小时前
Java中日期和字符串的处理
java·开发语言·日期
程序员天天困1 小时前
Arthas trace 命令怎么用?一行定位最慢那行代码
jvm·后端
Huiturn1 小时前
GPT 5.6 连续编码 10 小时,纯 Python 啃下 Word 二进制格式——doc2docx 实现拆解
后端
dkbnull1 小时前
Spring Boot请求处理组件对比详解
java·spring boot