飞道的博客

终于,月薪过5万了!

220人阅读  评论(0)

来看几个问题

  1. 想不想月薪超过5万?

  2. 想不想进入公司架构组?

  3. 想不想成为项目组的负责人?

  4. 想不想成为spring的高手,超越99%的对手?

那么本文内容是你必须要掌握的。

本文主要详解bean的生命周期,分为13个环节,每个环节中spring都提供了一些扩展点,我们都将进行详细说明,让大家全面掌握这块的知识。

Spring bean生命周期13个环节

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

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

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

  4. 阶段4:BeanDefinition合并阶段

  5. 阶段5:Bean Class加载阶段

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

  • Bean实例化前阶段

  • Bean实例化阶段

  1. 阶段7:合并后的BeanDefinition处理

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

  • Bean实例化后阶段

  • Bean属性赋值前阶段

  • Bean属性赋值阶段

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

  • Bean Aware接口回调阶段

  • Bean初始化前阶段

  • Bean初始化阶段

  • Bean初始化后阶段

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

  2. 阶段11:Bean的使用阶段

  3. 阶段12:Bean销毁前阶段

  4. 阶段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定义信息接口

表示bean定义信息的接口,里面定义了一些获取bean定义配置信息的各种方法,来看一下源码:


   
  1. public  interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
  2.      /**
  3.      * 设置此bean的父bean名称(对应xml中bean元素的parent属性)
  4.      */
  5.     void setParentName(@Nullable String parentName);
  6.      /**
  7.      * 返回此bean定义时指定的父bean的名称
  8.      */
  9.     @Nullable
  10.     String getParentName();
  11.      /**
  12.      * 指定此bean定义的bean类名(对应xml中bean元素的class属性)
  13.      */
  14.     void setBeanClassName(@Nullable String beanClassName);
  15.      /**
  16.      * 返回此bean定义的当前bean类名
  17.      * 注意,如果子定义重写/继承其父类的类名,则这不一定是运行时使用的实际类名。此外,这可能只是调用工厂方法的类,或者在调用方法的工厂bean引用的情况下,它甚至可能是空的。因此,不要认为这是运行时的最终bean类型,而只将其用于单个bean定义级别的解析目的。
  18.      */
  19.     @Nullable
  20.     String getBeanClassName();
  21.      /**
  22.      * 设置此bean的生命周期,如:singleton、prototype(对应xml中bean元素的scope属性)
  23.      */
  24.     void setScope(@Nullable String scope);
  25.      /**
  26.      * 返回此bean的生命周期,如:singleton、prototype
  27.      */
  28.     @Nullable
  29.     String getScope();
  30.      /**
  31.      * 设置是否应延迟初始化此bean(对应xml中bean元素的lazy属性)
  32.      */
  33.     void setLazyInit(boolean lazyInit);
  34.      /**
  35.      * 返回是否应延迟初始化此bean,只对单例bean有效
  36.      */
  37.     boolean isLazyInit();
  38.      /**
  39.      * 设置此bean依赖于初始化的bean的名称,bean工厂将保证dependsOn指定的bean会在当前bean初始化之前先初始化好
  40.      */
  41.     void setDependsOn(@Nullable String... dependsOn);
  42.      /**
  43.      * 返回此bean所依赖的bean名称
  44.      */
  45.     @Nullable
  46.     String[] getDependsOn();
  47.      /**
  48.      * 设置此bean是否作为其他bean自动注入时的候选者
  49.      * autowireCandidate
  50.      */
  51.     void setAutowireCandidate(boolean autowireCandidate);
  52.      /**
  53.      * 返回此bean是否作为其他bean自动注入时的候选者
  54.      */
  55.     boolean isAutowireCandidate();
  56.      /**
  57.      * 设置此bean是否为自动注入的主要候选者
  58.      * primary:是否为主要候选者
  59.      */
  60.     void setPrimary(boolean primary);
  61.      /**
  62.      * 返回此bean是否作为自动注入的主要候选者
  63.      */
  64.     boolean isPrimary();
  65.      /**
  66.      * 指定要使用的工厂bean(如果有)。这是要对其调用指定工厂方法的bean的名称。
  67.      * factoryBeanName:工厂bean名称
  68.      */
  69.     void setFactoryBeanName(@Nullable String factoryBeanName);
  70.      /**
  71.      * 返回工厂bean名称(如果有)(对应xml中bean元素的factory-bean属性)
  72.      */
  73.     @Nullable
  74.     String getFactoryBeanName();
  75.      /**
  76.      * 指定工厂方法(如果有)。此方法将使用构造函数参数调用,如果未指定任何参数,则不使用任何参数调用。该方法将在指定的工厂bean(如果有的话)上调用,或者作为本地bean类上的静态方法调用。
  77.      * factoryMethodName:工厂方法名称
  78.      */
  79.     void setFactoryMethodName(@Nullable String factoryMethodName);
  80.      /**
  81.      * 返回工厂方法名称(对应xml中bean的factory-method属性)
  82.      */
  83.     @Nullable
  84.     String getFactoryMethodName();
  85.      /**
  86.      * 返回此bean的构造函数参数值
  87.      */
  88.     ConstructorArgumentValues getConstructorArgumentValues();
  89.      /**
  90.      * 是否有构造器参数值设置信息(对应xml中bean元素的<constructor-arg />子元素)
  91.      */
  92.      default boolean hasConstructorArgumentValues() {
  93.          return !getConstructorArgumentValues().isEmpty();
  94.     }
  95.      /**
  96.      * 获取bean定义是配置的属性值设置信息
  97.      */
  98.     MutablePropertyValues getPropertyValues();
  99.      /**
  100.      * 这个bean定义中是否有属性设置信息(对应xml中bean元素的<property />子元素)
  101.      */
  102.      default boolean hasPropertyValues() {
  103.          return !getPropertyValues().isEmpty();
  104.     }
  105.      /**
  106.      * 设置bean初始化方法名称
  107.      */
  108.     void setInitMethodName(@Nullable String initMethodName);
  109.      /**
  110.      * bean初始化方法名称
  111.      */
  112.     @Nullable
  113.     String getInitMethodName();
  114.      /**
  115.      * 设置bean销毁方法的名称
  116.      */
  117.     void setDestroyMethodName(@Nullable String destroyMethodName);
  118.      /**
  119.      * bean销毁的方法名称
  120.      */
  121.     @Nullable
  122.     String getDestroyMethodName();
  123.      /**
  124.      * 设置bean的role信息
  125.      */
  126.     void setRole( int role);
  127.      /**
  128.      * bean定义的role信息
  129.      */
  130.      int getRole();
  131.      /**
  132.      * 设置bean描述信息
  133.      */
  134.     void setDescription(@Nullable String description);
  135.      /**
  136.      * bean描述信息
  137.      */
  138.     @Nullable
  139.     String getDescription();
  140.      /**
  141.      * bean类型解析器
  142.      */
  143.     ResolvableType getResolvableType();
  144.      /**
  145.      * 是否是单例的bean
  146.      */
  147.     boolean isSingleton();
  148.      /**
  149.      * 是否是多列的bean
  150.      */
  151.     boolean isPrototype();
  152.      /**
  153.      * 对应xml中bean元素的abstract属性,用来指定是否是抽象的
  154.      */
  155.     boolean isAbstract();
  156.      /**
  157.      * 返回此bean定义来自的资源的描述(以便在出现错误时显示上下文)
  158.      */
  159.     @Nullable
  160.     String getResourceDescription();
  161.     @Nullable
  162.     BeanDefinition getOriginatingBeanDefinition();
  163. }

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

  • AttributeAccessor

  • BeanMetadataElement

AttributeAccessor接口:属性访问接口

   
  1. public  interface AttributeAccessor {
  2.      /**
  3.      * 设置属性->值
  4.      */
  5.     void setAttribute(String name, @Nullable Object value);
  6.      /**
  7.      * 获取某个属性对应的值
  8.      */
  9.     @Nullable
  10.     Object getAttribute(String name);
  11.      /**
  12.      * 移除某个属性
  13.      */
  14.     @Nullable
  15.     Object removeAttribute(String name);
  16.      /**
  17.      * 是否包含某个属性
  18.      */
  19.     boolean hasAttribute(String name);
  20.      /**
  21.      * 返回所有的属性名称
  22.      */
  23.     String[] attributeNames();
  24. }

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

BeanMetadataElement接口

看一下其源码:


   
  1. public  interface BeanMetadataElement {
  2.     @Nullable
  3.      default Object getSource() {
  4.          return null;
  5.     }
  6. }

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

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对象,下面我们通过案例来感受一下。

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

来个简单的类

   
  1. package com.javacode2018.lesson002.demo1;
  2. public class Car {
  3.     private String name;
  4.     public String getName() {
  5.          return name;
  6.     }
  7.     public void setName(String name) {
  8.         this.name = name;
  9.     }
  10.     @Override
  11.     public String toString() {
  12.          return  "Car{" +
  13.                  "name='" + name +  '\'' +
  14.                  '}';
  15.     }
  16. }
测试用例

   
  1. @Test
  2. public void test1() {
  3.      //指定class
  4.     BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(Car.class.getName());
  5.      //获取BeanDefinition
  6.     BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
  7.     System.out. println(beanDefinition);
  8. }

等效于

<bean class="com.javacode2018.lesson002.demo1.Car" />
运行输出
Root bean: class [com.javacode2018.lesson002.demo1.Car]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null

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

代码

   
  1. @Test
  2. public void test2() {
  3.      //指定class
  4.     BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(Car.class.getName());
  5.      //设置普通类型属性
  6.     beanDefinitionBuilder.addPropertyValue( "name""奥迪");  //@1
  7.      //获取BeanDefinition
  8.     BeanDefinition carBeanDefinition = beanDefinitionBuilder.getBeanDefinition();
  9.     System.out. println(carBeanDefinition);
  10.      //创建spring容器
  11.     DefaultListableBeanFactory factory =  new DefaultListableBeanFactory();  //@2
  12.      //调用registerBeanDefinition向容器中注册bean
  13.     factory.registerBeanDefinition( "car", carBeanDefinition);  //@3
  14.     Car bean = factory.getBean( "car", Car.class);  //@4
  15.     System.out. println(bean);
  16. }

@1:调用addPropertyValue给Car中的name设置值

@2:创建了一个spring容器

@3:将carBeanDefinition这个bean配置信息注册到spring容器中,bean的名称为car

@4:从容器中获取car这个bean,最后进行输出

运行输出

   
  1. Root bean: class [com.javacode2018.lesson002.demo1.Car]; scope=; abstract= false; lazyInit=null; autowireMode= 0; dependencyCheck= 0; autowireCandidate= true; primary= false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
  2. Car{name= '奥迪'}

第二行输出了从容器中获取的car这个bean实例对象。

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

再来个类

下面这个类中有个car属性,我们通过spring将这个属性注入进来。


   
  1. package com.javacode2018.lesson002.demo1;
  2. public class User {
  3.     private String name;
  4.     private Car car;
  5.     public String getName() {
  6.          return name;
  7.     }
  8.     public void setName(String name) {
  9.         this.name = name;
  10.     }
  11.     public Car getCar() {
  12.          return car;
  13.     }
  14.     public void setCar(Car car) {
  15.         this.car = car;
  16.     }
  17.     @Override
  18.     public String toString() {
  19.          return  "User{" +
  20.                  "name='" + name +  '\'' +
  21.                  ", car=" + car +
  22.                  '}';
  23.     }
  24. }
