Spring-bean的生命周期-中篇

阶段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
案例:
spring bean

package com.shiguiwu.springmybatis.spring.lifecycle.definition;

import com.shiguiwu.springmybatis.spring.lifecycle.instance.MyAutowire;
import lombok.Data;

/**
 * @description: 小猪
 * @author: stone
 * @date: Created by 2021/3/17 14:08
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springmybatis.spring.lifecycle.definition
 */
@Data
public class Pig {

    private String name;
    private Integer age;

    private String description;

    public Pig() {
    }

    @MyAutowire
    public Pig(String name, Integer age) {
        System.out.println("增强候选注解@MyAutowire !!!!");
        this.name = name;
        this.age = age;
    }

    public Pig(String name, Integer age, String description) {
        this.name = name;
        this.age = age;
        this.description = description;
    }
}

xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 合并阶段 -->

    <bean id="p1" class="com.shiguiwu.springmybatis.spring.lifecycle.definition.Pig" >
        <property name="name" value="小猪佩奇"/>
    </bean>
    <bean id="p2" parent="p1">
        <property name="age" value="18" />
    </bean>
    <bean id="p3" parent="p2">
        <property name="description" value="佩奇是个可爱的小孩子"/>
    </bean>
</beans>

java 测试代码

package com.shiguiwu.springmybatis.spring.lifecycle.merge;

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

/**
 * @description: 4,合并阶段
 * @author: stone
 * @date: Created by 2021/3/23 23:06
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springmybatis.spring.lifecycle.merge
 */
public class MergeTests {

    public static void main(String[] args) {

        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);

        reader.loadBeanDefinitions("spring/merge.xml");

        String[] definitionNames = factory.getBeanDefinitionNames();
        for (String definitionName : definitionNames) {
            System.out.println(definitionName);
            System.out.println("========================================");

            BeanDefinition beanDefinition = factory.getBeanDefinition(definitionName);
            BeanDefinition mergedBeanDefinition = factory.getMergedBeanDefinition(definitionName);

            System.out.println("解析xml过程中的bean definitionName:" + beanDefinition);
            System.out.println("解析xml过程中的bean definitionName 的属性信息:" + beanDefinition.getPropertyValues());
            System.out.println("==========================================");

            System.out.println("解析xml过程中的合并bean definitionName:" + mergedBeanDefinition);
            System.out.println("解析xml过程中的合并bean definitionName 的属性信息:" + mergedBeanDefinition.getPropertyValues());

            System.out.println("-------------------------------------------");
        }
    }
}

输出效果如下:

23:57:59.842 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 3 bean definitions from class path resource [spring/merge.xml]
p1
========================================
解析xml过程中的bean definitionName:Generic bean: class [com.shiguiwu.springmybatis.spring.lifecycle.definition.Pig]; 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 [spring/merge.xml]
解析xml过程中的bean definitionName 的属性信息:PropertyValues: length=1; bean property 'name'
==========================================
解析xml过程中的合并bean definitionName:Root bean: class [com.shiguiwu.springmybatis.spring.lifecycle.definition.Pig]; 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 [spring/merge.xml]
解析xml过程中的合并bean definitionName 的属性信息:PropertyValues: length=1; bean property 'name'
-------------------------------------------
p2
========================================
解析xml过程中的bean definitionName:Generic bean with parent 'p1': 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 [spring/merge.xml]
解析xml过程中的bean definitionName 的属性信息:PropertyValues: length=1; bean property 'age'
==========================================
解析xml过程中的合并bean definitionName:Root bean: class [com.shiguiwu.springmybatis.spring.lifecycle.definition.Pig]; 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 [spring/merge.xml]
解析xml过程中的合并bean definitionName 的属性信息:PropertyValues: length=2; bean property 'name'; bean property 'age'
-------------------------------------------
p3
========================================
解析xml过程中的bean definitionName:Generic bean with parent 'p2': 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 [spring/merge.xml]
解析xml过程中的bean definitionName 的属性信息:PropertyValues: length=1; bean property 'description'
==========================================
解析xml过程中的合并bean definitionName:Root bean: class [com.shiguiwu.springmybatis.spring.lifecycle.definition.Pig]; 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 [spring/merge.xml]
解析xml过程中的合并bean definitionName 的属性信息:PropertyValues: length=3; bean property 'name'; bean property 'age'; bean property 'description'
-------------------------------------------

