Spring源码学习(

引言

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

入口

AbstractBeanFactory中有getBean的通用逻辑

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

核心逻辑在:doGetBean中。

逻辑说明:

getBean流程

老外点餐

获取BeanName,BeanFactory去掉&,根据别名找到对应的BeanName

饭店老板翻译老外说的

尝试从缓存中获取单例,如果存在就返回

餐馆老板看看有没有做好的,有就端出来给老外

检查是否是原型类型Bean在创建中,如果是,假设存在循环引用,抛出异常

老板看看是不是正在做,如果说是就不管了

找到定义bean对应的BeanFactory

老板找到张大厨

将多个GernericBeanDefinition合并为

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

老板将客人的要求汇总给,供厨师使用

保证bean的依赖先初始化,对DependOn注解的支持

完成做这道菜的必须工作,例如洗菜

按不同作用域创建Bean

厨师做菜

如果需要进行类型装换

 

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

源码注释:

1/** 2 3 * 获得一个实例,可以是共享(原型的),独立(单例的),指定的bean 4 * @param name the name of the bean to retrieve 5 * @param requiredType the required type of the bean to retrieve 6 * @param args arguments to use when creating a bean instance 7 * using explicit arguments 8 * (only applied when creating a new instance as opposed to 9 retrieving an existing one) 10 * args (仅在创建一个新实例时使用,而不是获取一个已经存在的bean) 11 * @param typeCheckOnly whether the instance is obtained 12 for a type check,not for actual use 13 * 是否仅仅是类型检查 14 * @return an instance of the bean 15 * @throws BeansException if the bean could not be created 16 */ 17@SuppressWarnings("unchecked") 18protected <T> T doGetBean( 19final String name, @Nullable final Class<T> requiredType, 20 @Nullable final Object[] args, boolean typeCheckOnly) 21 throws BeansException { 22 //1.获取对应的beanName ,BeanFactory去掉&,别名找到对应的BeanName 23 final String beanName = transformedBeanName(name); 24 Object bean; 25 26 // Eagerly check singleton cache for manually registered singletons. 27 //2. 尝试从缓存中获取单例 Spring会,在Bean未创建完成的情况下,创建Bean的ObjectFactory对象,提早曝光,以方便解决循环依赖。 28 Object sharedInstance = getSingleton(beanName); 29 if (sharedInstance != null && args == null) { 30 if (logger.isTraceEnabled()) { 31 if (isSingletonCurrentlyInCreation(beanName)) { 32 logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + 33 "' that is not fully initialized yet - a consequence of a circular reference"); 34 } 35 else { 36 logger.trace("Returning cached instance of singleton bean '" + beanName + "'"); 37 } 38 } 39 //根据bean实例获取对象,如果是FactoryBean 获取它创建的对象 40 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); 41 } 42 else { 43 // Fail if we're already creating this bean instance: 44 // We're assumably within a circular reference. 45 //3.原型依赖的检查,如果是原型,假设存在循环引用,抛出异常 46 if (isPrototypeCurrentlyInCreation(beanName)) { 47 throw new BeanCurrentlyInCreationException(beanName); 48 } 49 // Check if bean definition exists in this factory. 50 // 4.检查bean,是否定义在了BeanFactory中, 51 BeanFactory parentBeanFactory = getParentBeanFactory(); 52 // 如果父BeanFactory不为空&&当前并没有beanDefinitionMap不包含, 53 // 委托给父BeanFactory 54 if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { 55 // Not found -> check parent. 56 String nameToLookup = originalBeanName(name); 57 if (parentBeanFactory instanceof AbstractBeanFactory) { 58 return ((AbstractBeanFactory) parentBeanFactory).doGetBean( 59 nameToLookup, requiredType, args, typeCheckOnly); 60 } 61 else if (args != null) { 62 // Delegation to parent with explicit args. 63 //委托给,需要参数的 getBean方法 64 return (T) parentBeanFactory.getBean(nameToLookup, args); 65 } 66 else if (requiredType != null) { 67 // No args -> delegate to standard getBean method. 68 // 委托给标准的getBean方法 69 return parentBeanFactory.getBean(nameToLookup, requiredType); 70 } 71 else { 72 return (T) parentBeanFactory.getBean(nameToLookup); 73 } 74 } 75 76 if (!typeCheckOnly) { 77 //不仅是,类型检查,标记bean为创建 78 // 允许bean可以重新合并 79 markBeanAsCreated(beanName); 80 } 81 try { 82 //5.将GernericBeanDefinition转换为RootBeanDefinition, 83 //如果Bean有父Bean,时会合并父类的相关属性。 84 final RootBeanDefinition mbd = 85 getMergedLocalBeanDefinition(beanName); 86 checkMergedBeanDefinition(mbd, beanName, args); 87 88 // Guarantee initialization of beans that 89 // the current bean depends on. 90 // 6.保证bean的依赖先初始化了 91 String[] dependsOn = mbd.getDependsOn(); 92 if (dependsOn != null) { 93 for (String dep : dependsOn) { 94 // 对应@DependsOn 注解, 95 /** 96 * 检测是否存在 depends-on 循环依赖,若存在则抛异常。 97 * 比如 A 依赖 B, 98 * B 又依赖 A,他们的配置如下: 99 @Bean(name="a") 100 @DependsOn("b")public A a () { 101 return new A();} 102 103 @Bean(name = "b") 104 @DependsOn("a") 105 public B b () { 106 return new B(); 107 } 108 109 * a 要求 b 在其之前被创建,但 b 又要求 a 先于它 110 * 创建。这个时候形成了循环,对于 depends-on 循环,Spring 会直接 111 * 抛出异常 112 * 113 *@see org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan 114 */ 115 116 if (isDependent(beanName, dep)) { 117 throw new BeanCreationException(mbd.getResourceDescription(), beanName, 118 "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); 119 } 120 //注册,Dependent和Bean的关系 121 registerDependentBean(dep, beanName); 122 try { 123 //先创建Dependent 124 getBean(dep); 125 } 126 catch (NoSuchBeanDefinitionException ex) { 127 throw new BeanCreationException(mbd.getResourceDescription(), beanName, 128 "'" + beanName + "' depends on missing bean '" + dep + "'", ex); 129 } 130 } 131 } 132 133 // Create bean instance. 134 //7.创建Bean的实例 135 if (mbd.isSingleton()) { 136 sharedInstance = getSingleton(beanName, () -> { 137 try { 138 return createBean(beanName, mbd, args); 139 } 140 catch (BeansException ex) { 141 // Explicitly remove instance from singleton cache: It might have been put there 142 // eagerly by the creation process, to allow for circular reference resolution. 143 // Also remove any beans that received a temporary reference to the bean. 144 destroySingleton(beanName); 145 throw ex; 146 } 147 }); 148 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 149 } 150 else if (mbd.isPrototype()) { 151 // It's a prototype -> create a new instance. 152 Object prototypeInstance = null; 153 try { 154 beforePrototypeCreation(beanName); 155 prototypeInstance = createBean(beanName, mbd, args); 156 } 157 finally { 158 afterPrototypeCreation(beanName); 159 } 160 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); 161 } 162 163 else { 164 String scopeName = mbd.getScope(); 165 final Scope scope = this.scopes.get(scopeName); 166 if (scope == null) { 167 throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); 168 } 169 try { 170 Object scopedInstance = scope.get(beanName, () -> { 171 beforePrototypeCreation(beanName); 172 try { 173 return createBean(beanName, mbd, args); 174 } 175 finally { 176 afterPrototypeCreation(beanName); 177 } 178 }); 179 bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); 180 } 181 catch (IllegalStateException ex) { 182 throw new BeanCreationException(beanName, 183 "Scope '" + scopeName + "' is not active for the current thread; consider " + 184 "defining a scoped proxy for this bean if you intend to refer to it from a singleton", 185 ex); 186 } 187 } 188 } 189 catch (BeansException ex) { 190 cleanupAfterBeanCreationFailure(beanName); 191 throw ex; 192 } 193 } 194 195 // Check if required type matches the type of the actual bean instance. 196 // 8.进行类型转换 197 // requiredType.isInstance(bean) 类似 bean instanceof requiredType 198 // 为true表示可以直接返回,或强转 199 //clazz.isAssignableFrom(obj.getClass()) == clazz.isInstance(obj) 200 //仅当obj not null 201 if (requiredType != null && !requiredType.isInstance(bean)) { 202 try { 203 T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); 204 if (convertedBean == null) { 205 throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); 206 } 207 return convertedBean; 208 } 209 catch (TypeMismatchException ex) { 210 if (logger.isTraceEnabled()) { 211 logger.trace("Failed to convert bean '" + name + "' to required type '" + 212 ClassUtils.getQualifiedName(requiredType) + "'", ex); 213 } 214 throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); 215 } 216 } 217 return (T) bean; 218}

一图胜千言(时序图)

doGetBean时序图

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

  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方法中如如下代码:

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

也就是说doGetBean中的

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

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

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

啰嗦几句

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

下一篇解决 createBean 和getObjectForBeanInstance

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )