4、Spring之Bean生命周期~获取Bean

4、Spring之Bean生命周期~获取Bean

  • 获取Bean
    • transformedBeanName()方法
      • BeanFactoryUtils的transformedBeanName方法
      • canonicalName()方法
    • getObjectForBeanInstance()方法
      • getObjectFromFactoryBean()方法

获取Bean

  Spring Bean的生命周期首先会经过扫描,然后回经过合并,合并之后就会通过getBean()方法去获取bean,getBean()方法大致逻辑,先根据判断是单例bean还是原型bean,原型bean直接创建,单例bean会判断单例池中有没有,没有的话再去创建。废话不多说,直接上代码:

/*** Return an instance, which may be shared or independent, of the specified bean.** @param name          the name of the bean to retrieve* @param requiredType  the required type of the bean to retrieve* @param args          arguments to use when creating a bean instance using explicit arguments*                      (only applied when creating a new instance as opposed to retrieving an existing one)* @param typeCheckOnly whether the instance is obtained for a type check,*                      not for actual use* @return an instance of the bean* @throws BeansException if the bean could not be created*/
@SuppressWarnings("unchecked")
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)throws BeansException {// name有可能是 &xxx 或者 xxx,如果name是&xxx,那么beanName就是xxx// name有可能传入进来的是别名,那么beanName就是id// 拿到真正的beanNameString 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()) {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 + "'");}}// 如果sharedInstance是FactoryBean,那么就调用getObject()返回对象beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);} else {// Fail if we're already creating this bean instance:// We're assumably within a circular reference.// 判断是否是正在创建的原型bean  这里用到啦ThreadLocalif (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// Check if bean definition exists in this factory.BeanFactory parentBeanFactory = getParentBeanFactory();// 如果 父BeanFactory有值   且 BeanDefinition不存在if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {// Not found -> check parent.// &&&&xxx---->&xxxString nameToLookup = originalBeanName(name);if (parentBeanFactory instanceof AbstractBeanFactory) {return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);} else if (args != null) {// Delegation to parent with explicit args.return (T) parentBeanFactory.getBean(nameToLookup, args);} else if (requiredType != null) {// No args -> delegate to standard getBean method.return parentBeanFactory.getBean(nameToLookup, requiredType);} else {return (T) parentBeanFactory.getBean(nameToLookup);}}if (!typeCheckOnly) {markBeanAsCreated(beanName);}StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate").tag("beanName", name);try {if (requiredType != null) {beanCreation.tag("beanType", requiredType::toString);}// 根据 beanName 获取到合并之后的BeanDefinitionRootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);// 检查BeanDefinition是不是Abstract的checkMergedBeanDefinition(mbd, beanName, args);// Guarantee initialization of beans that the current bean depends on.String[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {// dependsOn表示当前beanName所依赖的,当前Bean创建之前dependsOn所依赖的Bean必须已经创建好了for (String dep : dependsOn) {// beanName是不是被dep依赖了,如果是则出现了循环依赖if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}// dep被beanName依赖了,存入dependentBeanMap中,dep为key,beanName为valueregisterDependentBean(dep, beanName);// 创建所依赖的beantry {getBean(dep);} catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex);}}}// Create bean instance.if (mbd.isSingleton()) {// 单例bean创建逻辑sharedInstance = getSingleton(beanName, () -> {try {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.destroySingleton(beanName);throw ex;}});beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);} else if (mbd.isPrototype()) {// 原型bean创建逻辑// It's a prototype -> create a new instance.Object prototypeInstance = null;try {beforePrototypeCreation(beanName);prototypeInstance = createBean(beanName, mbd, args);} finally {afterPrototypeCreation(beanName);}beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);} else {// 其他作用域bean的创建逻辑String scopeName = mbd.getScope();if (!StringUtils.hasLength(scopeName)) {throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");}Scope scope = this.scopes.get(scopeName);if (scope == null) {throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");}try {  // session.getAttriute(beaName)  setAttriObject scopedInstance = scope.get(beanName, () -> {beforePrototypeCreation(beanName);try {return createBean(beanName, mbd, args);} finally {afterPrototypeCreation(beanName);}});beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);} catch (IllegalStateException ex) {throw new ScopeNotActiveException(beanName, scopeName, ex);}}} catch (BeansException ex) {beanCreation.tag("exception", ex.getClass().toString());beanCreation.tag("message", String.valueOf(ex.getMessage()));cleanupAfterBeanCreationFailure(beanName);throw ex;} finally {beanCreation.end();}}// 检查通过name所获得到的beanInstance的类型是否是requiredTypereturn adaptBeanInstance(name, beanInstance, requiredType);
}

