热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SpringIoc源码(十八)BeanFactory(七)getBean(doCreateBeancreateBeanInstance实例创建)

目录1、Supplier方式创建对象2、工厂方法创建对象3、有参构造创建对象4、无参构造创建对象当创建Bean时,肯定是先通过反射创建该对象。只是Spring除了直接

目录

 1、Supplier方式创建对象

 2、工厂方法创建对象

 3、有参构造创建对象

 4、无参构造创建对象


    当创建Bean时,肯定是先通过反射创建该对象。只是Spring除了直接用反射实例化对象外还允许传入Supplier、或者设置factory-mtehod等方式。不论哪种方式初始化完成对象的创建后,会将该对象使用装饰器模式设置一些容器属性(丰富该对象)然后进行返回BeanWrapperImpl类型。

    1、先检查beanClass类型;

    2、如果存在Supplier类型的instanceSupplier存在,则调用其get方法初始化实例。

    3、然后判断是否存在FactoryMethodName,是则调用instantiateUsingFactoryMethod获取(过程很复杂先不分析了)

    4、如果有设置resolvedConstructorOrFactoryMethod属性则可能直接就能决定初始化的有参或者无参构造;否则就会遍历所有的SmartInstantiationAwareBeanPostProcessor,也可以指定构造器。比如只有一个有参数构造函数时则通过AutowiredAnnotationBeanPostProcessor将在这里返回构造器。如下:

@Component
public class AaaComponent {BbbComponent bbbComponent;public AaaComponent(BbbComponent bbbComponent) {this.bbbComponent = bbbComponent;}
}

    5、通过参数确定构造函数进行初始化调用autowireConstructor方法

    6、如果不存在工厂方法,也不存在参数构造,则调用默认无参构造函数初始化(instantiateBean方法)

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// Make sure bean class is actually resolved at this point.Class 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 instanceSupplier = mbd.getInstanceSupplier();if (instanceSupplier != null) {return obtainFromSupplier(instanceSupplier, beanName);}if (mbd.getFactoryMethodName() != null) {return instantiateUsingFactoryMethod(beanName, mbd, args);}// Shortcut when re-creating the same bean...boolean resolved = false;boolean autowireNecessary = false;if (args == null) {synchronized (mbd.constructorArgumentLock) {if (mbd.resolvedConstructorOrFactoryMethod != null) {resolved = true;autowireNecessary = mbd.constructorArgumentsResolved;}}}if (resolved) {if (autowireNecessary) {return autowireConstructor(beanName, mbd, null, null);}else {return instantiateBean(beanName, mbd);}}// Candidate constructors for autowiring?Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {return autowireConstructor(beanName, mbd, ctors, args);}// Preferred constructors for default construction?ctors = mbd.getPreferredConstructors();if (ctors != null) {return autowireConstructor(beanName, mbd, ctors, null);}// No special handling: simply use no-arg constructor.return instantiateBean(beanName, mbd);
}

 1、Supplier方式创建对象

protected BeanWrapper obtainFromSupplier(Supplier instanceSupplier, String beanName) {Object instance;String outerBean = this.currentlyCreatedBean.get();this.currentlyCreatedBean.set(beanName);// 省略try catchinstance = instanceSupplier.get();if (instance == null) {instance = new NullBean();}BeanWrapper bw = new BeanWrapperImpl(instance);initBeanWrapper(bw);return bw;
}

     如果BeanDefinition发现设置了instanceSupplier属性,则调用其get方法获取到的就认为是实例对象。

但是需要将其进行包装成BeanWrapperImpl返回。所以不论使用哪种方式创建对象都会调用initBeanWrapper方法。将容器级别的ConversionService和PropertyEditor列表,都设置给所以的Bean。即这两个类型的配置即使容器级别的,也是每个Bean都拥有的。

protected void initBeanWrapper(BeanWrapper bw) {bw.setConversionService(getConversionService());registerCustomEditors(bw);
}

 2、工厂方法创建对象

    如果在标签中设置了factory-bean属性,或者在BeanDefinition中设置了factoryMethodName属性。那么可以直接从该指定方法中获取对象。

protected BeanWrapper instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}

    instantiateUsingFactoryMethod方法太长,过程大致如下:

1、处理initBeanWrapper(如上)

2、根据factoryBeanName名称字符串,调用getBean(factoryBeanName)返回对象

3、根据对象的可用的方法,已经传入的参数等,排除其他最终决定调用方法和参数

4、调用下面的策略(CglibSubclassingInstantiationStrategy)方法实例化对象

beanFactory.getInstantiationStrategy().instantiate(mbd, beanName, this.beanFactory, factoryBean, factoryMethod, args)

核心代码为:

Object result = factoryMethod.invoke(factoryBean, args)

 3、有参构造创建对象

protected BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd, @Nullable Constructor[] ctors, @Nullable Object[] explicitArgs) {return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}

     创建过程大致与上面的相同,最终都会调用CglibSubclassingInstantiationStrategy的instantiate方法。

 4、无参构造创建对象

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {Object beanInstance;// 省略try catch代码final BeanFactory parent = this;beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);BeanWrapper bw = new BeanWrapperImpl(beanInstance);initBeanWrapper(bw);return bw;
}

    无参构造的过程,上面的方法都会经历。

 


推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文讨论了在Spring 3.1中,数据源未能自动连接到@Configuration类的错误原因,并提供了解决方法。作者发现了错误的原因,并在代码中手动定义了PersistenceAnnotationBeanPostProcessor。作者删除了该定义后,问题得到解决。此外,作者还指出了默认的PersistenceAnnotationBeanPostProcessor的注册方式,并提供了自定义该bean定义的方法。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • springmvc学习笔记(十):控制器业务方法中通过注解实现封装Javabean接收表单提交的数据
    本文介绍了在springmvc学习笔记系列的第十篇中,控制器的业务方法中如何通过注解实现封装Javabean来接收表单提交的数据。同时还讨论了当有多个注册表单且字段完全相同时,如何将其交给同一个控制器处理。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 浏览器中的异常检测算法及其在深度学习中的应用
    本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。 ... [详细]
  • Spring学习(4):Spring管理对象之间的关联关系
    本文是关于Spring学习的第四篇文章,讲述了Spring框架中管理对象之间的关联关系。文章介绍了MessageService类和MessagePrinter类的实现,并解释了它们之间的关联关系。通过学习本文,读者可以了解Spring框架中对象之间的关联关系的概念和实现方式。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 判断数组是否全为0_连续子数组的最大和的解题思路及代码方法一_动态规划
    本文介绍了判断数组是否全为0以及求解连续子数组的最大和的解题思路及代码方法一,即动态规划。通过动态规划的方法,可以找出连续子数组的最大和,具体思路是尽量选择正数的部分,遇到负数则不选择进去,遇到正数则保留并继续考察。本文给出了状态定义和状态转移方程,并提供了具体的代码实现。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
author-avatar
浅浅的思恋的小媳妇
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有