十四、Spring源码学习之createBean方法

AbstractAutowireCapableBeanFactory#createBean()方法

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {if (logger.isTraceEnabled()) {logger.trace("Creating instance of bean '" + beanName + "'");}//到这个方法创建Bean的时候beanDefinition的类型必须是RootBeanDefinition//RootBeanDefinition是顶级的父类BeanDefinition,是不允许再有父亲的BeanDefinition的//在调用这个方法之前,是会进行BeanDefinition的封装和合并的RootBeanDefinition mbdToUse = mbd;// Make sure bean class is actually resolved at this point, and// clone the bean definition in case of a dynamically resolved Class// which cannot be stored in the shared merged bean definition.//加载beanclass,将bean的class拿出来加载到jvm中Class<?> resolvedClass = resolveBeanClass(mbd, beanName);if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {//加载成功过后,然后创建一个对象RootBeanDefinition,这个RootBeanDefinition就是最终创建的单例对象放入到单例池mbdToUse = new RootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);}// Prepare method overrides.try {//检查是否有方法重载 避免args类型检查开销//lookup-mehtod标签 replace-method 标签mbdToUse.prepareMethodOverrides();}catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),beanName, "Validation of method overrides failed", ex);}try {// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.//上面的的英文是官方解释:给一个创建一个代理对象bean的机会在bean的后置处理器中//简单来说就是这里是提供给程序员实现的方法,比如你想代理一些bean,那么你就可以实现相关的后置处理器//比如aop,或者你想为一些bean添加一些职责,那么只要返回不为空,spring就不会为你创建bean了,会直接用你创建的bean//这个方法可以叫做bean的实例化前,可以简单这样理解Object bean = resolveBeforeInstantiation(beanName, mbdToUse);if (bean != null) {return bean;}}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,"BeanPostProcessor before instantiation of bean failed", ex);}try {//这个创建bean是spring容器自带的创建bean,也就是代码走到这里,则证明需要spring来创建bean了//一般在spring项目中,普通的bean一般都会在这里由spring来创建,而特殊的Bean可能在上面由resolveBeforeInstantiation//来直接创建了Object beanInstance = doCreateBean(beanName, mbdToUse, args);if (logger.isTraceEnabled()) {logger.trace("Finished creating instance of bean '" + beanName + "'");}return beanInstance;}catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {// A previously detected exception with proper bean creation context already,// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.throw ex;}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);}}

AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation()方法

/*** Apply before-instantiation post-processors, resolving whether there is a* before-instantiation shortcut for the specified bean.* @param beanName the name of the bean* @param mbd the bean definition for the bean* @return the shortcut-determined bean instance, or {@code null} if none* 这个方法其实就是调用bean的后置处理器,bean的后置处理器有点多,分为* 实例化前、实例化后、调用aware后、初始化前、初始化后* 而下面这个方法就是在bean的实例化之前调用的,而这个方法是返回一个对象* 所以如果说你这个方法调用完毕过后,返回的一个对象不为空,那么就说明你的bean已经存在了,已经有了* 那么就不会在调用你后面的调用aware就是不会再调用spring提供的创建Bean的方法了* 但是如果applyBeanPostProcessorsBeforeInstantiation返回的对象不为空,那么spring还猜想你可能还有* 实例化的一些操作,所以这里还要调用那个实例化后的bean后置处理器applyBeanPostProcessorsAfterInitialization* 按正常的逻辑,spring会通过实例化前、实例化后、调用aware后、初始化前、初始化后来调用后置处理器,但是下的这个方法* 是你人为的干预了spring的实例化和初始化,那么你既然实例化了,那么就自己去调用初始化后的一些后置处理器,* 请注意,这个方法也不会调用后面的aware方法了*/@Nullableprotected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {Object bean = null;if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {// Make sure bean class is actually resolved at this point.if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {Class<?> targetType = determineTargetType(beanName, mbd);if (targetType != null) {//是调用的bean的实例化的后置处理器bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);if (bean != null) {//如果返回的bean不为空,则证明spring不会去调用它自己的createBean方法了,因为你返回了对象//所以下面还要看你有没有自己的bean初始化后的逻辑,如果有就调用,所以卫生么这个方法有//bean的实例化前的方法和bean初始化后的方法//是调用的bean的初始化后置处理器bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);}}}mbd.beforeInstantiationResolved = (bean != null);}return bean;}

AbstractAutowireCapableBeanFactory#doCreateBean()方法

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {// Instantiate the bean.BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {//单例bean//从缓存中获取instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {//没有 则创建bean//bean的实例化,里面包含了推断构造方法,简单来说就是对bean进行实例化,这个方法后面来讲instanceWrapper = createBeanInstance(beanName, mbd, args);}Object bean = instanceWrapper.getWrappedInstance();Class<?> beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {mbd.resolvedTargetType = beanType;}// Allow post-processors to modify the merged bean definition.synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {try {//spring提供的又一个bean后置处理器,就是在bean实例化完成过后,可以进行调用//这个后置处理器可以传入指定的BeanDefinition,也就是你可以改变BeanDefinition的属性//但是这个时候bean都已经实例化完成了,就算你修改了beanclass也没有用了//但是有些属性我们还是可以设置的,比如可以手动设置初始化的方法mbd.setInitMethodName//@AutoWired注解的切入点就是在这个后置处理器中找到的并且注入到缓存中applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);}mbd.postProcessed = true;}}// Eagerly cache singletons to be able to resolve circular references// even when triggered by lifecycle interfaces like BeanFactoryAware.//当前bean 是否需要早期暴露boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {if (logger.isTraceEnabled()) {logger.trace("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}//和循环依赖有关,后面讲addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// Initialize the bean instance.Object exposedObject = bean;try {/*** 填充属性,处理@AutoWried,调用bean的实例化后的方法*/populateBean(beanName, mbd, instanceWrapper);/*** 这个方法是调用bean的初始化方法的*/exposedObject = initializeBean(beanName, exposedObject, mbd);}catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {throw (BeanCreationException) ex;}else {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);}}//下面是依赖注入的代码,这个后面说if (earlySingletonExposure) {Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {if (exposedObject == bean) {exposedObject = earlySingletonReference;}else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {String[] dependentBeans = getDependentBeans(beanName);Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);for (String dependentBean : dependentBeans) {if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);}}if (!actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName,"Bean with name '" + beanName + "' has been injected into other beans [" +StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +"] in its raw version as part of a circular reference, but has eventually been " +"wrapped. This means that said other beans do not use the final version of the " +"bean. This is often the result of over-eager type matching - consider using " +"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");}}}}// Register bean as disposable.try {registerDisposableBeanIfNecessary(beanName, bean, mbd);}catch (BeanDefinitionValidationException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);}return exposedObject;}

AbstractAutowireCapableBeanFactory#createBeanInstance()方法

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// Make sure bean class is actually resolved at this point.//解析bean 获取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());}//是否有bean的Supplier接口 如果有通过回调来创建beanSupplier<?> 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...// 标记下,防止重复创建同一个beanboolean resolved = false;// 是否需要自动装配boolean autowireNecessary = false;if (args == null) {//参数未空 则通过synchronized (mbd.constructorArgumentLock) {// 因为一个类可能由多个构造函数,所以需要根据配置文件中配置的参数或传入的参数来确定最终调用的构造函数。// 因为判断过程会比较,所以spring会将解析、确定好的构造函数缓存到BeanDefinition中的resolvedConstructorOrFactoryMethod字段中。// 在下次创建相同时直接从RootBeanDefinition中的属性resolvedConstructorOrFactoryMethod缓存的值获取,避免再次解析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?// 从bean后置处理器中为自动装配寻找构造方法, 有且仅有一个有参构造或者有且仅有@Autowired注解构造Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);// 以下情况符合其一即可进入// 1、存在可选构造方法// 2、自动装配模型为构造函数自动装配// 3、给BeanDefinition中设置了构造参数值// 4、有参与构造函数参数列表的参数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.// 使用默认无参构造函数创建对象,如果没有无参构造且存在多个有参构造且没有@AutoWired注解构造,会报错return instantiateBean(beanName, mbd);}

DefaultSingletonBeanRegistry#addSingletonFactory()方法

/*** Add the given singleton factory for building the specified singleton* if necessary.* <p>To be called for eager registration of singletons, e.g. to be able to* resolve circular references.* @param beanName the name of the bean* @param singletonFactory the factory for the singleton object*  将ObjectFactory 添加到三级缓存中*/protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(singletonFactory, "Singleton factory must not be null");synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {this.singletonFactories.put(beanName, singletonFactory);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}}

AbstractAutowireCapableBeanFactory#getEarlyBeanReference()方法

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);}}}return exposedObject;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/781052.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【unity】认识unity Hub的主要功能