从输出的结果中可以看到,合并之前,BeanDefinition是不完整的,比p2和p3中的class是null,属性信息也不完整,但是合并之后这些信息都完整了。
合并之前是 GenericBeanDefinition 类型的,合并之后得到的是 RootBeanDefinition 类型的。

获取p3合并的BeanDefinition时,内部会递归进行合并,先将p1和p2合并,然后将p2再和p3合并,最后得到合并之后的BeanDefinition。

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

2个小阶段

  • Bean实例化前操作
  • Bean实例化操作
Bean实例化前操作

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

private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();

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

@Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp =
                    (InstantiationAwareBeanPostProcessor) bp;
            Object result = ibp.postProcessBeforeInstantiation(beanClass,
                    beanName);
            if (result != null) {
                return result;
            }
        }
    }
    return null;
}

这段代码在bean实例化之前给开发者留了个口子,开发者自己可以在这个地方直接去创建一个对象作为bean实例,而跳过spring内部实例化bean的过程。上面代码中轮询 beanPostProcessors 列表,如果类型是InstantiationAwareBeanPostProcessor , 尝试调InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 获取bean的实例对象,如果能够获取到,那么将返回值作为当前bean的实例,那么spring自带的实例化bean的过程就被跳过了。

postProcessBeforeInstantiation 方法如下:

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

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

package com.shiguiwu.springmybatis.spring.lifecycle.instance;

import com.shiguiwu.springmybatis.spring.lifecycle.definition.User;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;

/**
 * @description: process
 * @author: stone
 * @date: Created by 2021/3/24 20:59
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springmybatis.spring.lifecycle.instance
 */
public class UserBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("调用InstantiationAwareBeanPostProcessor》》》》》》》》》》》》》");
        if (User.class.isAssignableFrom(beanClass)) {
            User user = new User();
            user.setName("石贵武!!");
            return user;
        }
        return null;
    }
}

测试案例

package com.shiguiwu.springmybatis.spring.lifecycle.instance;

import com.shiguiwu.springmybatis.spring.lifecycle.definition.User;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

/**
 * @description: 6.0, 实例前阶段
 * @author: stone
 * @date: Created by 2021/3/24 20:43
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springmybatis.spring.lifecycle.instance
 */
public class InstancedTests {

    public static void main(String[] args) {
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        //实例化前的干预
        //创建了一个InstantiationAwareBeanPostProcessor,丢到了容器中的BeanPostProcessor列表中
        factory.addBeanPostProcessor(new UserBeanPostProcessor());
        //定义个
        BeanDefinition definition = BeanDefinitionBuilder.genericBeanDefinition(User.class)
                //改修名称
                .addPropertyValue("name", "周冬")
                .getBeanDefinition();
        //注册定义对象
        factory.registerBeanDefinition("user", definition);
        System.out.println(factory.getBean("user"));

    }
}

输出结果如下:

