Spring源码分析(三) bean的生命周期 getBean()和doGetBean()

b、在中篇会正式经历一套生命周期流程

getBean() -> doGetBean() -> createBean() -> doCreateBean() -> createBeanInstance() -> populateBean() -> initializeBean() 流程

在这里插入图片描述

1、AbstractBeanFactory#getBean()

此处开始进行对象的获取也就是核心步骤

@Overridepublic Object getBean(String name) throws BeansException {// 此方法是实际获取bean的方法,也是触发依赖注入的方法return doGetBean(name, null, null, false);}

2、AbstractBeanFactory#doGetBean()

protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)throws BeansException {/*** 提取对应的beanName,有人可能会认为此处直接使用即可,为什么还要进行转换呢,原因在于当bean对象实现FactoryBean接口之后就会变成&beanName,同时如果存在别名,也需要把别名进行转换*/String beanName = transformedBeanName(name);Object bean;// Eagerly check singleton cache for manually registered singletons./**提前检查单例缓存中是否有手动注册的单例对象,跟循环依赖有关联*/Object sharedInstance = getSingleton(beanName);// 如果bean的单例对象找到了,且没有创建bean实例时要使用的参数if (sharedInstance != null && args == null) {if (logger.isTraceEnabled()) {if (isSingletonCurrentlyInCreation(beanName)) {logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +"' that is not fully initialized yet - a consequence of a circular reference");}else {logger.trace("Returning cached instance of singleton bean '" + beanName + "'");}}// 返回对象的实例,这句话的重点在于当你实现了FactoryBean接口的对象,需要获取具体的对象的时候就需要此方法来进行获取了bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}else {// Fail if we're already creating this bean instance:// We're assumably within a circular reference.// 当对象都是单例的时候会尝试解决循环依赖的问题,但是原型模式下如果存在循环依赖的情况,那么直接抛出异常if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// Check if bean definition exists in this factory.// 如果bean定义不存在,就检查父工厂是否有BeanFactory parentBeanFactory = getParentBeanFactory();// 如果beanDefinitionMap中也就是在所有已经加载的类中不包含beanName,那么就尝试从父容器中获取if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {// Not found -> check parent.// 获取name对应的规范名称【全类名】,如果name前面有'&',则会返回'&'+规范名称【全类名】String nameToLookup = originalBeanName(name);// 如果父工厂是AbstractBeanFactory的实例if (parentBeanFactory instanceof AbstractBeanFactory) {// 调用父工厂的doGetBean方法,就是该方法。【递归】return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);}else if (args != null) {// Delegation to parent with explicit args.// 如果有创建bean实例时要使用的参数// Delegation to parent with explicit args. 使用显示参数委派给父工厂// 使用父工厂获取该bean对象,通bean全类名和创建bean实例时要使用的参数return (T) parentBeanFactory.getBean(nameToLookup, args);}else if (requiredType != null) {// No args -> delegate to standard getBean method.// 没有创建bean实例时要使用的参数 -> 委托给标准的getBean方法。// 使用父工厂获取该bean对象,通bean全类名和所需的bean类型return parentBeanFactory.getBean(nameToLookup, requiredType);}else {// 使用父工厂获取bean,通过bean全类名return (T) parentBeanFactory.getBean(nameToLookup);}}// 如果不是做类型检查,那么表示要创建bean,此处在集合中做一个记录if (!typeCheckOnly) {// 为beanName标记为已经创建(或将要创建)markBeanAsCreated(beanName);}try {// 此处做了BeanDefinition对象的转换,当我们从xml文件中加载beandefinition对象的时候,封装的对象是GenericBeanDefinition,// 此处要做类型转换,如果是子类bean的话,会合并父类的相关属性RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);// 检查mbd的合法性,不合格会引发验证异常checkMergedBeanDefinition(mbd, beanName, args);// Guarantee initialization of beans that the current bean depends on.// 如果存在依赖的bean的话,那么则优先实例化依赖的beanString[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {// 如果存在依赖,则需要递归实例化依赖的beanfor (String dep : dependsOn) {// 如果beanName已注册依赖于dependentBeanName的关系if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}// 注册各个bean的依赖关系,方便进行销毁registerDependentBean(dep, beanName);try {// 递归优先实例化被依赖的BeangetBean(dep);}// 捕捉为找到BeanDefinition异常:'beanName'依赖于缺少的bean'dep'catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex);}}}// Create bean instance.// 创建bean的实例对象if (mbd.isSingleton()) {// 返回以beanName的(原始)单例对象,如果尚未注册,则使用singletonFactory创建并注册一个对象:sharedInstance = getSingleton(beanName, () -> {try {// 为给定的合并后BeanDefinition(和参数)创建一个bean实例return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.// 显示地从单例缓存中删除实例:它可能是由创建过程急切地放在那里,以允许循环引用解析。还要删除// 接收到该Bean临时引用的任何Bean// 销毁给定的bean。如果找到相应的一次性Bean实例,则委托给destoryBeandestroySingleton(beanName);// 重新抛出exthrow ex;}});// 从beanInstance中获取公开的Bean对象,主要处理beanInstance是FactoryBean对象的情况,如果不是// FactoryBean会直接返回beanInstance实例bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}// 原型模式的bean对象创建else if (mbd.isPrototype()) {// It's a prototype -> create a new instance.// 它是一个原型 -> 创建一个新实例// 定义prototype实例Object prototypeInstance = null;try {// 创建Prototype对象前的准备工作,默认实现将beanName添加到prototypesCurrentlyInCreation中beforePrototypeCreation(beanName);// 为mbd(和参数)创建一个bean实例prototypeInstance = createBean(beanName, mbd, args);}finally {// 创建完prototype实例后的回调,默认是将beanName从prototypesCurrentlyInCreation移除afterPrototypeCreation(beanName);}// 从beanInstance中获取公开的Bean对象,主要处理beanInstance是FactoryBean对象的情况,如果不是// FactoryBean会直接返回beanInstance实例bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}else {// 指定的scope上实例化beanString scopeName = mbd.getScope();if (!StringUtils.hasLength(scopeName)) {throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");}// 从scopes中获取scopeName对于的Scope对象Scope scope = this.scopes.get(scopeName);// 如果scope为nullif (scope == null) {// 抛出非法状态异常:没有名为'scopeName'的scope注册throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");}try {// 从scope中获取beanName对应的实例对象Object scopedInstance = scope.get(beanName, () -> {// 创建Prototype对象前的准备工作,默认实现 将beanName添加到prototypesCurrentlyInCreation中beforePrototypeCreation(beanName);try {// 为mbd(和参数)创建一个bean实例return createBean(beanName, mbd, args);}finally {// 创建完prototype实例后的回调,默认是将beanName从prototypesCurrentlyInCreation移除afterPrototypeCreation(beanName);}});// 从beanInstance中获取公开的Bean对象,主要处理beanInstance是FactoryBean对象的情况,如果不是// FactoryBean会直接返回beanInstance实例bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);}catch (IllegalStateException ex) {// 捕捉非法状态异常// 抛出Bean创建异常:作用域 'scopeName' 对于当前线程是不活动的;如果您打算从单个实例引用它,请考虑为此// beanDefinition一个作用域代理throw new BeanCreationException(beanName,"Scope '" + scopeName + "' is not active for the current thread; consider " +"defining a scoped proxy for this bean if you intend to refer to it from a singleton",ex);}}}catch (BeansException ex) {// 捕捉获取Bean对象抛出的Bean异常// 在Bean创建失败后,对缓存的元数据执行适当的清理cleanupAfterBeanCreationFailure(beanName);// 重新抛出exthrow ex;}}// Check if required type matches the type of the actual bean instance.// 检查requiredType是否与实际Bean实例的类型匹配// 如果requiredType不为null&&bean不是requiredType的实例if (requiredType != null && !requiredType.isInstance(bean)) {try {// 获取此BeanFactory使用的类型转换器,将bean转换为requiredTypeT convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);// 如果convertedBean为nullif (convertedBean == null) {// 抛出Bean不是必要类型的异常throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}// 返回convertedBeanreturn convertedBean;}catch (TypeMismatchException ex) {if (logger.isTraceEnabled()) {logger.trace("Failed to convert bean '" + name + "' to required type '" +ClassUtils.getQualifiedName(requiredType) + "'", ex);}throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}}// 将bean返回出去return (T) bean;}

3、 DefaultSingletonBeanRegistry#getSingleton()

/**
* 返回以给定名称注册的(原始)单例对象,如果尚未注册,则创建并注册一个对象
*/
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {// 如果beanName为null,抛出异常Assert.notNull(beanName, "Bean name must not be null");// 使用单例对象的高速缓存Map作为锁,保证线程同步synchronized (this.singletonObjects) {// 从单例对象的高速缓存Map中获取beanName对应的单例对象Object singletonObject = this.singletonObjects.get(beanName);// 如果单例对象获取不到if (singletonObject == null) {// 如果当前在destorySingletons中if (this.singletonsCurrentlyInDestruction) {throw new BeanCreationNotAllowedException(beanName,"Singleton bean creation not allowed while singletons of this factory are in destruction " +"(Do not request a bean from a BeanFactory in a destroy method implementation!)");}// 如果当前日志级别时调试if (logger.isDebugEnabled()) {logger.debug("Creating shared instance of singleton bean '" + beanName + "'");}// 创建单例之前的回调,默认实现将单例注册为当前正在创建中beforeSingletonCreation(beanName);// 表示生成了新的单例对象的标记,默认为false,表示没有生成新的单例对象boolean newSingleton = false;// 有抑制异常记录标记,没有时为true,否则为falseboolean recordSuppressedExceptions = (this.suppressedExceptions == null);// 如果没有抑制异常记录if (recordSuppressedExceptions) {// 对抑制的异常列表进行实例化(LinkedHashSet)this.suppressedExceptions = new LinkedHashSet<>();}try {// 从单例工厂中获取对象singletonObject = singletonFactory.getObject();// 生成了新的单例对象的标记为true,表示生成了新的单例对象newSingleton = true;}catch (IllegalStateException ex) {// Has the singleton object implicitly appeared in the meantime ->// if yes, proceed with it since the exception indicates that state.// 同时,单例对象是否隐式出现 -> 如果是,请继续操作,因为异常表明该状态// 尝试从单例对象的高速缓存Map中获取beanName的单例对象singletonObject = this.singletonObjects.get(beanName);// 如果获取失败,抛出异常if (singletonObject == null) {throw ex;}}// 捕捉Bean创建异常catch (BeanCreationException ex) {// 如果没有抑制异常记录if (recordSuppressedExceptions) {// 遍历抑制的异常列表for (Exception suppressedException : this.suppressedExceptions) {// 将抑制的异常对象添加到 bean创建异常 中,这样做的,就是相当于 '因XXX异常导致了Bean创建异常‘ 的说法ex.addRelatedCause(suppressedException);}}// 抛出异常throw ex;}finally {// 如果没有抑制异常记录if (recordSuppressedExceptions) {// 将抑制的异常列表置为null,因为suppressedExceptions是对应单个bean的异常记录,置为null// 可防止异常信息的混乱this.suppressedExceptions = null;}// 创建单例后的回调,默认实现将单例标记为不在创建中afterSingletonCreation(beanName);}// 生成了新的单例对象if (newSingleton) {// 将beanName和singletonObject的映射关系添加到该工厂的单例缓存中:addSingleton(beanName, singletonObject);}}// 返回该单例对象return singletonObject;}}

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

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

相关文章

shell脚本学习笔记02(小滴课堂)

可以在home目录下创建一个shell.sh文件。 按w进入命令行模式。按i进入插入模式。如果想返回命令行模式&#xff0c;按esc即可。然后可以使用x和dd进行删除内容。 在插入模式下我们点击esc键&#xff0c;再去按:键&#xff0c;我们就可以进入到底行模式了&#xff1a; 可以设…

PHP实现微信小程序状态检测(违规、暂停服务、维护中、正在修复)

实现原理 进入那些状态不正常的小程序会被重定向至一个Url&#xff0c;使用抓包软件抓取这个Url&#xff0c;剔除不必要参数&#xff0c;使用cURl函数请求网页获得HTML内容&#xff0c;根据内容解析出当前APPID的小程序的状态。 代码 <?php// 编码header(Content-type:ap…

数据库被攻击需要注意什么

没想到自己用了一个简单的腾讯虚拟机&#xff0c;里面自己安装了一个 MySQL 数据库也会被黑客攻击。 一、问题现象 小程序访问不了&#xff0c;后台程序报数据库相关的错误。 查看数据库&#xff0c;发现数据库被篡改。 二、问题原因 1、为了可以远程能够访问数据库&#xf…

基于Qt4开发曲线绘制交互软件Plotter

目前市面上有很多曲线绘制软件,但其交互功能较差。比如,想要实现数据的交互,同步联动等,都需要大量繁琐的人工操作。所以讲想开发一款轻量级的曲线绘制交互软件。下面就以此为案例,记录一下基于Qt4的开发过程。 目录 1 需求 2 技术路线 3 开发流程 1 框架搭建 2 菜单…

首家!亚信科技AntDB数据库完成中国信通院数据库迁移工具专项测试

近日&#xff0c;在中国信通院“可信数据库”数据库迁移工具专项测试中&#xff0c;湖南亚信安慧科技有限公司&#xff08;简称&#xff1a;亚信安慧科技&#xff09;数据库数据同步平台V2.1产品依据《数据库迁移工具能力要求》、结合亚信科技AntDB分布式关系型数据库产品&…

[每周一更]-(第61期):Rust入门策略(持续更新)

一门语言的学习&#xff0c;就要从最基本的语法开始认识&#xff0c;再分析不同语言的区别&#xff0c;再加上实战&#xff0c;才能更快的学会&#xff0c;领悟到作者的设计思想&#xff1b; 介绍 Rust编程练习 开发工具VSCode及插件 社区驱动的 rust-analyzerEven Better T…

Java基于SpringBoot的闲一品交易平台

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W,Csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 大家好&#xff0c;我是程序员徐师兄、今天给大家谈谈基于android的app开发毕设题目&#xff0c;以及基于an…

slickEdit 2022 (v27.0.2)Ubuntu安装以及破解

1去官网下载安装包 SlickEdit 也可以从我这里下载源码包 https://download.csdn.net/download/m0_38012470/88343180 2.解压压缩包并进入根目录 3.sudo ./vsinst 4按住回车不松手一直到显示需要你输入yes的时候 5.一路通过需要输入Y的时候就输入 6.一直到弹出对话框关闭…

Linux的常见指令

目录 pwd命令ls 指令mkdir指令touch指令cd 指令rmdir指令 && rm 指令man指令nanocp指令mv指令cat指令more指令less指令head指令tail指令grep指令热键zip/unzip指令tar指令uname –r指令输出重定向 图形化界面和命令行操作本质都是对操作系统进行直接或间接的操作 pwd命…

在微信公众号怎么实现每日签到功能

在微信公众号中实现每日签到功能&#xff0c;可以为企业或公众号运营者带来许多好处。每日签到功能不仅可以增加用户粘性&#xff0c;提高用户参与度&#xff0c;还可以为公众号带来更多的流量和曝光度。那么&#xff0c;如何在微信公众号中实现每日签到功能呢&#xff1f;本文…

vue3中css使用script中定义的变量

代码 <template><div class"box">haha</div> </template><script setup lang"ts"> const boxWidth 500px </script><style lang"scss"> .box {width: v-bind(boxWidth);height: 200px;background-c…

易优cms小程序插件升级到2.1版本

eyou小程序升级到2.1&#xff0c;主要新增一键获取手机号&#xff0c;统一返回格式等 升级内容&#xff1a; &#xff08;1&#xff09;对全部接口的返回格式做统一化设置 &#xff08;2&#xff09;新增一键获取手机号功能 &#xff08;3&#xff09;新增footprint足迹接口 &…

百度测开初面面试题分享(答案+文档)

1、java常用的异常处理机制 Java常用的异常处理机制有以下几种&#xff1a; 1&#xff09;try-catch-finally语句&#xff1a;用于捕获和处理异常。将可能抛出异常的代码放在try块中&#xff0c;然后在catch块中处理异常。无论是否发生异常&#xff0c;finally块中的代码都会…

长胜证券:怎么跟随主力进出?

跟着现在商场的快速改变和信息的普及化&#xff0c;人们在出资时越来越需求愈加精确的辅导和剖析。尤其是在股票商场&#xff0c;很多人想知道怎么跟从主力进出以获取更高的收益。在这篇文章中&#xff0c;咱们将从多个视点来评论这个论题。 一、了解主力资金的进出方向 首先&…

无涯教程-JavaScript - ISODD函数

描述 如果数字为奇数,则ISODD函数返回TRUE,如果数字为偶数,则返回FALSE。 语法 ISODD (number) 争论 Argument描述Required/OptionalNumber 要测试的值或表达式。 如果number不是整数,则将其截断。 Required Notes 您可以在执行计算之前使用此功能测试单元格的内容。 如果…

BUG:阿里巴巴图标库引入链接后,icon有时候会不显示的话svg下载到本地使用

忽然icon图标就不显示&#xff0c;但是代码、icon链接地址都没有发生变化 解决办法&#xff1a;将icon图标下载到本地&#xff0c;记住前后引用本地的名字要保持一致

软件设计师学习笔记9-进程调度

目录 1. PV操作 1.1进程的同步与互斥 1.1.1互斥 1.1.2同步 1.2 PV操作 1.2.1信号量 1.2.2 PV操作的概念 2.信号量与PV操作 2.1 PV操作与互斥模型 2.2 PV操作与同步模型 2.3 互斥与同步模型结合 3.前趋图与PV操作 1. PV操作 1.1进程的同步与互斥 1.1.1互斥 互斥&…

Apache HTTPD 漏洞复现

文章目录 Apache HTTPD 漏洞复现1. Apache HTTPD 多后缀解析漏洞1.1 漏洞描述1.2 漏洞复现1.3 漏洞利用1.4 获取GetShell1.5 漏洞防御 2. Apache HTTPD 换行解析漏洞-CVE-2017-157152.1 漏洞描述2.2 漏洞复现2.3 漏洞利用2.4 修复建议 3. Apache HTTP Server_2.4.49 路径遍历和…

无涯教程-JavaScript - ISREF函数

描述 如果指定的值是参考,则ISREF函数返回逻辑值TRUE。否则返回FALSE。 语法 ISREF (value) 争论 Argument描述Required/OptionalvalueA reference to a cell.Required Notes 您可以在执行任何操作之前使用此功能测试单元格的内容。 适用性 Excel 2007,Excel 2010,Exce…

【LeetCode】210. 课程表 II——拓扑排序

题目链接&#xff1a;210. 课程表 II 题目描述&#xff1a; 现在你总共有 numCourses 门课需要选&#xff0c;记为 0 到 numCourses - 1。给你一个数组 prerequisites &#xff0c;其中 prerequisites[i] [ai, bi] &#xff0c;表示在选修课程 ai 前 必须 先选修 bi 。 例如…