Spring源码阅读笔记06:bean加载之如何获取单例
前面的文章中主要分析Spring是如何加載配置文件以及將其轉(zhuǎn)化成BeanDefinition的,從本文開(kāi)始,我們繼續(xù)研究Spring是如何創(chuàng)建bean的。bean加載的功能實(shí)現(xiàn)遠(yuǎn)比bean的解析要復(fù)雜得多,會(huì)占用多篇文章的篇幅來(lái)進(jìn)行分析,按照流程大致可以分為獲取緩存bean、準(zhǔn)備創(chuàng)建bean、創(chuàng)建bean這幾個(gè)部分,本文會(huì)在瀏覽整個(gè)bean獲取過(guò)程的基礎(chǔ)上分析一下獲取緩存單例的邏輯,更復(fù)雜的bean創(chuàng)建的邏輯留待后面文章分析。
1. bean獲取過(guò)程概覽
對(duì)于加載bean的功能,在Spring中的調(diào)用方式為:
TestBean myTestBean = (TestBean) xmlBeanFactory.getBean("testBean");
這句代碼背后是怎樣實(shí)現(xiàn)的呢?我們可以先快速體驗(yàn)一下Spring中代碼是如何實(shí)現(xiàn)的,這部分的代碼是實(shí)現(xiàn)在AbstractBeanFactory中:
1 public Object getBean(String name) throws BeansException {
2 return doGetBean(name, null, null, false);
3 }
4
5 protected <T> T doGetBean(
6 final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
7 throws BeansException {
8 // 獲取對(duì)應(yīng)的beanName
9 final String beanName = transformedBeanName(name);
10 Object bean;
11 /* 檢查緩存中或者實(shí)例工廠中是否有對(duì)應(yīng)的實(shí)例
12 * 為什么首先會(huì)使用這段代碼呢,
13 * 因?yàn)樵趧?chuàng)建單例bean的時(shí)候會(huì)存在依賴注入的情況,而在創(chuàng)建依賴的時(shí)候?yàn)榱吮苊庋h(huán)依賴,
14 * Spring創(chuàng)建bean的原則是不等bean創(chuàng)建完成就會(huì)將創(chuàng)建bean的ObjectFact提早曝光
15 * 也就是將objectFactory加入到緩存中,
16 * 一旦下個(gè)bean創(chuàng)建時(shí)候需要依賴上個(gè)bean則直接使用objectFactory
17 **/
18 // Eagerly check singleton cache for manually registered singletons.
19 // 直接嘗試從緩存獲取或者singletonFactories中的ObjectFactory中獲取
20 Object sharedInstance = getSingleton(beanName);
21 if (sharedInstance != null && args == null) {
22 if (logger.isDebugEnabled()) {
23 if (isSingletonCurrentlyInCreation(beanName)) {
24 logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
25 "' that is not fully initialized yet - a consequence of a circular reference");
26 }
27 else {
28 logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
29 }
30 }
31 // 返回對(duì)應(yīng)的實(shí)例,有時(shí)候存在諸如BeanFactory的情況并不是直接返回實(shí)例本身,而是返回指定方法返回的實(shí)例
32 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
33 }
34
35 else {
36 // 只有在單例情況才會(huì)嘗試解決循環(huán)依賴,原型模式情況下,如果存在
37 // A中有B的屬性,B中有A的屬性,那么當(dāng)依賴注入的時(shí)候,就會(huì)產(chǎn)生當(dāng)A還未創(chuàng)建完的時(shí)候由于
38 // 對(duì)于B的創(chuàng)建而再次返回創(chuàng)建A,造循環(huán)依賴,也就是下面的情況
39 // Fail if we're already creating this bean instance:
40 // We're assumably within a circular reference.
41 if (isPrototypeCurrentlyInCreation(beanName)) {
42 throw new BeanCurrentlyInCreationException(beanName);
43 }
44
45 // Check if bean definition exists in this factory.
46 BeanFactory parentBeanFactory = getParentBeanFactory();
47 // 如果beanDefinitionMap中也就是在所有已經(jīng)加載的類中不包括beanName則嘗試從parentBeanFactory中檢測(cè)
48 if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
49 // Not found -> check parent.
50 String nameToLookup = originalBeanName(name);
51 // 遞歸到BeanFactory中尋找
52 if (args != null) {
53 // Delegation to parent with explicit args.
54 return (T) parentBeanFactory.getBean(nameToLookup, args);
55 }
56 else {
57 // No args -> delegate to standard getBean method.
58 return parentBeanFactory.getBean(nameToLookup, requiredType);
59 }
60 }
61 // 如果不是僅僅做類型檢查則是創(chuàng)建bean,這里要進(jìn)行記錄
62 if (!typeCheckOnly) {
63 markBeanAsCreated(beanName);
64 }
65
66 try {
67 // 將存儲(chǔ)XML配置文件的GernericBeanDefinition轉(zhuǎn)換為RootBeanDefinition,如果指定BeanName是子Bean的話同時(shí)會(huì)合并父類的相關(guān)屬性
68 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
69 checkMergedBeanDefinition(mbd, beanName, args);
70
71 // Guarantee initialization of beans that the current bean depends on.
72 // 確保當(dāng)前bean依賴的bean已經(jīng)實(shí)例化了,通過(guò)遞歸來(lái)實(shí)現(xiàn)
73 String[] dependsOn = mbd.getDependsOn();
74 if (dependsOn != null) {
75 for (String dependsOnBean : dependsOn) {
76 getBean(dependsOnBean);
77 // 緩存依賴調(diào)用
78 registerDependentBean(dependsOnBean, beanName);
79 }
80 }
81 // 實(shí)例化依賴的bean后便可以實(shí)例化mbd本身了
82 // singleton模式的創(chuàng)建
83 // Create bean instance.
84 if (mbd.isSingleton()) {
85 sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
86 public Object getObject() throws BeansException {
87 try {
88 return createBean(beanName, mbd, args);
89 }
90 catch (BeansException ex) {
91 // Explicitly remove instance from singleton cache: It might have been put there
92 // eagerly by the creation process, to allow for circular reference resolution.
93 // Also remove any beans that received a temporary reference to the bean.
94 destroySingleton(beanName);
95 throw ex;
96 }
97 }
98 });
99 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
100 }
101 else if (mbd.isPrototype()) {
102 // It's a prototype -> create a new instance.
103 Object prototypeInstance = null;
104 try {
105 beforePrototypeCreation(beanName);
106 prototypeInstance = createBean(beanName, mbd, args);
107 }
108 finally {
109 afterPrototypeCreation(beanName);
110 }
111 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
112 }
113
114 else {
115 String scopeName = mbd.getScope();
116 final Scope scope = this.scopes.get(scopeName);
117 if (scope == null) {
118 throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
119 }
120 try {
121 Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
122 public Object getObject() throws BeansException {
123 beforePrototypeCreation(beanName);
124 try {
125 return createBean(beanName, mbd, args);
126 }
127 finally {
128 afterPrototypeCreation(beanName);
129 }
130 }
131 });
132 bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
133 }
134 catch (IllegalStateException ex) {
135 throw new BeanCreationException(beanName,
136 "Scope '" + scopeName + "' is not active for the current thread; " +
137 "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
138 ex);
139 }
140 }
141 }
142 catch (BeansException ex) {
143 cleanupAfterBeanCreationFailure(beanName);
144 throw ex;
145 }
146 }
147
148 // Check if required type matches the type of the actual bean instance.
149 if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
150 try {
151 return getTypeConverter().convertIfNecessary(bean, requiredType);
152 }
153 catch (TypeMismatchException ex) {
154 if (logger.isDebugEnabled()) {
155 logger.debug("Failed to convert bean '" + name + "' to required type [" +
156 ClassUtils.getQualifiedName(requiredType) + "]", ex);
157 }
158 throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
159 }
160 }
161 return (T) bean;
162 }
其實(shí)我想說(shuō)我第一次看到這里,內(nèi)心是崩潰的,這個(gè)方法的代碼量。。。bean的加載經(jīng)歷了一個(gè)相當(dāng)復(fù)雜的過(guò)程,其中涉及到各種各樣的考慮,我也只是初略地了解一下Spring加載bean的過(guò)程,這里先總結(jié)一下所涉及的步驟吧:
轉(zhuǎn)換對(duì)應(yīng)beanName。
這部分對(duì)應(yīng)上面第9行,這里為什么要先轉(zhuǎn)換呢?因?yàn)檫@里傳入的參數(shù)可能是別名,也可能是FactoryBean(關(guān)于這個(gè)后面會(huì)專門(mén)總結(jié)),所以需要進(jìn)行專門(mén)的解析,解析操作如下:
去除FactoryBean的修飾符,也就是如果name="&aa",那么會(huì)首先去除&而使name="aa";
取指定alias所表示的最終beanName,例如別名A指向名稱為B的beanvxxx則返回B;若別名A指向別名B,別名B又指向名稱為C的bean則返回C;
嘗試從緩存中加載單例。
這部分對(duì)應(yīng)上面第20行代碼。我們知道,Spring對(duì)bean創(chuàng)建定義了多種作用域:
singleton,單例模式;
prototype,多例模式;
request,表示針對(duì)每一次HTTP請(qǐng)求都會(huì)產(chǎn)生一個(gè)新的bean,同時(shí)該bean僅在當(dāng)前HTTP request內(nèi)有效;
session,表示針對(duì)每一次HTTP請(qǐng)求都會(huì)產(chǎn)生一個(gè)新的bean,同時(shí)該bean僅在當(dāng)前HTTP session內(nèi)有效;
其中單例在一個(gè)Spring容器內(nèi)只會(huì)被創(chuàng)建一次,后續(xù)再獲取bean,就直接從單例緩存中獲取了。這里也只是嘗試加載,首先嘗試從緩存中加載,如果加載不成功則再次嘗試從singletonFactories中加載。因?yàn)樵趧?chuàng)建單例bean的時(shí)候會(huì)存在依賴注入的情況,而在創(chuàng)建依賴的時(shí)候?yàn)榱吮苊庋h(huán)依賴,在Spring中創(chuàng)建bean的原則是不等bean創(chuàng)建完成就會(huì)將創(chuàng)建bean的ObjectFactory提早曝光加入到緩存中,一旦下一個(gè)bean創(chuàng)建時(shí)候需要依賴上一個(gè)bean則直接使用ObjectFactory(后面會(huì)對(duì)循環(huán)依賴進(jìn)行重點(diǎn)分析)。
bean的實(shí)例化。
這部分對(duì)應(yīng)上面第32行代碼。如果從緩存中得到了bean的原始狀態(tài),則需要對(duì)bean進(jìn)行實(shí)例化。為什么緩存中記錄的只是最原始的bean狀態(tài),而并不一定是我們最終想要的bean呢?這是因?yàn)槿绻覀冃枰獙?duì)工廠bean進(jìn)行處理,那么這里得到的其實(shí)是工廠bean的初始狀態(tài),但是我們真正需要的是工廠bean中定義的factory-method方法中返回的bean,而getObjectForBeanInstance()方法就是完成這個(gè)工作的,這個(gè)后續(xù)也會(huì)詳細(xì)講解的,這里不清楚的可以先跳過(guò)去。
原型模式(即prototype)的依賴檢查。
這部分對(duì)應(yīng)上面第41行代碼。理解這一步的關(guān)鍵在于只有在單例情況下才會(huì)嘗試解決循環(huán)依賴,如果存在A中有B的屬性,B中有A的屬性,那么當(dāng)依賴注入的時(shí)候,就會(huì)產(chǎn)生當(dāng)A還未創(chuàng)建完的時(shí)候因?yàn)閷?duì)于B的創(chuàng)建再次返回創(chuàng)建A,造成循環(huán)依賴,也就是情況:isPrototypeCurrentlyInCreation(beanName)判斷為true。
檢測(cè)parentBeanFactory。
從代碼上看這部分對(duì)應(yīng)上面第46行到58行,如果緩存沒(méi)有數(shù)據(jù)的話就直接轉(zhuǎn)到父類工廠上去加載了,但是這里也別忽略其判斷條件:parentBeanFactory != null && !containsBeanDefinition(beanName)。
其中parentBeanFactory != null即parentBeanFactory如果為空,則其他一切都是浮云,也不會(huì)轉(zhuǎn)到父類工廠去加載;
而!containsBeanDefinition(beanName),則是檢測(cè)當(dāng)前加載的XML配置文件是否包含beanName所對(duì)應(yīng)的配置,如果沒(méi)有就到parentBeanFactory去嘗試下加載,然后再去遞歸的調(diào)用getBean()方法;
將存儲(chǔ)XML配置文件的GernericBeanDefinition轉(zhuǎn)換為RootBeanDefinition。
這部分對(duì)應(yīng)上面的68行。在上文中有分析到,從XML配置文件中讀取到的Bean信息是存儲(chǔ)在GernericBeanDefinition中的,但是所有Bean的后續(xù)處理都是針對(duì)RootBeanDefinition進(jìn)行的,所以這里需要進(jìn)行一個(gè)轉(zhuǎn)換,轉(zhuǎn)換的同時(shí)如果父類bean不為空的話,也會(huì)一并合并父類的屬性。
加載依賴。
這部分對(duì)應(yīng)上面的73到78行。因?yàn)閎ean的初始化過(guò)程中很可能會(huì)用到某些屬性,而某些屬性很可能是動(dòng)態(tài)配置的,并且配置成依賴于其他的bean,那么這個(gè)時(shí)候就有必要先加載依賴的bean,所以,在Spring的加載順序中,在初始化某一個(gè)bean的時(shí)候首先會(huì)初始化這個(gè)bean所對(duì)應(yīng)的所有依賴對(duì)象。
針對(duì)不同的scope進(jìn)行bean的創(chuàng)建。
這部分對(duì)應(yīng)上面的84到138行。我們都知道,在Spring中存在著不同的scope,其中默認(rèn)的是singleton,但是還有些其他的配置諸如prototype、request之類的。在這個(gè)步驟中,Spring會(huì)根據(jù)不同的配置進(jìn)行不同的初始化策略,這部分的過(guò)程很復(fù)雜,我們放到后面的文章中專門(mén)來(lái)解析這部分。
類型轉(zhuǎn)換。
這部分對(duì)應(yīng)上面的149到161行。bean的加載到這一步已經(jīng)基本結(jié)束了,通常對(duì)加載bean的實(shí)際執(zhí)行方法doGetBean()進(jìn)行調(diào)用時(shí)傳入的參數(shù)requiredType是為空,但是還是可能會(huì)存在這樣的情況,即返回的bean其實(shí)是個(gè)String,但是requiredType卻傳入Integer類型,那么這時(shí)候本步驟就會(huì)起作用了,它的功能是將返回的bean轉(zhuǎn)換為requiredType所指定的類型。當(dāng)然,String轉(zhuǎn)換為Integer是最簡(jiǎn)單的一種轉(zhuǎn)換,在Spring中提供了各種各樣的轉(zhuǎn)換器,用戶也可以自己擴(kuò)展轉(zhuǎn)換器來(lái)滿足需求。
經(jīng)過(guò)上面的步驟后bean的加載就結(jié)束了,這個(gè)時(shí)候就可以返回我們所需要的bean了。其中最重要的就是步驟8,針對(duì)不同的scope進(jìn)行bean的創(chuàng)建,這個(gè)后面會(huì)專門(mén)寫(xiě)一篇文章對(duì)這部分進(jìn)行解析,接下來(lái)先來(lái)看一下除此之外的一些主要功能實(shí)現(xiàn)吧。
2. 嘗試從緩存加載單例
前面提到過(guò),單例在同一個(gè)Spring容器內(nèi)只會(huì)被創(chuàng)建一次,所以每次獲取bean時(shí)都會(huì)先嘗試從緩存獲取,未獲取到則會(huì)嘗試從頭加載bean。
這里的步驟是先從緩存singletonObjects獲取,沒(méi)有則再次嘗試從singletonFactories中獲取。因?yàn)樵趧?chuàng)建單例bean的時(shí)候會(huì)存在依賴注入的情況,而在創(chuàng)建依賴bean的時(shí)候?yàn)榱吮苊庋h(huán)依賴,Spring創(chuàng)建bean的原則是不等bean創(chuàng)建完成就會(huì)將創(chuàng)建bean的ObjectFactory提早曝光加入到緩存中,一旦下一個(gè)bean創(chuàng)建時(shí)需要依賴上個(gè)bean,則直接使用ObjectFactory。
public Object getSingleton(String beanName) {
// 參數(shù)true設(shè)置允許早期依賴
return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 檢查緩存中是否存在實(shí)例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 如果為空,則鎖定全局變量并進(jìn)行處理
synchronized (this.singletonObjects) {
// 如果此bean正在加載則不處理
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 當(dāng)某些方法需要提前初始化的時(shí)候則會(huì)調(diào)用addSingletonFactory方法將對(duì)應(yīng)的ObjectFactory初始化策略存儲(chǔ)在singletonFactories
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 調(diào)用預(yù)先設(shè)定的getObject方法
singletonObject = singletonFactory.getObject();
// 記錄在緩存中,earlySingletonObjects和singletonFactories互斥
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
這里首先嘗試從singletonObjects里面獲取實(shí)例,如果獲取不到再?gòu)膃arlySingletonObjects里面獲取,如果還獲取不到,再嘗試從singletonFactories里面獲取beanName對(duì)應(yīng)的ObjectFactory,然后調(diào)用這個(gè)ObjectFactory的getObject()來(lái)創(chuàng)建bean,并放到earlySingletonObjects里面去,并且從singletonFacotories里面remove掉這個(gè)ObjectFactory,而對(duì)于后續(xù)的所有內(nèi)存操作都只是為了循環(huán)依賴檢測(cè)時(shí)使用,也就是在allowEarlyReference為true的情況下才會(huì)使用。
這里涉及用于存儲(chǔ)bean的不同的map,簡(jiǎn)單解釋如下:
singletonObjects:用于保存BeanName和bean實(shí)例之間的關(guān)系,bean name-->bean instance;
singletonFactories:用于保存BeanName和創(chuàng)建bean的工廠之間的關(guān)系,bean name-->ObjectFactory;
earlySingletonObjects:也是保存BeanName和bean實(shí)例之間的關(guān)系,與singletonObjects的不同之處在于,當(dāng)一個(gè)單例bean被放到這里面后,那么當(dāng)bean還在創(chuàng)建過(guò)程中,就可以通過(guò)getBean方法獲取到了,其目的是用來(lái)檢測(cè)循環(huán)引用;
registeredSingletons:用來(lái)保存當(dāng)前所有已注冊(cè)的bean;
這里從緩存獲取到object,并不一定是我們最終想要的bean,比如這個(gè)bean的類型是FactoryBean,這其實(shí)是bean的初始狀態(tài),我們真正需要的是工廠bean中定義的factory-method方法中返回的bean,而getobjectForBeanInstance方法就是完成這個(gè)工作的。關(guān)于工廠bean,這里再說(shuō)幾句。
2.1 FactoryBean
一般情況下,Spring通過(guò)反射機(jī)制利用beanDefinition的class屬性指定的實(shí)現(xiàn)類來(lái)實(shí)例化bean。如果按照傳統(tǒng)的方式,如果一個(gè)bean有很多屬性,則需要在<bean>中提供大量的配置信息,配置方式的靈活性是受限的,這時(shí)采用編碼的方式可能會(huì)得到一個(gè)更簡(jiǎn)單的方案。Spring為此提供了一個(gè)org.Springframework.bean.factory.FactoryBean的工廠類接口,用戶可以通過(guò)實(shí)現(xiàn)該接口定制實(shí)例化bean的邏輯。
FactoryBean接口對(duì)于Spring框架來(lái)說(shuō)占有重要地位,其自身就提供了許多FactoryBean的實(shí)現(xiàn),它們隱藏了實(shí)例化一些復(fù)雜bean的細(xì)節(jié),給上層應(yīng)用帶來(lái)了便利。該接口中定義了3個(gè)方法:
T getObject():返回由FactoryBean創(chuàng)建的bean實(shí)例,如果isSingleton()返回true,則該實(shí)例會(huì)放到Spring容器中單例實(shí)例緩存池中;
boolean isSingleton():返回由FactoryBean創(chuàng)建的bean實(shí)例的作用域是singleton還是prototype;
Class<T> getObjectType():返回FactoryBean創(chuàng)建的bean類型;
當(dāng)配置文件中<bean>的class屬性配置的實(shí)現(xiàn)類實(shí)現(xiàn)了FactoryBean接口時(shí),通過(guò)getBean()方法返回的并不是FactoryBean本身,而是FactoryBean#getObject()方法所返回的對(duì)象,相當(dāng)于FactoryBean#getObject()代理了getBean()方法。例如:如果使用傳統(tǒng)方式配置下面Car的<bean>時(shí),Car的每個(gè)屬性分別對(duì)應(yīng)一個(gè)<property>元素標(biāo)簽。
public class Car{
private int masSpeed;
private String brand;
private double price;
// get/set 方法
}
如果用FactoryBean的方式實(shí)現(xiàn)就會(huì)靈活一些,可以通過(guò)逗號(hào)分隔符的方式一次性配置所有屬性:
public class CarFactoryBean implements FactoryBean<Car> {
private String carInfo;
public car getObject() throws Exception {
Car car = new Car();
String[] infos = carInfo.split(",");
car.setBrand(infos[0]);
car.setMaxSpeed(Integer.valueOf(infos[1]));
car.setPrice(Double.valueOf(infos[2]));
return car;
}
public Class<Car> getObectType() {
return Car.class;
}
public boolean inSingleton() {
return false;
}
public String getCarInfo() {
return this.carInfo;
}
// 接收逗號(hào)分隔符設(shè)置屬性信息
public void setCarInfo(String carInfo) {
this.carInfo = carInfo;
}
}
有了這個(gè)CarFactoryBean后,就可以在配置文件中使用下面這種自定義的配置方式進(jìn)行配置了:
<bean id = "car" class = "xxx" carInfo = "保時(shí)捷,400,20000"/>
當(dāng)調(diào)用getBean("car")時(shí),Spring通過(guò)反射機(jī)制發(fā)現(xiàn)CarFactoryBean實(shí)現(xiàn)了FactoryBean的接口,這時(shí)Spring容器就調(diào)用接口方法CarFactoryBean#getObject()返回Car的實(shí)例bean。如果希望獲取CarFactoryBean的實(shí)例,則需要在使用getBean(beanName)方法時(shí)在beanName前面顯示的加上"&"前綴,比如getBean("&car")。
3. FactoryBean的實(shí)例化
在getBean方法中,getObjectForBeanInstance()是個(gè)高頻率使用的方法,無(wú)論是從緩存中獲得bean還是根據(jù)不同的scope策略加載bean。總之,我們得到bean的實(shí)例后要做的第一步就是調(diào)用這個(gè)方法來(lái)檢測(cè)一下正確性,其實(shí)就是用于檢測(cè)當(dāng)前bean是否是FactoryBean類型的bean,如果是,那么需要調(diào)用該bean對(duì)應(yīng)的FactoryBean實(shí)例中的getobject()方法。
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.
// 如果指定的name是工廠相關(guān)(以&為前綴)且beanInstance又不是FactoryBean類型則驗(yàn)證不通過(guò)
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.
// 現(xiàn)在我們有了個(gè)bean的實(shí)例,這個(gè)實(shí)例可能會(huì)是正常的bean或者是FactoryBean
// 如果是FactoryBean我們將使用它創(chuàng)建實(shí)例,但是如果用戶想要直接獲取工廠實(shí)例而不是工廠的getObject方法對(duì)應(yīng)的實(shí)例那么傳入的name應(yīng)該加入前綴&
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
// 加載FactoryBean
Object object = null;
if (mbd == null) {
// 嘗試從緩存中加載bean
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
// 到這里已經(jīng)明確知道beanInstance一定是FactoryBean類型
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// containBeanDefinition檢測(cè)beanDefinitionMap中也就是在所有已經(jīng)加載的類中檢測(cè)是否定義beanName
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
//將存儲(chǔ)XML配置文件的GernericBeanDefinition轉(zhuǎn)換為RootBeanDefinition,如果指定BeanName是子Bean的話同時(shí)會(huì)合并父類的相關(guān)屬性
mbd = getMergedLocalBeanDefinition(beanName);
}
// 是否是用戶定義的而不是應(yīng)用程序本身定義的
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
這部分并沒(méi)有實(shí)質(zhì)性的工作,主要是對(duì)傳入的bean判斷是否是FactoryBean,不是則直接返回,是則將解析bean的工作委托給getObjectFromFactoryBean()。
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
// 如果是單例模式
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (object != null && shouldPostProcess) {
try {
// 調(diào)用objectFactory的后處理器
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
}
this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
}
}
return (object != NULL_OBJECT ? object : null);
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (object != null && shouldPostProcess) {
try {
// 調(diào)用objectFactory的后處理器
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
如上代碼中,如果返回的bean是單例的,那就必須要保證全局唯一,同時(shí),也因?yàn)槭菃卫模圆槐刂貜?fù)創(chuàng)建,可以使用緩存來(lái)提高性能,也就是說(shuō)已經(jīng)加載過(guò)就要記錄下來(lái)以便于下次復(fù)用,否則的話就直接獲取了。
如果判斷返回的bean是單例,為了避免重復(fù)創(chuàng)建,使用了緩存(factoryBeanObjectCache)來(lái)提高性能,如果有則直接獲取。而且必須保證全局唯一,這里使用同步鎖,并且在調(diào)用doGetObjectFromFactoryBean()之后又一次從緩存嘗試獲取,如果有則使用已創(chuàng)建的,并且不會(huì)執(zhí)行后處理器,即調(diào)用postProcessObjectFromFactoryBean()方法,這里面主要是調(diào)用注冊(cè)的BeanPostProcessor的postProcessAfterInitialization方法進(jìn)行處理,我們?cè)趯?shí)際開(kāi)發(fā)過(guò)程中可以針對(duì)此特性設(shè)計(jì)自己的業(yè)務(wù)邏輯。
在上面的方法中還是沒(méi)有真正加載bean的操作,這部分委托給doGetObjectFromFactoryBean()來(lái)完成:
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
// 需要權(quán)限驗(yàn)證
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 {
// 直接調(diào)用getObject()方法
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");
}
return object;
}
在doGetObjectFromFactoryBean()方法中我們終于看到了我們想要看到的方法,也就是object = factory.getObject(),是的,就是這句代碼,我們的歷程猶如剝洋蔥一樣,一層一層的直到最內(nèi)部的代碼實(shí)現(xiàn),雖然最終實(shí)現(xiàn)很簡(jiǎn)單。
4. 總結(jié)
本文在瀏覽了完整的bean獲取流程的基礎(chǔ)上,著重分析了從緩存中獲取bean,這只是整個(gè)bean獲取流程中的第一步,如果從緩存獲取bean未果,那么就要開(kāi)始從頭創(chuàng)建一個(gè)bean了,而這個(gè)過(guò)程留待后文分析。
總結(jié)
以上是生活随笔為你收集整理的Spring源码阅读笔记06:bean加载之如何获取单例的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 公安部:醉驾入刑以来 醉驾发生率减少70
- 下一篇: 字体图标生成网站-icon