关于不同Scope的bean,spring通过不同的策略来处理以及创建过程,在整个过程中我们知道默认为Singleton,当然还有prototype和request等等,首先我们来看spring对Singleton的处理过程:
AbstractBeanFactory.java
//单例的情况下
if (mbd.isSingleton()) {
//从缓存(singletonObjects)中去拿
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
//最后从缓存中移除对应的实例原因有:
//1.每当有bean在创建时,允许循环参考来解析对应的beanDefinition
//2.删除临时引用该bean的bean
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
方法很明确,当我们合并后rootBeanDefinition是单例的时候,通过调用#getSingleton(String beanName, ObjectFactory<?> singletonFactory)来实现,关于spring获取Singleton bean的过程请参考spring容器之单例bean的获取这篇文章,若如果在缓存中没有了spring又是如何处理的呢?接着看:
DefaultSingletonBeanRegistry.java
/**
* Return the (raw) singleton object registered under the given name,
* creating and registering a new one if none registered yet.
* @param beanName the name of the bean
* @param singletonFactory the ObjectFactory to lazily create the singleton
* with, if necessary
* @return the registered singleton object
*/
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
//考虑到并发情况,锁住全局变量
synchronized (this.singletonObjects) {
//1.通过参数beanName从singletonObjects缓存中获取
Object singletonObject = this.singletonObjects.get(beanName);
//如果没获取到
if (singletonObject == null) {
//1.1. 判断当前bean是否是销毁状态
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 + "'");
}
//2.单例bean创建之前的检验
beforeSingletonCreation(beanName);
boolean newSingleton = false;
//2.1.异常集合的初始化过程
//suppressedExceptions用来保存单例bean获取过程中的不必要的异常
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
//3.初始化singletonObject实例
//该过程实际上调用的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;
}
//单例bean创建之后的处理过程
afterSingletonCreation(beanName);
}
//将创建之后的bean保存到singletonObjects中
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
这就是当缓存中没有时,spring的处理过程,还是尝试着去从缓存中获取,如果没有获取到,通过ObjectFactory#getObject()进行bean实例的初始化,然后在保存到singletonObjects缓存中,在整个的过程中,实际上我们发现并没有看到创建bean的过程,只是做了一些创建bean前提的准备工作,我们来看一下都做了些什么:
- 首先在1处尝试着去获取,如果有的话直接返回该bean的instance即可
- 如果在缓存没获取到,开始进行bean的加载过程
- 在2处我们可以看到的是首先在加载bean之前的检验,在之前的文章单例bean的获取过程说过了,这里就不多说了.
- 检验之后首先是对异常集合的初始化过程
private Set<Exception> suppressedExceptions;
//2.1.异常集合的初始化过程
//suppressedExceptions用来保存单例bean获取过程中的不必要的异常
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
- 前提的过程完成后,我们可以看到在3处是真正的初始化bean的过程,可以看到的是通过我们的参数ObjectFactory#getObject()来完成,如何实现我们后续说.
- 在我们bean实例初始化完成后,进行后续的扫尾工作,对我们实例化的bean进行不能重复创建的标记处理,下次获取直接获取即可,关于afterSingletonCreation(String beanName)详细讲解我们在单例bean获取的过程中详细的说过了,这里不再重复了.
- 最后将我们实例化的bean保存在singletonObjects缓存中
/**存放单例bean的映射集合map*/
//对应关系: bean name -----> bean instance
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/**存放objectFactory的map映射集合*/
//对应关系: bean name-----------> objectFactory
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/**存放早期单例bean的映射集合*/
//对应关系: bean name ---------> bean instance
//与singletonObjects不同区别是,如果单例的bean保存到earlySingletonObjects时,如果该bean此时处于创建过程中,可以直接通过getBean()方法获取,也就是提早的暴露该bean,主要是为了解决循环依赖的问题
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/**存放的是当前已经完成注册的bean*/
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
/**
* 将单例的bean保存到缓存中
* @param beanName
* @param singletonObject
*/
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
//保存到singletonObjects缓存里
this.singletonObjects.put(beanName, singletonObject);
//从singletonFactories工厂缓存中移除相应的bean的实例
this.singletonFactories.remove(beanName);
//从早期单例缓存中移除对应的bean实例
this.earlySingletonObjects.remove(beanName);
//将该bean添加注册表中
this.registeredSingletons.add(beanName);
}
}
以上就是缓存中不存在的情况下,spring还是通过#getSingleton(String beanName, ObjectFactory<?> singletonFactory)来完成了单例bean的获取
- 完成了单例bean的获取之后,紧接着是通过#getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) 方法来获取我们想要的bean对象,关于该方法的详细过程在之前的[spring容器之从bean的实例中获取对象spring容器之从bean的实例中获取对象
)详细的讲解了,感兴趣的可以去看看
#######原型(prototype)模式
AbstractBeanFactory.java
//原型的情况下:
else if (mbd.isPrototype()) {
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
//创建完bean的处理
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
上面代码就是spring对原型模式的处理过程,很简单,直接调用#createBean()方法创建一个bean即可
- 先是判断是否是原型(prototype)
- 调用#beforePrototypeCreation(String beanName)方法进行原型创建之前的状态记录
/** Names of beans that are currently in creation. */
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
new NamedThreadLocal<>("Prototype beans currently in creation");
/**
* Callback before prototype creation.
* <p>The default implementation register the prototype as currently in creation.
* @param beanName the name of the prototype about to be created
* @see #isPrototypeCurrentlyInCreation
*/
@SuppressWarnings("unchecked")
protected void beforePrototypeCreation(String beanName) {
//从prototypesCurrentlyInCreation获取当前所有的正在创建的bean
Object curVal = this.prototypesCurrentlyInCreation.get();
//没有正在创建的bean, 然后进行保存
if (curVal == null) {
this.prototypesCurrentlyInCreation.set(beanName);
}
//如果是正在创建的bean是String类型的
else if (curVal instanceof String) {
//进行保存操作
Set<String> beanNameSet = new HashSet<>(2);
beanNameSet.add((String) curVal);
beanNameSet.add(beanName);
this.prototypesCurrentlyInCreation.set(beanNameSet);
}
//是set集合的的话
else {
Set<String> beanNameSet = (Set<String>) curVal;
beanNameSet.add(beanName);
}
}
- 状态记录完成之后,接着是调用#createBean(String beanName, RootBeanDefinition mbd, Object[] args)进行bean的创建,关于详细的创建过程后面在学习
4.bean的创建完成后调用#afterPrototypeCreation(String beanName)进行后置处理操作.
/**
* Callback after prototype creation.
* <p>The default implementation marks the prototype as not in creation anymore.
* @param beanName the name of the prototype that has been created
* @see #isPrototypeCurrentlyInCreation
*/
@SuppressWarnings("unchecked")
protected void afterPrototypeCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
if (curVal instanceof String) {
this.prototypesCurrentlyInCreation.remove();
}
else if (curVal instanceof Set) {
Set<String> beanNameSet = (Set<String>) curVal;
beanNameSet.remove(beanName);
if (beanNameSet.isEmpty()) {
this.prototypesCurrentlyInCreation.remove();
}
}
}
4.紧接着是通过#getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) 方法来获取我们想要的bean对象,关于该方法的详细过程在之前的[spring容器之从bean的实例中获取对象spring容器之从bean的实例中获取对象
)详细的讲解了,感兴趣的可以去看看
其它scope
else {
//获取bean的作用域
String scopeName = mbd.getScope();
final 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 = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
处理的流程都差不多,只是在获取bean的过程不一样,是通过Scope#get(String name, ObjectFactory<?> objectFactory)方法来实现,代码如下:
SimpleThreadScope.java
private final ThreadLocal<Map<String, Object>> threadScope =
new NamedThreadLocal<Map<String, Object>>("SimpleThreadScope") {
@Override
protected Map<String, Object> initialValue() {
return new HashMap<>();
}
};
public Object get(String name, ObjectFactory<?> objectFactory) {
//获取scope
Map<String, Object> scope = this.threadScope.get();
//获取bean实例
Object scopedObject = scope.get(name);
//如果为null的话
if (scopedObject == null) {
//调用ObjectFactory的getobject方法获取实例
scopedObject = objectFactory.getObject();
//保存操作
scope.put(name, scopedObject);
}
return scopedObject;
}
该方法位于org.springframework.beans.factory.config.Scope 接口,在该接口中还有很多方法,感兴趣的可以自己去看看
总结
本篇文章主要是针对于不同作用域的bean进行处理的过程,其实质上都很类似,上面说的也很清楚了,这里就不啰嗦了