重点代码

   
  1. @Test
  2. public void test3() {
  3.      //先创建car这个BeanDefinition
  4.     BeanDefinition carBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Car.class.getName()).addPropertyValue( "name""奥迪").getBeanDefinition();
  5.      //创建User这个BeanDefinition
  6.     BeanDefinition userBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class.getName()).
  7.             addPropertyValue( "name""路人甲Java").
  8.             addPropertyReference( "car""car").  //@1
  9.             getBeanDefinition();
  10.      //创建spring容器
  11.     DefaultListableBeanFactory factory =  new DefaultListableBeanFactory();
  12.      //调用registerBeanDefinition向容器中注册bean
  13.     factory.registerBeanDefinition( "car", carBeanDefinition); 
  14.     factory.registerBeanDefinition( "user", userBeanDefinition);
  15.     System.out. println(factory.getBean( "car"));
  16.     System.out. println(factory.getBean( "user"));
  17. }

@1:注入依赖的bean,需要使用addPropertyReference方法,2个参数,第一个为属性的名称,第二个为需要注入的bean的名称

上面代码等效于


   
  1. <bean id= "car" class= "com.javacode2018.lesson002.demo1.Car">
  2.     <property name= "name" value= "奥迪"/>
  3. </bean>
  4. <bean id= "user" class= "com.javacode2018.lesson002.demo1.User">
  5.     <property name= "name" value= "路人甲Java"/>
  6.     <property name= "car" ref= "car"/>
  7. </bean>
运行输出

   
  1. Car{name= '奥迪'}
  2. User{name= '路人甲Java', car=Car{name= '奥迪'}}

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


   
  1. @Test
  2. public void test4() {
  3.      //先创建car这个BeanDefinition
  4.     BeanDefinition carBeanDefinition1 = BeanDefinitionBuilder.
  5.             genericBeanDefinition(Car.class).
  6.             addPropertyValue( "name""保时捷").
  7.             getBeanDefinition();
  8.     BeanDefinition carBeanDefinition2 = BeanDefinitionBuilder.
  9.             genericBeanDefinition().  //内部生成一个GenericBeanDefinition对象
  10.             setParentName( "car1").  //@1:设置父bean的名称为car1
  11.             getBeanDefinition();
  12.      //创建spring容器
  13.     DefaultListableBeanFactory factory =  new DefaultListableBeanFactory();
  14.      //调用registerBeanDefinition向容器中注册bean
  15.      //注册car1->carBeanDefinition1
  16.     factory.registerBeanDefinition( "car1", carBeanDefinition1);
  17.      //注册car2->carBeanDefinition2
  18.     factory.registerBeanDefinition( "car2", carBeanDefinition2);
  19.      //从容器中获取car1
  20.     System.out. println(String.format( "car1->%s", factory.getBean( "car1")));
  21.      //从容器中获取car2
  22.     System.out. println(String.format( "car2->%s", factory.getBean( "car2")));
  23. }

等效于


   
  1. <bean id= "car1" class= "com.javacode2018.lesson002.demo1.Car">
  2.     <property name= "name" value= "保时捷"/>
  3. </bean>
  4. <bean id= "car2" parent= "car1" />
运行输出

   
  1. car1->Car{name= '保时捷'}
  2. car2->Car{name= '保时捷'}

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

下面我们来演示注入List、Map、Set,内部元素为普通类型及其他bean元素。

来个类

   
  1. package com.javacode2018.lesson002.demo1;
  2. import java.util.List;
  3. import java.util.Map;
  4. import java.util.Set;
  5. public class CompositeObj {
  6.     private String name;
  7.     private Integer salary;
  8.     private Car car1;
  9.     private List<String> stringList;
  10.     private List<Car> carList;
  11.     private Set<String> stringSet;
  12.     private Set<Car> carSet;
  13.     private Map<String, String> stringMap;
  14.     private Map<String, Car> stringCarMap;
  15.      //此处省略了get和set方法,大家写的时候记得补上
  16.     @Override
  17.     public String toString() {
  18.          return  "CompositeObj{" +
  19.                  "name='" + name +  '\'' +
  20.                  "\n\t\t\t, salary=" + salary +
  21.                  "\n\t\t\t, car1=" + car1 +
  22.                  "\n\t\t\t, stringList=" + stringList +
  23.                  "\n\t\t\t, carList=" + carList +
  24.                  "\n\t\t\t, stringSet=" + stringSet +
  25.                  "\n\t\t\t, carSet=" + carSet +
  26.                  "\n\t\t\t, stringMap=" + stringMap +
  27.                  "\n\t\t\t, stringCarMap=" + stringCarMap +
  28.                  '}';
  29.     }
  30. }

注意:上面省略了get和set方法,大家写的时候记得补上

先用xml来定义一个CompositeObj的bean,如下

   
  1. <?xml version= "1.0" encoding= "UTF-8"?>
  2. <beans xmlns= "http://www.springframework.org/schema/beans"
  3.        xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
  4.        xsi:schemaLocation= "http://www.springframework.org/schema/beans
  5.     http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
  6.     <bean id= "car1" class= "com.javacode2018.lesson002.demo1.Car">
  7.         <property name= "name" value= "奥迪"/>
  8.     </bean>
  9.     <bean id= "car2" class= "com.javacode2018.lesson002.demo1.Car">
  10.         <property name= "name" value= "保时捷"/>
  11.     </bean>
  12.     <bean id= "compositeObj" class= "com.javacode2018.lesson002.demo1.CompositeObj">
  13.         <property name= "name" value= "路人甲Java"/>
  14.         <property name= "salary" value= "50000"/>
  15.         <property name= "car1" ref= "car1"/>
  16.         <property name= "stringList">
  17.             <list>
  18.                 <value>java高并发系列</value>
  19.                 <value>mysql系列</value>
  20.                 <value>maven高手系列</value>
  21.             </list>
  22.         </property>
  23.         <property name= "carList">
  24.             <list>
  25.                 <ref bean= "car1"/>
  26.                 <ref bean= "car2"/>
  27.             </list>
  28.         </property>
  29.         <property name= "stringSet">
  30.             <set>
  31.                 <value>java高并发系列</value>
  32.                 <value>mysql系列</value>
  33.                 <value>maven高手系列</value>
  34.             </set>
  35.         </property>
  36.         <property name= "carSet">
  37.             <set>
  38.                 <ref bean= "car1"/>
  39.                 <ref bean= "car2"/>
  40.             </set>
  41.         </property>
  42.         <property name= "stringMap">
  43.             < map>
  44.                 <entry key= "系列1" value= "java高并发系列"/>
  45.                 <entry key= "系列2" value= "Maven高手系列"/>
  46.                 <entry key= "系列3" value= "mysql系列"/>
  47.             </ map>
  48.         </property>
  49.         <property name= "stringCarMap">
  50.             < map>
  51.                 <entry key= "car1" value-ref= "car1"/>
  52.                 <entry key= "car2" value-ref= "car2"/>
  53.             </ map>
  54.         </property>
  55.     </bean>
  56. </beans>
下面我们采用纯api的方式实现,如下

   
  1. @Test
  2. public void test5() {
  3.      //定义car1
  4.     BeanDefinition car1 = BeanDefinitionBuilder.
  5.             genericBeanDefinition(Car.class).
  6.             addPropertyValue( "name""奥迪").
  7.             getBeanDefinition();
  8.      //定义car2
  9.     BeanDefinition car2 = BeanDefinitionBuilder.
  10.             genericBeanDefinition(Car.class).
  11.             addPropertyValue( "name""保时捷").
  12.             getBeanDefinition();
  13.      //定义CompositeObj这个bean
  14.      //创建stringList这个属性对应的值
  15.     ManagedList<String> stringList =  new ManagedList<>();
  16.     stringList.addAll(Arrays.asList( "java高并发系列""mysql系列""maven高手系列"));
  17.      //创建carList这个属性对应的值,内部引用其他两个bean的名称[car1,car2]
  18.     ManagedList<RuntimeBeanReference> carList =  new ManagedList<>();
  19.     carList.add( new RuntimeBeanReference( "car1"));
  20.     carList.add( new RuntimeBeanReference( "car2"));
  21.      //创建stringList这个属性对应的值
  22.     ManagedSet<String> stringSet =  new ManagedSet<>();
  23.     stringSet.addAll(Arrays.asList( "java高并发系列""mysql系列""maven高手系列"));
  24.      //创建carSet这个属性对应的值,内部引用其他两个bean的名称[car1,car2]
  25.     ManagedList<RuntimeBeanReference> carSet =  new ManagedList<>();
  26.     carSet.add( new RuntimeBeanReference( "car1"));
  27.     carSet.add( new RuntimeBeanReference( "car2"));
  28.      //创建stringMap这个属性对应的值
  29.     ManagedMap<String, String> stringMap =  new ManagedMap<>();
  30.     stringMap.put( "系列1""java高并发系列");
  31.     stringMap.put( "系列2""Maven高手系列");
  32.     stringMap.put( "系列3""mysql系列");
  33.     ManagedMap<String, RuntimeBeanReference> stringCarMap =  new ManagedMap<>();
  34.     stringCarMap.put( "car1"new RuntimeBeanReference( "car1"));
  35.     stringCarMap.put( "car2"new RuntimeBeanReference( "car2"));
  36.      //下面我们使用原生的api来创建BeanDefinition
  37.     GenericBeanDefinition compositeObj =  new GenericBeanDefinition();
  38.     compositeObj.setBeanClassName(CompositeObj.class.getName());
  39.     compositeObj.getPropertyValues().add( "name""路人甲Java").
  40.             add( "salary"50000).
  41.             add( "car1"new RuntimeBeanReference( "car1")).
  42.             add( "stringList", stringList).
  43.             add( "carList", carList).
  44.             add( "stringSet", stringSet).
  45.             add( "carSet", carSet).
  46.             add( "stringMap", stringMap).
  47.             add( "stringCarMap", stringCarMap);
  48.      //将上面bean 注册到容器
  49.     DefaultListableBeanFactory factory =  new DefaultListableBeanFactory();
  50.     factory.registerBeanDefinition( "car1", car1);
  51.     factory.registerBeanDefinition( "car2", car2);
  52.     factory.registerBeanDefinition( "compositeObj", compositeObj);
  53.      //下面我们将容器中所有的bean输出
  54.      for (String beanName : factory.getBeanDefinitionNames()) {
  55.         System.out. println(String.format( "%s->%s", beanName, factory.getBean(beanName)));
  56.     }
  57. }

有几点需要说一下:

RuntimeBeanReference:用来表示bean引用类型,类似于xml中的ref

ManagedList:属性如果是List类型的,t需要用到这个类进行操作,这个类继承了ArrayList

ManagedSet:属性如果是Set类型的,t需要用到这个类进行操作,这个类继承了LinkedHashSet

ManagedMap:属性如果是Map类型的,t需要用到这个类进行操作,这个类继承了LinkedHashMap

上面也就是这几个类结合的结果。

看一下效果,运行输出

   
  1. car1->Car{name= '奥迪'}
  2. car2->Car{name= '保时捷'}
  3. compositeObj->CompositeObj{name= '路人甲Java'
  4.             , salary= 50000
  5.             , car1=Car{name= '奥迪'}
  6.             , stringList=[java高并发系列, mysql系列, maven高手系列]
  7.             , carList=[Car{name= '奥迪'}, Car{name= '保时捷'}]
  8.             , stringSet=[java高并发系列, mysql系列, maven高手系列]
  9.             , carSet=[Car{name= '奥迪'}, Car{name= '保时捷'}]
  10.             , stringMap={系列 1=java高并发系列, 系列 2=Maven高手系列, 系列 3=mysql系列}
  11.             , stringCarMap={car1=Car{name= '奥迪'}, car2=Car{name= '保时捷'}}}

