Spring系列(20-22)

烟雨 3年前 (2022-10-09) 阅读数 505 #Spring
文章标签 Spring

二十、注解实现依赖注入(@Autowired、@Resource、@Primary、@Qulifier)

1、@Autowired:注入依赖对象

实现依赖注入,Spring容器会对bean中所有字段、方法进行遍历,标注有@Autowired注解的,都会进行注入。
看一下其定义:
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER,
ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    /**
    * Declares whether the annotated dependency is required.
    * <p>Defaults to {@code true}.
    */
    boolean required() default true;
}
可以用在构造器、方法、方法参数、字段、注解上。
参数:
    required:标注的对象是否必须注入,可能这个对象在容器中不存在,如果为true的时候,找不到匹配的候选者就会报错,为false时,找不到也没关系 。

@Autowire查找候选者的过程

@Autowired标注在字段上面:假定字段类型为一个自定义的普通的类型,候选者查找过程如下

image.png

@Autowired标注在方法上或者方法参数上面:假定参数类型为为一个自定义的普通的类型,候选者查找过程如下:

image.png

@Autowired查找候选者可以简化为下面这样(概括为:先按类型找,然后按名称找)
    按类型找->通过限定符@Qualifier过滤->@Primary指定优先->@Priority优先级->根据名称找(字段名称或者参数名称)

将指定类型的所有bean注入到Collection中

如果被注入的对象是Collection类型的,可以指定泛型的类型,然后会按照上面的方式查找所有满足泛型类型所有的bean
@Autowired
private List<IService> services;

将指定类型的所有bean注入到Map中

如果被注入的对象是Map类型的,可以指定泛型的类型,key通常为String类型,value为需要查找的bean的类型,然后会按照上面方式查找所有注入value类型的bean,将bean的name作为key,bean对象作为value,放在HashMap中,然后注入。
@Autowired
private Map<String, IService> serviceMap;
Spring使用下面这个类处理@Autowired注解
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor

2、@Resource:注意依赖对象

和@Autowired注解类似,也是用来注入依赖的对象的,Spring容器会对bean中所有字段、方法进行遍历,标注有@Resource注解的,都会进行注入。
javax.annotation.Resource

@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
    String name() default "";
    // 其他不常用的参数省略
}
这个注解是javax中定义的,并不是Spring中定义的注解。从定义上可以见,这个注解可以用在任何类型上面、字段、方法上面。
注意点:
    用在方法上的时候,方法参数只能有一个。

@Resource查找候选者的过程

@Resource标注在字段上面:假定字段类型为一个自定义的普通的类型,候选者查找过程如下

image.png

@Resource标注在方法上或者方法参数上面:假定参数类型为为一个自定义的普通的类型,候选者查找过程如下:

image.png

@Resource查找候选者可以简化为(概括为:先按名称找,然后按类)
先按Resource的name值作为bean名称找->按名称(字段名称、方法名称、set属性名称)找->按类型找->通过限定符@Qualifier过滤->@Primary指定优先->@Priority优先级->根据名称找(字段名称或者方法参数名称)

将指定类型的所有bean注入到Collection中

如果被注入的对象是Collection类型的,可以指定泛型的类型,然后会按照上面的方式查找所有满足泛型类型所有的bean
@Resource
private List<IService> services;

将指定类型的所有bean注入到Map中

如果被注入的对象是Map类型的,可以指定泛型的类型,key通常为String类型,value为需要查找的bean的类型,然后会按照上面方式查找所有注入value类型的bean,将bean的name作为key,bean对作为value,放在HashMap中,然后注入
@Resource
private Map<String, IService> serviceMap;
Spring使用下面这个类处理@Resource注解
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor

3、Qualifier:限定符

可以在依赖注入查找候选者的过程中对候选者进行过滤。
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER,
ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {
	String value() default "";
}
可以用在字段、方法、参数、任意类型、注解上面,有一个参数value。
可以@Autowired结合@Qulifier指定注入的bean。

4、@Primary:设置为主要候选者

注入依赖的过程中,当有多个候选者的时候,可以指定哪个候选者为主要的候选者。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Primary {
}
可以用在类上或者方法上面。
通常定义bean常见的有2种方式:
方式1:在类上标注@Component注解,此时可以配合@Primary,标注这个bean为主要候选者
方式2:在配置文件中使用@Bean注解标注方法,来注册bean,可以在@Bean标注的方法上加上@Primary,标注这个bean为主要候选bean。