这里我们主要讲解unity Hub中的【项目】和【安装】功能&#xff0c;其他对应的功能栏相信大家根据文字就可以知道相应的作用。 首先是介绍【项目】功能&#xff0c;在这里我们可以创建本地项目和云端项目&#xff0c;作为初学者我们创建本地项目皆可&#xff0c;当然如果你是多…

UE4_碰撞_使用蓝图控制物体移动时如何让被阻挡

当我们这样设置蓝图时&#xff1a; 运行效果&#xff1a; 利用蓝图更改一个物体的位置&#xff0c;发现本来两个应该相互阻挡的物体被穿过去了。为了不让相互阻挡的物体被穿过去&#xff0c;我们需要设置好蓝图节点的参数Sweep。 勾选之后 墙的蓝图我们这样设置&#xff1a; 运…

C#-ConcurrentDictionary用于多线程并发字典

ConcurrentDictionary 是 .NET Framework 中用于多线程并发操作的一种线程安全的字典集合类。它提供了一种在多个线程同时访问和修改字典时保持数据一致性的机制。 以下是 ConcurrentDictionary 类的一些重要特性和用法&#xff1a; 线程安全性&#xff1a;ConcurrentDictiona…

【软件工程】需求分析

1. 导言 1.1. 需求文档的目的 该文档是关于用户对于“学生成绩管理系统”的功能和性能的要求&#xff0c;重点描述了“学生成绩管理系统”的设计需求&#xff0c;将作为对该工具在概要设计阶段的设计输入。编写本文档的目的在于说明软件工程管理系统的业务需求内容&#xff0…

