引言

AbstractBeanFactory.getBean的流程,有点像老外点餐,不信咱们往下看。

入口

AbstractBeanFactory中有getBean的通用逻辑

//AbstractBeanFactory 中getBean方法第源码
@Override
public Object getBean(String name, Object... args) throws BeansException {return doGetBean(name, null, args, false);
}

核心逻辑在:doGetBean中。

逻辑说明:

getBean流程 老外点餐
获取BeanName,BeanFactory去掉&,根据别名找到对应的BeanName 饭店老板翻译老外说的
尝试从缓存中获取单例,如果存在就返回 餐馆老板看看有没有做好的,有就端出来给老外
检查是否是原型类型Bean在创建中,如果是,假设存在循环引用,抛出异常 老板看看是不是正在做,如果说是就不管了
找到定义bean对应的BeanFactory 老板找到张大厨

将多个GernericBeanDefinition合并为

RootBeanDefinition,如果Bean有父Bean,时会合并父类的相关属性

老板将客人的要求汇总给,供厨师使用
保证bean的依赖先初始化,对DependOn注解的支持 完成做这道菜的必须工作,例如洗菜
按不同作用域创建Bean 厨师做菜
如果需要进行类型装换  

玩笑过后让我们看点实在的。

源码注释:

/*** 获得一个实例,可以是共享(原型的),独立(单例的),指定的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)*        args      (仅在创建一个新实例时使用,而不是获取一个已经存在的bean)* @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(
final String name, @Nullable final Class<T> requiredType,@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {//1.获取对应的beanName ,BeanFactory去掉&,别名找到对应的BeanNamefinal String beanName = transformedBeanName(name);Object bean;// Eagerly check singleton cache for manually registered singletons.//2. 尝试从缓存中获取单例 Spring会,在Bean未创建完成的情况下,创建Bean的ObjectFactory对象,提早曝光,以方便解决循环依赖。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 + "'");}}//根据bean实例获取对象,如果是FactoryBean 获取它创建的对象bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}else {// Fail if we're already creating this bean instance:// We're assumably within a circular reference.//3.原型依赖的检查,如果是原型,假设存在循环引用,抛出异常if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// Check if bean definition exists in this factory.// 4.检查bean,是否定义在了BeanFactory中,BeanFactory parentBeanFactory = getParentBeanFactory();// 如果父BeanFactory不为空&&当前并没有beanDefinitionMap不包含,// 委托给父BeanFactoryif (parentBeanFactory != null && !containsBeanDefinition(beanName)) {// Not found -> check parent.String 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.//委托给,需要参数的 getBean方法return (T) parentBeanFactory.getBean(nameToLookup, args);}else if (requiredType != null) {// No args -> delegate to standard getBean method.// 委托给标准的getBean方法return parentBeanFactory.getBean(nameToLookup, requiredType);}else {return (T) parentBeanFactory.getBean(nameToLookup);}}if (!typeCheckOnly) {//不仅是,类型检查,标记bean为创建// 允许bean可以重新合并markBeanAsCreated(beanName);}try {//5.将GernericBeanDefinition转换为RootBeanDefinition,//如果Bean有父Bean,时会合并父类的相关属性。final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd, beanName, args);// Guarantee initialization of beans that //  the current bean depends on.// 6.保证bean的依赖先初始化了String[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {for (String dep : dependsOn) {// 对应@DependsOn 注解,/*** 检测是否存在 depends-on 循环依赖,若存在则抛异常。* 比如 A 依赖 B,* B 又依赖 A,他们的配置如下:@Bean(name="a")@DependsOn("b")public A a () {return new A();}@Bean(name = "b")@DependsOn("a")public B b () {return new B();}* a 要求 b 在其之前被创建,但 b 又要求 a 先于它* 创建。这个时候形成了循环,对于 depends-on 循环,Spring 会直接* 抛出异常**@see org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan*/if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}//注册,Dependent和Bean的关系registerDependentBean(dep, beanName);try {//先创建DependentgetBean(dep);}catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex);}}}// Create bean instance.//7.创建Bean的实例if (mbd.isSingleton()) {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;}});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}else if (mbd.isPrototype()) {// It's a prototype -> create a new instance.Object prototypeInstance = null;try {beforePrototypeCreation(beanName);prototypeInstance = createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}else {String scopeName = mbd.getScope();final Scope scope = this.scopes.get(scopeName);if (scope == null) {throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");}try {Object scopedInstance = scope.get(beanName, () -> {beforePrototypeCreation(beanName);try {return createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}});bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);}catch (IllegalStateException ex) {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) {cleanupAfterBeanCreationFailure(beanName);throw ex;}}// Check if required type matches the type of the actual bean instance.// 8.进行类型转换//  requiredType.isInstance(bean) 类似 bean instanceof requiredType// 为true表示可以直接返回,或强转//clazz.isAssignableFrom(obj.getClass()) == clazz.isInstance(obj)  //仅当obj not nullif (requiredType != null && !requiredType.isInstance(bean)) {try {T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);if (convertedBean == null) {throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}return 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());}}return (T) bean;
}

