写点什么

Spring 获取单例流程 (三)

用户头像
CoderLi
关注
发布于: 2020 年 06 月 15 日

读完这篇文章你将会收获到



  • ``Spring` 何时将 `bean`` 加入到第三级缓存和第一级缓存中

  • ``Spring` 何时回调各种 `Aware` 接口、`BeanPostProcessor``InitializingBean`` 等



相关文章



概述

上两篇文章介绍了 ``getBean`` 前面的流程,今天最后的收尾,把后面的流程继续一起学习下



源码分析

// 我依赖的大哥都好了
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
} catch (BeansException ex) {
// 从三级缓存中移除这个 beanName 因为它可能被放进去了 因为放进去三级缓存可以解决 setter 的循环依赖
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}



如果我们要创建的 ``bean`` 是一个单例,

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
// 看看第一级缓存中有没有
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 将 beanName 加入到 singletonsCurrentlyInCreation 中,代表它正在创建中
beforeSingletonCreation(beanName);
boolean newSingleton = false;
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
} catch (IllegalStateException ex) {
throw ex;
} catch (BeanCreationException ex) {
throw ex;
} finally {
// singletonsCurrentlyInCreation 从这里面移除掉
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 加入缓存中
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}



删减了部分不重要的代码,我们大致来看看其流程



  1. 获取同步锁,然后判断第一级缓存是否已经存在这个 ``bean`` 了

  2. 如果不存在则将 ``beanName` 加入到 `singletonsCurrentlyInCreation`` 中,代表它正在创建中

  3. 然后调用参数的 ``ObjectFactory``getObject` 方法获得一个 `bean``

  4. 最后将其从 ``singletonsCurrentlyInCreation`` 中移除、代表其已经创建完成了

  5. 最后将其加入到第一级缓存中、从第二级和第三级缓存中移除掉



全篇完结.终 !!!



其实真正的秘密藏身在参数的 ``ObjectFactory` 中,从上面的流程中可以宏观的知道 `Spring` 创建 `bean`` 的一个流程



现在我们在看看参数的 ``ObjectFactory`` 究竟干啥子了



protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
...........
...........
try {
// 真正 处理逻辑
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
} catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(xxxx);
}
}



干活的还是 ``do`` 开头的大佬



protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 根据指定 bean 使用对应的策略创建新的实例、如工厂方法、构造函数自动注入、简单初始化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
..........
.........
// 是否需要提前曝光、用来解决循环依赖的问题
// 是单例&允许循环依赖&正在创建中
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// 为了避免后期循环依赖、可以在 bean 初始化前将创建实例的ObjectFactory 加入工厂
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 填充属性
populateBean(beanName, mbd, instanceWrapper);
// 调用初始方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
} catch (Throwable ex) {
.........
}
........
.......
return exposedObject;
}



上面的流程大致就是



  • ``createBeanInstance` 这个方法根据你的配置以及你的 `bean` 的情况选择出一种创建 `bean` 的方法、可能是工厂方法、可能是某个构造函数、可能是默认的构造函数。这里包含了当一个构造函数的参数是另一个 `bean` 的时候、它会通过 `getBean` 的方法获取这个参数的 `bean``



  • 然后将创建好的 ``bean`` 加入到第三级缓存中,默认设置我们是允许循环依赖的



  • ``populateBean` 方法就是我们填充属性了、如果你依赖的其他 `Spring` 的其他 `bean` 是通过这种方式注入的话(`autowireByName` `autowireByType` )、就是在这一步注入的了,他获取其他 `bean` 也是通过 `getBean ``的方式获取

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
.........
.........
if (resolvedAutowireMode == AUTOWIREBYNAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIREBYTYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
.........
.........
}
  • ``initializeBean` 则是调用我们的各种回调接口、`Aware` 类型的、`BeanPostProcessor``InitializingBean``、自定义初始化函数

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {。
// 调用各种 Aware 接口
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
} else {
// 调用各种 Aware 接口
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 调用 BeanPostProcessor postProcessBeforeInitialization
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 调用 InitializingBean 、自定义的初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 调用 BeanPostProcessor postProcessAfterInitialization
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}

其实整体的流程就差不多了

总结

  • 根据参数中的 ``name` 找出对应的 `beanName`、无论这个 `name` 是别名或者是一个 `factoryBean``beanName``

  • 查看缓存中是否包含这个 ``beanName`` 对象

- 先从一级缓存 ``singletonObjects`` 中看看有没有

- 然后从二级缓存 ``earlySingletonObjects``

- 都没有的话再从三级缓存 ``singletonFactories`` 中看看有没有

  • 如果缓存中有 ``bean`、那么我们还是需要处理一下这个 `bean``

- 如果 ``Spring` 缓存中返回的 `bean``factoryBean` 、而用户也想要的是一个 `beanFactory` (参数 `name` 中的前缀是 `&`` )、那么我们直接返回

- 如果 ``Spring` 缓存中返回的 `bean` 是普通的 `bean`、而用户也想要的是一个普通的 `bean`` 、那么就直接返回

- 如果 ``Spring` 缓存中返回的 `bean` 是一个 `factoryBean` 、而用户想要的是一个普通的 `bean` 、那么我们就要从 `factoryBean` 中获取这个 `bean``

- 而从 ``factoryBean` 中获取这个 `bean` 的过程中、需要调用到前置处理、后置处理和我们常用的接口回调 `BeanPostProcessor``

  • 如果缓存中没有 ``bean` 、则判断是否是 `prototype`` 类型并且循环依赖

  • 如果没有则尝试能否在父容器中找到该 ``bean``

  • 如果父容器也没有则获取该 ``beanName` 对应的 `beanDefinition` 找出其依赖的 `beanName``

  • 判断该 ``beanName` 与 依赖的 `beanName` 是否循环依赖、没有则注册其依赖关系并调用 `getBean` 方法去创建依赖的 `beanName``

  • 将 ``beanName` 加入到 `singletonsCurrentlyInCreation`` 中

  • 根据指定 bean 使用对应的策略创建新的实例、如工厂方法、构造函数、创建一个不完整的 bean

  • 将创建好的 bean 加入到第三级缓存

  • 进行属性填充、进行各种接口回调

  • 最后将其从 ``singletonsCurrentlyInCreation`` 中移除、代表其已经创建完成了

  • 最后将其加入到第一级缓存中、从第二级和第三级缓存中移除掉

  • 返回 ``bean`` 给调用方



其实总体的流程还是不算复杂把、我们也可以从中收获到一些东西。其实我们最关心也是面试最常问的一个问题就是、Spring 如何解决循环依赖的问题、感兴趣的可以看看这篇文章公众号内的 ``Spring 循环依赖`` 这篇文章



发布于: 2020 年 06 月 15 日阅读数: 60
用户头像

CoderLi

关注

微信公众号:CoderLi ,专注于 Java 后端开发 2019.07.14 加入

还未添加个人简介

评论

发布
暂无评论
Spring 获取单例流程(三)