D:\jdk8\bin\java.exe -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:65150,suspend=y,server=n -javaagent:D:\idea\20190304\system\captureAgent\debugger-agent.jar -Dfile.encoding=UTF-8 -classpath "D:\jdk8\jre\lib\charsets.jar;D:\jdk8\jre\lib\deploy.jar;D:\jdk8\jre\lib\ext\access-bridge-64.jar;D:\jdk8\jre\lib\ext\cldrdata.jar;D:\jdk8\jre\lib\ext\dnsns.jar;D:\jdk8\jre\lib\ext\jaccess.jar;D:\jdk8\jre\lib\ext\jfxrt.jar;D:\jdk8\jre\lib\ext\localedata.jar;D:\jdk8\jre\lib\ext\nashorn.jar;D:\jdk8\jre\lib\ext\sunec.jar;D:\jdk8\jre\lib\ext\sunjce_provider.jar;D:\jdk8\jre\lib\ext\sunmscapi.jar;D:\jdk8\jre\lib\ext\sunpkcs11.jar;D:\jdk8\jre\lib\ext\zipfs.jar;D:\jdk8\jre\lib\javaws.jar;D:\jdk8\jre\lib\jce.jar;D:\jdk8\jre\lib\jfr.jar;D:\jdk8\jre\lib\jfxswt.jar;D:\jdk8\jre\lib\jsse.jar;D:\jdk8\jre\lib\management-agent.jar;D:\jdk8\jre\lib\plugin.jar;D:\jdk8\jre\lib\resources.jar;D:\jdk8\jre\lib\rt.jar;G:\workspace\ideaWorkspace\spring-mybatis\target\classes;G:\maven_repository\com\baomidou\mybatis-plus-boot-starter\3.2.0\mybatis-plus-boot-starter-3.2.0.jar;G:\maven_repository\com\baomidou\mybatis-plus\3.2.0\mybatis-plus-3.2.0.jar;G:\maven_repository\com\baomidou\mybatis-plus-extension\3.2.0\mybatis-plus-extension-3.2.0.jar;G:\maven_repository\com\baomidou\mybatis-plus-core\3.2.0\mybatis-plus-core-3.2.0.jar;G:\maven_repository\com\baomidou\mybatis-plus-annotation\3.2.0\mybatis-plus-annotation-3.2.0.jar;G:\maven_repository\com\github\jsqlparser\jsqlparser\2.1\jsqlparser-2.1.jar;G:\maven_repository\org\mybatis\mybatis\3.5.2\mybatis-3.5.2.jar;G:\maven_repository\org\mybatis\mybatis-spring\2.0.2\mybatis-spring-2.0.2.jar;G:\maven_repository\org\springframework\boot\spring-boot-autoconfigure\2.3.11.RELEASE\spring-boot-autoconfigure-2.3.11.RELEASE.jar;G:\maven_repository\org\springframework\boot\spring-boot\2.3.11.RELEASE\spring-boot-2.3.11.RELEASE.jar;G:\maven_repository\org\springframework\boot\spring-boot-starter-jdbc\2.3.11.RELEASE\spring-boot-starter-jdbc-2.3.11.RELEASE.jar;G:\maven_repository\com\zaxxer\HikariCP\3.4.5\HikariCP-3.4.5.jar;G:\maven_repository\org\springframework\spring-jdbc\5.2.15.RELEASE\spring-jdbc-5.2.15.RELEASE.jar;G:\maven_repository\org\springframework\boot\spring-boot-starter-web\2.3.11.RELEASE\spring-boot-starter-web-2.3.11.RELEASE.jar;G:\maven_repository\org\springframework\boot\spring-boot-starter\2.3.11.RELEASE\spring-boot-starter-2.3.11.RELEASE.jar;G:\maven_repository\org\springframework\boot\spring-boot-starter-logging\2.3.11.RELEASE\spring-boot-starter-logging-2.3.11.RELEASE.jar;G:\maven_repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;G:\maven_repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;G:\maven_repository\org\apache\logging\log4j\log4j-to-slf4j\2.13.3\log4j-to-slf4j-2.13.3.jar;G:\maven_repository\org\apache\logging\log4j\log4j-api\2.13.3\log4j-api-2.13.3.jar;G:\maven_repository\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;G:\maven_repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;G:\maven_repository\org\yaml\snakeyaml\1.26\snakeyaml-1.26.jar;G:\maven_repository\org\springframework\boot\spring-boot-starter-json\2.3.11.RELEASE\spring-boot-starter-json-2.3.11.RELEASE.jar;G:\maven_repository\com\fasterxml\jackson\core\jackson-databind\2.11.4\jackson-databind-2.11.4.jar;G:\maven_repository\com\fasterxml\jackson\core\jackson-annotations\2.11.4\jackson-annotations-2.11.4.jar;G:\maven_repository\com\fasterxml\jackson\core\jackson-core\2.11.4\jackson-core-2.11.4.jar;G:\maven_repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.11.4\jackson-datatype-jdk8-2.11.4.jar;G:\maven_repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.11.4\jackson-datatype-jsr310-2.11.4.jar;G:\maven_repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.11.4\jackson-module-parameter-names-2.11.4.jar;G:\maven_repository\org\springframework\boot\spring-boot-starter-tomcat\2.3.11.RELEASE\spring-boot-starter-tomcat-2.3.11.RELEASE.jar;G:\maven_repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.46\tomcat-embed-core-9.0.46.jar;G:\maven_repository\org\glassfish\jakarta.el\3.0.3\jakarta.el-3.0.3.jar;G:\maven_repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.46\tomcat-embed-websocket-9.0.46.jar;G:\maven_repository\org\springframework\spring-web\5.2.15.RELEASE\spring-web-5.2.15.RELEASE.jar;G:\maven_repository\org\springframework\spring-beans\5.2.15.RELEASE\spring-beans-5.2.15.RELEASE.jar;G:\maven_repository\org\springframework\spring-webmvc\5.2.15.RELEASE\spring-webmvc-5.2.15.RELEASE.jar;G:\maven_repository\org\springframework\spring-context\5.2.15.RELEASE\spring-context-5.2.15.RELEASE.jar;G:\maven_repository\org\springframework\spring-expression\5.2.15.RELEASE\spring-expression-5.2.15.RELEASE.jar;G:\maven_repository\org\springframework\boot\spring-boot-starter-aop\2.3.11.RELEASE\spring-boot-starter-aop-2.3.11.RELEASE.jar;G:\maven_repository\org\springframework\spring-aop\5.2.15.RELEASE\spring-aop-5.2.15.RELEASE.jar;G:\maven_repository\org\aspectj\aspectjweaver\1.9.6\aspectjweaver-1.9.6.jar;G:\maven_repository\org\springframework\boot\spring-boot-starter-cache\2.3.11.RELEASE\spring-boot-starter-cache-2.3.11.RELEASE.jar;G:\maven_repository\org\springframework\spring-context-support\5.2.15.RELEASE\spring-context-support-5.2.15.RELEASE.jar;G:\maven_repository\mysql\mysql-connector-java\8.0.25\mysql-connector-java-8.0.25.jar;G:\maven_repository\org\springframework\boot\spring-boot-configuration-processor\2.3.11.RELEASE\spring-boot-configuration-processor-2.3.11.RELEASE.jar;G:\maven_repository\org\projectlombok\lombok\1.18.20\lombok-1.18.20.jar;G:\maven_repository\cn\hutool\hutool-all\5.3.7\hutool-all-5.3.7.jar;G:\maven_repository\com\shiguiwu\facade\facade-spring-boot-starter-autoconfigurer\1.0.1-SNAPSHOT\facade-spring-boot-starter-autoconfigurer-1.0.1-SNAPSHOT.jar;G:\maven_repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;G:\maven_repository\org\springframework\spring-core\5.2.15.RELEASE\spring-core-5.2.15.RELEASE.jar;G:\maven_repository\org\springframework\spring-jcl\5.2.15.RELEASE\spring-jcl-5.2.15.RELEASE.jar;G:\maven_repository\org\springframework\boot\spring-boot-starter-data-redis\2.3.11.RELEASE\spring-boot-starter-data-redis-2.3.11.RELEASE.jar;G:\maven_repository\org\springframework\data\spring-data-redis\2.3.9.RELEASE\spring-data-redis-2.3.9.RELEASE.jar;G:\maven_repository\org\springframework\data\spring-data-keyvalue\2.3.9.RELEASE\spring-data-keyvalue-2.3.9.RELEASE.jar;G:\maven_repository\org\springframework\data\spring-data-commons\2.3.9.RELEASE\spring-data-commons-2.3.9.RELEASE.jar;G:\maven_repository\org\springframework\spring-tx\5.2.15.RELEASE\spring-tx-5.2.15.RELEASE.jar;G:\maven_repository\org\springframework\spring-oxm\5.2.15.RELEASE\spring-oxm-5.2.15.RELEASE.jar;G:\maven_repository\io\lettuce\lettuce-core\5.3.7.RELEASE\lettuce-core-5.3.7.RELEASE.jar;G:\maven_repository\io\netty\netty-common\4.1.65.Final\netty-common-4.1.65.Final.jar;G:\maven_repository\io\netty\netty-handler\4.1.65.Final\netty-handler-4.1.65.Final.jar;G:\maven_repository\io\netty\netty-resolver\4.1.65.Final\netty-resolver-4.1.65.Final.jar;G:\maven_repository\io\netty\netty-buffer\4.1.65.Final\netty-buffer-4.1.65.Final.jar;G:\maven_repository\io\netty\netty-codec\4.1.65.Final\netty-codec-4.1.65.Final.jar;G:\maven_repository\io\netty\netty-transport\4.1.65.Final\netty-transport-4.1.65.Final.jar;G:\maven_repository\io\projectreactor\reactor-core\3.3.17.RELEASE\reactor-core-3.3.17.RELEASE.jar;G:\maven_repository\org\reactivestreams\reactive-streams\1.0.3\reactive-streams-1.0.3.jar;D:\JetBrains\IntelliJ IDEA 2019.3.4\lib\idea_rt.jar" com.shiguiwu.springmybatis.spring.lifecycle.instance.InstancedTests
Connected to the target VM, address: '127.0.0.1:65150', transport: 'socket'
20:19:14.485 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'user'
调用InstantiationAwareBeanPostProcessor》》》》》》》》》》》》》
User(pig=null, name=石贵武!!, pigList=null, pigSet=null, stringMap=null, stringPigMap=null, strings=null, stringSet=null)
Disconnected from the target VM, address: '127.0.0.1:65150', transport: 'socket'