Xml文件方式

这种方式已经讲过很多次了,大家也比较熟悉,即通过xml的方式来定义bean,如下


   
  1. <?xml version= "1.0" encoding= "UTF-8"?>
  2. <beans xmlns= "http://www.springframework.org/schema/beans"
  3.        xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
  4.        xsi:schemaLocation= "http://www.springframework.org/schema/beans
  5.     http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
  6.     <bean id= "bean名称" class= "bean完整类名"/>
  7. </beans>

xml中的bean配置信息会被解析器解析为BeanDefinition对象,一会在第二阶段详解。

properties文件的方式

这种方式估计大家比较陌生,将bean定义信息放在properties文件中,然后通过解析器将配置信息解析为BeanDefinition对象。

properties内容格式如下:


   
  1. employee.(class)=MyClass        // 等同于:<bean class="MyClass" />
  2. employee.(abstract)= true        // 等同于:<bean abstract="true" />
  3. employee.group=Insurance        // 为属性设置值,等同于:<property name="group" value="Insurance" />
  4. employee.usesDialUp= false       // 为employee这个bean中的usesDialUp属性设置值,等同于:等同于:<property name="usesDialUp" value="false" />
  5. salesrep.(parent)=employee      // 定义了一个id为salesrep的bean,指定父bean为employee,等同于:<bean id="salesrep" parent="employee" />
  6. salesrep.(lazy-init)= true       // 设置延迟初始化,等同于:<bean lazy-init="true" />
  7. salesrep.manager(ref)=tony      // 设置这个bean的manager属性值,是另外一个bean,名称为tony,等同于:<property name="manager" ref="tony" />
  8. salesrep.department=Sales       // 等同于:<property name="department" value="Sales" />
  9. techie.(parent)=employee        // 定义了一个id为techie的bean,指定父bean为employee,等同于:<bean id="techie" parent="employee" />
  10. techie.(scope)=prototype        // 设置bean的作用域,等同于<bean scope="prototype" />
  11. techie.manager(ref)=jeff        // 等同于:<property name="manager" ref="jeff" />
  12. techie.department=Engineering   // <property name="department" value="Engineering" />
  13. techie.usesDialUp= true          // <property name="usesDialUp" value="true" />
  14. ceo.$ 0(ref)=secretary           // 设置构造函数第1个参数值,等同于:<constructor-arg index="0" ref="secretary" />
  15. 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配置文件


   
  1. <?xml version= "1.0" encoding= "UTF-8"?>
  2. <beans xmlns= "http://www.springframework.org/schema/beans"
  3.        xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
  4.        xsi:schemaLocation= "http://www.springframework.org/schema/beans
  5.     http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
  6.     <bean id= "car" class= "com.javacode2018.lesson002.demo1.Car">
  7.         <property name= "name" value= "奥迪"/>
  8.     </bean>
  9.     <bean id= "car1" class= "com.javacode2018.lesson002.demo1.Car">
  10.         <property name= "name" value= "保时捷"/>
  11.     </bean>
  12.     <bean id= "car2" parent= "car1"/>
  13.     <bean id= "user" class= "com.javacode2018.lesson002.demo1.User">
  14.         <property name= "name" value= "路人甲Java"/>
  15.         <property name= "car" ref= "car1"/>
  16.     </bean>
  17. </beans>

上面注册了4个bean,不多解释了。

将bean xml解析为BeanDefinition对象


   
  1. /**
  2.  * xml方式bean配置信息解析
  3.  */
  4. @Test
  5. public void test1() {
  6.      //定义一个spring容器,这个容器默认实现了BeanDefinitionRegistry,所以本身就是一个bean注册器
  7.     DefaultListableBeanFactory factory =  new DefaultListableBeanFactory();
  8.      //定义一个xml的BeanDefinition读取器,需要传递一个BeanDefinitionRegistry(bean注册器)对象
  9.     XmlBeanDefinitionReader xmlBeanDefinitionReader =  new XmlBeanDefinitionReader(factory);
  10.      //指定bean xml配置文件的位置
  11.     String location =  "classpath:/com/javacode2018/lesson002/demo2/beans.xml";
  12.      //通过XmlBeanDefinitionReader加载bean xml文件,然后将解析产生的BeanDefinition注册到容器容器中
  13.      int countBean = xmlBeanDefinitionReader.loadBeanDefinitions(location);
  14.     System.out. println(String.format( "共注册了 %s 个bean", countBean));
  15.      //打印出注册的bean的配置信息
  16.      for (String beanName : factory.getBeanDefinitionNames()) {
  17.          //通过名称从容器中获取对应的BeanDefinition信息
  18.         BeanDefinition beanDefinition = factory.getBeanDefinition(beanName);
  19.          //获取BeanDefinition具体使用的是哪个类
  20.         String beanDefinitionClassName = beanDefinition.getClass().getName();
  21.          //通过名称获取bean对象
  22.         Object bean = factory.getBean(beanName);
  23.          //打印输出
  24.         System.out. println(beanName +  ":");
  25.         System.out. println( "    beanDefinitionClassName:" + beanDefinitionClassName);
  26.         System.out. println( "    beanDefinition:" + beanDefinition);
  27.         System.out. println( "    bean:" + bean);
  28.     }
  29. }

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

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

运行输出


   
  1. 共注册了  4 个bean
  2. car:
  3.     beanDefinitionClassName:org.springframework.beans.factory.support.GenericBeanDefinition
  4.     beanDefinition:Generic bean: class [com.javacode2018.lesson002.demo1.Car]; 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 [com/javacode2018/lesson002/demo2/beans.xml]
  5.     bean:Car{name= '奥迪'}
  6. car1:
  7.     beanDefinitionClassName:org.springframework.beans.factory.support.GenericBeanDefinition
  8.     beanDefinition:Generic bean: class [com.javacode2018.lesson002.demo1.Car]; 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 [com/javacode2018/lesson002/demo2/beans.xml]
  9.     bean:Car{name= '保时捷'}
  10. car2:
  11.     beanDefinitionClassName:org.springframework.beans.factory.support.GenericBeanDefinition
  12.     beanDefinition:Generic bean with parent 'car1': 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 [com/javacode2018/lesson002/demo2/beans.xml]
  13.     bean:Car{name= '保时捷'}
  14. user:
  15.     beanDefinitionClassName:org.springframework.beans.factory.support.GenericBeanDefinition
  16.     beanDefinition:Generic bean: class [com.javacode2018.lesson002.demo1.User]; 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 [com/javacode2018/lesson002/demo2/beans.xml]
  17.     bean:User{name= '路人甲Java', car=Car{name= '奥迪'}}

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

properties文件定义bean的解析:PropertiesBeanDefinitionReader

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

来看案例代码。

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

来个properties文件:beans.properties


   
  1. car.(class)=com.javacode2018.lesson002.demo1.Car
  2. car.name=奥迪
  3. car1.(class)=com.javacode2018.lesson002.demo1.Car
  4. car1.name=保时捷
  5. car2.(parent)=car1
  6. user.(class)=com.javacode2018.lesson002.demo1.User
  7. user.name=路人甲Java
  8. user.car(ref)=car

将bean properties文件解析为BeanDefinition对象


   
  1. /**
  2.  * properties文件方式bean配置信息解析
  3.  */
  4. @Test
  5. public void test2() {
  6.      //定义一个spring容器,这个容器默认实现了BeanDefinitionRegistry,所以本身就是一个bean注册器
  7.     DefaultListableBeanFactory factory =  new DefaultListableBeanFactory();
  8.      //定义一个properties的BeanDefinition读取器,需要传递一个BeanDefinitionRegistry(bean注册器)对象
  9.     PropertiesBeanDefinitionReader propertiesBeanDefinitionReader =  new PropertiesBeanDefinitionReader(factory);
  10.      //指定bean xml配置文件的位置
  11.     String location =  "classpath:/com/javacode2018/lesson002/demo2/beans.properties";
  12.      //通过PropertiesBeanDefinitionReader加载bean properties文件,然后将解析产生的BeanDefinition注册到容器容器中
  13.      int countBean = propertiesBeanDefinitionReader.loadBeanDefinitions(location);
  14.     System.out. println(String.format( "共注册了 %s 个bean", countBean));
  15.      //打印出注册的bean的配置信息
  16.      for (String beanName : factory.getBeanDefinitionNames()) {
  17.          //通过名称从容器中获取对应的BeanDefinition信息
  18.         BeanDefinition beanDefinition = factory.getBeanDefinition(beanName);
  19.          //获取BeanDefinition具体使用的是哪个类
  20.         String beanDefinitionClassName = beanDefinition.getClass().getName();
  21.          //通过名称获取bean对象
  22.         Object bean = factory.getBean(beanName);
  23.          //打印输出
  24.         System.out. println(beanName +  ":");
  25.         System.out. println( "    beanDefinitionClassName:" + beanDefinitionClassName);
  26.         System.out. println( "    beanDefinition:" + beanDefinition);
  27.         System.out. println( "    bean:" + bean);
  28.     }
  29. }

运行输出


   
  1. user:
  2.     beanDefinitionClassName:org.springframework.beans.factory.support.GenericBeanDefinition
  3.     beanDefinition:Generic bean: class [com.javacode2018.lesson002.demo1.User]; scope=singleton; abstract= false; lazyInit= false; autowireMode= 0; dependencyCheck= 0; autowireCandidate= true; primary= false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
  4.     bean:User{name= '路人甲Java', car=Car{name= '奥迪'}}
  5. car1:
  6.     beanDefinitionClassName:org.springframework.beans.factory.support.GenericBeanDefinition
  7.     beanDefinition:Generic bean: class [com.javacode2018.lesson002.demo1.Car]; scope=singleton; abstract= false; lazyInit= false; autowireMode= 0; dependencyCheck= 0; autowireCandidate= true; primary= false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
  8.     bean:Car{name= '保时捷'}
  9. car:
  10.     beanDefinitionClassName:org.springframework.beans.factory.support.GenericBeanDefinition
  11.     beanDefinition:Generic bean: class [com.javacode2018.lesson002.demo1.Car]; scope=singleton; abstract= false; lazyInit= false; autowireMode= 0; dependencyCheck= 0; autowireCandidate= true; primary= false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
  12.     bean:Car{name= '奥迪'}
  13. car2:
  14.     beanDefinitionClassName:org.springframework.beans.factory.support.GenericBeanDefinition
  15.     beanDefinition:Generic bean with parent 'car1': class [null]; scope=singleton; abstract= false; lazyInit= false; autowireMode= 0; dependencyCheck= 0; autowireCandidate= true; primary= false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
  16.     bean:Car{name= '保时捷'}

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

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

注解方式:PropertiesBeanDefinitionReader

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

通过注解来标注2个类

Service1

   
  1. package com.javacode2018.lesson002.demo2;
  2. import org.springframework.beans.factory.config.ConfigurableBeanFactory;
  3. import org.springframework.context.annotation.Lazy;
  4. import org.springframework.context.annotation.Primary;
  5. import org.springframework.context.annotation.Scope;
  6. @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
  7. @Primary
  8. @Lazy
  9. public class Service1 {
  10. }

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

上面这个bean是个多例的。

Service2

   
  1. package com.javacode2018.lesson002.demo2;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. public class Service2 {
  4.     @Autowired
  5.     private Service1 service1;  //@1
  6.     @Override
  7.     public String toString() {
  8.          return  "Service2{" +
  9.                  "service1=" + service1 +
  10.                  '}';
  11.     }
  12. }

@1:标注了@Autowired,说明需要注入这个对象

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


   
  1. @Test
  2. public void test3() {
  3.      //定义一个spring容器,这个容器默认实现了BeanDefinitionRegistry,所以本身就是一个bean注册器
  4.     DefaultListableBeanFactory factory =  new DefaultListableBeanFactory();
  5.      //定义一个注解方式的BeanDefinition读取器,需要传递一个BeanDefinitionRegistry(bean注册器)对象
  6.     AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader =  new AnnotatedBeanDefinitionReader(factory);
  7.      //通过PropertiesBeanDefinitionReader加载bean properties文件,然后将解析产生的BeanDefinition注册到容器容器中
  8.     annotatedBeanDefinitionReader.register(Service1.class, Service2.class);
  9.      //打印出注册的bean的配置信息
  10.      for (String beanName :  new String[]{ "service1""service2"}) {
  11.          //通过名称从容器中获取对应的BeanDefinition信息
  12.         BeanDefinition beanDefinition = factory.getBeanDefinition(beanName);
  13.          //获取BeanDefinition具体使用的是哪个类
  14.         String beanDefinitionClassName = beanDefinition.getClass().getName();
  15.          //通过名称获取bean对象
  16.         Object bean = factory.getBean(beanName);
  17.          //打印输出
  18.         System.out. println(beanName +  ":");
  19.         System.out. println( "    beanDefinitionClassName:" + beanDefinitionClassName);
  20.         System.out. println( "    beanDefinition:" + beanDefinition);
  21.         System.out. println( "    bean:" + bean);
  22.     }
  23. }

运行输出


   
  1. service1:
  2.     beanDefinitionClassName:org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition
  3.     beanDefinition:Generic bean: class [com.javacode2018.lesson002.demo2.Service1]; scope=prototype; abstract= false; lazyInit= true; autowireMode= 0; dependencyCheck= 0; autowireCandidate= true; primary= true; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
  4.     bean:com.javacode2018.lesson002.demo2.Service1@ 21a947fe
  5. service2:
  6.     beanDefinitionClassName:org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition
  7.     beanDefinition:Generic bean: class [com.javacode2018.lesson002.demo2.Service2]; scope=singleton; abstract= false; lazyInit=null; autowireMode= 0; dependencyCheck= 0; autowireCandidate= true; primary= false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
  8.     bean:Service2{service1=null}

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

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

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

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


   
  1. @Test
  2. public void test3() {
  3.      //定义一个spring容器,这个容器默认实现了BeanDefinitionRegistry,所以本身就是一个bean注册器
  4.     DefaultListableBeanFactory factory =  new DefaultListableBeanFactory();
  5.      //定义一个注解方式的BeanDefinition读取器,需要传递一个BeanDefinitionRegistry(bean注册器)对象
  6.     AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader =  new AnnotatedBeanDefinitionReader(factory);
  7.      //通过PropertiesBeanDefinitionReader加载bean properties文件,然后将解析产生的BeanDefinition注册到容器容器中
  8.     annotatedBeanDefinitionReader.register(Service1.class, Service2.class);
  9.     factory.getBeansOfType(BeanPostProcessor.class).values().forEach(factory::addBeanPostProcessor);  // @1
  10.      //打印出注册的bean的配置信息
  11.      for (String beanName :  new String[]{ "service1""service2"}) {
  12.          //通过名称从容器中获取对应的BeanDefinition信息
  13.         BeanDefinition beanDefinition = factory.getBeanDefinition(beanName);
  14.          //获取BeanDefinition具体使用的是哪个类
  15.         String beanDefinitionClassName = beanDefinition.getClass().getName();
  16.          //通过名称获取bean对象
  17.         Object bean = factory.getBean(beanName);
  18.          //打印输出
  19.         System.out. println(beanName +  ":");
  20.         System.out. println( "    beanDefinitionClassName:" + beanDefinitionClassName);
  21.         System.out. println( "    beanDefinition:" + beanDefinition);
  22.         System.out. println( "    bean:" + bean);
  23.     }
  24. }

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


   
  1. service1:
  2.     beanDefinitionClassName:org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition
  3.     beanDefinition:Generic bean: class [com.javacode2018.lesson002.demo2.Service1]; scope=prototype; abstract= false; lazyInit= true; autowireMode= 0; dependencyCheck= 0; autowireCandidate= true; primary= true; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
  4.     bean:com.javacode2018.lesson002.demo2.Service1@ 564718df
  5. service2:
  6.     beanDefinitionClassName:org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition
  7.     beanDefinition:Generic bean: class [com.javacode2018.lesson002.demo2.Service2]; scope=singleton; abstract= false; lazyInit=null; autowireMode= 0; dependencyCheck= 0; autowireCandidate= true; primary= false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
  8.     bean:Service2{service1=com.javacode2018.lesson002.demo2.Service1@ 52aa2946}

目前进行到第二个阶段了,还有14个阶段,本文内容比较长,建议先收藏起来,慢慢看,咱们继续。

阶段3:Spring Bean注册阶段

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

Bean注册接口:BeanDefinitionRegistry

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


   
  1. public  interface BeanDefinitionRegistry extends AliasRegistry {
  2.      /**
  3.      * 注册一个新的bean定义
  4.      * beanName:bean的名称
  5.      * beanDefinition:bean定义信息
  6.      */
  7.     void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
  8.             throws BeanDefinitionStoreException;
  9.      /**
  10.      * 通过bean名称移除已注册的bean
  11.      * beanName:bean名称
  12.      */
  13.     void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
  14.      /**
  15.      * 通过名称获取bean的定义信息
  16.      * beanName:bean名称
  17.      */
  18.     BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
  19.      /**
  20.      * 查看beanName是否注册过
  21.      */
  22.     boolean containsBeanDefinition(String beanName);
  23.      /**
  24.      * 获取已经定义(注册)的bean名称列表
  25.      */
  26.     String[] getBeanDefinitionNames();
  27.      /**
  28.      * 返回注册器中已注册的bean数量
  29.      */
  30.      int getBeanDefinitionCount();
  31.      /**
  32.      * 确定给定的bean名称或者别名是否已在此注册表中使用
  33.      * beanName:可以是bean名称或者bean的别名
  34.      */
  35.     boolean isBeanNameInUse(String beanName);
  36. }

别名注册接口:AliasRegistry

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


   
  1. public  interface AliasRegistry {
  2.      /**
  3.      * 给name指定别名alias
  4.      */
  5.     void registerAlias(String name, String alias);
  6.      /**
  7.      * 从此注册表中删除指定的别名
  8.      */
  9.     void removeAlias(String alias);
  10.      /**
  11.      * 判断name是否作为别名已经被使用了
  12.      */
  13.     boolean isAlias(String name);
  14.      /**
  15.      * 返回name对应的所有别名
  16.      */
  17.     String[] getAliases(String name);
  18. }

BeanDefinitionRegistry唯一实现:DefaultListableBeanFactory

spring中BeanDefinitionRegistry接口有一个唯一的实现类:

org.springframework.beans.factory.support.DefaultListableBeanFactory

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

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

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

案例

代码


   
  1. package com.javacode2018.lesson002.demo3;
  2. import org.junit.Test;
  3. import org.springframework.beans.factory.support.DefaultListableBeanFactory;
  4. import org.springframework.beans.factory.support.GenericBeanDefinition;
  5. import java.util.Arrays;
  6. /**
  7.  * BeanDefinitionRegistry 案例
  8.  */
  9. public class BeanDefinitionRegistryTest {
  10.     @Test
  11.     public void test1() {
  12.          //创建一个bean工厂,这个默认实现了BeanDefinitionRegistry接口,所以也是一个bean注册器
  13.         DefaultListableBeanFactory factory =  new DefaultListableBeanFactory();
  14.          //定义一个bean
  15.         GenericBeanDefinition nameBdf =  new GenericBeanDefinition();
  16.         nameBdf.setBeanClass(String.class);
  17.         nameBdf.getConstructorArgumentValues().addIndexedArgumentValue( 0"路人甲Java");
  18.          //将bean注册到容器中
  19.         factory.registerBeanDefinition( "name", nameBdf);
  20.          //通过名称获取BeanDefinition
  21.         System.out. println(factory.getBeanDefinition( "name"));
  22.          //通过名称判断是否注册过BeanDefinition
  23.         System.out. println(factory.containsBeanDefinition( "name"));
  24.          //获取所有注册的名称
  25.         System.out. println(Arrays.asList(factory.getBeanDefinitionNames()));
  26.          //获取已注册的BeanDefinition的数量
  27.         System.out. println(factory.getBeanDefinitionCount());
  28.          //判断指定的name是否使用过
  29.         System.out. println(factory.isBeanNameInUse( "name"));
  30.          //别名相关方法
  31.          //为name注册2个别名
  32.         factory.registerAlias( "name""alias-name-1");
  33.         factory.registerAlias( "name""alias-name-2");
  34.          //判断alias-name-1是否已被作为别名使用
  35.         System.out. println(factory.isAlias( "alias-name-1"));
  36.          //通过名称获取对应的所有别名
  37.         System.out. println(Arrays.asList(factory.getAliases( "name")));
  38.          //最后我们再来获取一下这个bean
  39.         System.out. println(factory.getBean( "name"));
  40.     }
  41. }

运行输出


   
  1. Generic bean: class [java.lang.String]; scope=; abstract= false; lazyInit=null; autowireMode= 0; dependencyCheck= 0; autowireCandidate= true; primary= false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
  2. true
  3. [name]
  4. 1
  5. true
  6. true
  7. [alias-name -2, alias-name -1]
  8. 路人甲Java

下面要介绍的从阶段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

案例

来一个普通的类


   
  1. package com.javacode2018.lesson002.demo4;
  2. public class LessonModel {
  3.      //课程名称
  4.     private String name;
  5.      //课时
  6.     private  int lessonCount;
  7.      //描述信息
  8.     private String description;
  9.     public String getName() {
  10.          return name;
  11.     }
  12.     public void setName(String name) {
  13.         this.name = name;
  14.     }
  15.     public  int getLessonCount() {
  16.          return lessonCount;
  17.     }
  18.     public void setLessonCount( int lessonCount) {
  19.         this.lessonCount = lessonCount;
  20.     }
  21.     public String getDescription() {
  22.          return description;
  23.     }
  24.     public void setDescription(String description) {
  25.         this.description = description;
  26.     }
  27.     @Override
  28.     public String toString() {
  29.          return  "LessonModel{" +
  30.                  "name='" + name +  '\'' +
  31.                  ", lessonCount=" + lessonCount +
  32.                  ", description='" + description +  '\'' +
  33.                  '}';
  34.     }
  35. }

通过xml定义3个具有父子关系的bean


   
  1. <?xml version= "1.0" encoding= "UTF-8"?>
  2. <beans xmlns= "http://www.springframework.org/schema/beans"
  3.        xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
  4.        xsi:schemaLocation= "http://www.springframework.org/schema/beans
  5.     http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
  6.     <bean id= "lesson1" class= "com.javacode2018.lesson002.demo4.LessonModel"/>
  7.     <bean id= "lesson2" parent= "lesson1">
  8.         <property name= "name" value= "spring高手系列"/>
  9.         <property name= "lessonCount" value= "100"/>
  10.     </bean>
  11.     <bean id= "lesson3" parent= "lesson2">
  12.         <property name= "description" value= "路人甲Java带你学spring,超越90%开发者!"/>
  13.     </bean>
  14. </beans>

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