30-3 越权漏洞 - 水平越权(横向越权)

环境准备:构建完善的安全渗透测试环境:推荐工具、资源和下载链接_渗透测试靶机下载-CSDN博客 一、定义 攻击者可以访问和操作与其拥有同级权限的用户资源。 示例: 学生A在教务系统上正常只能修改自己的作业内容,但由于不合理的权限校验规则等原因,学生A可以修改学生B的内…

点云从入门到精通技术详解100篇-基于3D点云的盘类元件识别与定位

目录 前言 2 3D视觉机器人抓取系统方案设计 2.1 系统硬件方案选型 2.1.1 相机选取方案

记录C++中,vector的迭代器在push_back以后扩容导致迭代器失效的问题

前言 vector是我们用到最多的数据结构&#xff0c;其底层数据结构是单端动态数组&#xff0c;由于数组的特点&#xff0c;vector也具有以下特性&#xff1a; ①O(1)时间的快速访问&#xff1b; ②顺序存储&#xff0c;所以插入到非尾结点位置所需时间复杂度为O(n)&#xff0c;删…

动态规划--(递推2(最长上升子序列,格子染色,斐波那切数列,奇数塔问题,最长子段和))

1281&#xff1a;最长上升子序列 【题目描述】 一个数的序列bi &#xff0c;当b1<b2<…<bS 的时候&#xff0c;我们称这个序列是上升的。对于给定的一个序列(a1,a2,…,aN) &#xff0c;我们可以得到一些上升的子序列(ai1,ai2,…,aiK) &#xff0c;这里1≤i1<i2<…

uniapp开发微信小程序设置分包,简单易学

文章目录 前言一、在 manifest.json文件中的源码试图中配置二、配置pages.json 前言 我们使用uniapp开发微信小程序的时候&#xff0c;当我们的包体积过大的时候&#xff0c;无法真机模拟。 因为小程序单个包只支持2MB&#xff08;现已支持预览4MB&#xff09;&#xff0c;所以…

