1 Bean创建的入口
-
在AbstractApplicationContext的refresh()方法中有
this.finishBeanFactoryInitialization(beanFactory)
方法 -
该方法中调用了DefaultListableBeanFactory的preInstantiateSingletons()方法,该方法会初始化所有非延时加载的Bean实例
-
preInstantiateSingletons()方法会调用getBean()方法创建出示例
if (isEagerInit) { this.getBean(beanName); }
-
getBean()方法中调用
AbstractBeanFactory的doGetBean()
方法进行Bean的创建public Object getBean(String name) throws BeansException { return this.doGetBean(name, (Class)null, (Object[])null, false); }
-
在doGetBean()方法中使用了一个匿名内部类来创建Bean
// 这里使用了一个匿名内部类,创建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. // 显式从单例缓存中删除 bean 实例 // 因为单例模式下为了解决循环依赖,可能它已经存在了,所以将其销毁 destroySingleton(beanName); throw ex; } });
-
AbstractAutowireCapableBeanFactory实现了createBean()方法,该类提供自动装配的服务
-
在createBean()方法中找到了doCreateBean(),这就是创建Bean的入口
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
2 学习路线
3 doGetBean()
- AbstractBeanFactory提供了doGetBean()方法,能够根据Scope去进行不同的处理,这里主要研究Singleton
- 针对prototype的循环依赖,spring无解,直接抛出异常
3.1 尝试从缓存中获取Bean
3.1.1 获取BeanName - transformedBeanName(name)
3.1.2 尝试获取Bean实例 - getSingleton()
- doGetBean()调用DefaultSingletonBeanRegistry类的getSingleton()方法尝试从缓存中获取单例实例
- 该方法在DefaultSingletonBeanRegistry中,这里涉及到了
三级缓存
- 注入属性的Bean存放在singletonObjects
- 不完备的Bean存放在earlySingletonObjects 或者 singletonFactories
/** Cache of singleton objects: bean name to bean instance. */ //一级缓存:单例对象缓存池,beanName->Bean,其中存储的就是实例化,属性赋值成功之后的单例对象 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); /** Cache of singleton factories: bean name to ObjectFactory. */ //三级缓存:单例工厂的缓存,beanName->ObjectFactory,添加进去的时候实例还未具备属性 // 用于保存beanName和创建bean的工厂之间的关系map,单例Bean在创建之初过早的暴露出去的Factory, // 为什么采用工厂方式,是因为有些Bean是需要被代理的,总不能把代理前的暴露出去那就毫无意义了 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); /** Cache of early singleton objects: bean name to bean instance. */ //二级缓存:早期的单例对象,beanName->Bean,其中存储的是实例化之后,属性未赋值的单例对象 // 执行了工厂方法生产出来的Bean,bean被放进去之后, // 那么当bean在创建过程中,就可以通过getBean方法获取到 private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
流程分析
- 首先从以及缓存 singletonObjects 尝试获取Bean实例,那肯定是找不到
- 该ConcurrentHashMap存储的是最终形态的Bean(填充了属性)
//尝试从一级缓存里面获取完备的Bean,已经注入了属性 Object singletonObject = this.singletonObjects.get(beanName);
- 此时 singletonObject == null,再判断 isSingletonCurrentlyInCreation(beanName) ,即是否是正在创建的单例Bean实例,因为该方法执行是还未判断Bean的Scope属性所以这里未false,也就跳过了 if
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {}
- 最终返回 null
3.1.2.2 三级缓存
if 流程分析
-
如果Bean是单例的并且是正在创建的,对singleObjects上同步锁
- 上锁之后操作二级缓存和三级缓存是安全的,因此二级缓存和三级缓存都是用的是HashMap
synchronized (this.singletonObjects)
-
尝试从二级缓存earlySingletonObjects获取Bean实例,它存储的是还没进行属性添加操作的Bean实例
singletonObject = this.earlySingletonObjects.get(beanName);
-
如果获取到了就不进入if 直接返回了
if (singletonObject == null && allowEarlyReference)
-
如果没获取到并且 allowEarlyReference = true ,就进入if,根据beanName尝试从三级缓存 singletonFactories 中获取创建此Bean的单例工厂实例
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
- ObjectFactory是一个函数实接口,里面只有一个getObject()方法,后序能调用getObject()来创建Bean实例
- 不使用FactoryBean是为了区分用户使用的和框架使用的,FactoryBean有它单独的处理逻辑
-
如果没获取到该单例对应的对象工厂实例就返回null
-
获取到了就会调用获取到的对象工厂实例的getObject()方法来创建Bean实例,由于这时Bean的属性可能还未注入,会将它先放入二级缓存earlySingletonObjects中。为了保证三级缓存中只有一级是有Bean实例的,所以创建完Bean实例后会将三级缓存中的对象工厂实例移除
if (singletonFactory != null) { //调用单例工厂的getObject方法返回对象实例 singletonObject = singletonFactory.getObject(); //将实例放入二级缓存里 this.earlySingletonObjects.put(beanName, singletonObject); //从三级缓存里移除 // 保证三层缓存只有一层由Bean,也就是单例的 this.singletonFactories.remove(beanName); }
3.1.3 getObjectForBeanInstance() - TODO
- 再听一遍 8 - 2
- 此方法的作用时判断是否是如果是FactoryBean
- 如果是普通bean,直接返回,如果是FactoryBean,则返回他的getObject生成的Bean实例
// 如果先前已经创建过单例Bean的实例,并且调用的getBean方法传入的参数为空 // 则执行if里面的逻辑 // args之所以要求为空是因为如果有args,则需要做进一步赋值,因此无法直接返回 if (sharedInstance != null && args == null) { if (logger.isTraceEnabled()) { //如果Bean还在创建中,则说明是循环引用 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,直接返回,如果是FactoryBean,则返回他的getObject生成的Bean实例 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); }
3.2 Prototype循环依赖的判断
- 3.1中讲的是能从缓存获取到Bean的逻辑,本节讲解的是scope不为singleton(是prototype)或者scope为sigleton但是Bean没有被创建(从缓存中获取不到值)
3.2.1 isPrototypeCurrentlyInCreation()
-
如果scope为prototype并且显示还在创建中,则基本是循环依赖的情况
- 针对prototype的循环依赖,
spring无解
,直接抛出BeanCurrentlyInCreationException
异常,prototype 的循环依赖Spring是不支持的
if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); }
- 针对prototype的循环依赖,
-
该方法尝试从prototypesCurrentlyInCreation中获取
Object curVal = this.prototypesCurrentlyInCreation.get();
- prototypesCurrentlyInCreation是ThreadLocal类型的,也就是说仅仅是本次线程创建的Scope为prototype的Bean实例会放到这张存储正在创建的Bean的名字列表里
/** Names of beans that are currently in creation. */ private final ThreadLocal<Object> prototypesCurrentlyInCreation = new NamedThreadLocal<>("Prototype beans currently in creation");
- prototypesCurrentlyInCreation是ThreadLocal类型的,也就是说仅仅是本次线程创建的Scope为prototype的Bean实例会放到这张存储正在创建的Bean的名字列表里
3.3 递归去父容器获取Bean实例 - TODO
-
如果不是循环以来的情况,则递归去父容器中尝试获取Bean
-
获取父容器
BeanFactory parentBeanFactory = getParentBeanFactory();
-
递归去父容器中尝试获取Bean
//如果parent容器依旧是AbstractBeanFactory的实例 //instanceof通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例 if (parentBeanFactory instanceof AbstractBeanFactory) { //直接递归调用方法来查找 return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); }
3.4 合并子类和父类的BeanDefination
-
将父类的BeanDefinition与子类的BeanDefinition进行合并覆盖
//将父类的BeanDefinition与子类的BeanDefinition进行合并覆盖 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
- 尝试从 mergedBeanDefinitions 获取合并好的BeanDefination
- 获取到直接返回
- 获取不到从新合并一遍
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)); }
- 尝试从 mergedBeanDefinitions 获取合并好的BeanDefination
-
对合并的BeanDefinition做验证,主要看属性是否为abstract的
checkMergedBeanDefinition(mbd, beanName, args);
3.5 递归实例化显示依赖的Bean - depends-on
depends-on用来指定Bean初始化及销毁时的顺序
<bean id=a Class="com.njupt.A" depends-on="b" />
<bean id=b Class="com.njupt.B" />
- 注意:Spring不支持定义显示的循环依赖
<bean id="beanA" class="BeanA" depends-on="beanB"> <bean id="beanB" class="BeanB" depends-on="beanA">
- 如果有会直接抛出异常
if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); }
执行流程
-
从获取到的BeanDefination中查找有没有depend-on
String[] dependsOn = mbd.getDependsOn();
-
如果有显示的循环依赖则抛出异常
if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); }
-
如果有depends-on,并且不是循环依赖,则会先将依赖的Bean进行注册
registerDependentBean(dep, beanName);
public void registerDependentBean(String beanName, String dependentBeanName) { // 获取到Bean的真实的名字 String canonicalName = canonicalName(beanName); // 双重注册 synchronized (this.dependentBeanMap) { /* 1.Map<String, Set<String>> dependentBeanMap: 存放着当前Bean被引用的Bean的集合 String: 被依赖的Bean的名字 Set<String>: value则是依赖于该bean的所有bean 比如当前需要实例化的是Bean的名字是userInfo,userInfo中有个Human类型的属性human, 那么就有human被userInfo引用的关系 human=[userInfo] 2.computeIfAbsent:若key对应的value为空,会将第二个参数的返回值存入并返回 */ Set<String> dependentBeans = this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8)); if (!dependentBeans.add(dependentBeanName)) { return; } } synchronized (this.dependenciesForBeanMap) { // dependenciesForBeanMap中存放的是当前Bean所依赖的Bean的集合 Set<String> dependenciesForBean = this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8)); dependenciesForBean.add(canonicalName); } }
-
递归调用getBean方法,注册Bean之间的依赖
// 递归调用getBean方法,注册Bean之间的依赖(如C需要晚于B初始化,而B需要晚于A初始化) // 初始化依赖的bean getBean(dep);
3.6 针对不同Scope进行Bean实例的创建
3.6.1 singleton
3.6.1.1 总体流程分析
- 这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
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. // 显式从单例缓存中删除 bean 实例 // 因为单例模式下为了解决循环依赖,可能它已经存在了,所以将其销毁 destroySingleton(beanName); throw ex; } }); // 如果是普通bean,直接返回,是FactoryBean,返回他的getObject bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }
getSingleton()方法流程
-
getSingleton()由DefaultSingletonBeanRegistry类实现,发现匿名内部类也是ObjectFactory
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {}
-
首先尝试从一级缓存中获取Bean
Object singletonObject = this.singletonObjects.get(beanName);
-
-
获取不到,判断容器是否正在销毁单例,如果不是,就开始真正的创建
-
调用beforeSingletonCreation(beanName)将当前beanName加入正在创建的Bean列表中
this.singletonsCurrentlyInCreation.add(beanName)
-
调用ObjectFactory的getObject来进行Bean的创建,也就是最开始的那个匿名内部类,创建完成后将newSingleton 设为 true
singletonObject = singletonFactory.getObject(); newSingleton = true;
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. // 显式从单例缓存中删除 bean 实例 // 因为单例模式下为了解决循环依赖,可能它已经存在了,所以将其销毁 destroySingleton(beanName); throw ex; } });
-
调用afterSingletonCreation(beanName);将beanName从正在创建的名字列表中移除
this.singletonsCurrentlyInCreation.remove(beanName)
-
调用 addSingleton(beanName, singletonObject) 方法
- 将新创建的Bean加入一级缓存,移除二三级缓存的Bean
- 将beanName添加到单例Bean的名单列表
protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { //Bean实例完成创建之后,只保留一级缓存以及注册beanName的顺序,其余的清除 this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } }
-
最终返回Bean实例
getObjectForBeanInstance()
- 调用该方法返回Bean实例本身。如果是普通bean,直接返回,是FactoryBean,返回他的getObject
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
3.6.2 prototype
-
首先将当前Bean的beanName注册进类型为ThreadLoacl表示当前线程正在创建的prototype的Bean的名字列表,防止循环依赖
beforePrototypeCreation(beanName);
- 这也就解释了为什么一开始会判断Bean是否在创建中
if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); }
-
调用createBean()方法创建对象
prototypeInstance = createBean(beanName, mbd, args);
-
清楚保存beanName的缓存
// 默认的功能是将先前注册的正在创建中的Bean信息给抹除掉 afterPrototypeCreation(beanName);
-
获取到创建的Bean实例或者BeanFactory创建的Bean实例
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
3.6.3 !singleton && !prototype
- 要创建的Bean既不是单例模式,也不是原型模式,则根据Bean定义资源中配置的生命周期范围,选择实例化Bean的合适方法,这种在Web应用程序中 比较常用,如:request、session、application等生命周期
- request:每次请求都创建一个新的实例
- session:在session的有效期内使用的是同一个Bean实例
- 在匿名参数中调用createBean()方法
Object scopedInstance = scope.get(beanName, () -> { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } });
- 匿名参数实现的是ObjectFactory接口的getObject()逻辑
Object get(String name, ObjectFactory<?> objectFactory);
3.7 对创建的Bean进行类型检查
补充
为什么要去考虑Bean有可能已经被创建
- 因为容器均是通过getBean方法从容器获取bean实例的,而有的bean在容器初始化的时候就会被创建,有的是延迟加载的。
- 比如说,我们某个Service类在容器初始化的时候就已经被容器通过getBean方法提前创建出来了。而在我们的某个Controller类下面如果拥有该Service类作为成员变量,并标记上@Autowired标签,并且该controller类咱们将其设置成延迟加载的。此时该Controller类只有在首次被调用的时候才会创建出对应的Bean实例来,而创建的过程中,就会调用getBean去获取这个Service的Bean,此时Service的Bean由于已经创建好,就可以直接从容器的缓存里返回