通过doGetBean方法我们可以看到:

  1. 首先通过transformedBeanName()方法去获取真正的beanName,因为传进来BeanName可能是别名;
  2. 调用getSingleton()方法判断单例池中是否存在,此方法涉及到解决循环依赖问题,详情敬请期待
  3. 如果单例池中存在调用getObjectForBeanInstance()方法;
  4. 如果单例池中不存在;
  5. 判断是否是正在创建中的原型Bean,如果是会报错;
  6. 获取BeanFactory,这里是和启动相关,不展开赘述;
  7. 再往下可以看到,spring.beans.instantiate,Bean的实例化;
  8. 调用getMergedLocalBeanDefinition()方法拿到合并之后的BeanDefinition,getMergedLocalBeanDefinition()方法在《Spring之Bean生命周期~合并BeanDefinition》有详细介绍;
  9. 调用checkMergedBeanDefinition()方法,判断BeanDefinition是否是抽象的;抽象的BeanDefinition不能被实例化,会报错;
  10. 判断是否有@DependsOn注解,如果有@DependsOn注解,先创建@DependsOn注解引用的Bean对象,如果两个Bean对象相互通过@DependsOn注解依赖,会报错;
  11. 再往下我们可以看到,不管scope属性是单例bean、原型Bean还是其他,都会调用createBean()方法;
  12. 请移步到《Spring之Bean生命周期~创建Bean》,精彩不断哦。

transformedBeanName()方法

transformedBeanName()方法详解

/*** Return the bean name, stripping out the factory dereference prefix if necessary,* and resolving aliases to canonical names.** @param name the user-specified name* @return the transformed bean name*/
protected String transformedBeanName(String name) {return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}

通过transformedBeanName方法我们可以看到,在调用canonicalName()方法之前会先调用一下BeanFactoryUtils.transformedBeanName()方法去掉BeanName开头的&(FactoryBean的BeanName是以&开头),然后再调用canonicalName()方法去获取真正的BeanName

BeanFactoryUtils的transformedBeanName方法

BeanFactoryUtils的transformedBeanName方法详解

/*** Return the actual bean name, stripping out the factory dereference* prefix (if any, also stripping repeated factory prefixes if found).* @param name the name of the bean* @return the transformed name* @see BeanFactory#FACTORY_BEAN_PREFIX*/
public static String transformedBeanName(String name) {Assert.notNull(name, "'name' must not be null");// 判断是否是以&开头,不是直接返回if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {return name;}return transformedBeanNameCache.computeIfAbsent(name, beanName -> {do {// 截取掉 & beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());}while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));return beanName;});
}

这里我们可以看到如果BeanName是以&开头的话,会截取掉开头所有的&;
回到transformedBeanName()方法;

canonicalName()方法

canonicalName()方法详解

/*** Determine the raw name, resolving aliases to canonical names.* @param name the user-specified name* @return the transformed name*/
public String canonicalName(String name) {String canonicalName = name;// Handle aliasing...String resolvedName;do {resolvedName = this.aliasMap.get(canonicalName);if (resolvedName != null) {canonicalName = resolvedName;}}while (resolvedName != null);return canonicalName;
}

  通过canonicalName()方法我们可以看到,会不断地从aliasMap中回去,直到获取到的是null,说明是真正的BeanName;
  aliasMap的结构:<别名,真正的BeanName>
  回到doGetBean()方法

getObjectForBeanInstance()方法

getObjectForBeanInstance()方法详解