Docker 学习总结(81)—— 冷门而又实用的 Docker 使用技巧总结

1、docker top 这个命令是用来查看一个容器里面的进程信息的,比如你想查看一个 nginx 容器里面有几个 nginx 进程的时候,就可以这么做。 ➜ ~ docker top 3b307a09d20d UID PID PPID C STIME …

JAVA面试大全之开发基础篇

目录 1、常用类库 1.1、平时常用的开发工具库有哪些? 1.2、Java常用的JSON库有哪些?有啥注意点? 1.3、Lombok工具库用来解决什么问题?

AI:155-基于深度学习的股票价格预测模型

本文收录于专栏:精通AI实战千例专栏合集 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 每一个案例都附带关键代码,详细讲解供大家学习,希望可以帮到大家。正在不断更新中~ 一.基于深度学习的股票价格预测模型 …

基于k8s的web服务器构建

文章目录 k8s综合项目1、项目规划图2、项目描述3、项目环境4、前期准备4.1、环境准备4.2、ip划分4.3、静态配置ip地址4.4、修改主机名4.5、部署k8s集群4.5.1、关闭防火墙和selinux4.5.2、升级系统4.5.3、每台主机都配置hosts文件&#xff0c;相互之间通过主机名互相访问4.5.4、…

深入解析大数据Scala面试题及参考答案(持续更新)

Scala,作为一种多范式编程语言,因其强大的功能性和与Java的互操作性,在大数据和并发编程领域备受青睐。本文将深入探讨10个常见的Scala面试题,并提供详尽的参考答案,以期帮助读者在面试中展现其Scala编程的深厚功底。 目录 1. Scala的基本特性是什么? 2. 什么是函数式…

总结IP协议各类知识点

前言 本篇博客博主将详解IP协议中的各类知识点&#xff0c;坐好板凳发车啦~ 一.IP协议格式 1.1 4位版本号&#xff08;version&#xff09; 指定IP协议的版本&#xff0c;对于IPv4来说&#xff0c;就是4。 1.2 4位头部长度&#xff08;header length&#xff09; IP头部的…

HarmonyOS像素转换-如何使用像素单位设置组件的尺寸。

1 卡片介绍 基于像素单位&#xff0c;展示了像素单位的基本知识与像素转换API的使用。 2 标题 像素转换&#xff08;ArkTS&#xff09; 3 介绍 本篇Codelab介绍像素单位的基本知识与像素单位转换API的使用。通过像素转换案例&#xff0c;向开发者讲解了如何使用像素单位设…

【LeetCode热题100】【多维动态规划】最长公共子序列

我昨天面了天美L1的游戏客户端开发&#xff0c;面了我100分钟&#xff0c;问完实习、项目、计算机图形学和C后给了我两道算法题做&#xff0c;一道是最长公共子序列&#xff0c;一道是LRU缓存&#xff0c;我知道是经典的题目&#xff0c;但是我都没敲过&#xff0c;最长公共子序…

大数据-Hadoop---基础配置案例

VMware17创建新虚拟机&#xff1a; 1.静态设置与关闭防火墙 在终端命令行依次输入&#xff1a; 1&#xff09;cd /etc 2) ls 3) cd sysconfig/ 4) cd network-scripts/ 5) ls 6) vi ifcfg-nes33 在cmd命令栏输入&#xff1a;ncpa.cpl,是找网络适配器的命令 IPADDR&qu…

elementui el-input输入框类型为textarea时,将输入的数据保存换行和空格,并展示换行和空格

el-input输入框类型为textarea时&#xff0c;如果不做数据处理&#xff0c;是不会保存换行和空格的说输入了换行&#xff0c;但是保存数据后不会进行换行&#xff0c;需要保存输入的换行。 1、效果图 输入状态&#xff1a; 显示时&#xff1a; 2、实现代码 2.1、html部分&am…

在jupyter notebook中使用conda环境

在jupyter notebook中使用conda环境 1. 环境配置 conda activate my-conda-env # this is the environment for your project and code conda install ipykernel conda deactivateconda activate base # could be also some other environment conda install nb_cond…