Spring源码 - 获取单例(上)
作者:互联网
Spring
源码 - 获取单例(上)
Spring
版本:Spring 5.3.13-release
# 1、doGetBean()
创建Bean
实例
在AbstractBeanFactory#doGetBean()
的源码中:
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object beanInstance;
// 尝试从缓存中获取 Bean 实例对象
Object sharedInstance = getSingleton(beanName);
// 如果 Bean 的单例对象找到了, 并且没有创建实例时需要使用的参数
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 + "'");
}
}
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 源码篇幅过长,省略部分源码
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
// 源码篇幅过长,省略部分源码
// 单实例 Bean 实例化
if (mbd.isSingleton()) {
// 返回以 beanName 的(原始)单例对象, 如果未注册, 则使用 SingletonFactory 创建并注册一个对象
sharedInstance = getSingleton(beanName, () -> {
try {
// 为给定的合并后的 BeanDefinition 和创建该 Bean 所需的参数来创建一个 Bean 实例对象
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 临时引用的任何 Bean
destroySingleton(beanName);
// 重新抛出异常
throw ex;
}
});
// 从 BeanInstance 中获取公开的 Bean 对象, 主要处理 BeanInstance 是 FactoryBean 的情况
// 如果不是 FactoryBean 会直接返回 beanInstance 实例
beanInstance = 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 是否是 FactoryBean<?> 类型的 Bean 实例
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
// 指定 Scope 上实例化 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 {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
// 检查当前 Bean 是否是 FactoryBean<?> 类型的 Bean 实例
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();
}
}
// 对实例化的 Bean 实例进行类型转换
return adaptBeanInstance(name, beanInstance, requiredType);
}
doGetBean()
方法的源码篇幅较长,总结下来Spring
会优先尝试从缓存中获取Bean
实例,如果未获取到则需要创建当前beanName
对应的Bean
实例。对于单实例Bean
的加载,Spring
则是将详细的加载过程委派给了DefaultSingletonBeanRegistry#getSingleton()
方法。
# 2、getSingleton()
加载Bean
实例
DefaultSingletonBeanRegistry#getSingleton()
重载方法源码:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
// 同步全局变量, 保证线程安全
synchronized (this.singletonObjects) {
// 这一步是非常有必要的, 否则可能会重复创建 Bean 实例
Object singletonObject = this.singletonObjects.get(beanName);
// 如果获取不到对象, 则进行 singleton 的初始化
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
// 创建单例之前的回调, 默认实现将单例注册为当前正在创建中, 便于循环依赖的检测
beforeSingletonCreation(beanName);
// 表示生成了新单例对象的标记, 默认为 false, 表示没有生成新的单例对象
boolean newSingleton = false;
// 有抑制异常记录标记, 没有时为 true, 否则为 false
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
// 如果没有抑制异常记录
if (recordSuppressedExceptions) {
// 对抑制的异常列表进行实例化
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 从单例工厂中获取对象, 调用在 AbstractBeanFactory 中传递进来的 ObjectFactory<T> 函数式接口
singletonObject = singletonFactory.getObject();
// 生成了新的单例对象标记为 true, 表示生成了新的单例对象
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 当 Bean 加载结束后需要移除缓存中对该 Bean 的正在加载状态的记录
afterSingletonCreation(beanName);
}
// 如果是生成新的单例 Bean
if (newSingleton) {
// 加入一级缓存
addSingleton(beanName, singletonObject);
}
}
// 返回加载的 Bean 实例
return singletonObject;
}
}
如果有不了解ObjectFactory<T>
接口的可以查看这篇文章:Spring源码 - 核心接口ObjectFactory
Spring
首先会锁定全局变量,然后尝试从一级缓存中获取,这一步非常重要,避免重复创建。如果获取到了则直接返回。- 如果没有从缓存中获取到,首先会将当前
beanName
对应的Bean
实例状态记录为正在创建,便于循环依赖的检测。 - 调用
ObjectFactory<T>
接口中的getObject()
方法进行Bean
的实例化。如果实例化成功则记录当前Bean
为新创建的Bean
。 - 无论创建成功或者失败,首先移除
beanName
对应的Bean
的正在创建的状态。 - 如果创建成功则将其加入一级缓存中。同时删除加载
Bean
过程中所记录的各种辅助状态。 - 最终返回创建的
Bean
实例。
需要注意,在调用ObjectFactory<?>
接口中的getObject()
方法其实质则是激活AbstractAutowireCapableBeanFactory#doCreateBean()
方法中的createBean()
方法。
# 3、createBean()
创建Bean
实例
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
// 锁定 class, 根据设置的 class 属性或者根据 className 来解析 class
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
// 进行条件筛选, 重新赋值 RootBeanDefinition, 并设置 BeanClass 属性
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
// 重新创建一个 RootBeanDefinition 对象
mbdToUse = new RootBeanDefinition(mbd);
// 设置 BeanClass 属性
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
// 验证及准备覆盖的方法 : lookup-method, replace-method。当需要创建的 Bean 对象中包含了
// lookup-method 和 replace-method 标签的时候, 会产生覆盖操作
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 给 BeanPostProcessors 一个机会来返回代理来替代正真的实例, 应用实例化前的前置处理器, 用户自定义动态代理的方式
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
// 实际创建 Bean 调用
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
Spring
首先会锁定class
,根据设置的class
属性或者根据className
来解析class
。- 对
overrides
属性进行标记以及验证。 - 激活之前容器中所有注册的
BeanPostProcessor
,并且解析指定Bean
是否存在初始化前的短路操作,AOP
功能的实现就是基于这里的判断。 - 将创建
Bean
实例委托给doCreateBean()
重载方法。
在分析doCreateBean()
方法源码之前还需了解Spring
的循环依赖,请见Spring
源码 - 获取单例(下)
GitHub源码地址:https://github.com/kapbc/kapcb-spring-source/tree/master/Spring-Framework-v5.3.13
备注:此文为笔者学习
Spring
源码的笔记,鉴于本人技术有限,文中难免出现一些错误,感谢大家批评指正。
更多Java技术笔记可扫码关注下方微信公众号。
标签:实例,mbd,Spring,beanName,bean,Bean,源码,ex,单例 来源: https://blog.csdn.net/qq_43911324/article/details/122642180