5、泛型注入

定义两个普通类,一个泛型接口。两个接口实现类
public class UserModel {}

public class OrderModel {}

// 泛型接口
public interface IDao<T> {}

// 泛型接口实现类
@Component
public class UserDao implements IDao<UserModel> {// 指定泛型的类型为UserMod
}

@Component
public class OrderDao implements IDao<OrderModel> {//  指定泛型的类型为OrderModel
}

定义一个泛型service

public class BaseService<T> {
    @Autowired
    private IDao<T> dao;
    
    public IDao<T> getDao() {
    	return dao;
    }
    public void setDao(IDao<T> dao) {
    	this.dao = dao;
    }
}

定义泛型service实现类

@Component
public class UserService extends BaseService<UserModel> {// 指定注入的类型UserModel
}

@Component
public class OrderService extends BaseService<OrderModel> {// 指定注入的类型OrderModel
}
二十一、@Scope、@DependsOn、@ImportResource、@Lazy

1、@Scope

@Scope用来配置bean的作用域,等效于bean xml中的bean元素中的scope属性。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {
    @AliasFor("scopeName")
    String value() default "";
    @AliasFor("value")
    String scopeName() default "";
    ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
}

@Scope可以用在类上和方法上
参数:value和scopeName效果一样,用来指定bean作用域名称,如:singleton、prototype
@Component
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class ServiceA {
}

ConfigurableBeanFactory接口中定义了几个作用域相关的常量,可以直接拿来使用,如:

String SCOPE_SINGLETON = "singleton";
String SCOPE_PROTOTYPE = "prototype";

2、@DependsOn:指定当前bean依赖的bean

@DependsOn等效于bean xml中的bean元素中的depend-on属性。
@DependsOn可以指定当前bean依赖的bean,通过这个可以确保@DependsOn指定的bean在当前bean创建之前先创建好。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DependsOn {
	String[] value() default {};
}
可以用在任意类型和方法上。
value:String类型的数组,用来指定当前bean需要依赖的bean名称。

3、@ImportResource:配置类中导入bean定义的配置文件

有些项目,前期可能采用xml的方式配置bean,后期可能想采用Spring注解的方式来重构项目,但是有些老的模块可能还是xml的方式,Spring为了方便在注解方式中兼容老的xml的方式,提供了@ImportResource注解来引入bean定义的配置文件。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface ImportResource {
    @AliasFor("locations")
    String[] value() default {};
    
    @AliasFor("value")
    String[] locations() default {};
    
    Class<? extends BeanDefinitionReader> reader() default BeanDefinitionReader.class;
}
通常将其用在配置类上。
有3个参数:
  • value和locations效果一样,只能配置其中一个,是一个String类型的数组,用来指定需要导入的配置文件的路径。

  • reader:用来指定bean定义的读取器,目前我们知道的配置bean的方式有xml文件的方式,注解的方式,其实还有其他的方式,比如properties文件的方式,如果用其他的方式,你得告诉Spring具体要用那种解析器去解析这个bean配置文件,这个解析器就是BeanDefinitionReader。

资源文件路径的写法

通常我们的项是采用maven来组织的,配置文件一般会放在resources目录,这个目录中的文件被编译之后会在target/classes目录中。
Spring中资源文件路径最常用的有2种写法:
  • 以classpath:开头:检索目标为当前项目的classes目录。

  • 以classpath*:开头:检索目标为当前项目的classes目录,以及项目中所有jar包中的目录,如果你确定jar不是检索目标,就不要用这种方式,由于需要扫描所有jar包,所以速度相对于第一种会慢一些。

那我们再来说classpath:和classpath*:后面的部分,后面的部分是确定资源文件的位置地方,几种常见的如下:
// 文件通配符的方式
classpath:/com/javacode2018/lesson001/demo27/test5/beans-*.xml
// 目录通配符的方式
classpath:/com/javacode2018/lesson001/demo27/*/beans-*.xml
// 递归任意子目录的方式
classpath:/com/javacode2018/**/beans-*.xml

4、@Lazy:延迟初始化

@Lazy等效于bean xml中bean元素的lazy-init属性,可以实现bean的延迟初始化。
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR,
ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Lazy {
	boolean value() default true;
}
可以用在任意类型、方法、构造器、参数、字段上面。
参数:
value:boolean类型,用来配置是否应发生延迟初始化,默认为true。

