阶段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
packagecom.shiguiwu.springmybatis.spring.lifecycle.definition;importcom.shiguiwu.springmybatis.spring.lifecycle.instance.MyAutowire;importlombok.Data;/**
* @description: 小猪
* @author: stone
* @date: Created by 2021/3/17 14:08
* @version: 1.0.0
* @pakeage: com.shiguiwu.springmybatis.spring.lifecycle.definition
*/@DatapublicclassPig{privateString name;privateInteger age;privateString description;publicPig(){}@MyAutowirepublicPig(String name,Integer age){System.out.println("增强候选注解@MyAutowire !!!!");this.name = name;this.age = age;}publicPig(String name,Integer age,String description){this.name = name;this.age = age;this.description = description;}}
xml如下:
<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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"><!-- 合并阶段 --><beanid="p1"class="com.shiguiwu.springmybatis.spring.lifecycle.definition.Pig"><propertyname="name"value="小猪佩奇"/></bean><beanid="p2"parent="p1"><propertyname="age"value="18"/></bean><beanid="p3"parent="p2"><propertyname="description"value="佩奇是个可爱的小孩子"/></bean></beans>
java 测试代码
packagecom.shiguiwu.springmybatis.spring.lifecycle.merge;importorg.springframework.beans.factory.config.BeanDefinition;importorg.springframework.beans.factory.support.DefaultListableBeanFactory;importorg.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
*/publicclassMergeTests{publicstaticvoidmain(String[] args){DefaultListableBeanFactory factory =newDefaultListableBeanFactory();XmlBeanDefinitionReader reader =newXmlBeanDefinitionReader(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
privatevolatileObject 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 ,这个类中有个非常非常重要的字段:
privatefinalList<BeanPostProcessor> beanPostProcessors =newCopyOnWriteArrayList<>();
是一个 BeanPostProcessor 类型的集合,从阶段6开始,spring就开始为我们提供扩展点。
BeanPostProcessor是一个接口,还有很多子接口,这些接口中提供了很多方法,spring在bean生命周期的不同阶段,会调用上面这个列表中的BeanPostProcessor中的一些方法,来对生命周期进行扩展,bean生命周期中的所有扩展点都是依靠这个集合中的BeanPostProcessor来实现的,所以如果大家想对bean的生命周期进行干预,这块一定要掌握好。
下面是实例化前的扩展:
@NullableprotectedObjectapplyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass,String beanName){for(BeanPostProcessor bp :getBeanPostProcessors()){if(bp instanceofInstantiationAwareBeanPostProcessor){InstantiationAwareBeanPostProcessor ibp =(InstantiationAwareBeanPostProcessor) bp;Object result = ibp.postProcessBeforeInstantiation(beanClass,
beanName);if(result !=null){return result;}}}returnnull;}
这段代码在bean实例化之前给开发者留了个口子,开发者自己可以在这个地方直接去创建一个对象作为bean实例,而跳过spring内部实例化bean的过程。上面代码中轮询 beanPostProcessors 列表,如果类型是InstantiationAwareBeanPostProcessor , 尝试调InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 获取bean的实例对象,如果能够获取到,那么将返回值作为当前bean的实例,那么spring自带的实例化bean的过程就被跳过了。
postProcessBeforeInstantiation 方法如下:
defaultObjectpostProcessBeforeInstantiation(Class<?> beanClass,String
beanName)throwsBeansException{returnnull;}
这个地方给开发者提供了一个扩展点,允许开发者在这个方法中直接返回bean的一个实例。
案例
先定义一个postProcessor class
packagecom.shiguiwu.springmybatis.spring.lifecycle.instance;importcom.shiguiwu.springmybatis.spring.lifecycle.definition.User;importorg.springframework.beans.BeansException;importorg.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
*/publicclassUserBeanPostProcessorimplementsInstantiationAwareBeanPostProcessor{@OverridepublicObjectpostProcessBeforeInstantiation(Class<?> beanClass,String beanName)throwsBeansException{System.out.println("调用InstantiationAwareBeanPostProcessor》》》》》》》》》》》》》");if(User.class.isAssignableFrom(beanClass)){User user =newUser();
user.setName("石贵武!!");return user;}returnnull;}}
测试案例
packagecom.shiguiwu.springmybatis.spring.lifecycle.instance;importcom.shiguiwu.springmybatis.spring.lifecycle.definition.User;importorg.springframework.beans.factory.config.BeanDefinition;importorg.springframework.beans.factory.support.BeanDefinitionBuilder;importorg.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
*/publicclassInstancedTests{publicstaticvoidmain(String[] args){DefaultListableBeanFactory factory =newDefaultListableBeanFactory();//实例化前的干预//创建了一个InstantiationAwareBeanPostProcessor,丢到了容器中的BeanPostProcessor列表中
factory.addBeanPostProcessor(newUserBeanPostProcessor());//定义个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 instanceofSmartInstantiationAwareBeanPostProcessor){SmartInstantiationAwareBeanPostProcessor ibp =(SmartInstantiationAwareBeanPostProcessor) bp;Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);if(ctors !=null){return ctors;}}}
会调用 SmartInstantiationAwareBeanPostProcessor接口determineCandidateConstructors 方法,这个方法会返回候选的构造器列表,也可以返回空,看一下这个方法的源码:
defaultConstructor<?>[] determineCandidateConstructors (Class<?> beanClass,String beanName)throwsBeansException{returnnull;}
这个方法有个比较重要的实现类
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
可以将 @Autowired 标注的方法作为候选构造器返回,有兴趣的可以去看一下代码。
来个案例
下面我们来个案例,自定义一个注解,当构造器被这个注解标注的时候,让spring自动选择使用这个构造器创建对象。
先定义一个注解
packagecom.shiguiwu.springmybatis.spring.lifecycle.instance;importjava.lang.annotation.Documented;importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.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)@Documentedpublic@interfaceMyAutowire{}
再定义一个post类
packagecom.shiguiwu.springmybatis.spring.lifecycle.instance;importcn.hutool.core.collection.CollUtil;importorg.springframework.beans.BeansException;importorg.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;importjava.lang.reflect.Constructor;importjava.util.Arrays;importjava.util.List;importjava.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
*/publicclassMySmartInstantiationAwareBeanPostProcessorimplementsSmartInstantiationAwareBeanPostProcessor{@OverridepublicConstructor<?>[]determineCandidateConstructors(Class<?> beanClass,String beanName)throwsBeansException{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;}}
测试代码:
packagecom.shiguiwu.springmybatis.spring.lifecycle.instance;importcom.shiguiwu.springmybatis.spring.lifecycle.definition.Pig;importorg.springframework.beans.factory.config.BeanDefinition;importorg.springframework.beans.factory.support.BeanDefinitionBuilder;importorg.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
*/publicclassInstancingTests{publicstaticvoidmain(String[] args){DefaultListableBeanFactory factory =newDefaultListableBeanFactory();
factory.addBeanPostProcessor(newMySmartInstantiationAwareBeanPostProcessor());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]DEBUGorg.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]DEBUGorg.springframework.beans.factory.support.DefaultListableBeanFactory-Creating shared instance of singleton bean 'name'
bean的名称:name
java.lang.String
调用 SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors
21:00:40.928[main]DEBUGorg.springframework.beans.factory.support.DefaultListableBeanFactory-Creating shared instance of singleton bean 'age'
bean的名称:age
java.lang.Integer
调用 SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors
21:00:40.945[main]DEBUGorg.springframework.beans.factory.support.DefaultListableBeanFactory-Autowiring by type from bean name 'pig' via constructor tobean named 'name'21:00:40.945[main]DEBUGorg.springframework.beans.factory.support.DefaultListableBeanFactory-Autowiring by type from bean name 'pig' via constructor tobean named 'age'
增强候选注解@MyAutowire !!!!
Pig(name=小猪佩奇, age=1, description=null)
从输出中可以看出调用了Person中标注@MyAutowired标注的构造器。
到目前为止bean实例化阶段结束了,继续进入后面的阶段。
阶段7:合并后的BeanDefinition处理
合并后的处理,这里spring也为我们提供了扩展点,在合并之后,做些我们自己的动作和业务等。源码如下:
protectedvoidapplyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd,Class<?> beanType,String beanName){for(BeanPostProcessor bp :getBeanPostProcessors()){if(bp instanceofMergedBeanDefinitionPostProcessor){MergedBeanDefinitionPostProcessor bdp =(MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);}}}
会调用 MergedBeanDefinitionPostProcessor接口的postProcessMergedBeanDefinition 方法,看一下这个方法的源码:
voidpostProcessMergedBeanDefinition(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的生命周期中篇完结,后面会更新终篇
版权归原作者 码农小伙 所有, 如有侵权,请联系我们删除。