Process finished with exit code 0

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

Bean实例化操作

这个过程会通过反射来调用bean的构造器来创建bean的实例。具体需要使用哪个构造器,spring为开发者提供了一个接口,允许开发者自己来判断用哪个构造器。
看一下这块的代码逻辑:

for (BeanPostProcessor bp : getBeanPostProcessors()) {
  if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
    SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
    Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
    if (ctors != null) {
      return ctors;
   }
 }
}

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

default Constructor<?>[] determineCandidateConstructors (Class < ? > beanClass, String beanName) throws BeansException {
    return null;
}

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

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor

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

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

package com.shiguiwu.springmybatis.spring.lifecycle.instance;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @description: 自定义候选注解
 * @author: stone
 * @date: Created by 2021/3/24 23:43
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springmybatis.spring.lifecycle.instance
 */
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAutowire {


}

再定义一个post类

package com.shiguiwu.springmybatis.spring.lifecycle.instance;

import cn.hutool.core.collection.CollUtil;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;

import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @description: 自定义候选构造器
 * @author: stone
 * @date: Created by 2021/3/24 23:42
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springmybatis.spring.lifecycle.instance
 */
public class MySmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
    @Override
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("bean的名称:" + beanName);
        System.out.println(beanClass.getName());
        System.out.println("调用 SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors ");

        Constructor<?>[] constructors = beanClass.getDeclaredConstructors();
        Constructor[] array = Arrays.stream(constructors)
                .filter(c -> c.isAnnotationPresent(MyAutowire.class)).toArray(Constructor[]::new);
        return (array.length!=0) ? array : null;
    }
}