解析xml注册bean

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


   
  1. package com.javacode2018.lesson002.demo4;
  2. import org.junit.Test;
  3. import org.springframework.beans.factory.config.BeanDefinition;
  4. import org.springframework.beans.factory.support.DefaultListableBeanFactory;
  5. import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
  6. /**
  7.  * BeanDefinition 合并
  8.  */
  9. public class MergedBeanDefinitionTest {
  10.     @Test
  11.     public void test1() {
  12.          //创建bean容器
  13.         DefaultListableBeanFactory factory =  new DefaultListableBeanFactory();
  14.          //创建一个bean xml解析器
  15.         XmlBeanDefinitionReader beanDefinitionReader =  new XmlBeanDefinitionReader(factory);
  16.          //解析bean xml,将解析过程中产生的BeanDefinition注册到DefaultListableBeanFactory中
  17.         beanDefinitionReader.loadBeanDefinitions( "com/javacode2018/lesson002/demo4/beans.xml");
  18.          //遍历容器中注册的所有bean信息
  19.          for (String beanName : factory.getBeanDefinitionNames()) {
  20.              //通过bean名称获取原始的注册的BeanDefinition信息
  21.             BeanDefinition beanDefinition = factory.getBeanDefinition(beanName);
  22.              //获取合并之后的BeanDefinition信息
  23.             BeanDefinition mergedBeanDefinition = factory.getMergedBeanDefinition(beanName);
  24.             System.out. println(beanName);
  25.             System.out. println( "解析xml过程中注册的beanDefinition:" + beanDefinition);
  26.             System.out. println( "beanDefinition中的属性信息" + beanDefinition.getPropertyValues());
  27.             System.out. println( "合并之后得到的mergedBeanDefinition:" + mergedBeanDefinition);
  28.             System.out. println( "mergedBeanDefinition中的属性信息" + mergedBeanDefinition.getPropertyValues());
  29.             System.out. println( "---------------------------");
  30.         }
  31.     }
  32. }

运行输出


   
  1. lesson1
  2. 解析xml过程中注册的beanDefinition:Generic bean: class [com.javacode2018.lesson002.demo4.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 [com/javacode2018/lesson002/demo4/beans.xml]
  3. beanDefinition中的属性信息PropertyValues: length= 0
  4. 合并之后得到的mergedBeanDefinition:Root bean: class [com.javacode2018.lesson002.demo4.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 [com/javacode2018/lesson002/demo4/beans.xml]
  5. mergedBeanDefinition中的属性信息PropertyValues: length= 0
  6. ---------------------------
  7. lesson2
  8. 解析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 [com/javacode2018/lesson002/demo4/beans.xml]
  9. beanDefinition中的属性信息PropertyValues: length= 2; bean property  'name'; bean property  'lessonCount'
  10. 合并之后得到的mergedBeanDefinition:Root bean: class [com.javacode2018.lesson002.demo4.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 [com/javacode2018/lesson002/demo4/beans.xml]
  11. mergedBeanDefinition中的属性信息PropertyValues: length= 2; bean property  'name'; bean property  'lessonCount'
  12. ---------------------------
  13. lesson3
  14. 解析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 [com/javacode2018/lesson002/demo4/beans.xml]
  15. beanDefinition中的属性信息PropertyValues: length= 1; bean property  'description'
  16. 合并之后得到的mergedBeanDefinition:Root bean: class [com.javacode2018.lesson002.demo4.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 [com/javacode2018/lesson002/demo4/beans.xml]
  17. mergedBeanDefinition中的属性信息PropertyValues: length= 3; bean property  'name'; bean property  'lessonCount'; bean property  'description'
  18. ---------------------------

从输出的结果中可以看到,合并之前,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实例化之前会调用一段代码:


   
  1. @Nullable
  2.     protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
  3.          for (BeanPostProcessor bp : getBeanPostProcessors()) {
  4.              if (bp instanceof InstantiationAwareBeanPostProcessor) {
  5.                 InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
  6.                 Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
  7.                  if (result != null) {
  8.                      return result;
  9.                 }
  10.             }
  11.         }
  12.          return null;
  13.     }

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

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

postProcessBeforeInstantiation方法如下:


   
  1. default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
  2.      return null;
  3. }

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

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

案例


   
  1. package com.javacode2018.lesson002.demo5;
  2. import com.javacode2018.lesson002.demo1.Car;
  3. import org.junit.Test;
  4. import org.springframework.beans.BeansException;
  5. import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
  6. import org.springframework.beans.factory.support.AbstractBeanDefinition;
  7. import org.springframework.beans.factory.support.BeanDefinitionBuilder;
  8. import org.springframework.beans.factory.support.DefaultListableBeanFactory;
  9. import org.springframework.lang.Nullable;
  10. /**
  11.  * bean初始化前阶段,会调用:{@link org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor#postProcessBeforeInitialization(Object, String)}
  12.  */
  13. public class InstantiationAwareBeanPostProcessorTest {
  14.     @Test
  15.     public void test1() {
  16.         DefaultListableBeanFactory factory =  new DefaultListableBeanFactory();
  17.          //添加一个BeanPostProcessor:InstantiationAwareBeanPostProcessor
  18.         factory.addBeanPostProcessor( new InstantiationAwareBeanPostProcessor() {  //@1
  19.             @Nullable
  20.             @Override
  21.             public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
  22.                 System.out. println( "调用postProcessBeforeInstantiation()");
  23.                  //发现类型是Car类型的时候,硬编码创建一个Car对象返回
  24.                  if (beanClass == Car.class) {
  25.                     Car car =  new Car();
  26.                     car.setName( "保时捷");
  27.                      return car;
  28.                 }
  29.                  return null;
  30.             }
  31.         });
  32.          //定义一个car bean,车名为:奥迪
  33.         AbstractBeanDefinition carBeanDefinition = BeanDefinitionBuilder.
  34.                 genericBeanDefinition(Car.class).
  35.                 addPropertyValue( "name""奥迪").   //@2
  36.                 getBeanDefinition();
  37.         factory.registerBeanDefinition( "car", carBeanDefinition);
  38.          //从容器中获取car这个bean的实例,输出
  39.         System.out. println(factory.getBean( "car"));
  40.     }
  41. }

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

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

运行输出


   
  1. 调用postProcessBeforeInstantiation()
  2. Car{name= '保时捷'}

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

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

小结

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

Bean实例化操作

这个过程可以干什么?

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

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

看一下这块的代码逻辑:


   
  1. for (BeanPostProcessor bp : getBeanPostProcessors()) {
  2.      if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
  3.         SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
  4.         Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
  5.          if (ctors != null) {
  6.              return ctors;
  7.         }
  8.     }
  9. }

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


   
  1. @Nullable
  2. default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName)
  3. throws BeansException {
  4.      return null;
  5. }

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

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor

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

案例

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

自定义一个注解

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


   
  1. package com.javacode2018.lesson002.demo6;
  2. import java.lang.annotation.*;
  3. @Target(ElementType.CONSTRUCTOR)
  4. @Retention(RetentionPolicy.RUNTIME)
  5. @Documented
  6. public @ interface MyAutowried {
  7. }
来个普通的类

下面这个类3个构造器,其中一个使用@MyAutowried,让其作为bean实例化的方法。


   
  1. package com.javacode2018.lesson002.demo6;
  2. public class Person {
  3.     private String name;
  4.     private Integer age;
  5.     public Person() {
  6.         System.out. println( "调用 Person()");
  7.     }
  8.     @MyAutowried
  9.     public Person(String name) {
  10.         System.out. println( "调用 Person(String name)");
  11.         this.name = name;
  12.     }
  13.     public Person(String name, Integer age) {
  14.         System.out. println( "调用 Person(String name, int age)");
  15.         this.name = name;
  16.         this.age = age;
  17.     }
  18.     @Override
  19.     public String toString() {
  20.          return  "Person{" +
  21.                  "name='" + name +  '\'' +
  22.                  ", age=" + age +
  23.                  '}';
  24.     }
  25. }
自定义一个SmartInstantiationAwareBeanPostProcessor

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


   
  1. package com.javacode2018.lesson002.demo6;
  2. import org.springframework.beans.BeansException;
  3. import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
  4. import org.springframework.lang.Nullable;
  5. import java.lang.reflect.Constructor;
  6. import java.util.Arrays;
  7. import java.util.List;
  8. import java.util.stream.Collectors;
  9. public class MySmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
  10.     @Nullable
  11.     @Override
  12.     public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
  13.         System.out. println(beanClass);
  14.         System.out. println( "调用 MySmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors 方法");
  15.         Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
  16.          if (declaredConstructors != null) {
  17.              //获取有@MyAutowried注解的构造器列表
  18.             List<Constructor<?>> collect = Arrays.stream(declaredConstructors).
  19.                     filter(constructor -> constructor.isAnnotationPresent(MyAutowried.class)).
  20.                     collect(Collectors.toList());
  21.             Constructor[] constructors = collect.toArray( new Constructor[collect.size()]);
  22.              return constructors.length !=  0 ? constructors : null;
  23.         }  else {
  24.              return null;
  25.         }
  26.     }
  27. }
来个测试用例

   
  1. package com.javacode2018.lesson002.demo6;
  2. import org.junit.Test;
  3. import org.springframework.beans.factory.support.BeanDefinitionBuilder;
  4. import org.springframework.beans.factory.support.DefaultListableBeanFactory;
  5. /**
  6.  * 通过{@link org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors(Class, String)}来确定使用哪个构造器来创建bean实例
  7.  */
  8. public class SmartInstantiationAwareBeanPostProcessorTest {
  9.     @Test
  10.     public void test1() {
  11.         DefaultListableBeanFactory factory =  new DefaultListableBeanFactory();
  12.          //创建一个SmartInstantiationAwareBeanPostProcessor,将其添加到容器中
  13.         factory.addBeanPostProcessor( new MySmartInstantiationAwareBeanPostProcessor());
  14.         factory.registerBeanDefinition( "name",
  15.                 BeanDefinitionBuilder.
  16.                         genericBeanDefinition(String.class).
  17.                         addConstructorArgValue( "路人甲Java").
  18.                         getBeanDefinition());
  19.         factory.registerBeanDefinition( "age",
  20.                 BeanDefinitionBuilder.
  21.                         genericBeanDefinition(Integer.class).
  22.                         addConstructorArgValue( 30).
  23.                         getBeanDefinition());
  24.         factory.registerBeanDefinition( "person",
  25.                 BeanDefinitionBuilder.
  26.                         genericBeanDefinition(Person.class).
  27.                         getBeanDefinition());
  28.         Person person = factory.getBean( "person", Person.class);
  29.         System.out. println(person);
  30.     }
  31. }
运行输出

   
  1. class com.javacode2018.lesson002.demo6.Person
  2. 调用 MySmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors 方法
  3. class java.lang.String
  4. 调用 MySmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors 方法
  5. 调用 Person(String name)
  6. Person{name= '路人甲Java', age=null}

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

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

阶段7:合并后的BeanDefinition处理

