有關(guān)Spring加載bean系列债沮,今天這是最后一篇了,主要接上篇對(duì)于從Spring容器中獲取Bean的一些細(xì)節(jié)實(shí)現(xiàn)的補(bǔ)充晓铆。
- 《Spring讀書(shū)筆記——bean加載》——Spring如何加載消化一個(gè)xml配置文件
- 《Spring讀書(shū)筆記——bean解析》——Spring如何將xml文件的各種標(biāo)簽轉(zhuǎn)換為BeanDefinition并注冊(cè)到Spring容器下
- 《Spring讀書(shū)筆記——bean創(chuàng)建(上)》——概述Spring如何從容器中取出需要的那個(gè)Bean
從緩存中加載單例
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
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對(duì)于單例bean出現(xiàn)循環(huán)依賴(lài)的解決方法铅檩。如果出現(xiàn)上面我們介紹的A->B->C->A的情況,那是不是說(shuō)Spring就無(wú)能為力了粱玲,顯然Spring沒(méi)有那么弱躬柬。那么Spring是怎么做的?
鑒于單例bean的循環(huán)依賴(lài)問(wèn)題密幔,Spring創(chuàng)建bean的原則是不等bean創(chuàng)建完成就會(huì)將bean的ObjectFactory提前曝光加入到緩存中楔脯,一旦有某個(gè)bean創(chuàng)建時(shí)需要依賴(lài)這個(gè)bean了,那么就可以直接使用ObjectFactory胯甩。
簡(jiǎn)單說(shuō)昧廷,創(chuàng)建bean的時(shí)候,就是打包快遞發(fā)貨偎箫,主管為了知道你今天要派發(fā)多少個(gè)包裹木柬,為了節(jié)省大家時(shí)間以及以免統(tǒng)計(jì)漏掉的情況。你可以先拿出一個(gè)包裹箱子淹办,上面寫(xiě)上要寄收件人眉枕、收貨地址、聯(lián)系方式等等怜森,但是這時(shí)候還沒(méi)有往里面打包真正的快遞速挑。
這里曝光的bean就相當(dāng)于這個(gè)快遞箱子。
好了副硅,知道了這個(gè)原則之后姥宝,我們就好理解代碼了。
首先從singletonObjects中獲取實(shí)例恐疲,取不到則從earlySingletonObjects中獲取腊满,仍然取不到,我們還可以到singletonFactories中獲取相應(yīng)的ObjectFactory培己,在調(diào)用這個(gè)ObjectFactory的getObject方法來(lái)創(chuàng)建bean碳蛋。
然后將其加入到earlySingletonObjects中,在將其從singletonFactories中刪除省咨。
想必肃弟,你已經(jīng)被這些用來(lái)存儲(chǔ)和刪除的集合搞瘋了,沒(méi)關(guān)系茸炒,我們來(lái)理一下:
- singletonObjects
/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);
用于保存BeanName和創(chuàng)建bean實(shí)例之間的關(guān)系愕乎。
- singletonFactories:
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory> singletonFactories = new HashMap<String, ObjectFactory>(16);
用于保存BeanName和創(chuàng)建bean的工廠之間的關(guān)系
- earlySingletonObjects:
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
用于保存BeanName和創(chuàng)建bean的工廠之間的關(guān)系阵苇,與singletonObjects的區(qū)別是當(dāng)一個(gè)bean被放入這個(gè)集合后,可以用于其他bean做循環(huán)依賴(lài)檢查
bean實(shí)例化
我們從緩存中拿到bean之后感论,就需要根據(jù)bean的不同類(lèi)型做不同的處理绅项,返回相應(yīng)的bean,實(shí)現(xiàn)這個(gè)功能的就是getObjectForBeanInstance方法
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
- 首先檢測(cè)指定的beanName是否是工廠bean相關(guān)比肄,如果既不是工廠bean又是以"&"開(kāi)頭快耿,則校驗(yàn)失敗,拋出異常
- 如果這個(gè)bean不是工廠Bean(FactoryBean)芳绩,那么就直接返回bean實(shí)例
- 剩下代碼就是處理FactoryBean掀亥,我們順著這樣的順序依次來(lái)到getObjectForBeanInstance->getObjectFromFactoryBean->doGetObjectFromFactoryBean
private Object doGetObjectFromFactoryBean(
final FactoryBean factory, final String beanName, final boolean shouldPostProcess)
throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
return factory.getObject();
}
}, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null && isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
if (object != null && shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of the FactoryBean's object failed", ex);
}
}
return object;
}
這么長(zhǎng)的代碼,如果嫌累妥色,就只看factory.getObject()這行就好搪花,這詮釋了FactoryBean的加載時(shí)通過(guò)factory.getObject的方式獲取到對(duì)應(yīng)的bean實(shí)例的。
如何創(chuàng)建單例bean
在上篇的doGetBean方法中嘹害,如果從緩存中加載不到撮竿,那么我們就需要老老實(shí)實(shí)的從頭開(kāi)始加載bean了,對(duì)于單例bean的加載就都在這里實(shí)現(xiàn)了
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
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;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
創(chuàng)建bean
我們從AbstractBeanFactory的createBean方法來(lái)到了AbstractAutowiredCapableBeanFactory的createbean方法笔呀,而真正的創(chuàng)建bean其實(shí)在doCreateBean方法中
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);}});}// Initialize the bean instance. Object exposedObject = bean;try {populateBean(beanName, mbd, instanceWrapper);if (exposedObject != null) {exposedObject = initializeBean(beanName, exposedObject, mbd);}}catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {throw (BeanCreationException) ex;}else {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);}}if (earlySingletonExposure) {Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {if (exposedObject == bean) {exposedObject = earlySingletonReference;}else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {String[] dependentBeans = getDependentBeans(beanName);Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);for (String dependentBean : dependentBeans) {if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);}}if (!actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName,"Bean with name '" + beanName + "' has been injected into other beans [" +StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +"] in its raw version as part of a circular reference, but has eventually been " +"wrapped. This means that said other beans do not use the final version of the " +"bean. This is often the result of over-eager type matching - consider using " +"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");}}}}// Register bean as disposable. try {registerDisposableBeanIfNecessary(beanName, bean, mbd);}catch (BeanDefinitionValidationException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);}return exposedObject;}
- 如果是單例Bean幢踏,那么首先是從factoryBeanInstanceCache中清除該beanName對(duì)應(yīng)的記錄
- 實(shí)例化bean,將BeanDefinition轉(zhuǎn)換為BeanWrapper對(duì)象
- bean合并后的處理
- 解決循環(huán)依賴(lài)問(wèn)題
- 屬性填充许师,將所有屬性填充到bean的實(shí)例中
這個(gè)方法房蝉,本身不算長(zhǎng),但是層層深入就會(huì)發(fā)現(xiàn)其下面包羅了創(chuàng)建bean的諸多繁雜的細(xì)節(jié)(這塊自己看的也是云里霧里微渠,就不往下延伸擴(kuò)展了)搭幻。
雖然對(duì)于Spring加載bean,我只寫(xiě)了四篇逞盆,但是其內(nèi)部實(shí)現(xiàn)遠(yuǎn)比我表述的要復(fù)雜的多粗卜。
看源碼確實(shí)很煎熬,對(duì)于目前看不懂的地方要么多看幾遍纳击,要么先跳過(guò)。閱讀代碼的過(guò)程中要懂得取舍攻臀,對(duì)于非重點(diǎn)部分比如日志或者異常處理可以先忽略焕数,沿著一條主線往下看,最主要是先弄懂代碼的只要意圖刨啸。
Spring的bean加載代碼量雖然巨大堡赔,但是思路還是比較清晰的,我們知道Spring如何加載xml然后解析xml设联,再到如何把xml的元素轉(zhuǎn)為自己的BeanDefinition善已,最后又是如何取出對(duì)應(yīng)的beanName然后返回一個(gè)bean實(shí)例供容器使用的灼捂。
網(wǎng)上有一位大神用一張圖就把整個(gè)過(guò)程畫(huà)出來(lái)了
注:圖片來(lái)源http://blog.csdn.net/zghwaicsdn/article/details/50910384