/*** Get the object for the given bean instance, either the bean* instance itself or its created object in case of a FactoryBean.** @param beanInstance the shared bean instance* @param name         the name that may include factory dereference prefix* @param beanName     the canonical bean name* @param mbd          the merged bean definition* @return the object to expose for the 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.// 如果&xxx,那么就直接返回单例池中的对象if (BeanFactoryUtils.isFactoryDereference(name)) {if (beanInstance instanceof NullBean) {return beanInstance;}if (!(beanInstance instanceof FactoryBean)) {throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());}if (mbd != null) {mbd.isFactoryBean = true;}return beanInstance;}// Now we have the bean instance, which may be a normal bean or a FactoryBean.// If it's a FactoryBean, we use it to create a bean instance, unless the// caller actually wants a reference to the factory.// 单例池中的对象不是FactoryBean,则直接返回if (!(beanInstance instanceof FactoryBean)) {return beanInstance;}/*** name中不包含&  且  bean对象实现啦FactoryBean接口* 说明要获取FactoryBean的getObject方法返回的对象* */Object object = null;if (mbd != null) {mbd.isFactoryBean = true;} else {// 从factoryBeanObjectCache中直接拿对象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);}// synthetic为true,表示这个Bean不是正常的一个Bean,可能只是起到辅助作用的,所以这种Bean就不用去执行PostProcessor了boolean synthetic = (mbd != null && mbd.isSynthetic());object = getObjectFromFactoryBean(factory, beanName, !synthetic);}return object;
}

通过getObjectForBeanInstance()方法我们可以看到

  1. 先判断调用getBean方法的传进来的name,是否是FactoryBean,如果name是&xxx,直接返回单例池中Bean对象,如果name是&xxx,但Bean对象不是FactoryBean的话会报错;
  2. 传进来的name不是&xxx,且不是FactoryBean说明就是普通Bean对象,直接返回单例池中的Bean对象;
  3. name不是以&开头且bean对象实现啦FactoryBean接口,说明要获取FactoryBean的getObject方法返回的对象;
  4. 首先判断factoryBeanObjectCache缓存中是否存在,存在直接返回;
  5. 如果还没合并BeanDefinition,先合并BeanDefinition;
  6. 然后调用getObjectFromFactoryBean()方法
  7. 回到doGetBean()方法;

getObjectFromFactoryBean()方法

getObjectFromFactoryBean()方法详解

/*** Obtain an object to expose from the given FactoryBean.** @param factory           the FactoryBean instance* @param beanName          the name of the bean* @param shouldPostProcess whether the bean is subject to post-processing* @return the object obtained from the FactoryBean* @throws BeanCreationException if FactoryBean object creation failed* @see org.springframework.beans.factory.FactoryBean#getObject()*/
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) {// 执行getObject()方法,返回的object不可能为null(会返回NullBean)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) {object = alreadyThere;} else {if (shouldPostProcess) {if (isSingletonCurrentlyInCreation(beanName)) {// Temporarily return non-post-processed object, not storing it yet..return object;}beforeSingletonCreation(beanName);try {// getObject()方法返回的对象进行后置处理object = postProcessObjectFromFactoryBean(object, beanName);} catch (Throwable ex) {throw new BeanCreationException(beanName,"Post-processing of FactoryBean's singleton object failed", ex);} finally {afterSingletonCreation(beanName);}}if (containsSingleton(beanName)) {this.factoryBeanObjectCache.put(beanName, object);}}}return object;}} else {Object object = doGetObjectFromFactoryBean(factory, beanName);if (shouldPostProcess) {try {object = postProcessObjectFromFactoryBean(object, beanName);} catch (Throwable ex) {throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);}}return object;}
}

线程相关知识,这里不在展开详细赘述,通过阅读getObjectFromFactoryBean()方法我们可以看到:

  1. 首先判断这个Bean是单例的,且单例池中存在BeanName(这里BeanName不包含&)对应的Bean对象;
  2. 判断factoryBeanObjectCache缓存中是否存在,存在直接返回;
  3. 调用doGetObjectFromFactoryBean()方法,doGetObjectFromFactoryBean()方法会通过反射调用对象的getObject()方法;
  4. 回到getObjectForBeanInstance()方法中;

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

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