这块的源码如下


   
  1. protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
  2.          for (BeanPostProcessor bp : getBeanPostProcessors()) {
  3.              if (bp instanceof MergedBeanDefinitionPostProcessor) {
  4.                 MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
  5.                 bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
  6.             }
  7.         }
  8.     }

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

void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);

spring会轮询BeanPostProcessor,依次调用MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition

第一个参数为beanDefinition,表示合并之后的RootBeanDefinition,我们可以在这个方法内部对合并之后的BeanDefinition进行再次处理

postProcessMergedBeanDefinition有2个实现类,前面我们介绍过,用的也比较多,面试的时候也会经常问的:


   
  1. org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
  2. 在 postProcessMergedBeanDefinition 方法中对 @Autowired、@Value 标注的方法、字段进行缓存
  3. org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
  4. 在 postProcessMergedBeanDefinition 方法中对 @Resource 标注的字段、@Resource 标注的方法、 @PostConstruct 标注的字段、 @PreDestroy标注的方法进行缓存

阶段8:Bean属性设置阶段

属性设置阶段分为3个小的阶段

  • 实例化后阶段

  • Bean属性赋值前处理

  • Bean属性赋值

实例化后阶段

会调用InstantiationAwareBeanPostProcessor接口的postProcessAfterInstantiation这个方法,调用逻辑如下:

看一下具体的调用逻辑如下:


   
  1. for (BeanPostProcessor bp : getBeanPostProcessors()) {
  2.      if (bp instanceof InstantiationAwareBeanPostProcessor) {
  3.         InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
  4.          if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
  5.              return;
  6.         }
  7.     }
  8. }

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

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


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

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

案例

来个类

   
  1. package com.javacode2018.lesson002.demo7;
  2. public class UserModel {
  3.     private String name;
  4.     private Integer age;
  5.     public String getName() {
  6.          return name;
  7.     }
  8.     public void setName(String name) {
  9.         this.name = name;
  10.     }
  11.     public Integer getAge() {
  12.          return age;
  13.     }
  14.     public void setAge(Integer age) {
  15.         this.age = age;
  16.     }
  17.     @Override
  18.     public String toString() {
  19.          return  "UserModel{" +
  20.                  "name='" + name +  '\'' +
  21.                  ", age=" + age +
  22.                  '}';
  23.     }
  24. }
测试用例

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


   
  1. package com.javacode2018.lesson002.demo7;
  2. import org.junit.Test;
  3. import org.springframework.beans.BeansException;
  4. import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
  5. import org.springframework.beans.factory.support.BeanDefinitionBuilder;
  6. import org.springframework.beans.factory.support.DefaultListableBeanFactory;
  7. /**
  8.  * {@link InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation(java.lang.Object, java.lang.String)}
  9.  * 返回false,可以阻止bean属性的赋值
  10.  */
  11. public class InstantiationAwareBeanPostProcessoryTest1 {
  12.     @Test
  13.     public void test1() {
  14.         DefaultListableBeanFactory factory =  new DefaultListableBeanFactory();
  15.         factory.registerBeanDefinition( "user1", BeanDefinitionBuilder.
  16.                 genericBeanDefinition(UserModel.class).
  17.                 addPropertyValue( "name""路人甲Java").
  18.                 addPropertyValue( "age"30).
  19.                 getBeanDefinition());
  20.         factory.registerBeanDefinition( "user2", BeanDefinitionBuilder.
  21.                 genericBeanDefinition(UserModel.class).
  22.                 addPropertyValue( "name""刘德华").
  23.                 addPropertyValue( "age"50).
  24.                 getBeanDefinition());
  25.          for (String beanName : factory.getBeanDefinitionNames()) {
  26.             System.out. println(String.format( "%s->%s", beanName, factory.getBean(beanName)));
  27.         }
  28.     }
  29. }

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

运行输出

   
  1. user1->UserModel{name= '路人甲Java', age= 30}
  2. user2->UserModel{name= '刘德华', age= 50}

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

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


   
  1. factory.addBeanPostProcessor( new InstantiationAwareBeanPostProcessor() {
  2.     @Override
  3.     public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
  4.          if ( "user1".equals(beanName)) {
  5.              return  false;
  6.         }  else {
  7.              return  true;
  8.         }
  9.     }
  10. });

再次运行测试输出:


   
  1. user1->UserModel{name= 'null', age=null}
  2. user2->UserModel{name= '刘德华', age= 50}

user1的属性赋值被跳过了。

Bean属性赋值前阶段

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


   
  1. for (BeanPostProcessor bp : getBeanPostProcessors()) {
  2.      if (bp instanceof InstantiationAwareBeanPostProcessor) {
  3.         InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
  4.         PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
  5.          if (pvsToUse == null) {
  6.              if (filteredPds == null) {
  7.                 filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
  8.             }
  9.             pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
  10.              if (pvsToUse == null) {
  11.                  return;
  12.             }
  13.         }
  14.         pvs = pvsToUse;
  15.     }
  16. }

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

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


   
  1. @Nullable
  2. default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
  3.     throws BeansException {
  4.      return null;
  5. }

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

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

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

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

案例

案例代码

   
  1. @Test
  2. public void test3() {
  3.     DefaultListableBeanFactory factory =  new DefaultListableBeanFactory();
  4.     factory.addBeanPostProcessor( new InstantiationAwareBeanPostProcessor() {  // @0
  5.         @Nullable
  6.         @Override
  7.         public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
  8.              if ( "user1".equals(beanName)) {
  9.                  if (pvs == null) {
  10.                     pvs =  new MutablePropertyValues();
  11.                 }
  12.                  if (pvs instanceof MutablePropertyValues) {
  13.                     MutablePropertyValues mpvs = (MutablePropertyValues) pvs;
  14.                      //将姓名设置为:路人
  15.                     mpvs.add( "name""路人");
  16.                      //将年龄属性的值修改为18
  17.                     mpvs.add( "age"18);
  18.                 }
  19.             }
  20.              return null;
  21.         }
  22.     });
  23.      //注意 user1 这个没有给属性设置值
  24.     factory.registerBeanDefinition( "user1", BeanDefinitionBuilder.
  25.             genericBeanDefinition(UserModel.class).
  26.             getBeanDefinition());  //@1
  27.     factory.registerBeanDefinition( "user2", BeanDefinitionBuilder.
  28.             genericBeanDefinition(UserModel.class).
  29.             addPropertyValue( "name""刘德华").
  30.             addPropertyValue( "age"50).
  31.             getBeanDefinition());
  32.      for (String beanName : factory.getBeanDefinitionNames()) {
  33.         System.out. println(String.format( "%s->%s", beanName, factory.getBean(beanName)));
  34.     }
  35. }

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

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

运行输出

   
  1. user1->UserModel{name= '路人', age= 18}
  2. user2->UserModel{name= '刘德华', age= 50}

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

Bean属性赋值阶段

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

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

阶段9:Bean初始化阶段

这个阶段分为5个小的阶段

  • Bean Aware接口回调

  • Bean初始化前操作

  • Bean初始化操作

  • Bean初始化后操作

  • Bean初始化完成操作

Bean Aware接口回调

这块的源码:


   
  1. private void invokeAwareMethods(final String beanName, final Object bean) {
  2.          if (bean instanceof Aware) {
  3.              if (bean instanceof BeanNameAware) {
  4.                 ((BeanNameAware) bean).setBeanName(beanName);
  5.             }
  6.              if (bean instanceof BeanClassLoaderAware) {
  7.                 ClassLoader bcl = getBeanClassLoader();
  8.                  if (bcl != null) {
  9.                     ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
  10.                 }
  11.             }
  12.              if (bean instanceof BeanFactoryAware) {
  13.                 ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
  14.             }
  15.         }
  16.     }

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


   
  1. BeanNameAware:将bean的名称注入进去
  2. BeanClassLoaderAware:将BeanClassLoader注入进去
  3. BeanFactoryAware:将BeanFactory注入进去

来个案例感受一下

来个类,实现上面3个接口。


   
  1. package com.javacode2018.lesson002.demo8;
  2. import org.springframework.beans.BeansException;
  3. import org.springframework.beans.factory.BeanClassLoaderAware;
  4. import org.springframework.beans.factory.BeanFactory;
  5. import org.springframework.beans.factory.BeanFactoryAware;
  6. import org.springframework.beans.factory.BeanNameAware;
  7. public class AwareBean implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware {
  8.     @Override
  9.     public void setBeanName(String name) {
  10.         System.out. println( "setBeanName:" + name);
  11.     }
  12.     @Override
  13.     public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
  14.         System.out. println( "setBeanFactory:" + beanFactory);
  15.     }
  16.     @Override
  17.     public void setBeanClassLoader(ClassLoader classLoader) {
  18.         System.out. println( "setBeanClassLoader:" + classLoader);
  19.     }
  20. }

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


   
  1. package com.javacode2018.lesson002.demo8;
  2. import org.junit.Test;
  3. import org.springframework.beans.factory.support.BeanDefinitionBuilder;
  4. import org.springframework.beans.factory.support.DefaultListableBeanFactory;
  5. public class InvokeAwareTest {
  6.     @Test
  7.     public void test1() {
  8.         DefaultListableBeanFactory factory =  new DefaultListableBeanFactory();
  9.         factory.registerBeanDefinition( "awareBean", BeanDefinitionBuilder.genericBeanDefinition(AwareBean.class).getBeanDefinition());
  10.          //调用getBean方法获取bean,将触发bean的初始化
  11.         factory.getBean( "awareBean");
  12.     }
  13. }

运行输出


   
  1. setBeanName:awareBean
  2. setBeanClassLoader:sun.misc.Launcher$AppClassLoader@ 18b4aac2
  3. setBeanFactory:org.springframework.beans.factory.support.DefaultListableBeanFactory@ 5bb21b69: defining beans [awareBean]; root of factory hierarchy

Bean初始化前操作

这个阶段的源码:


   
  1. @Override
  2. public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
  3.     throws BeansException {
  4.     Object result = existingBean;
  5.      for (BeanPostProcessor processor : getBeanPostProcessors()) {
  6.         Object current = processor.postProcessBeforeInitialization(result, beanName);
  7.          if (current == null) {
  8.              return result;
  9.         }
  10.         result = current;
  11.     }
  12.      return result;
  13. }

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

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

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


   
  1. org.springframework.context.support.ApplicationContextAwareProcessor
  2. org.springframework.context.annotation.CommonAnnotationBeanPostProcessor

ApplicationContextAwareProcessor注入6个Aware接口对象

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


   
  1. EnvironmentAware:注入Environment对象
  2. EmbeddedValueResolverAware:注入EmbeddedValueResolver对象
  3. ResourceLoaderAware:注入ResourceLoader对象
  4. ApplicationEventPublisherAware:注入ApplicationEventPublisher对象
  5. MessageSourceAware:注入MessageSource对象
  6. ApplicationContextAware:注入ApplicationContext对象

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

CommonAnnotationBeanPostProcessor调用@PostConstruct标注的方法

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

来个案例,感受一下。

案例

来个类