一图胜千言(时序图)

当看完主流程时,我有如下疑问:

  1. getObjectForBeanInstance的作用?
  2. markBeanAsCreated 和getMergedLocalBeanDefinition的作用
  3. bean的DependsOn是什么?
  4. createBean的逻辑

getObjectForBeanInstance和createBean的逻辑下一篇再聊,预计20190921前上传。 这里先说下2,4。

补充说明:

markBeanAsCreated 和getMergedLocalBeanDefinition的作用

简单说,就是清除原有的RootBeanDefinition,再通过当前的多个GenericBeanDefinition合并成新的RootBeanDefinition,供BeanFactory使用。

什么是BeanDefinition

  • BeanDefinition 是一个极简接口,主要目的是允许BeanFactoryPostProcessor(例如:PropertyPlaceholderConfigurer)去反射和修改属性值和其他的bean元数据。
  • GenericBeanDefinition 用于一站式定义标准的bean。和其他beanDefinition一样,它允许指定一个类,属性值,可选的构造器参数值,并且可以通过配置parentName,来支持派生关系。
  • RootBeanDefinition 代表合并的beanDefinition,Spring的BeanFactory使用RootBeanDefinition创建指定的bean它可能继承了多个原始的BeanDefinition,这些源BeanDefinition通常是GenericBeanDefinition,RootBeanDefinition本质上是运行时的“统一”bean定义视图。

如果有兴趣可以搜索

org.springframework.beans.factory.config.BeanDefinition org.springframework.beans.factory.support.GenericBeanDefinition org.springframework.beans.factory.support.RootBeanDefinition

bean的DependOn是什么?

我最开始以为是bean需要依赖,处理Autowired注解,然而不是。 利用IDEA查找了调用BeanDefinition的setDependsOn的地方,

发现了AnnotationConfigUtils.processCommonDefinitionAnnotations方法中如如下代码:

AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if (dependsOn != null) {abd.setDependsOn(dependsOn.getStringArray("value"));
}

