【Spring Bean 生命周期系列】传送门

1、Spring Bean生命周期: Bean元信息的配置与解析阶段

2、Spring Bean生命周期: Bean的注册

3、Spring Bean生命周期: BeanDefinition的合并过程

4、Spring Bean生命周期: Bean的实例化

5、Spring Bean生命周期:属性赋值阶段

6、Spring Bean生命周期:Bean的初始化阶段

写在前面

注:本文章使用的 SpringBoot 版本为 2.2.4.RELEASE,其 Spring 版本为 5.2.3.RELEASE

前言

上一节说到了BeanDefinition的合并过程,这节该说Bean的实例化过程了。根据AbstractAutowireCapableBeanFactory#createBean源码逻辑 可将实例化过程分为实例化前阶段实例化过程实例化后阶段

实例化前阶段

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {//省略无关代码try {// 这里就是我们分析的重点了 ⭐️Object bean = resolveBeforeInstantiation(beanName, mbdToUse);//⭐️ 注意这个逻辑:如果postProcessBeforeInstantiation方法返回非null 则将返回值作为创建的Bean。并中断正常的创建流程if (bean != null) {return bean;}}catch (Throwable ex) {//省略异常信息}try {//真正创建Bean的逻辑 实例化Bean对象,为Bean属性赋值等,这里暂不展开Object beanInstance = doCreateBean(beanName, mbdToUse, args);//省略日志输出return beanInstance;}catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {//省略异常信息}

resolveBeforeInstantiation这个方法在BeanPostProcessor浅析 这一节分析过了 这里不再具体展开了。

如果InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 方法返回null,那么将不会中断正常Bean创建过程。
下面就来到的Bean实例化部分了。

实例化阶段

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException {// Instantiate the bean.BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {//Bean实例化instanceWrapper = createBeanInstance(beanName, mbd, args);}//省略其他代码 try {//Bean实例化后属性赋值populateBean(beanName, mbd, instanceWrapper);//Bean的初始化exposedObject = initializeBean(beanName, exposedObject, mbd);}catch (Throwable ex) {//省略异常信息}//省略其他代码return exposedObject;}

上面将doCreateBean精简一下,只暴露出我们比较关系的部分。一目了然,Bean的实例化过程就藏在createBeanInstance方法中。

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {//解析BeanClass,在BeanDefinition中类信息是以字符串形式展现,这里解析到字符串后 会将其加载为ClassClass<?> beanClass = resolveBeanClass(mbd, beanName);if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());}//如果设置了 Supplier 回调,则使用给定的回调方法初始化策略,通过获取Supplier#get得到实例化对象 Supplier<?> instanceSupplier = mbd.getInstanceSupplier();if (instanceSupplier != null) {return obtainFromSupplier(instanceSupplier, beanName);}//如果工厂方法不为空,则使用工厂方法初始化if (mbd.getFactoryMethodName() != null) {return instantiateUsingFactoryMethod(beanName, mbd, args);}boolean resolved = false;boolean autowireNecessary = false;if (args == null) {//加锁synchronized (mbd.constructorArgumentLock) {//条件成立 说明构造函数或FactoryMethod已经被解析并被缓存,可直接利用构造函数解析//与后面的SimpleInstantiationStrategy#instantiate呼应if (mbd.resolvedConstructorOrFactoryMethod != null) {resolved = true;autowireNecessary = mbd.constructorArgumentsResolved;}}}//如果已经被解析过if (resolved) {//条件成立 使用构造函数注入if (autowireNecessary) {return autowireConstructor(beanName, mbd, null, null);}else {//使用默认构造函数解析return instantiateBean(beanName, mbd);}}// 使用SmartInstantiationAwareBeanPostProcessor 找到候选的构造函数 用于注入Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);// AutowireMode==AUTOWIRE_CONSTRUCTOR 条件成立 说明使用基于构造函数的注入方式 (默认是AUTOWIRE_NO,需要动态检测)// mbd.hasConstructorArgumentValues() 条件成立 说明构造函数中拥有参数if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {//基于构造函数自动注入return autowireConstructor(beanName, mbd, ctors, args);}// 如果mbd中配置了构造函数 则使用它进行注入ctors = mbd.getPreferredConstructors();if (ctors != null) {return autowireConstructor(beanName, mbd, ctors, null);}// 使用默认构造函数实例化return instantiateBean(beanName, mbd);}

分析了上面的源码之后,我们试着总结一下上面代码主要完成的事情:

1、如果mbd配置了instanceSupplier回调,则使用instanceSupplier去初始化BeanDefinition

2、如果mbd配置了工厂方法,则使用工厂方法区初始化BeanDefinition

3、实例化BeanDefinition

  • 如果mbd已经被解析过了,则根据缓存 选择使用有参构造函数注入还是默认构造函数注入
  • 如果mbd没有被解析过,找到mbd中候选的构造函数(一个类可能有多个构造函数),再根据一些限定条件 选择是基于有参构造函数初始化还是默认构造函数初始化

针对第1点,其实就是lambda8 supplier接口的使用,不再介绍。
针对第3点,其实就是通过反射机制 创建实例对象,最终调用了SimpleInstantiationStrategy#instantiate方法
针对第2点 举例说明下 工厂方法静态工厂生成Bean的两种形式,再来展开说下instantiateUsingFactoryMethod源码。

配置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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="peopleFactory" class="com.wojiushiwo.factorymethod.PeopleFactory"/><!--实例方法--><bean id="instanceMethod" factory-bean="peopleFactory" factory-method="createPeople"/><!--静态方法--><bean id="staticFactoryMethod" class="com.wojiushiwo.factorymethod.People" factory-method="createPeople"/>
</beans>
//实体对象
@Data
public class People implements Serializable {private String name;private Integer age;public People() {}public static People createPeople() {People people = new People();people.setAge(18);people.setName("我就是我");return people;}
}
//People工厂类
public class PeopleFactory {public People createPeople() {return People.createPeople();}
}public class FactoryMethodDemo {public static void main(String[] args) {ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("META-INF/spring.xml");context.refresh();People people = (People) context.getBean("staticFactoryMethod");System.out.println(people);People people = (People) context.getBean("instanceMethod");System.out.println(people);      context.close();}
}
public BeanWrapper instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {BeanWrapperImpl bw = new BeanWrapperImpl();this.beanFactory.initBeanWrapper(bw);Object factoryBean;Class<?> factoryClass;boolean isStatic;//获取FactoryBeanName,实例方法与静态工厂方法的区别就在于有没有FactoryBeanNameString factoryBeanName = mbd.getFactoryBeanName();if (factoryBeanName != null) {//如果存在FactoryBeanName,则说明是实例方法if (factoryBeanName.equals(beanName)) {throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,"factory-bean reference points back to the same bean definition");}//获取当前factoryBeanName名称的BeanfactoryBean = this.beanFactory.getBean(factoryBeanName);if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {throw new ImplicitlyAppearedSingletonException();}//获取工厂类ClassfactoryClass = factoryBean.getClass();//标记为非静态isStatic = false;}else {// 走到这里,说明是静态工厂方法if (!mbd.hasBeanClass()) {throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,"bean definition declares neither a bean class nor a factory-bean reference");}//factoryBean设置为nullfactoryBean = null;//获取工厂类Class,这里使用BeanDefinition作为其工厂类factoryClass = mbd.getBeanClass();//标记为非静态isStatic = true;}Method factoryMethodToUse = null;ArgumentsHolder argsHolderToUse = null;Object[] argsToUse = null;//explicitArgs 这个是getBean方法传递过来的,一般为nullif (explicitArgs != null) {argsToUse = explicitArgs;}else {Object[] argsToResolve = null;//加锁synchronized (mbd.constructorArgumentLock) {//获取被解析的工厂方法factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;//条件成立 说明工厂方法已经被解析过了,并存到了mbd中缓存起来了if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {// Found a cached factory method...argsToUse = mbd.resolvedConstructorArguments;if (argsToUse == null) {argsToResolve = mbd.preparedConstructorArguments;}}}if (argsToResolve != null) {argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);}}if (factoryMethodToUse == null || argsToUse == null) {//获取工厂类factoryClass = ClassUtils.getUserClass(factoryClass);//获取类中的方法Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);List<Method> candidateList = new ArrayList<>();for (Method candidate : rawCandidates) {//如果方法修饰符包含static,并且方法名称是配置的FactoryMethod,则添加到候选集合中if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {candidateList.add(candidate);}}//如果候选集合有1个元素 并且BeanDefinition中未设置构造参数 (explicitArgs一般都为null )if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {//获取方法Method uniqueCandidate = candidateList.get(0);//如果方法参数为空if (uniqueCandidate.getParameterCount() == 0) {mbd.factoryMethodToIntrospect = uniqueCandidate;synchronized (mbd.constructorArgumentLock) {//将下面这些全缓存到mbd中,下次直接用(与createBeanInstance方法呼应上了)mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;mbd.constructorArgumentsResolved = true;mbd.resolvedConstructorArguments = EMPTY_ARGS;}//实例化bd,设置到BeanWrapper中bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));return bw;}}//程序走到这里 大概率是BeanDefinition中设置了构造参数Method[] candidates = candidateList.toArray(new Method[0]);//按照修饰符及方法参数 进行排序AutowireUtils.sortFactoryMethods(candidates);ConstructorArgumentValues resolvedValues = null;//是否构造函数注入boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);int minTypeDiffWeight = Integer.MAX_VALUE;Set<Method> ambiguousFactoryMethods = null;//最小参数数量 默认是0int minNrOfArgs;if (explicitArgs != null) {minNrOfArgs = explicitArgs.length;}else {//走到这里 说明explicitArgs未被设置参数//如果bd设置了构造参数,则从bd中解析参数if (mbd.hasConstructorArgumentValues()) {ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();resolvedValues = new ConstructorArgumentValues();//得到解析的最小参数数量minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);}else {minNrOfArgs = 0;}}LinkedList<UnsatisfiedDependencyException> causes = null;//下面主要是推断参数、FactoryMethod,代码比较长 就先不分析了for (Method candidate : candidates) {Class<?>[] paramTypes = candidate.getParameterTypes();if (paramTypes.length >= minNrOfArgs) {ArgumentsHolder argsHolder;if (explicitArgs != null) {// Explicit arguments given -> arguments length must match exactly.if (paramTypes.length != explicitArgs.length) {continue;}argsHolder = new ArgumentsHolder(explicitArgs);}else {// Resolved constructor arguments: type conversion and/or autowiring necessary.try {String[] paramNames = null;ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();if (pnd != null) {paramNames = pnd.getParameterNames(candidate);}argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,paramTypes, paramNames, candidate, autowiring, candidates.length == 1);}catch (UnsatisfiedDependencyException ex) {if (logger.isTraceEnabled()) {logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex);}// Swallow and try next overloaded factory method.if (causes == null) {causes = new LinkedList<>();}causes.add(ex);continue;}}int typeDiffWeight = (mbd.isLenientConstructorResolution() ?argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));// Choose this factory method if it represents the closest match.if (typeDiffWeight < minTypeDiffWeight) {factoryMethodToUse = candidate;argsHolderToUse = argsHolder;argsToUse = argsHolder.arguments;minTypeDiffWeight = typeDiffWeight;ambiguousFactoryMethods = null;}// Find out about ambiguity: In case of the same type difference weight// for methods with the same number of parameters, collect such candidates// and eventually raise an ambiguity exception.// However, only perform that check in non-lenient constructor resolution mode,// and explicitly ignore overridden methods (with the same parameter signature).else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&!mbd.isLenientConstructorResolution() &&paramTypes.length == factoryMethodToUse.getParameterCount() &&!Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {if (ambiguousFactoryMethods == null) {ambiguousFactoryMethods = new LinkedHashSet<>();ambiguousFactoryMethods.add(factoryMethodToUse);}ambiguousFactoryMethods.add(candidate);}}}if (factoryMethodToUse == null) {if (causes != null) {UnsatisfiedDependencyException ex = causes.removeLast();for (Exception cause : causes) {this.beanFactory.onSuppressedException(cause);}throw ex;}List<String> argTypes = new ArrayList<>(minNrOfArgs);if (explicitArgs != null) {for (Object arg : explicitArgs) {argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");}}else if (resolvedValues != null) {Set<ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());valueHolders.addAll(resolvedValues.getGenericArgumentValues());for (ValueHolder value : valueHolders) {String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :(value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));argTypes.add(argType);}}String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);//抛出异常}else if (void.class == factoryMethodToUse.getReturnType()) {//抛出异常}else if (ambiguousFactoryMethods != null) {//抛出异常}if (explicitArgs == null && argsHolderToUse != null) {mbd.factoryMethodToIntrospect = factoryMethodToUse;argsHolderToUse.storeCache(mbd, factoryMethodToUse);}}Assert.state(argsToUse != null, "Unresolved factory method arguments");//实例化bd 设置到BeanWrapper中bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));return bw;}

至此经过createBeanInstance方法 就为我们创建了一个实例对象,但是现在这个对象属性还未被赋值。

实例化后阶段

实例对象创建之后,就来到了对象属性赋值过程了,我们大致看一下populateBean方法,观察下InstantiationAwareBeanPostProcessor对属性赋值过程的影响

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {//省略无关代码boolean continueWithPropertyPopulation = true;//条件一 synthetic默认值是false 一般都会成立//条件二 成立的话 说明存在InstantiationAwareBeanPostProcessorif (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;//在BeanPostProcessor浅析中分析到此方法时说过,若Bean实例化后回调不返回true 则对属性赋值过程产生影响。以下代码就是说明if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {continueWithPropertyPopulation = false;break;}}}}//ibp.postProcessAfterInstantiation=false时 属性赋值过程终止if (!continueWithPropertyPopulation) {return;}

以上就是本章讨论的主要内容了,如您在阅读过程中发现有错误,还望指出,感谢!

Spring Bean生命周期: Bean的实例化相关推荐

  1. Spring Bean生命周期:Bean的初始化阶段

    [Spring Bean 生命周期系列]传送门 1.Spring Bean生命周期: Bean元信息的配置与解析阶段 2.Spring Bean生命周期: Bean的注册 3.Spring Bean生 ...

  2. 去字节面试,直接让人出门左拐:Bean 生命周期都不知道!

    Spring Bean 的生命周期,面试时非常容易问,这不,前段时间就有个粉丝去字节面试,因为不会回答这个问题,一面都没有过. 如果只讲基础知识,感觉和网上大多数文章没有区别,但是我又想写得稍微深入一 ...

  3. Bean 生命周期详解

    Spring Bean 的生命周期,面试时非常容易问,这不,前段时间就有个粉丝去字节面试,因为不会回答这个问题,一面都没有过. 如果只讲基础知识,感觉和网上大多数文章没有区别,但是我又想写得稍微深入一 ...

  4. springboot学习:bean生命周期

    1.bean 生命周期 bean创建-初始化-销毁 构造(对象创建): 单实例:在容器启动的时候创建对象; 多实例:在每次获取的时候创建对象: 初始化: 对象创建完成,并赋值好,调用初始化方法 销毁: ...

  5. 【Spring】- Bean生命周期

    2019独角兽企业重金招聘Python工程师标准>>> Spring Bean的生命周期: bean对象实例化 属性注入 beanfactory ApplicationContext ...

  6. Spring5源码 - 07 Spring Bean 生命周期流程 源码解读02

    文章目录 Pre 通俗流程 finishBeanFactoryInitialization Pre Spring5源码 - 06 Spring Bean 生命周期流程 概述 01 接上文 通俗流程 下 ...

  7. Spring5源码 - 06 Spring Bean 生命周期流程 概述 01

    文章目录 Bean生命周期概述 Demo finishBeanFactoryInitialization(beanFactory) 核心流程 Bean生命周期概述 说到Spring Bean的生命周期 ...

  8. 《Spring揭秘》——IOC梳理2(容器启动,bean生命周期)

    IoC容器背后的秘密 主要分为两个阶段:容器启动阶段.Bean实例化阶段. 容器启动阶段: 容器需要依赖某些工具类(BeanDefinitionReader)对加载的Configuration Met ...

  9. Spring Bean默认配置为单实例 Spring Bean生命周期

    2019独角兽企业重金招聘Python工程师标准>>> Spring 的Bean默认的是单例的. 如果不想单例需要如下配置: <bean id="user" ...

最新文章

  1. 【python教程入门学习】利用Python绘制关系网络图
  2. Middleware Monitor Cockpit SMWP
  3. esmini LongSpeedAction修改
  4. JavaScript 刷新当前页面
  5. HtmlAgilityPack/xpath
  6. ggplot2中显示坐标轴_qplot()——ggplot2的快速绘图
  7. Linux远程管理协议(RFB、RDP、Telnet和SSH)
  8. 《嵌入式系统可靠性设计技术及案例解析》读书笔记(七)
  9. linux ipc 信号量,linux ipc信号量
  10. 0penCV_(Watershed Segmenter)使用 分水岭算法 对图像进行分割
  11. 海森堡量子力学与计算机,量子力学诞生后的120年,没有人真正懂他
  12. 我的编程之路点滴记录(四)
  13. FPGA中latch
  14. OSChina 周四乱弹 ——程序员要赚多少钱才能让妻子保持温柔和美丽
  15. 拼多多店铺logo怎么做?
  16. 《101 Windows Phone 7 Apps》读书笔记-BABY NAME ELIMINATOR
  17. 英国AI研究员揭开真相,中国人工智能为何能发展迅猛?
  18. PCL学习笔记1 —— PCL库简要说明
  19. 软考高项论文范文——论信息系统项目的采购管理
  20. [Depricated]适用coremail邮件系统,第三方客户端绑定校园邮箱(南邮、河海,以iOS邮件为例)

热门文章

  1. 亲民地理35期-雨中登泰山_我是亲民_新浪博客
  2. AUTOSAR——MBD应用之NM模块Stateflow实现
  3. 安装lux:推荐一款网页视频下载工具。并简单使用。(win)
  4. 阿里云 ECS 7 天实践训练营 - day01 -基于ECS搭建FTP服务
  5. c 语言除法运算,C 语言简单加减乘除运算
  6. android studio在夜神上打开_Android Studio之使用连接夜神模拟器分析Smail 【详文】8.7日更正...
  7. 360全景偏移调整_360全景拼接之调水平
  8. React基础-React中发送Ajax请求以及Mock数据
  9. spring cloud系列eureka
  10. 【SVN异常】svn: E175003: The server at ‘https://svn.example.com/!/%23MyRepo/‘ does not support the HTTP/