下面的类有2个方法标注了@PostConstruct,并且实现了上面说的那6个Aware接口。


   
  1. package com.javacode2018.lesson002.demo9;
  2. import org.springframework.beans.BeansException;
  3. import org.springframework.context.*;
  4. import org.springframework.core.env.Environment;
  5. import org.springframework.core.io.ResourceLoader;
  6. import org.springframework.util.StringValueResolver;
  7. import javax.annotation.PostConstruct;
  8. public class Bean1 implements EnvironmentAware, EmbeddedValueResolverAware, ResourceLoaderAware, ApplicationEventPublisherAware, MessageSourceAware, ApplicationContextAware {
  9.     @PostConstruct
  10.     public void postConstruct1() {  //@1
  11.         System.out. println( "postConstruct1()");
  12.     }
  13.     @PostConstruct
  14.     public void postConstruct2() {  //@2
  15.         System.out. println( "postConstruct2()");
  16.     }
  17.     @Override
  18.     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  19.         System.out. println( "setApplicationContext:" + applicationContext);
  20.     }
  21.     @Override
  22.     public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
  23.         System.out. println( "setApplicationEventPublisher:" + applicationEventPublisher);
  24.     }
  25.     @Override
  26.     public void setEmbeddedValueResolver(StringValueResolver resolver) {
  27.         System.out. println( "setEmbeddedValueResolver:" + resolver);
  28.     }
  29.     @Override
  30.     public void setEnvironment(Environment environment) {
  31.         System.out. println( "setEnvironment:" + environment.getClass());
  32.     }
  33.     @Override
  34.     public void setMessageSource(MessageSource messageSource) {
  35.         System.out. println( "setMessageSource:" + messageSource);
  36.     }
  37.     @Override
  38.     public void setResourceLoader(ResourceLoader resourceLoader) {
  39.         System.out. println( "setResourceLoader:" + resourceLoader);
  40.     }
  41. }
来个测试案例

   
  1. package com.javacode2018.lesson002.demo9;
  2. import org.junit.Test;
  3. import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  4. public class PostProcessBeforeInitializationTest {
  5.     @Test
  6.     public void test1() {
  7.         AnnotationConfigApplicationContext context =  new AnnotationConfigApplicationContext();
  8.         context.register(Bean1.class);
  9.         context.refresh();
  10.     }
  11. }
运行输出

   
  1. setEmbeddedValueResolver:org.springframework.beans.factory.config.EmbeddedValueResolver@ 15b204a1
  2. setResourceLoader:org.springframework.context.annotation.AnnotationConfigApplicationContext@ 64bf3bbf, started on Sun Apr  05  21: 16: 00 CST  2020
  3. setApplicationEventPublisher:org.springframework.context.annotation.AnnotationConfigApplicationContext@ 64bf3bbf, started on Sun Apr  05  21: 16: 00 CST  2020
  4. setMessageSource:org.springframework.context.annotation.AnnotationConfigApplicationContext@ 64bf3bbf, started on Sun Apr  05  21: 16: 00 CST  2020
  5. setApplicationContext:org.springframework.context.annotation.AnnotationConfigApplicationContext@ 64bf3bbf, started on Sun Apr  05  21: 16: 00 CST  2020
  6. postConstruct1()
  7. postConstruct2()

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

Bean初始化阶段

2个步骤

  1. 调用InitializingBean接口的afterPropertiesSet方法

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

调用InitializingBean接口的afterPropertiesSet方法

来看一下InitializingBean这个接口


   
  1. public  interface InitializingBean {
  2.     void afterPropertiesSet() throws Exception;
  3. }

当我们的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

案例

来个类

   
  1. package com.javacode2018.lesson002.demo10;
  2. import org.springframework.beans.factory.InitializingBean;
  3. public class Service implements InitializingBean{
  4.     public void init() {
  5.         System.out. println( "调用init()方法");
  6.     }
  7.     @Override
  8.     public void afterPropertiesSet() throws Exception {
  9.         System.out. println( "调用afterPropertiesSet()");
  10.     }
  11. }
下面我们定义Service这个bean,指定init方法为初始化方法

   
  1. package com.javacode2018.lesson002.demo10;
  2. import org.junit.Test;
  3. import org.springframework.beans.factory.config.BeanDefinition;
  4. import org.springframework.beans.factory.support.BeanDefinitionBuilder;
  5. import org.springframework.beans.factory.support.DefaultListableBeanFactory;
  6. /**
  7.  * 初始化方法测试
  8.  */
  9. public class InitMethodTest {
  10.     @Test
  11.     public void test1() {
  12.         DefaultListableBeanFactory factory =  new DefaultListableBeanFactory();
  13.         BeanDefinition service = BeanDefinitionBuilder.genericBeanDefinition(Service.class).
  14.                 setInitMethodName( "init").  //@1:指定初始化方法
  15.                 getBeanDefinition();
  16.         factory.registerBeanDefinition( "service", service);
  17.         System.out. println(factory.getBean( "service"));
  18.     }
  19. }
运行输出

   
  1. 调用afterPropertiesSet()
  2. 调用init()方法
  3. com.javacode2018.lesson002.demo10.Service@ 12f41634

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

Bean初始化后阶段

这块的源码:


   
  1. @Override
  2. public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
  3.     throws BeansException {
  4.     Object result = existingBean;
  5.      for (BeanPostProcessor processor : getBeanPostProcessors()) {
  6.         Object current = processor.postProcessAfterInitialization(result, beanName);
  7.          if (current == null) {
  8.              return result;
  9.         }
  10.         result = current;
  11.     }
  12.      return result;
  13. }

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

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

来个案例:


   
  1. package com.javacode2018.lesson002.demo11;
  2. import org.junit.Test;
  3. import org.springframework.beans.BeansException;
  4. import org.springframework.beans.factory.config.BeanPostProcessor;
  5. import org.springframework.beans.factory.support.BeanDefinitionBuilder;
  6. import org.springframework.beans.factory.support.DefaultListableBeanFactory;
  7. import org.springframework.lang.Nullable;
  8. /**
  9.  * {@link BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String)}
  10.  * bean初始化后置处理
  11.  */
  12. public class PostProcessAfterInitializationTest {
  13.     @Test
  14.     public void test1() {
  15.         DefaultListableBeanFactory factory =  new DefaultListableBeanFactory();
  16.          //加入bean初始化后置处理器方法实现
  17.         factory.addBeanPostProcessor( new BeanPostProcessor() {
  18.             @Nullable
  19.             @Override
  20.             public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  21.                 System.out. println( "postProcessAfterInitialization:" + beanName);
  22.                  return bean;
  23.             }
  24.         });
  25.          //下面注册2个String类型的bean
  26.         factory.registerBeanDefinition( "name",
  27.                 BeanDefinitionBuilder.
  28.                         genericBeanDefinition(String.class).
  29.                         addConstructorArgValue( "公众号:【路人甲Java】").
  30.                         getBeanDefinition());
  31.         factory.registerBeanDefinition( "personInformation",
  32.                 BeanDefinitionBuilder.genericBeanDefinition(String.class).
  33.                         addConstructorArgValue( "带领大家成为java高手!").
  34.                         getBeanDefinition());
  35.         System.out. println( "-------输出bean信息---------");
  36.          for (String beanName : factory.getBeanDefinitionNames()) {
  37.             System.out. println(String.format( "%s->%s", beanName, factory.getBean(beanName)));
  38.         }
  39.     }
  40. }

运行输出


   
  1. -------输出bean信息---------
  2. postProcessAfterInitialization:name
  3. name->公众号:【路人甲Java】
  4. postProcessAfterInitialization:personInformation
  5. personInformation->带领大家成为java高手!

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

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


   
  1. public  interface SmartInitializingSingleton {
  2.     void afterSingletonsInstantiated();
  3. }

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


   
  1. /**
  2.  * 确保所有非lazy的单例都被实例化,同时考虑到FactoryBeans。如果需要,通常在工厂设置结束时调用。
  3.  */
  4. org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

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

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

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

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

Service1:


   
  1. package com.javacode2018.lesson002.demo12;
  2. import org.springframework.stereotype.Component;
  3. @Component
  4. public class Service1 {
  5.     public Service1() {
  6.         System.out. println( "create " + this.getClass());
  7.     }
  8. }

Service2:


   
  1. package com.javacode2018.lesson002.demo12;
  2. import org.springframework.stereotype.Component;
  3. @Component
  4. public class Service2 {
  5.     public Service2() {
  6.         System.out. println( "create " + this.getClass());
  7.     }
  8. }

自定义一个SmartInitializingSingleton


   
  1. package com.javacode2018.lesson002.demo12;
  2. import org.springframework.beans.factory.SmartInitializingSingleton;
  3. import org.springframework.stereotype.Component;
  4. @Component
  5. public class MySmartInitializingSingleton implements SmartInitializingSingleton {
  6.     @Override
  7.     public void afterSingletonsInstantiated() {
  8.         System.out. println( "所有bean初始化完毕!");
  9.     }
  10. }

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


   
  1. package com.javacode2018.lesson002.demo12;
  2. import org.junit.Test;
  3. import org.springframework.beans.factory.SmartInitializingSingleton;
  4. import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  5. import org.springframework.context.annotation.ComponentScan;
  6. /**
  7.  * 所有bean初始化完毕,容器会回调{@link SmartInitializingSingleton#afterSingletonsInstantiated()}
  8.  */
  9. @ComponentScan
  10. public class SmartInitializingSingletonTest {
  11.     @Test
  12.     public void test1() {
  13.         AnnotationConfigApplicationContext context =  new AnnotationConfigApplicationContext();
  14.         context.register(SmartInitializingSingletonTest.class);
  15.         System.out. println( "开始启动容器!");
  16.         context.refresh();
  17.         System.out. println( "容器启动完毕!");
  18.     }
  19. }

运行输出


   
  1. 开始启动容器!
  2. create class com.javacode2018.lesson002.demo12.Service1
  3. create class com.javacode2018.lesson002.demo12.Service2
  4. 所有bean初始化完毕!
  5. 容器启动完毕!

案例2:通过api的方式让DefaultListableBeanFactory去回调SmartInitializingSingleton


   
  1. @Test
  2. public void test2() {
  3.     DefaultListableBeanFactory factory =  new DefaultListableBeanFactory();
  4.     factory.registerBeanDefinition( "service1", BeanDefinitionBuilder.genericBeanDefinition(Service1.class).getBeanDefinition());
  5.     factory.registerBeanDefinition( "service2", BeanDefinitionBuilder.genericBeanDefinition(Service2.class).getBeanDefinition());
  6.     factory.registerBeanDefinition( "mySmartInitializingSingleton", BeanDefinitionBuilder.genericBeanDefinition(MySmartInitializingSingleton.class).getBeanDefinition());
  7.     System.out. println( "准备触发所有单例bean初始化");
  8.      //触发所有bean初始化,并且回调 SmartInitializingSingleton#afterSingletonsInstantiated 方法
  9.     factory.preInstantiateSingletons();
  10. }

上面通过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接口

看一下源码:


   
  1. public  interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {
  2.      /**
  3.      * bean销毁前调用的方法
  4.      */
  5.     void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;
  6.      /**
  7.      * 用来判断bean是否需要触发postProcessBeforeDestruction方法
  8.      */
  9.      default boolean requiresDestruction(Object bean) {
  10.          return  true;
  11.     }
  12. }

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

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

下面来看销毁的案例

案例1:自定义DestructionAwareBeanPostProcessor

来个类


   
  1. package com.javacode2018.lesson002.demo13;
  2. public class ServiceA {
  3.     public ServiceA() {
  4.         System.out. println( "create " + this.getClass());
  5.     }
  6. }

自定义一个DestructionAwareBeanPostProcessor


   
  1. package com.javacode2018.lesson002.demo13;
  2. import org.springframework.beans.BeansException;
  3. import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
  4. public class MyDestructionAwareBeanPostProcessor implements DestructionAwareBeanPostProcessor {
  5.     @Override
  6.     public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
  7.         System.out. println( "准备销毁bean:" + beanName);
  8.     }
  9. }