二十二、Bean生命周期详解

1、Bean元信息配置阶段

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

Bean信息定义4种方式

  1. API的方式

  2. Xml文件方式

  3. properties文件的方式

  4. 注解的方式

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(是否是主要的候选者)等信息。

image.png

BeanDefinition接口:bean定义信息接口

表示bean定义信息的接口,里面定义了一些获取bean定义配置信息的各种方法,来看一下源码:
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接口:属性访问接口

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接口

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

Definition分类

RootBeanDefinition类:表示根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对象

案例

准备一个Car类
public class Car {
    private String name;
    //此处省略了get和set方法 toString方法
}

组装一个有属性的bean

@Test
public void test2() {
    //指定class
    BeanDefinitionBuilder beanDefinitionBuilder =
    BeanDefinitionBuilder.rootBeanDefinition(Car.class.getName());
    // 调用addPropertyValue给Car中的name设置值
    beanDefinitionBuilder.addPropertyValue("name", "奥迪");
    //获取BeanDefinition
    BeanDefinition carBeanDefinition = beanDefinitionBuilder.getBeanDefinition();
    System.out.println(carBeanDefinition);
    
    //创建spring容器
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    //调用registerBeanDefinition向容器中注册bean,bean的名称为car
    factory.registerBeanDefinition("car", carBeanDefinition);
    Car bean = factory.getBean("car", Car.class);
    System.out.println(bean);
}

组装一个有依赖关系的bean

下面这个类中有个car属性,我们通过Spring将这个属性注入进
public class User {
    private String name;
    private Car car;
    //此处省略了get和set方法 toString方法
}
@Test
public void test3() {
    // 先创建car这个BeanDefinition
    BeanDefinition carBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Car.class.getName()).addPropertyValue("name", "奥迪").getBeanDefinition();
    // 创建User这个BeanDefinition
    BeanDefinition userBeanDefinition = BeanDefinitionBuilder
        .rootBeanDefinition(User.class.getName())
        .addPropertyValue("name", "路人甲Java")
        // 注入依赖的bean,需要使用addPropertyReference方法,2个参数,第一个为属性的名称,第二个为需要注入的bean的名称
        .addPropertyReference("car", "car").getBeanDefinition();
    
    // 创建Spring容器
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    // 调用registerBeanDefinition向容器中注册bean
    factory.registerBeanDefinition("car", carBeanDefinition);
    factory.registerBeanDefinition("user", userBeanDefinition);
    System.out.println(factory.getBean("car"));
    System.out.println(factory.getBean("user"));
}

2个有父子关系的bean

@Test
public void test4() {
    //先创建car这个BeanDefinition
    BeanDefinition carBeanDefinition1 = BeanDefinitionBuilder.genericBeanDefinition(Car.class).addPropertyValue("name", "保时捷").getBeanDefinition();
    BeanDefinition carBeanDefinition2 = BeanDefinitionBuilder.genericBeanDefinition().setParentName("car1"). // 设置父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")));
}

通过api设置(Map、Set、List)属性

public class CompositeObj {
    private String name;
    private Integer salary;
    private Car car1;
    private List<String> stringList;
    private List<Car> carList;
    private Set<String> stringSet;
    private Set<Car> carSet;
    private Map<String, String> stringMap;
    private Map<String, Car> stringCarMap;
    
    //此处省略了get和set方法 toString方法
}
@Test
public void test5() {
    // 定义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<>();
    // RuntimeBeanReference:用来表示bean引用类型,类似于xml中的ref
    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)));
    }
}
RuntimeBeanReference:用来表示bean引用类型,类似于xml中的ref。
ManagedList:属性如果是List类型的,t需要用到这个类进行操作,这个类继承了ArrayList。
ManagedSet:属性如果是Set类型的,t需要用到这个类进行操作,这个类继承了LinkedHashSet。
ManagedMap:属性如果是Map类型的,t需要用到这个类进行操作,这个类继承了LinkedHashMap。

2、Bean元信息解析阶段

Bean元信息的解析就是将各种方式定义的bean配置信息解析为BeanDefinition对象。
Bean元信息的解析主要有3种方式
  1. xml文件定义bean的解析。

  2. properties文件定义bean的解析。

  3. 注解方式定义bean的解析。

XML方式解析:XmlBeanDefinitionReader

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