相关文章

git本地配置及IDEA下Git合并部分文件

目录 1、IDEA 下 Git 合并部分文件 2、分支合并忽略特定文件步骤 3、git本地配置 1、IDEA 下 Git 合并部分文件 1.1Git 下存在两个分支&#xff0c;foo 和 bar 分支&#xff0c;想要把 bar 分支上的部分文件合并到 foo 分支: 首先切换到 foo 分支&#xff0c;点击右下角的 …

Java Web学习笔记31——Maven介绍

Maven&#xff1a;Java项目的构建工具。 Maven&#xff1a; Maven是Apache旗下的一个开源项目&#xff0c;是一款用于管理和构建Java项目的工具。 Apache软件基金会&#xff0c;成立于1999年7月&#xff0c;是目前世界上最大的最受欢迎的开源软件基金会&#xff0c;也是一个专…

Java | Leetcode Java题解之第132题分割回文串II

题目&#xff1a; 题解&#xff1a; class Solution {public int minCut(String s) {int n s.length();boolean[][] g new boolean[n][n];for (int i 0; i < n; i) {Arrays.fill(g[i], true);}for (int i n - 1; i > 0; --i) {for (int j i 1; j < n; j) {g[i]…

深度学习中几种常见数据标准化方法

目录 一、介绍 二、总结 三、详情 1. StandardScaler 2. MinMaxScaler 3. RobustScaler 4. MaxAbsScaler 5. Normalizer 6. QuantileTransformer 7. PowerTransformer 8. Log Transform 四、示例 五、心得 一、介绍 方法名称缩放范围适用条件StandardScaler均值…

vue基础P7-17

1、模板语法 插值语法 {{xxxx}}用在标签体中&#xff0c;也就是<>{{xxx}}</> xxx是js表达式&#xff0c;有返回值&#xff0c;如num1、Date.now()。不是js代码 指令语法 以v开头&#xff0c;用于解析标签&#xff0c;包括标签属性、标签体内容、绑定事件 v-o…

web前端常识:深入理解与实战应用

web前端常识&#xff1a;深入理解与实战应用 Web前端作为现代互联网技术的核心组成部分&#xff0c;涉及的知识点既广泛又深入。对于初学者和进阶者而言&#xff0c;掌握Web前端常识是构建扎实基础、提升技能水平的关键。本文将从四个方面、五个方面、六个方面和七个方面对Web…

python 判断点和线段相交

python 判断点和线段相交 import numpy as np import cv2 import numpy as npdef point_to_line_distance(points, line_segments):# line_segments [[549, 303], [580, 303]]# points [565, 304]x0, y0, x1, y1line_segments[0][0], line_segments[0][1], line_segments[1]…

【python】OpenCV GUI——Trackbar(14.2)

学习来自 OpenCV基础&#xff08;12&#xff09;OpenCV GUI中的鼠标和滑动条 文章目录 GUI 滑条介绍cv2.createTrackbar 介绍牛刀小试 GUI 滑条介绍 GUI滑动条是一种直观且快速的调节控件&#xff0c;主要用于改变一个数值或相对值。以下是关于GUI滑动条的详细介绍&#xff1a…

win10文件夹.git或者文件被隐藏的开启姿势

按需排查&#xff0c;有的文件隐藏是好事 基本操作更多操作某些系统设置的隐藏操作在idea或者pycharm项目中显示.git文件夹 基本操作 文件夹-> 查看 -> 隐藏的项目点亮 更多操作 文件夹 -> 查看 -> 选项 -> 查看 -> 高级设置 -> 文件和文件夹 -> 隐…

服务器部署spring项目jar包使用bat文件,省略每次输入java -jar了

echo off set pathC:\Program Files\Java\jre1.8.0_191\bin START "YiXiangZhengHe-8516" "%path%/java" -Xdebug -jar -Dspring.profiles.activeprod -Dserver.port8516 YiXiangZhengHe-0.0.1-SNAPSHOT.jar 将set path后面改成jre的bin文件夹 START 后…

