Spring BeanFactory對於含有@RefreshScope註解的bean加載
Spring BeanFactory對於Bean的加載是大致分爲三種的,第一種:單例bean,Scope爲Singleton,第二種:多例bean,Scope爲Prototype,然後就是第三種,除上述兩類的都屬於第三種,其中就有Scope爲refresh的bean,即被@RefreshScope註解過的bean,BeanFactory對於Scope爲refresh的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);
}
分析如下:
- 1.首先根據BeanDefinition獲取scopeName,然後從Scope實例列表裏面獲取到相應的實例,針對@RefreshScope而言,scopeName爲refresh,Scope實例爲RefreshScope類型的實例
- 2.接下來通過Scope的get(String name, ObjectFactory<?> objectFactory)方法獲取實例,如果獲取不到將會通過傳遞的ObjectFactory工廠對象創建一個實例(創建的具體過程這裏不贅述)
RefreshScope類詳解
RefreshScope是繼承的GenericScope的get(String name, ObjectFactory<?> objectFactory)方法,GenericScope中會爲bean做一個簡單的緩存,如下:
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
BeanLifecycleWrapper value = this.cache.put(name,
new BeanLifecycleWrapper(name, objectFactory));
this.locks.putIfAbsent(name, new ReentrantReadWriteLock());
try {
return value.getBean();
}
catch (RuntimeException e) {
this.errors.put(name, e);
throw e;
}
}
分析如下:
- 1.初始化一個管理bean生命週期的BeanLifecycleWrapper實例,如果不存在這個beanName的緩存的情況下會將這個BeanLifecycleWrapper實例放入BeanLifecycleWrapperCache緩存(其實這裏有點缺陷,就是並不需要每次去初始化一個BeanLifecycleWrapper實例)
- 2.如果不存在這個beanName對應的讀寫鎖,將會初始化一個ReentrantReadWriteLock放入locks這個map集合中
- 3.通過BeanLifecycleWrapper的getBean()方法獲取bean
- 4.如果有異常,先統計異常然後再重新拋出去
BeanLifecycleWrapper的getBean()
public Object getBean() {
if (this.bean == null) {
synchronized (this.name) {
if (this.bean == null) {
this.bean = this.objectFactory.getObject();
}
}
}
return this.bean;
}
其實就是通過對象創建工廠ObjectFactory創建一個新的bean(這裏的雙重檢查鎖也有點問題,bean字段並沒有用volatile聲明,多線程創建的話即使有某個線程創建成功了,其他線程也感知不到)
由此可見,如果BeanLifecycleWrapperCache中關於beanName的緩存的BeanLifecycleWrapper實例不變的話,那麼將一直獲取的是上述過程創建的bean(BeanLifecycleWrapper沒有提供公開的setBean方法,因此基本不用擔心BeanLifecycleWrapper緩存的bean實例被重新設置爲null)
RefreshScope的refresh與refreshAll
@ManagedOperation(description = "Dispose of the current instance of bean name "
+ "provided and force a refresh on next method execution.")
public boolean refresh(String name) {
if (!name.startsWith(SCOPED_TARGET_PREFIX)) {
// User wants to refresh the bean with this name but that isn't the one in the
// cache...
name = SCOPED_TARGET_PREFIX + name;
}
// Ensure lifecycle is finished if bean was disposable
if (super.destroy(name)) {
this.context.publishEvent(new RefreshScopeRefreshedEvent(name));
return true;
}
return false;
}
@ManagedOperation(description = "Dispose of the current instance of all beans "
+ "in this scope and force a refresh on next method execution.")
public void refreshAll() {
super.destroy();
this.context.publishEvent(new RefreshScopeRefreshedEvent());
}
分析如下:
- 1.refresh專門針對某一個bean的,在成功銷燬之後發推送一個針對該bean的RefreshScopeRefreshedEvent事件
- 2.refreshAll會銷燬所有Scope爲refresh的bean,在銷燬完成之後會推送一個RefreshScopeRefreshedEvent事件
refresh bean的銷燬
單個銷燬
protected boolean destroy(String name) {
BeanLifecycleWrapper wrapper = this.cache.remove(name);
if (wrapper != null) {
Lock lock = this.locks.get(wrapper.getName()).writeLock();
lock.lock();
try {
wrapper.destroy();
}
finally {
lock.unlock();
}
this.errors.remove(name);
return true;
}
return false;
}
分析如下:
- 1.從BeanLifecycleWrapperCache中移除針對該bean設置的緩存
- 2.如果存在該bean的緩存,先獲取到讀寫鎖,然後加鎖並執行BeanLifecycleWrapper的destroy()方法,執行完成之後解鎖,移除錯誤列表errors中該bean對應的錯誤信息
全部銷燬
@Override
public void destroy() {
List<Throwable> errors = new ArrayList<Throwable>();
Collection<BeanLifecycleWrapper> wrappers = this.cache.clear();
for (BeanLifecycleWrapper wrapper : wrappers) {
try {
Lock lock = this.locks.get(wrapper.getName()).writeLock();
lock.lock();
try {
wrapper.destroy();
}
finally {
lock.unlock();
}
}
catch (RuntimeException e) {
errors.add(e);
}
}
if (!errors.isEmpty()) {
throw wrapIfNecessary(errors.get(0));
}
this.errors.clear();
}
跟單個銷燬是差不多的過程,不贅述
BeanLifecycleWrapper之destroy()
public void destroy() {
if (this.callback == null) {
return;
}
synchronized (this.name) {
Runnable callback = this.callback;
if (callback != null) {
callback.run();
}
this.callback = null;
this.bean = null;
}
}
執行銷燬方法,並將緩存的bean以及callback設置爲null,下一次獲取bean的話將會重新執行ObjectFactory的getObject()方法獲取新的bean
註冊銷燬方法
// BeanLifecycleWrapper
public void setDestroyCallback(Runnable callback) {
this.callback = callback;
}
// GenericScope
@Override
public void registerDestructionCallback(String name, Runnable callback) {
BeanLifecycleWrapper value = this.cache.get(name);
if (value == null) {
return;
}
value.setDestroyCallback(callback);
}
// AbstractBeanFactory
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
if (mbd.isSingleton()) {
// Register a DisposableBean implementation that performs all destruction
// work for the given bean: DestructionAwareBeanPostProcessors,
// DisposableBean interface, custom destroy method.
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
else {
// A bean with a custom scope...
Scope scope = this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
}
scope.registerDestructionCallback(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
}
}
在看到registerDisposableBeanIfNecessary這個方法時,相信看過之前寫的一篇Spring bean銷燬的文章的朋友會比較熟系,文章地址:Spring bean銷燬的過程