案例

<?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="car" class="com.javacode2018.lesson002.demo1.Car">
    	<property name="name" value="奥迪"/>
    </bean>
    
    <bean id="car1" class="com.javacode2018.lesson002.demo1.Car">
    	<property name="name" value="保时捷"/>
    </bean>
    
    <bean id="car2" parent="car1"/>
    
    <bean id="user" class="com.javacode2018.lesson002.demo1.User">
        <property name="name" value="路人甲Java"/>
        <property name="car" ref="car1"/>
    </bean>
</beans>

将bean xml解析为BeanDefinition对象

/**
* xml方式bean配置信息解析
*/
@Test
public void test1() {
    // 定义一个spring容器,这个容器默认实现了BeanDefinitionRegistry,所以本身就是一个bean注册器
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    // 定义一个xml的BeanDefinition读取器,需要传递一个BeanDefinitionRegistry(bean注册器)对象
    XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(factory);
    // 指定bean xml配置文件的位置
    String location = "classpath:/com/javacode2018/lesson002/demo2/beans.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);
    }
}

properties文件定义bean的解析:PropertiesBeanDefinitionReader

car.(class)=com.javacode2018.lesson002.demo1.Car
car.name=奥迪
car1.(class)=com.javacode2018.lesson002.demo1.Car
car1.name=保时捷
car2.(parent)=car1
user.(class)=com.javacode2018.lesson002.demo1.User
user.name=路人甲Java
user.car(ref)=car

将bean properties文件解析为BeanDefinition对象

/**
* properties文件方式bean配置信息解析
*/
@Test
public void test2() {
    // 定义一个spring容器,这个容器默认实现了BeanDefinitionRegistry,所以本身就是一个bean注册器
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    // 定义一个properties的BeanDefinition读取器,需要传递一个BeanDefinitionRegistry(bean注册器)对象
    PropertiesBeanDefinitionReader propertiesBeanDefinitionReader = new
    PropertiesBeanDefinitionReader(factory);
    // 指定bean xml配置文件的位置
    String location ="classpath:/com/javacode2018/lesson002/demo2/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);
    }
}

注解方式:PropertiesBeanDefinitionReader

注解的方式定义的bean,需要使用PropertiesBeanDefinitionReader这个类来进行解析,方式也和上面2种方式类似,直接来看案例。
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Primary
@Lazy
public class Service1 {
    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
    }
}

public class Service2 {
    @Autowired
    private Service1 service1;
    
    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
    }
}

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

@Test
public void test3() {
    // 定义一个spring容器,这个容器默认实现了BeanDefinitionRegistry,所以本身就是一个bean注册器
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    // 定义一个注解方式的BeanDefinition读取器,需要传递一个BeanDefinitionRegistry(bean注册器)对象
    AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(factory);
    // 通过PropertiesBeanDefinitionReader加载bean properties文件,然后将解析产生的BeanDefinition注册到容器容器中
    annotatedBeanDefinitionReader.register(Service1.class, Service2.class);
    // 打印出注册的bean的配置信息
    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);
    }
}

运行输出

image.png

注意下:最后一行中的service1为什么为null,不是标注了@Autowired么?
for循环前面加上如下代码即可
factory.getBeansOfType(BeanPostProcessor.class).values().forEach(factory::addBeanPostProcessor);

3、Spring Bean注册阶段

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

Bean注册接口:BeanDefinitionRegistry

这个接口中定义了注册bean常用到的一些方法,源码如下:
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别名的一些方法,看一下其源码:

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

Spring中BeanDefinitionRegistry接口有一个唯一的实现类:
org.springframework.beans.factory.support.DefaultListableBeanFactory
DefaultListableBeanFactory是整个bean加载的核心,是spring注册及加载bean的默认实现。大家可能看到有很多类也实现了 BeanDefinitionRegistry 接口,比如我们经常用到的AnnotationConfigApplicationContext ,但实际上其内部是转发给了DefaultListableBeanFactory 进行处理的,所以真正实现这个接口的类是DefaultListableBeanFactory。

4、BeanDefinition合并阶段

