Spring中的設計模式-單例模式
單例模式確保一個類在應用中只有一個例項。
我們以依賴注入建立bean例項為線索分析一下spring中單例模式。
Spring的依賴注入(包括lazy-init方式)都是發生在AbstractBeanFactory的getBean裡。getBean的doGetBean方法呼叫getSingleton進行bean的建立。lazy-init方式,在容器初始化時候進行呼叫,非lazy-init方式,在使用者向容器第一次索要bean時進行呼叫。
帶同步的單例模式
下面是單例模式的核心程式碼。
protected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { synchronized (this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { ObjectFactory singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return (singletonObject != NULL_OBJECT ? singletonObject : null); }
從上面程式碼可以看到,spring依賴注入時,使用了雙重判斷加鎖的單例模式,首先從快取中獲取bean例項,如果為null,對快取map加鎖,然後再從快取中獲取bean,如果繼續為null,就建立一個bean。這樣雙重判斷,能夠避免在加鎖的瞬間,有其他依賴注入引發bean例項的建立,從而造成重複建立的結果。
在這裡Spring並沒有使用私有構造方法來建立bean,而是通過singletonFactory.getObject()返回具體beanName對應的ObjectFactory來建立bean。我們一路跟蹤下去,發現實際上是呼叫了AbstractAutowireCapableBeanFactory的doCreateBean方法,返回了BeanWrapper包裝並建立的bean例項。
(ObjectFactory主要檢查是否有使用者定義的BeanPostProcessor後處理內容,並在建立bean時進行處理,如果沒有,就直接返回bean本身)
見如下程式碼:
8行建立bean例項返回給BeanWrapper
30行addSingletonFactory增加beanName和ObjectFactory的鍵值對應關係。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) { // Instantiate the bean. BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null); Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null); // Allow post-processors to modify the merged bean definition. synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); mbd.postProcessed = true; } } // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isDebugEnabled()) { logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } addSingletonFactory(beanName, new ObjectFactory() { public Object getObject() throws BeansException { return getEarlyBeanReference(beanName, mbd, bean); } }); }....
getEarlyBeanReference獲取bean的所有後處理器,並進行處理。如果是SmartInstantiationAwareBeanPostProcessor型別,就進行處理,如果沒有相關處理內容,就返回預設的實現。
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
if (exposedObject == null) {
return exposedObject;
}
}
}
}
return exposedObject;
}
另外,在Spring的其他程式碼中也有使用的單例模式,如AOP的切點定義中。
公有靜態成員,私有建構函式的單例模式。
class TruePointcut implements Pointcut, Serializable {
private static final TruePointcut INSTANCE = new TruePointcut();
/**
* Enforce Singleton pattern.
*/
private TruePointcut() {
}
....
public static TruePointcut getInstance(){
return INSTANCE;
}
}
上面的程式碼可以改成:靜態工廠方法的單例模式
class TruePointcut implements Pointcut, Serializable {
private static final TruePointcut INSTANCE = new TruePointcut();
/**
* Enforce Singleton pattern.
*/
private TruePointcut() {
}
....
public static TruePointcut getInstance(){
return INSTANCE;
}
}
或者改成:用列舉實現單例模式
enum TruePointcut implements Pointcut, Serializable {
INSTANCE ;
...
}