knoXSS(case01~10)

case 01: 先在每个框里都输入:<script>alert(1)</script> 检查源码 这里第三个和第四个点都被处理过了&#xff0c;所以先考虑第一个和第二个点 这里试了一下&#xff0c;发现GET也能传参&#xff0c;所以构造 成功 case 02: 这里发现变量a和这个似乎有关联&…

专业学习|南开大学《随机过程》学习笔记(一)

&#xff08;1&#xff09;有哪些经典的关于基本随机过程的书籍推荐&#xff1f; 对于想要系统学习基本随机过程的学生来说&#xff0c;可以参考Sheldon M.Rose编著的经典著作《随机过程》。该书涉及的内容也比较宽泛。但并不局限于单个细节论证。 此外&#xff0c;萨缪尔科林(…

嵌入式学习——Linux高级编程复习(标准IO)——day36

1. 标准IO概念——&#xff08;有缓存、流指针&#xff09; &#xff08;1&#xff09;标准IO是编程语言中处理输入和输出的一种通用方法&#xff0c;涉及以下三个预定义的文件指针&#xff1a; 1. stdin&#xff1a;标准输入&#xff0c;通常默认关联到键盘输入。 2. stdout&…

抓住时机的核心:坚持学习准备着

在这个快节奏的时代&#xff0c;时间对于每个人来说都是宝贵的。能否在合适的时间做正确的事情&#xff0c;往往决定了我们成功的概率。但同时&#xff0c;我们也要认识到&#xff0c;逆风翻盘虽少&#xff0c;却并非不可能。在这个过程中&#xff0c;投资自己&#xff0c;投资…

LabVIEW与Python的比较及联合开发

LabVIEW和Python在工业自动化和数据处理领域各具优势&#xff0c;联合开发可以充分发挥两者的优点。本文将从语言特性、开发效率、应用场景等多个角度进行比较&#xff0c;并详细介绍如何实现LabVIEW与Python的联合开发。 语言特性 LabVIEW 图形化编程&#xff1a;LabVIEW使用…

【数据结构】队列的应用(详解)

目录 0 引言 1 打印机任务队列 2 广度优先搜索&#xff08;BFS&#xff09; 3 总结 0 引言 队列&#xff08;Queue&#xff09;是一种先进先出&#xff08;FIFO&#xff09;的数据结构&#xff0c;它允许在尾部添加元素&#xff08;入队操作&#xff09;&#xff0c;并…

三维地图Cesium,加载一个模型,模型沿着给定的一组经纬度路线移动

目录 实现效果 实现思路 功能点 选择移动路线 加载模型和移动路线 重新运行 指定位置(经纬度点)开始移动 视角切换 到站提示 运行 停止 联动接口 完整代码 html js逻辑 trainOperation.js sourceData.js gitee仓库项目代码 疑问解答 实现效果 三维地图Cesiu…

CopyOnWriteArrayList详解

目录 CopyOnWriteArrayList详解1、CopyOnWriteArrayList简介2、如何理解"写时复制"3、CopyOnWriteArrayList的继承体系4、CopyOnWriteArrayList的构造函数5、CopyOnWriteArrayList的使用示例6、CopyOnWriteArrayList 的 add方法7、CopyOnWriteArrayList弱一致性的体现…

LeetCode790多米诺和托米诺平铺

题目描述 有两种形状的瓷砖&#xff1a;一种是 2 x 1 的多米诺形&#xff0c;另一种是形如 “L” 的托米诺形。两种形状都可以旋转。给定整数 n &#xff0c;返回可以平铺 2 x n 的面板的方法的数量。返回对 109 7 取模 的值。平铺指的是每个正方形都必须有瓷砖覆盖。两个平铺…

Android基础-binder机制

一、引言 在Android系统中&#xff0c;进程间的通信&#xff08;IPC&#xff09;是一个至关重要的概念。不同于传统操作系统中的进程间通信方式&#xff0c;如管道、消息队列、信号量、共享内存等&#xff0c;Android采用了独特的Binder机制来实现进程间的通信。Binder机制不仅…