测试代码:

package com.shiguiwu.springmybatis.spring.lifecycle.instance;

import com.shiguiwu.springmybatis.spring.lifecycle.definition.Pig;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

/**
 * @description: 6.1实例化中
 * 利用bean定义信息,借助反射,调用构造器,生成实例。构造器可有开发者决定
 *
 *
 * @author: stone
 * @date: Created by 2021/3/24 23:15
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springmybatis.spring.lifecycle.instance
 */
public class InstancingTests {

    public static void main(String[] args) {
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

        factory.addBeanPostProcessor(new MySmartInstantiationAwareBeanPostProcessor());
        BeanDefinition stringBean = BeanDefinitionBuilder.genericBeanDefinition(String.class)
                .addConstructorArgValue("小猪佩奇")
                .getBeanDefinition();
        BeanDefinition integerBean = BeanDefinitionBuilder.genericBeanDefinition(Integer.class)
                .addConstructorArgValue(1)
                .getBeanDefinition();
        BeanDefinition pig = BeanDefinitionBuilder.genericBeanDefinition(Pig.class)
                .getBeanDefinition();
        factory.registerBeanDefinition("age", integerBean);
        factory.registerBeanDefinition("name", stringBean);
        factory.registerBeanDefinition("pig", pig);

        System.out.println(factory.getBean(Pig.class));

    }
}

输出如下:

21:00:40.255 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'pig'
bean的名称:pig
com.shiguiwu.springmybatis.spring.lifecycle.definition.Pig
调用 SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors 
21:00:40.436 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'name'
bean的名称:name
java.lang.String
调用 SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors 
21:00:40.928 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'age'
bean的名称:age
java.lang.Integer
调用 SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors 
21:00:40.945 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'pig' via constructor to bean named 'name'
21:00:40.945 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'pig' via constructor to bean named 'age'
增强候选注解@MyAutowire !!!!
Pig(name=小猪佩奇, age=1, description=null)

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

阶段7:合并后的BeanDefinition处理

合并后的处理,这里spring也为我们提供了扩展点,在合并之后,做些我们自己的动作和业务等。源码如下:

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

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

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

spring会轮询 BeanPostProcessor ,依次调用MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
第一个参数为beanDefinition,表示合并之后的RootBeanDefinition,我们可以在这个方法内部对合并之后的 BeanDefinition 进行再次处理
postProcessMergedBeanDefinition有2个实现类,前面我们介绍过,用的也比较多,面试的时候也会经常问的:

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

此致,spring bean的生命周期中篇完结,后面会更新终篇

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值