合并阶段是做什么的?
可能我们定义bean的时候有父子bean关系,此时子BeanDefinition中的信息是不完整的,比如设置属性的时候配置在父BeanDefinition中,此时子BeanDefinition中是没有这些信息的,需要将子bean的BeanDefinition和父bean的BeanDefinition进行合并,得到最终的一个 RootBeanDefinition ,合并之后得到的 RootBeanDefinition 包含bean定义的所有信息,包含了从父bean中继承过来的所有信息,后续bean的所有创建工作就是依靠合并之后RootBeanDefinition来进行的。
合并BeanDefinition会使用下面这个方法:
org.springframework.beans.factory.support.AbstractBeanFactory#getMergedBeanDefinition
bean定义可能存在多级父子关系,合并的时候进进行递归合并,最终得到一个包含完整信息的RootBeanDefinition。

5、Bean Class加载阶段

这个阶段就是将bean的class名称转换为Class类型的对象。
BeanDefinition中有个Object类型的字段:beanClass。
private volatile Object beanClass;
用来表示bean的class对象,通常这个字段的值有2种类型,一种是bean对应的Class类型的对象,另一种是bean对应的Class的完整类名,第一种情况不需要解析,第二种情况:即这个字段是bean的类名的时候,就需要通过类加载器将其转换为一个Class对象。
此时会对 BeanDefinition合并阶段 中合并产生的 RootBeanDefinition 中的 beanClass 进行解析,将bean的类名转换为Class对象 ,然后赋值给 beanClass 字段。
源码位置:
org.springframework.beans.factory.support.AbstractBeanFactory#resolveBeanClass
上面得到了Bean Class对象以及合并之后的RootBeanDefinition,下面就开始进入实例化这个对象的阶段了。

6、Bean实例化阶段

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

  2. Bean实例化操作。

Bean实例化前操作

先来看一下 DefaultListableBeanFactory ,这个类中有个非常非常重要的字段,是一个 BeanPostProcessor 类型的集合:
private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();
BeanPostProcessor是一个接口,还有很多子接口,这些接口中提供了很多方法,Spring在bean生命周期的不同阶段,会调用上面这个列表中的BeanPostProcessor中的一些方法,来对生命周期进行扩展,bean生命周期中的所有扩展点都是依靠这个集合中的BeanPostProcessor来实现的,所以如果大家想对bean的生命周期进行干预,这块一定要掌握好。
注意:很多以BeanPostProcessor结尾的,都实现了BeanPostProcessor接口,有些是直接实现的,有些是实现了它的子接口。
Bean实例化之前会调用一段代码:
@Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
            if (result != null) {
            	return result;
            }
        }
    }
    return null;
}
这段代码在bean实例化之前给开发者留了个口子,开发者自己可以在这个地方直接去创建一个对象作为bean实例,而跳过Spring内部实例化bean的过程。
上面代码中轮询 beanPostProcessors 列表,如果类型是InstantiationAwareBeanPostProcessor , 尝试调用InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 获取bean的实例对象,如果能够获取到,那么将返回值作为当前bean的实例,那么Spring自带的实例化bean的过程就被跳过了。
postProcessBeforeInstantiation 方法如下:
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
	return null;
}
这个地方给开发者提供了一个扩展点,允许开发者在这个方法中直接返回bean的一个实例,从而跳过Spring自带的实例化bean过程。

Bean实例化操作

这个过程会通过反射来调用bean的构造器来创建bean的实例。
具体需要使用哪个构造器,Spring为开发者提供了一个接口,允许开发者自己来判断用哪个构造器。
看一下这块的代码逻辑:
for (BeanPostProcessor bp : getBeanPostProcessors()) {
    if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
        SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
        Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass,  beanName);
        if (ctors != null) {
        	return ctors;
        }
    }
}

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

@Nullable
default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
	return null;
}
这个方法有个比较重要的实现类:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
可以将 @Autowired 标注的方法作为候选构造器返回。

案例

自定义一个注解,当构造器被这个注解标注的时候,让Spring自动选择使用这个构造器创建对象。
下面这个注解可以标注在构造器上面,使用这个标注之后,创建bean的时候将使用这个构造器。
@Target(ElementType.CONSTRUCTOR)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAutowried {
}
public class Person {
    private String name;
    private Integer age;
    
    public Person() {
    	System.out.println("调用 Person()");
    }
    
    @MyAutowried
    public Person(String name) {
    	System.out.println("调用 Person(String name)");
    	this.name = name;
    }
    
    public Person(String name, Integer age) {
    	System.out.println("调用 Person(String name, int age)");
    	this.name = name;
    	this.age = age;
    }
    //省略get set toString方法
}