来个测试类


   
  1. package com.javacode2018.lesson002.demo13;
  2. import org.junit.Test;
  3. import org.springframework.beans.factory.support.BeanDefinitionBuilder;
  4. import org.springframework.beans.factory.support.DefaultListableBeanFactory;
  5. /**
  6.  * 自定义 {@link org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor}
  7.  */
  8. public class DestructionAwareBeanPostProcessorTest {
  9.     @Test
  10.     public void test1() {
  11.         DefaultListableBeanFactory factory =  new DefaultListableBeanFactory();
  12.          //添加自定义的DestructionAwareBeanPostProcessor
  13.         factory.addBeanPostProcessor( new MyDestructionAwareBeanPostProcessor());
  14.          //向容器中注入3个单例bean
  15.         factory.registerBeanDefinition( "serviceA1", BeanDefinitionBuilder.genericBeanDefinition(ServiceA.class).getBeanDefinition());
  16.         factory.registerBeanDefinition( "serviceA2", BeanDefinitionBuilder.genericBeanDefinition(ServiceA.class).getBeanDefinition());
  17.         factory.registerBeanDefinition( "serviceA3", BeanDefinitionBuilder.genericBeanDefinition(ServiceA.class).getBeanDefinition());
  18.          //触发所有单例bean初始化
  19.         factory.preInstantiateSingletons();  //@1
  20.         System.out. println( "销毁serviceA1"); 
  21.          //销毁指定的bean
  22.         factory.destroySingleton( "serviceA1"); //@2
  23.         System.out. println( "触发所有单例bean的销毁");
  24.         factory.destroySingletons();
  25.     }
  26. }

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

运行输出


   
  1. create class com.javacode2018.lesson002.demo13.ServiceA
  2. create class com.javacode2018.lesson002.demo13.ServiceA
  3. create class com.javacode2018.lesson002.demo13.ServiceA
  4. 销毁serviceA1
  5. 准备要销毁bean:serviceA1
  6. 触发所有单例bean的销毁
  7. 准备要销毁bean:serviceA3
  8. 准备要销毁bean:serviceA2

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

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

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

再来个类


   
  1. package com.javacode2018.lesson002.demo13;
  2. import javax.annotation.PreDestroy;
  3. public class ServiceB {
  4.     public ServiceB() {
  5.         System.out. println( "create " + this.getClass());
  6.     }
  7.     @PreDestroy
  8.     public void preDestroy() {  //@1
  9.         System.out. println( "preDestroy()");
  10.     }
  11. }

@1:标注了@PreDestroy注解

测试用例


   
  1. @Test
  2. public void test2() {
  3.     DefaultListableBeanFactory factory =  new DefaultListableBeanFactory();
  4.      //添加自定义的DestructionAwareBeanPostProcessor
  5.     factory.addBeanPostProcessor( new MyDestructionAwareBeanPostProcessor());  //@1
  6.      //将CommonAnnotationBeanPostProcessor加入
  7.     factory.addBeanPostProcessor( new CommonAnnotationBeanPostProcessor());  //@2
  8.      //向容器中注入bean
  9.     factory.registerBeanDefinition( "serviceB", BeanDefinitionBuilder.genericBeanDefinition(ServiceB.class).getBeanDefinition());
  10.      //触发所有单例bean初始化
  11.     factory.preInstantiateSingletons();
  12.     System.out. println( "销毁serviceB");
  13.      //销毁指定的bean
  14.     factory.destroySingleton( "serviceB");
  15. }

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

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

看效果运行输出


   
  1. create class com.javacode2018.lesson002.demo13.ServiceB
  2. 销毁serviceB
  3. 准备销毁bean:serviceB
  4. preDestroy()

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

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


   
  1. 1.org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
  2.   用来处理@Resource、@PostConstruct、@PreDestroy的
  3. 2.org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
  4.   用来处理@Autowired、@Value注解
  5. 3.org.springframework.context.support.ApplicationContextAwareProcessor
  6.   用来回调Bean实现的各种Aware接口

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

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

来一个类


   
  1. package com.javacode2018.lesson002.demo14;
  2. import org.springframework.beans.factory.DisposableBean;
  3. import javax.annotation.PreDestroy;
  4. public class ServiceA implements DisposableBean {
  5.     public ServiceA() {
  6.         System.out. println( "创建ServiceA实例");
  7.     }
  8.     @PreDestroy
  9.     public void preDestroy1() {
  10.         System.out. println( "preDestroy1()");
  11.     }
  12.     @PreDestroy
  13.     public void preDestroy2() {
  14.         System.out. println( "preDestroy2()");
  15.     }
  16.     @Override
  17.     public void destroy() throws Exception {
  18.         System.out. println( "DisposableBean接口中的destroy()");
  19.     }
  20.      //自定义的销毁方法
  21.     public void customDestroyMethod() {  //@1
  22.         System.out. println( "我是自定义的销毁方法:customDestroyMethod()");
  23.     }
  24. }

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

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

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

来看测试用例


   
  1. package com.javacode2018.lesson002.demo14;
  2. import org.junit.Test;
  3. import org.springframework.beans.factory.annotation.Configurable;
  4. import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  5. import org.springframework.context.annotation.Bean;
  6. @Configurable
  7. public class DestroyTest {
  8.     @Bean(destroyMethod =  "customDestroyMethod"//@1
  9.     public ServiceA serviceA() {
  10.          return  new ServiceA();
  11.     }
  12.     @Test
  13.     public void test1() {
  14.         AnnotationConfigApplicationContext context =  new AnnotationConfigApplicationContext();
  15.         context.register(DestroyTest.class);
  16.          //启动容器
  17.         System.out. println( "准备启动容器");
  18.         context.refresh();
  19.         System.out. println( "容器启动完毕");
  20.         System.out. println( "serviceA:" + context.getBean(ServiceA.class));
  21.          //关闭容器
  22.         System.out. println( "准备关闭容器");
  23.          //调用容器的close方法,会触发bean的销毁操作
  24.         context. close();  //@2
  25.         System.out. println( "容器关闭完毕");
  26.     }
  27. }

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

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

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

来运行test1,输出


   
  1. 准备启动容器
  2. 创建ServiceA实例
  3. 容器启动完毕
  4. serviceA:com.javacode2018.lesson002.demo14.ServiceA@ 243c4f91
  5. 准备关闭容器
  6. preDestroy1()
  7. preDestroy2()
  8. DisposableBean接口中的destroy()
  9. 我是自定义的销毁方法:customDestroyMethod()
  10. 容器关闭完毕

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

  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个比较重要的方法


   
  1. public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
  2. protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory)

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

第一个方法:getBeanFactory()

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

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

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

第二个方法:registerBeanPostProcessors

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

看一下这个方法的源码:


   
  1. protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
  2.     PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
  3. }

会将请求转发给PostProcessorRegistrationDelegate#registerBeanPostProcessors

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


   
  1. List<BeanPostProcessor> priorityOrderedPostProcessors =  new ArrayList<>();
  2. List<BeanPostProcessor> orderedPostProcessors
  3. List<BeanPostProcessor> nonOrderedPostProcessors;
  4. 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列表。

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

Bean生命周期流程图

Spring学习建议

这里我列一下自己学习spring的一些方法。

看官方文档

spring中的所有知识点,官网上都有,质量方面是非常高的,可能对英文有些要求,不过可以使用翻译软件翻一下。

官网地址:

https://docs.spring.io/spring/docs/5.2.3.RELEASE/spring-framework-reference/

看好的视频

视频算是学习技术最快的一种方式,视频中可以呈现更多细节的东西,同样的内容,可能视频只需要1小时,而用文档描述出来可能需要写一整天,视频的信息量更大,让观看者更容易理解一些。

网上关于spring的视频也比较多,质量不一,很难去选择,不过有一套我强烈建议大家去看,这套视频是有门槛的,前提是你对spring要有一定的了解。

就是极客时间上面的《小马哥讲Spring核心编程思想》,这个系列如果你都能看懂,spring方面不说多的,在大部分公司基本上是无敌状态,目前这套课程已经出了一半了,所有的内容我都看过,质量非常棒,可以扫描下面二维码购买。

看源码

想窥视spring中的原貌,成为顶尖高手,源码是必须要看的,spring整体的设计是非常优秀的,里面用到了很多设计模式,很多java中的api,看源码的过程中,这些好东西慢慢就变成你自己的了。

写博客

技术有没有掌握,你写篇文章就知道了,如果你能通过文章的方式将技术描述出来,让别人能够看懂,那么说明你确实是掌握了这个技术。写博客的过程中会让你想各种办法去深入了解需要介绍的要点,这样收获是非常大的。

总结

本文内容比较多,强烈建议大家先收藏,要反复看,反复去联系,一定要掌握。

关于spring方面有任何问题的,欢迎大家留言。

顺便说下:帮忙点个再看,转发到朋友圈,让更多朋友一起学习。

案例源码

https://gitee.com/javacode2018/spring-series

路人甲java所有案例代码以后都会放到这个上面,大家watch一下,可以持续关注动态。

Spring系列

  1. Spring系列第1篇:为何要学spring?

  2. Spring系列第2篇:控制反转(IoC)与依赖注入(DI)

  3. Spring系列第3篇:Spring容器基本使用及原理

  4. Spring系列第4篇:xml中bean定义详解(-)

  5. Spring系列第5篇:创建bean实例这些方式你们都知道?

  6. Spring系列第6篇:玩转bean scope,避免跳坑里!

  7. Spring系列第7篇:依赖注入之手动注入

  8. Spring系列第8篇:自动注入(autowire)详解,高手在于坚持

  9. Spring系列第9篇:depend-on到底是干什么的?

  10. Spring系列第10篇:primary可以解决什么问题?

  11. Spring系列第11篇:bean中的autowire-candidate又是干什么的?

  12. Spring系列第12篇:lazy-init:bean延迟初始化

  13. Spring系列第13篇:使用继承简化bean配置(abstract & parent)

  14. Spring系列第14篇:lookup-method和replaced-method比较陌生,怎么玩的?

  15. Spring系列第15篇:代理详解(Java动态代理&cglib代理)?

  16. Spring系列第16篇:深入理解java注解及spring对注解的增强(预备知识)

  17. Spring系列第17篇:@Configration和@Bean注解详解(bean批量注册)

  18. Spring系列第18篇:@ComponentScan、@ComponentScans详解(bean批量注册)

  19. Spring系列第18篇:@import详解(bean批量注册)

  20. Spring系列第20篇:@Conditional通过条件来控制bean的注册

  21. Spring系列第21篇:注解实现依赖注入(@Autowired、@Resource、@Primary、@Qulifier)

  22. Spring系列第22篇:@Scope、@DependsOn、@ImportResource、@Lazy 详解

更多好文章

  1. Java高并发系列(共34篇)

  2. MySql高手系列(共27篇)

  3. Maven高手系列(共10篇)

  4. Mybatis系列(共12篇)

  5. 聊聊db和缓存一致性常见的实现方式

  6. 接口幂等性这么重要,它是什么?怎么实现?

  7. 泛型,有点难度,会让很多人懵逼,那是因为你没有看这篇文章!

感谢大家的阅读,也欢迎您把这篇文章分享给更多的朋友一起阅读!谢谢!

路人甲java

▲长按图片识别二维码关注

路人甲Java:工作10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活!


转载:https://blog.csdn.net/likun557/article/details/105355394
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场