也就是说doGetBean中的

  String[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {.....}

是对@DependOn注解的支持,我孤陋寡闻,工作中重来没有使用过@DependOn注解。从网上查阅了资料。
当时我查下的资料的url:https://blog.csdn.net/qq_30257149/article/details/88350320

@DependOn注解用来表示一个bean A的实例化依赖另一个bean B的实例化, 但是A并不需要持有一个B的对象

啰嗦几句

读源码不容易,最开始我总是揪住一个方法不放,个把小时下来,已经不知道自己读到哪里了,后来总是囫囵吞枣,一味求快,好像看了很多,实际上什么也不知道。今年9月初,不知道是北京的天气变凉快了,还是什么别的原因,我自己也不清楚,竟然能静下心来,不求快,一层一层读,一点一点翻译,每天仅读40分钟,总算感觉是明白了点,不禁感慨如下:
只抓细节太糊涂
囫囵吞枣净瞎看
静心慢读未必快
反正我是入门了

下一篇解决 createBean 和getObjectForBeanInstance

Spring源码学习(-)别怕,老外点中餐与AbstractBeanFactory.getBean的主流程差不多相关推荐

  1. spring源码学习之路---深入AOP(终)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章和各位一起看了一下sp ...

  2. Spring源码学习的初步体会

    Spring源码学习的初步体会: 深入学习和巩固java的基础知识,其中的java知识范围全部,可以边研究源码边巩固复习基础知识 体会其中用到的设计思想:其中包含的设计原则和设计模式. 加深对spri ...

  3. spring源码学习之整合Mybatis原理分析

    本文主要解析spring是如何与mybatis进行整合,整合的过程中需要哪些组件的支持.以前面提到过的配置例子<spring源码学习之aop事物标签解析> 整合的过程中需要使用以下这个依赖 ...

  4. 【Spring源码学习】Spring Bean的销毁

    [Spring源码学习]Spring Bean的销毁 一.注册bean销毁的类 1.registerDisposableBeanIfNecessary() 2.DisposableBeanAdapte ...

  5. Spring源码学习(四) | @Configuration的cglib动态代理

    文章目录 前言 例子 @Configuration :full or lite 设置 full or lite Cglib生成代理类AppConfig Where is it generated Ho ...

  6. Spring源码学习路线

     如果你想加入spring源码的学习,笔者的建议是从 spring-core入手,其次是spring-beans和spring-aop,随后是spring-context,再其次是spring-t ...

  7. Spring源码学习笔记:经典设计模式之代理模式

    1.博客内容均出自于咕泡学院架构师第三期 2.架构师系列内容:架构师学习笔记(持续更新) 0.代理模式(Proxy Pattern) 指为其他对象提供一种代理,以控制对这个对象的访问.代理对象在客户端 ...

  8. Spring源码学习笔记:经典设计模式之策略模式

    1.博客内容均出自于咕泡学院架构师第三期 2.架构师系列内容:架构师学习笔记(持续更新) 0.策略模式(Strategy pattern) 指定义了算法家族,分别封装起来,让它们之间可以互相替换,此模 ...

  9. Spring源码学习(三)-- 底层架构核心概念解析

    前面,我们大概了解了Spring中的一些概念和底层工作流程,这篇是后续看Spring源码所必备的,防止后续看源码的过程中,遇到不会的概念得单独跳出来学习.​ BeanDefinition BeanDe ...

最新文章

  1. ***:***之路的必备技能
  2. office频繁显示停止工作
  3. Linux系统中fflush,sync,syncfs,fdatasync,fsync的比较
  4. web安全_皮卡丘_csrf
  5. MySQL通信类型:同步或者异步
  6. 云计算产值将超3000亿美元 亚马逊微软谷歌居三甲
  7. 记录——《C Primer Plus (第五版)》第七章编程练习第六题
  8. [Swift]LeetCode289. 生命游戏 | Game of Life
  9. # 遍历结构体_关于二叉树怎样建立和四种遍历方法你知道吗?
  10. ibm服务器怎么收集日志信息,IBM X86 服务器Linux下收集DSA日志方法(包含BMC信息)...
  11. 用科学数据求真:月球的激光发射器有用吗?
  12. 自定义注解+AOP,优雅的打印方法接受和返回的参数内容
  13. 16个外接SMA天线R2000超高频RFID写卡器HXU2899M上位机命令数据块
  14. 减速器课程设计指导系统使用方法
  15. ICLR 2022最佳论文:基于对比消歧的偏标签学习
  16. 计算机硬盘无法共享文件,求解磁盘为什么不能共享
  17. 2021Eclipse 的安装使用说明
  18. 设计模式----单利模式
  19. 校园网连接后,浏览器打不开登录界面可能的一种解决方法
  20. 解决CDH HiveServer2 因OutOfMemory errors原因造成异常退出问题

热门文章

  1. telnet 失去了跟主机的连接
  2. 如何在 RHEL 8 / CentOS 8 系统中下载 RPM 包而不安装它们 ?
  3. comparable java_java的Comparable接口详解
  4. ThunderNet——快速目标检测算法
  5. 老虎基金购入2亿美元阿里股份
  6. 台哥算法练习 - 12345变为一万两千三百四十五
  7. 少儿计算机兴趣小组活动记录,舞蹈兴趣小组的相关活动记录
  8. 器件打散 617版本 cadence virtuoso layout
  9. python 培训讲师 上海
  10. html div淡出,CSS3过渡 – 淡出效果