自定义一个SmartInstantiationAwareBeanPostProcessor。代码的逻辑:将 @MyAutowried 标注的构造器列表返回

public class MySmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
    @Override
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println(beanClass);
        System.out.println("调用 MySmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors 方法");
        Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
        //获取有@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;
    }
}

测试

@Test
public void test2() {
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    //创建一个SmartInstantiationAwareBeanPostProcessor,将其添加到容器中
    factory.addBeanPostProcessor(new MySmartInstantiationAwareBeanPostProcessor());

    factory.registerBeanDefinition("name",
                                   BeanDefinitionBuilder.
                                   genericBeanDefinition(String.class).
                                   addConstructorArgValue("Java").
                                   getBeanDefinition());

    factory.registerBeanDefinition("person",
                                   BeanDefinitionBuilder.
                                   genericBeanDefinition(Person.class).
                                   getBeanDefinition());
    Person person = factory.getBean("person", Person.class);
    System.out.println(person);
}

image.png

从输出中可以看出调用了Person中标注@MyAutowired标注的构造器。
到目前为止bean实例化阶段结束了,继续进入后面的阶段。

7、BeanDefinition的后置处理

这块的源码如下
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd,Class<?> beanType, String beanName) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof MergedBeanDefinitionPostProcessor) {
        	MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
        	bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
        }
    }
}

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

void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName)
Spring会轮询 BeanPostProcessor ,依次调用MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition 方法
第一个参数为beanDefinition,表示合并之后的RootBeanDefinition,我们可以在这个方法内部对合并之后的 BeanDefinition 进行再次处理
postProcessMergedBeanDefinition有2个实现类,前面我们介绍过,用的也比较多,面试的时候也会经常问的:
// 在 postProcessMergedBeanDefinition 方法中对 @Autowired、@Value 标注的方法、字段进行缓存
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
// 在 postProcessMergedBeanDefinition 方法中对 @Resource 标注的字段、@Resource 标注的方法、 @PostConstruct 标注的字段、 @PreDestroy标注的方法进行缓存
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor

8、Bean属性设置阶段

属性设置阶段分为3个小的阶段
  1. 实例化后阶段。

  2. Bean属性赋值前处理。

  3. Bean属性赋值。

实例化后阶段

会调用 InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation 这个方法,调用逻辑如下:
for (BeanPostProcessor bp : getBeanPostProcessors()) {
    if (bp instanceof InstantiationAwareBeanPostProcessor) {
        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
        if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(),  beanName)) {
            return;
        }
    }
}

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

default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
	return true;
}

Bean属性赋值前阶段

这个阶段会调用 InstantiationAwareBeanPostProcessor#postProcessProperties 方法,调用逻辑:
for (BeanPostProcessor bp : getBeanPostProcessors()) {
    if (bp instanceof InstantiationAwareBeanPostProcessor) {
        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
        PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
        if (pvsToUse == null) {
            if (filteredPds == null) {
                filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            }
            pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
                return;
            }
        }
        pvs = pvsToUse;
    }
}
从上面可以看出,如果 InstantiationAwareBeanPostProcessor 中的postProcessProperties 和 postProcessPropertyValues 都返回空的时候,表示这个bean不需要设置属性,直接返回了,直接进入下一个阶段。

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

@Nullable
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
	return null;
}
PropertyValues中保存了bean实例对象中所有属性值的设置,所以我们可以在这个这个方法中对PropertyValues值进行修改。
这个方法有2个比较重要的实现类
  • AutowiredAnnotationBeanPostProcessor:在这个方法中对@Autowired、@Value标注的字段、方法注入值。

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

Bean属性赋值阶段

这个过程比较简单了,循环处理 PropertyValues 中的属性值信息,通过反射调用set方法将属性的值设置到bean实例中。
PropertyValues中的值是通过bean xml中property元素配置的,或者调用MutablePropertyValues中add方法设置的值。

9、Bean初始化阶段

这个阶段分为下面的小阶段
  1. Bean Aware接口回调。

  2. Bean初始化前操作。

  3. Bean初始化操作。

  4. Bean初始化后操作。

Bean Aware接口回调

private void invokeAwareMethods(final String beanName, final 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、BeanClassLoaderAware、BeanFactoryAware),会按照下面的顺序依次进行调用:
  1. BeanNameAware:将bean的名称注入进去。

  2. BeanClassLoaderAware:将BeanClassLoader注入进去。

  3. BeanFactoryAware:将BeanFactory注入进去。

