前言
我们都知道在Spring中配置Bean的时候有一个属性scope,它默认是singleton,还有prototype、request等其它的scope,之前的文章有了解关于singleton的大致的流程,那么其它的步骤是怎么样的呢?接下来我们进行一下简单的梳理:
scope之singleton
Spring的scope属性默认为singleton
,上一篇文章分析了在缓存中获取单例模式的Bean,但是如果缓存中不存在的呢?则需要从头开始加载Bean,这个过程有getSingleton()
函数实现:
- 看源码(
AbstractBeanFactory.java
)
if (mbd.isSingleton()) {
// 实例化依赖的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.
destroySingleton(beanName);
throw ex;
}
}
);
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
- 源码分析
上一篇文章我们主要讲解了如何在缓存中获取,但是如果缓存中不存在呢?上述代码就诠释了如果缓存中没有,它会如何去做。
我们可以看到上述代码利用了Java 8的新特性 lambda 表达式 () -> ,getSingleton方法的第二个参数为 ObjectFactory< ? > singletonFactory。()-> 相当于创建了一个ObjectFactory类型的匿名内部类,去实现ObjectFactory接口中的getObject()方法,其中** { }** 中的代码相当于写在匿名内部类中getObject()的代码片段,等着getSingleton()方法里面通过ObjectFactory< ? > singletonFactory去显式调用,如:singletonFactory.getObject()。上述的代码可以写成如下格式:
代码语言:javascript复制sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
}
}
);
接下来我们进入getSingleton()的方法体中看一下具体实现:
- 看源码(
DefaultSingletonBeanRegistry.java
)
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
// 加锁
synchronized (this.singletonObjects) {
// 从缓存中检查一遍
// 因为singleton模式其实就是复用已经创建的,所以这一步很重要必须要检查,
Object singletonObject = this.singletonObjects.get(beanName);
// 如果为空,开始加载过程
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);
Boolean newSingleton = false;
Boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 初始化bean,
// 这个过程就是 AbstractBeanFactory中 sharedInstance = getSingleton(beanName, () -> {...}) 调用匿名内部类的方法
// 其实是调用 createBean() 方法
singletonObject = singletonFactory.getObject();
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;
}
// 后置处理
afterSingletonCreation(beanName);
}
// 加入缓存中
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
// 直接返回
return singletonObject;
}
- 源码解析
上述代码中我们其实可以看到它使用了回调方法,使得程序可以在单例创建的前后做一些准备及处理操作,而真正的获取单例bean的方法其实并不是在此方法中实现的。其实逻辑是在ObjectFactory类型的实例singletonFactory中实现的(即上面的第一段代码)。主要处理操作及内容如下:
- 检查缓存是否已经加载过。
- 如果没有加载,则记录beanName的正在加载状态
- 加载单例前记录加载状态,不要觉得beforeSingletonCreation方法是一个空实现,没有逻辑;其实这个函数做了很重要的操作**记录加载状态,也就是通过this.singletonsCurrentlyInCreation.add(beanName)**将当前正要创建的bean记录在缓存中,这样便可对循环依赖进行检测。具体可以看一下上一篇文章.
一文带你解读Spring5源码解析 IOC之开启Bean的加载,以及FactoryBean和BeanFactory的区别。
- 通过调用参数传入的ObjectFactory的个体Object方法实例化Bean
- 加载单例Bean后的处理方法调用。同步骤3的记录加载状态相似,当bean加载结束后需要移除缓存中对该Bean的正在加载状态的记录。
- 将结果记录在缓存中并且删除加载bean过程中所记录的各种辅助状态。
- 返回处理结果。
接着我们在看一下方法addSingleton()
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
上面的代码很简单,可以见看出来有一个put,一个get,两个remove。
singletonObjects单例bean的缓存
;
singletonFactories 单例bean Factory
;
earlySingletonObjects '早期'创建的单例bean的缓存
;
registeredSingletons 已经注册的单例缓存
;
加载完了单例bean后,调用getObjectsForBeanInstance()
从bean实例中获取对象,方法也可以看一下上一篇文章:
一文带你解读Spring5源码解析 IOC之开启Bean的加载,以及FactoryBean和BeanFactory的区别。
scope之prototype
- 看源码(
AbstractBeanFactory.java
)
// 原型模式
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);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
- 源码分析
原型模式的初始化过程相对比较简单一些:直接创建一个新的实例就可以了。过程如下:
- 调用
beforeSingletonCreation()
记录加载原型模式bean之前的加载状态,即前置处理 - 调用
createBean()
创建一个bean实例对象 - 调用
afterSingletonCreation()
进行加载原型模式bean后的后置处理 - 调用
getObjectForBeanInstance()
从bean实例中获取对象
其它作用域
代码语言:javascript复制// 从指定的 scope 模式下创建 Bean
else {
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 {
// 具体实现在 SimpleThreadScope 下的get
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
);
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
具体的流程和原型模式基本一样的,只不过是bean实例是由scope.get()
实现,如下:
- 看源码(
SimpleThreadScope.java
)
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
// 获取 scope 缓存
Map<String, Object> scope = this.threadScope.get();
// NOTE: Do NOT modify the following to use Map::computeIfAbsent. For details,
// see https://github.com/spring-projects/spring-framework/issues/25801.
Object scopedObject = scope.get(name);
if (scopedObject == null) {
scopedObject = objectFactory.getObject();
// 加入缓存
scope.put(name, scopedObject);
}
return scopedObject;
}