前言
上一篇文章,跟大家一起阅读了一下Spring中getBean方法前面的流程,今天这篇文章,接着跟大家一起阅读它后面的流程。
getBean方法最终会调用doGetBean方法,其中有三个创建普通bean实例的关键方法。
1 单例bean
在Spring中,使用最多的可能是单例bean,即在Spring容器中,该bean从始至终都只有一个实例。
如果没有对bean的scope做特别的指定,Spring默认的scope就是单例的。是通过isSingleton方法判断的:
这个小技巧可以在工作中使用一下。
有时候默认值,可以不用设置,通过isSingleton方法的 || SCOPE_DEFAULT.equals(this.scope)可以实现默认值的情况,避免有很多地方需要设置默认值的情况。
单例bean是通过下面的方法实例化的:
它的源码逻辑比较清晰。
其中getSingleton是获取单例bean实例的主要方法,使用lamda表达式调用了createBean方法创建bean,最后通过getObjectForBeanInstance方法,处理FactoryBean的情况,上一篇文章专门介绍过的。
publicObjectgetSingleton(StringbeanName,ObjectFactory<?>singletonFactory){
//判断beanName如果为空则抛异常
Assert.notNull(beanName,"Beannamemustnotbenull");
//加锁
synchronized(this.singletonObjects){
//从一级缓存中获取bean实例
ObjectsingletonObject=this.singletonObjects.get(beanName);
//如果bean实例为空
if(singletonObject==null){
if(this.singletonsCurrentlyInDestruction){
thrownewBeanCreationNotAllowedException(beanName,
"Singletonbeancreationnotallowedwhilesingletonsofthisfactoryareindestruction"+
"(DonotrequestabeanfromaBeanFactoryinadestroymethodimplementation!)");
}
//如果beanName在正在创建的集合中,则抛异常
beforeSingletonCreation(beanName);
booleannewSingleton=false;
...
try{
//回调外面的方法
singletonObject=singletonFactory.getObject();
newSingleton=true;
}
catch(IllegalStateExceptionex){
//如果创建对象出现异常,则从一级缓存中获取bean实例
singletonObject=this.singletonObjects.get(beanName);
//如果bean实例为空,则抛异常
if(singletonObject==null){
throwex;
}
}
catch(BeanCreationExceptionex){
throwex;
}
finally{
//将beanName从正在创建的集合中删除
afterSingletonCreation(beanName);
}
if(newSingleton){
//将bean实例放入一级缓存
addSingleton(beanName,singletonObject);
}
}
//返回bean实例
returnsingletonObject;
}
}下面用一张图总结一下,上面这段代码中的关键流程:
其中createBean方法是创建bean的核心方法,逻辑非常多,下一篇文章会有专门介绍,这里就不过多介绍了。
2 多例bean
如果定义bean的时候scope配置成SCOPE_PROTOTYPE,则Spring创建的bean是多例的。
它里面包含的逻辑也非常清晰,只有:beforePrototypeCreation、createBean、afterPrototypeCreation和getObjectForBeanInstance,这4个方法。
beforePrototypeCreation方法很简单:
它会将beanName保存到prototypesCurrentlyInCreation当中。
而prototypesCurrentlyInCreation其实是一个ThreadLocal对象。
在afterPrototypeCreation方法中:
将prototypesCurrentlyInCreation中的beanName删除了。
这是一个非常标准的ThreadLocal的用法。
在try中set值,在finally中remove该值,并且ThreadLocal对象定义成private final的。
假如不用ThreadLocal,则需要把prototypesCurrentlyInCreation在createBean方法中,一层层往下传递下去,有可能传递的层级非常非常深,让代码不太好维护。
多例bean的代码跟单例的区别是,这里没有使用Spring的一级缓存,每一次请求,都会调用一次createBean方法创建一次bean实例。
3 自定义Scope
如果bean定义的scope不是单例,也不是多例的,则会走自定义Scope创建bean的逻辑:
它会先获取bean定义时指定的scopeName,然后从scopes集合中获取相应的Scope对象。
scopes其实是一个map。
而Scope其实是一个接口:
最主要的是get和remove方法。
我们一起看看哪些类型实现了Scope接口:
其中:
- AbstractRequestAttributesScope:作用范围是一个request请求。
- SessionScope:作用范围是服务器的session当中。
- ServletContextScope:作用范围是整个应用当中。
这里以AbstractRequestAttributesScope为例:
它的get方法中,先从request中获取属性集合,然后从属性集合中,根据name和scope,获取具体的对象。
如果对象为空,则通过objectFactory.getObject方法获取一个对象,重新设置到属性集合中。
最后返回获取的对象。
4 自定义Scope实战
比如,我们想在同一个线程中从spring容器获取到的bean都是同一个对象,该怎么办?
这就需要自定义Scope了。
第一步实现Scope接口:
publicclassThreadLocalScopeimplementsScope{
privatestaticfinalThreadLocalTHREAD_LOCAL_SCOPE=newThreadLocal();
@Override
publicObjectget(Stringname,ObjectFactory<?>objectFactory){
Objectvalue=THREAD_LOCAL_SCOPE.get();
if(value!=null){
returnvalue;
}
Objectobject=objectFactory.getObject();
THREAD_LOCAL_SCOPE.set(object);
returnobject;
}
@Override
publicObjectremove(Stringname){
THREAD_LOCAL_SCOPE.remove();
returnnull;
}
@Override
publicvoidregisterDestructionCallback(Stringname,Runnablecallback){
}
@Override
publicObjectresolveContextualObject(Stringkey){
returnnull;
}
@Override
publicStringgetConversationId(){
returnnull;
}
}第二步将新定义的Scope注入到spring容器中:
@Component
publicclassThreadLocalBeanFactoryPostProcessorimplementsBeanFactoryPostProcessor{
@Override
publicvoidpostProcessBeanFactory(ConfigurableListableBeanFactorybeanFactory)throwsBeansException{
beanFactory.registerScope("threadLocalScope",newThreadLocalScope());
}
}第三步使用新定义的Scope:
@Scope("threadLocalScope")
@Service
publicclassCService{
publicvoidadd(){
}
}4 adaptBeanInstance方法
在doGetBean方法中,最后有一个比较特殊的方法:adaptBeanInstance。
它会校验当前的bean实例,跟传入的Class类型是否匹配。
比如:通过getBean(a,B.class);获取bean时,获取到的bean实例的类型是A,则传入的Class是B,这种情况就不匹配,需要报错,提示用户。
先通过getTypeConverter方法获取TypeConverter:
如果用户自定义了typeConverter,则直接使用用户自定义的typeConverter。如果用户没有自定义typeConverter,则使用SimpleTypeConverter。
再调用它的convertIfNecessary做bean和Class是否匹配的校验。
后面会有专题介绍TypeConverter的,敬请期待。
好了,今天的内容先分享到这里,我们下期再见。
未完。。。待续。。。