Bean初始化前操作

@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.CommonAnnotationBeanPostProcess

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注解的方法
@PostConstruct
public void postConstruct1() {
    System.out.println("postConstruct1()");
}
@Test
public void test6() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(Person.class);
    context.refresh();
}

image.png

Bean初始化阶段

2个步骤
  1. 调用InitializingBean接口的afterPropertiesSet方法。

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

调用InitializingBean接口的afterPropertiesSet方法

来看一下InitializingBean这个接口
public interface InitializingBean {
	void afterPropertiesSet() throws Exception;
}
当我们的bean实现了这个接口的时候,会在这个阶段被调用。

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

如何下如何指定bean的初始化方法,3种方式
方式1:xml方式指定初始化方法
<bean init-method="bean中方法名称"/>

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

@Bean(initMethod = "初始化的方法")

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

this.beanDefinition.setInitMethodName(methodName);

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

org.springframework.beans.factory.support.AbstractBeanDefinition#initMethodName

Bean初始化后阶段

@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初始化后置操作。

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

所有单例bean实例化完成之后,Spring会回调下面这个接口:
public interface SmartInitializingSingleton {
	void afterSingletonsInstantiated();
}

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

/**
* 确保所有非lazy的单例都被实例化,同时考虑到FactoryBeans。如果需要,通常在工厂设置结束时调用。
*/
org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
这个方法内部会先触发所有非延迟加载的单例bean初始化,然后从容器中找到类型是SmartInitializingSingleton的bean,调用他们的 afterSingletonsInstantiated() 方法。

例子

@Component
public class Service1 {
    public Service1() {
    	System.out.println("create " + this.getClass());
    }
}

@Component
public class Service2 {
    public Service2() {
    	System.out.println("create " + this.getClass());
    }
}

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

@Test
public void test1() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(DemoTest.class);
    System.out.println("开始启动容器!");
    context.refresh();
    System.out.println("容器启动完毕!");
}
开始启动容器!
create class com.Service1
create class com.Service2
所有bean初始化完毕!
容器启动完毕!

通过api的方式让DefaultListableBeanFactory去回调SmartInitializingSingleton。

@Test
public void test2() {
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    factory.registerBeanDefinition("service1", BeanDefinitionBuilder.genericBeanDefinition(Service1.class).getBeanDefinition());
    factory.registerBeanDefinition("service2", BeanDefinitionBuilder.genericBeanDefinition(Service2.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销毁的几种方式

  • 调用org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#destroyBean

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

  • 调用ApplicationContext中的close方法

Bean销毁阶段会依次执行

  1. 轮询beanPostProcessors列表,如果是DestructionAwareBeanPostProcessor这种类型的,会调用其内部的postProcessBeforeDestruction()方法。

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

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

DestructionAwareBeanPostProcessor接口

public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {
    /**
    * bean销毁前调用的方法
    */
    void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;
    
    /**
    * 用来判断bean是否需要触发postProcessBeforeDestruction方法
    */
    default boolean requiresDestruction(Object bean) {
    	return true;
    }
}
这个接口有个关键的实现类:
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor#postProcessBeforeDestruction方法中会调用bean中所有标注了@PreDestroy的方法。

自定义销毁方法有3种方式

方式1:xml中指定销毁方法
<bean destroy-method="bean中方法名称"/>

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

@Bean(destroyMethod = "初始化的方法")

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

this.beanDefinition.setDestroyMethodName(methodName);

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

org.springframework.beans.factory.support.AbstractBeanDefinition#destroyMethodName

自定义DestructionAwareBeanPostProcessor

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

触发@PreDestroy标注的方法被调用

上面说了这个注解是在 CommonAnnotationBeanPostProcessor#postProcessBeforeDestruction 中被处理的,所以只需要将这个加入BeanPostProcessor列表就可以了。
public class ServiceB {
    public ServiceB() {
    	System.out.println("create " + this.getClass());
    }
    
    @PreDestroy
    public void preDestroy() {
    	System.out.println("preDestroy()");
    }
}
@Test
public void test2() {
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    //添加自定义的DestructionAwareBeanPostProcessor
    factory.addBeanPostProcessor(new MyDestructionAwareBeanPostProcessor());
    //将CommonAnnotationBeanPostProcessor加入,这个会处理bean中标注@PreDestroy注解的方法
    factory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());
    //向容器中注入bean
    factory.registerBeanDefinition("serviceB", BeanDefinitionBuilder.genericBeanDefinition(ServiceB.class).getBeanDefinition());
    //触发所有单例bean初始化
    factory.preInstantiateSingletons();
    
    System.out.println("销毁serviceB");
    //销毁指定的bean
    factory.destroySingleton("serviceB");
}

销毁方法调用的顺序

  1. @PreDestroy标注的所有方法。

  2. DisposableBean接口中的destroy()。

  3. 自定义的销毁方法。

AbstractApplicationContext类(非常重要的类)

image.png

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容器。
第二个方法:registerBeanPostProcessors
说的通俗点:这个方法就是向ConfigurableListableBeanFactory中注册BeanPostProcessor,内部会从Spring容器中获取所有类型的BeanPostProcessor,将其添加到DefaultListableBeanFactory#beanPostProcessors列表中
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)
实现了org.springframework.core.annotation.Order接口的BeanPostProcessor,但是不包含MergedBeanDefinitionPostProcessor类型的
nonOrderedPostProcessors(未指定顺序的BeanPostProcessor)
上面2中类型置为以及MergedBeanDefinitionPostProcessor之外的
internalPostProcessors
MergedBeanDefinitionPostProcessor类型的BeanPostProcessor列表。
大家可以去看一下 CommonAnnotationBeanPostProcessor 和AutowiredAnnotationBeanPostProcessor ,这两个类都实现了 PriorityOrdered 接口,但是他们也实现了 MergedBeanDefinitionPostProcessor 接口,所以最终他们会被丢到internalPostProcessors 这个集合中,会被放入BeanPostProcessor的最后面。
总结
Spring创建Bean的生命周期如下:
  1. Bean元信息配置阶段:获取Bean元信息,Bean原信息定义方式(API的方式、xml方式、properties文件的方式、注解方式)。

  2. Bean元信息解析阶段:利用Bean元信息,生成BeanDefinition。

  3. Spring Bean注册阶段:利用生成BeanDefinition去注册Bean。

  4. BeanDefinition合并阶段:合并具有父子关系bean。最终得到一个RootBeanDefinition。

  5. Bean Class加载阶段:这个阶段就是将bean的class名称转换为Class类型的对象。

  6. Bean实例化阶段:

    1. Bean实例化前操作:会调用InstantiationAwareBeanPostProcessor#postProcessBeforeInitialization()方法,我们可以利用这个方法跳过Spring自带的实例化bean过程。

    2. 实例化操作:会调用SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors()方法逻辑,如何实例化(Supplier\工厂方法创建对象\推断构造方法)。

  7. BeanDefinition的后置处理:调用MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition()方法。

  8. Bean属性设置阶段:

    1. Bean实例化后:会调用InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation()方法,方法返回false则跳过属性赋值。

    2. Bean属性赋值前:会调用InstantiationAwareBeanPostProcessor#postProcessProperties()方法。

    3. Bean属性赋值:循环处理PropertyValues中的属性值信息,通过反射调用set方法将属性的值设置到bean实例中。

  9. Bean初始化阶段:

    1. Bean Aware接口回调:如果Bean实现了BeanNameAware、 BeanClassLoaderAware、 BeanFactoryAware、EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware。会依次调用相应实现的接口方法。

    2. Bean初始化前:会调用BeanPostProcessor#postProcessBeforeInitialization()方法。

    3. Bean初始化:

      1. 调用InitializingBean#afterPropertiesSet()方法。

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

    4. Bean初始化后:调用BeanPostProcessor#postProcessAfterInitialization()方法。

  10. 所有单例bean初始化完成后阶段:所有单例bean实例化完成之后,Spring会回调SmartInitializingSingleton#afterSingletonsInstantiated()方法。

  11. Bean使用阶段。

  12. Bean销毁阶段:

    1. 轮询beanPostProcessors列表,如果是DestructionAwareBeanPostProcessor这种类型的,会调用其内部的postProcessBeforeDestruction()方法。

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

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

Bean生命周期流程图

image.png


参考:路人甲-Spring系列

版权声明

非特殊说明,本文由Zender原创或收集发布,欢迎转载。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

作者文章
热门