Spring源码阅读笔记06:bean加载之如何获取单例
前面的文章中主要分析Spring是如何加載配置文件以及將其轉化成BeanDefinition的,從本文開始,我們繼續研究Spring是如何創建bean的。bean加載的功能實現遠比bean的解析要復雜得多,會占用多篇文章的篇幅來進行分析,按照流程大致可以分為獲取緩存bean、準備創建bean、創建bean這幾個部分,本文會在瀏覽整個bean獲取過程的基礎上分析一下獲取緩存單例的邏輯,更復雜的bean創建的邏輯留待后面文章分析。
1. bean獲取過程概覽
對于加載bean的功能,在Spring中的調用方式為:
TestBean myTestBean = (TestBean) xmlBeanFactory.getBean("testBean");
這句代碼背后是怎樣實現的呢?我們可以先快速體驗一下Spring中代碼是如何實現的,這部分的代碼是實現在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 // 獲取對應的beanName
9 final String beanName = transformedBeanName(name);
10 Object bean;
11 /* 檢查緩存中或者實例工廠中是否有對應的實例
12 * 為什么首先會使用這段代碼呢,
13 * 因為在創建單例bean的時候會存在依賴注入的情況,而在創建依賴的時候為了避免循環依賴,
14 * Spring創建bean的原則是不等bean創建完成就會將創建bean的ObjectFact提早曝光
15 * 也就是將objectFactory加入到緩存中,
16 * 一旦下個bean創建時候需要依賴上個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 // 返回對應的實例,有時候存在諸如BeanFactory的情況并不是直接返回實例本身,而是返回指定方法返回的實例
32 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
33 }
34
35 else {
36 // 只有在單例情況才會嘗試解決循環依賴,原型模式情況下,如果存在
37 // A中有B的屬性,B中有A的屬性,那么當依賴注入的時候,就會產生當A還未創建完的時候由于
38 // 對于B的創建而再次返回創建A,造循環依賴,也就是下面的情況
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中也就是在所有已經加載的類中不包括beanName則嘗試從parentBeanFactory中檢測
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 // 如果不是僅僅做類型檢查則是創建bean,這里要進行記錄
62 if (!typeCheckOnly) {
63 markBeanAsCreated(beanName);
64 }
65
66 try {
67 // 將存儲XML配置文件的GernericBeanDefinition轉換為RootBeanDefinition,如果指定BeanName是子Bean的話同時會合并父類的相關屬性
68 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
69 checkMergedBeanDefinition(mbd, beanName, args);
70
71 // Guarantee initialization of beans that the current bean depends on.
72 // 確保當前bean依賴的bean已經實例化了,通過遞歸來實現
73 String[] dependsOn = mbd.getDependsOn();
74 if (dependsOn != null) {
75 for (String dependsOnBean : dependsOn) {
76 getBean(dependsOnBean);
77 // 緩存依賴調用
78 registerDependentBean(dependsOnBean, beanName);
79 }
80 }
81 // 實例化依賴的bean后便可以實例化mbd本身了
82 // singleton模式的創建
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 }
其實我想說我第一次看到這里,內心是崩潰的,這個方法的代碼量。。。bean的加載經歷了一個相當復雜的過程,其中涉及到各種各樣的考慮,我也只是初略地了解一下Spring加載bean的過程,這里先總結一下所涉及的步驟吧:
轉換對應beanName。
這部分對應上面第9行,這里為什么要先轉換呢?因為這里傳入的參數可能是別名,也可能是FactoryBean(關于這個后面會專門總結),所以需要進行專門的解析,解析操作如下:
去除FactoryBean的修飾符,也就是如果name="&aa",那么會首先去除&而使name="aa";
取指定alias所表示的最終beanName,例如別名A指向名稱為B的beanvxxx則返回B;若別名A指向別名B,別名B又指向名稱為C的bean則返回C;
嘗試從緩存中加載單例。
這部分對應上面第20行代碼。我們知道,Spring對bean創建定義了多種作用域:
singleton,單例模式;
prototype,多例模式;
request,表示針對每一次HTTP請求都會產生一個新的bean,同時該bean僅在當前HTTP request內有效;
session,表示針對每一次HTTP請求都會產生一個新的bean,同時該bean僅在當前HTTP session內有效;
其中單例在一個Spring容器內只會被創建一次,后續再獲取bean,就直接從單例緩存中獲取了。這里也只是嘗試加載,首先嘗試從緩存中加載,如果加載不成功則再次嘗試從singletonFactories中加載。因為在創建單例bean的時候會存在依賴注入的情況,而在創建依賴的時候為了避免循環依賴,在Spring中創建bean的原則是不等bean創建完成就會將創建bean的ObjectFactory提早曝光加入到緩存中,一旦下一個bean創建時候需要依賴上一個bean則直接使用ObjectFactory(后面會對循環依賴進行重點分析)。
bean的實例化。
這部分對應上面第32行代碼。如果從緩存中得到了bean的原始狀態,則需要對bean進行實例化。為什么緩存中記錄的只是最原始的bean狀態,而并不一定是我們最終想要的bean呢?這是因為如果我們需要對工廠bean進行處理,那么這里得到的其實是工廠bean的初始狀態,但是我們真正需要的是工廠bean中定義的factory-method方法中返回的bean,而getObjectForBeanInstance()方法就是完成這個工作的,這個后續也會詳細講解的,這里不清楚的可以先跳過去。
原型模式(即prototype)的依賴檢查。
這部分對應上面第41行代碼。理解這一步的關鍵在于只有在單例情況下才會嘗試解決循環依賴,如果存在A中有B的屬性,B中有A的屬性,那么當依賴注入的時候,就會產生當A還未創建完的時候因為對于B的創建再次返回創建A,造成循環依賴,也就是情況:isPrototypeCurrentlyInCreation(beanName)判斷為true。
檢測parentBeanFactory。
從代碼上看這部分對應上面第46行到58行,如果緩存沒有數據的話就直接轉到父類工廠上去加載了,但是這里也別忽略其判斷條件:parentBeanFactory != null && !containsBeanDefinition(beanName)。
其中parentBeanFactory != null即parentBeanFactory如果為空,則其他一切都是浮云,也不會轉到父類工廠去加載;
而!containsBeanDefinition(beanName),則是檢測當前加載的XML配置文件是否包含beanName所對應的配置,如果沒有就到parentBeanFactory去嘗試下加載,然后再去遞歸的調用getBean()方法;
將存儲XML配置文件的GernericBeanDefinition轉換為RootBeanDefinition。
這部分對應上面的68行。在上文中有分析到,從XML配置文件中讀取到的Bean信息是存儲在GernericBeanDefinition中的,但是所有Bean的后續處理都是針對RootBeanDefinition進行的,所以這里需要進行一個轉換,轉換的同時如果父類bean不為空的話,也會一并合并父類的屬性。
加載依賴。
這部分對應上面的73到78行。因為bean的初始化過程中很可能會用到某些屬性,而某些屬性很可能是動態配置的,并且配置成依賴于其他的bean,那么這個時候就有必要先加載依賴的bean,所以,在Spring的加載順序中,在初始化某一個bean的時候首先會初始化這個bean所對應的所有依賴對象。
針對不同的scope進行bean的創建。
這部分對應上面的84到138行。我們都知道,在Spring中存在著不同的scope,其中默認的是singleton,但是還有些其他的配置諸如prototype、request之類的。在這個步驟中,Spring會根據不同的配置進行不同的初始化策略,這部分的過程很復雜,我們放到后面的文章中專門來解析這部分。
類型轉換。
這部分對應上面的149到161行。bean的加載到這一步已經基本結束了,通常對加載bean的實際執行方法doGetBean()進行調用時傳入的參數requiredType是為空,但是還是可能會存在這樣的情況,即返回的bean其實是個String,但是requiredType卻傳入Integer類型,那么這時候本步驟就會起作用了,它的功能是將返回的bean轉換為requiredType所指定的類型。當然,String轉換為Integer是最簡單的一種轉換,在Spring中提供了各種各樣的轉換器,用戶也可以自己擴展轉換器來滿足需求。
經過上面的步驟后bean的加載就結束了,這個時候就可以返回我們所需要的bean了。其中最重要的就是步驟8,針對不同的scope進行bean的創建,這個后面會專門寫一篇文章對這部分進行解析,接下來先來看一下除此之外的一些主要功能實現吧。
2. 嘗試從緩存加載單例
前面提到過,單例在同一個Spring容器內只會被創建一次,所以每次獲取bean時都會先嘗試從緩存獲取,未獲取到則會嘗試從頭加載bean。
這里的步驟是先從緩存singletonObjects獲取,沒有則再次嘗試從singletonFactories中獲取。因為在創建單例bean的時候會存在依賴注入的情況,而在創建依賴bean的時候為了避免循環依賴,Spring創建bean的原則是不等bean創建完成就會將創建bean的ObjectFactory提早曝光加入到緩存中,一旦下一個bean創建時需要依賴上個bean,則直接使用ObjectFactory。
public Object getSingleton(String beanName) {
// 參數true設置允許早期依賴
return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 檢查緩存中是否存在實例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 如果為空,則鎖定全局變量并進行處理
synchronized (this.singletonObjects) {
// 如果此bean正在加載則不處理
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 當某些方法需要提前初始化的時候則會調用addSingletonFactory方法將對應的ObjectFactory初始化策略存儲在singletonFactories
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 調用預先設定的getObject方法
singletonObject = singletonFactory.getObject();
// 記錄在緩存中,earlySingletonObjects和singletonFactories互斥
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
這里首先嘗試從singletonObjects里面獲取實例,如果獲取不到再從earlySingletonObjects里面獲取,如果還獲取不到,再嘗試從singletonFactories里面獲取beanName對應的ObjectFactory,然后調用這個ObjectFactory的getObject()來創建bean,并放到earlySingletonObjects里面去,并且從singletonFacotories里面remove掉這個ObjectFactory,而對于后續的所有內存操作都只是為了循環依賴檢測時使用,也就是在allowEarlyReference為true的情況下才會使用。
這里涉及用于存儲bean的不同的map,簡單解釋如下:
singletonObjects:用于保存BeanName和bean實例之間的關系,bean name-->bean instance;
singletonFactories:用于保存BeanName和創建bean的工廠之間的關系,bean name-->ObjectFactory;
earlySingletonObjects:也是保存BeanName和bean實例之間的關系,與singletonObjects的不同之處在于,當一個單例bean被放到這里面后,那么當bean還在創建過程中,就可以通過getBean方法獲取到了,其目的是用來檢測循環引用;
registeredSingletons:用來保存當前所有已注冊的bean;
這里從緩存獲取到object,并不一定是我們最終想要的bean,比如這個bean的類型是FactoryBean,這其實是bean的初始狀態,我們真正需要的是工廠bean中定義的factory-method方法中返回的bean,而getobjectForBeanInstance方法就是完成這個工作的。關于工廠bean,這里再說幾句。
2.1 FactoryBean
一般情況下,Spring通過反射機制利用beanDefinition的class屬性指定的實現類來實例化bean。如果按照傳統的方式,如果一個bean有很多屬性,則需要在<bean>中提供大量的配置信息,配置方式的靈活性是受限的,這時采用編碼的方式可能會得到一個更簡單的方案。Spring為此提供了一個org.Springframework.bean.factory.FactoryBean的工廠類接口,用戶可以通過實現該接口定制實例化bean的邏輯。
FactoryBean接口對于Spring框架來說占有重要地位,其自身就提供了許多FactoryBean的實現,它們隱藏了實例化一些復雜bean的細節,給上層應用帶來了便利。該接口中定義了3個方法:
T getObject():返回由FactoryBean創建的bean實例,如果isSingleton()返回true,則該實例會放到Spring容器中單例實例緩存池中;
boolean isSingleton():返回由FactoryBean創建的bean實例的作用域是singleton還是prototype;
Class<T> getObjectType():返回FactoryBean創建的bean類型;
當配置文件中<bean>的class屬性配置的實現類實現了FactoryBean接口時,通過getBean()方法返回的并不是FactoryBean本身,而是FactoryBean#getObject()方法所返回的對象,相當于FactoryBean#getObject()代理了getBean()方法。例如:如果使用傳統方式配置下面Car的<bean>時,Car的每個屬性分別對應一個<property>元素標簽。
public class Car{
private int masSpeed;
private String brand;
private double price;
// get/set 方法
}
如果用FactoryBean的方式實現就會靈活一些,可以通過逗號分隔符的方式一次性配置所有屬性:
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;
}
// 接收逗號分隔符設置屬性信息
public void setCarInfo(String carInfo) {
this.carInfo = carInfo;
}
}
有了這個CarFactoryBean后,就可以在配置文件中使用下面這種自定義的配置方式進行配置了:
<bean id = "car" class = "xxx" carInfo = "保時捷,400,20000"/>
當調用getBean("car")時,Spring通過反射機制發現CarFactoryBean實現了FactoryBean的接口,這時Spring容器就調用接口方法CarFactoryBean#getObject()返回Car的實例bean。如果希望獲取CarFactoryBean的實例,則需要在使用getBean(beanName)方法時在beanName前面顯示的加上"&"前綴,比如getBean("&car")。
3. FactoryBean的實例化
在getBean方法中,getObjectForBeanInstance()是個高頻率使用的方法,無論是從緩存中獲得bean還是根據不同的scope策略加載bean。總之,我們得到bean的實例后要做的第一步就是調用這個方法來檢測一下正確性,其實就是用于檢測當前bean是否是FactoryBean類型的bean,如果是,那么需要調用該bean對應的FactoryBean實例中的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是工廠相關(以&為前綴)且beanInstance又不是FactoryBean類型則驗證不通過
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.
// 現在我們有了個bean的實例,這個實例可能會是正常的bean或者是FactoryBean
// 如果是FactoryBean我們將使用它創建實例,但是如果用戶想要直接獲取工廠實例而不是工廠的getObject方法對應的實例那么傳入的name應該加入前綴&
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.
// 到這里已經明確知道beanInstance一定是FactoryBean類型
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// containBeanDefinition檢測beanDefinitionMap中也就是在所有已經加載的類中檢測是否定義beanName
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
//將存儲XML配置文件的GernericBeanDefinition轉換為RootBeanDefinition,如果指定BeanName是子Bean的話同時會合并父類的相關屬性
mbd = getMergedLocalBeanDefinition(beanName);
}
// 是否是用戶定義的而不是應用程序本身定義的
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
這部分并沒有實質性的工作,主要是對傳入的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 {
// 調用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 {
// 調用objectFactory的后處理器
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
如上代碼中,如果返回的bean是單例的,那就必須要保證全局唯一,同時,也因為是單例的,所以不必重復創建,可以使用緩存來提高性能,也就是說已經加載過就要記錄下來以便于下次復用,否則的話就直接獲取了。
如果判斷返回的bean是單例,為了避免重復創建,使用了緩存(factoryBeanObjectCache)來提高性能,如果有則直接獲取。而且必須保證全局唯一,這里使用同步鎖,并且在調用doGetObjectFromFactoryBean()之后又一次從緩存嘗試獲取,如果有則使用已創建的,并且不會執行后處理器,即調用postProcessObjectFromFactoryBean()方法,這里面主要是調用注冊的BeanPostProcessor的postProcessAfterInitialization方法進行處理,我們在實際開發過程中可以針對此特性設計自己的業務邏輯。
在上面的方法中還是沒有真正加載bean的操作,這部分委托給doGetObjectFromFactoryBean()來完成:
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
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 {
// 直接調用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(),是的,就是這句代碼,我們的歷程猶如剝洋蔥一樣,一層一層的直到最內部的代碼實現,雖然最終實現很簡單。
4. 總結
本文在瀏覽了完整的bean獲取流程的基礎上,著重分析了從緩存中獲取bean,這只是整個bean獲取流程中的第一步,如果從緩存獲取bean未果,那么就要開始從頭創建一個bean了,而這個過程留待后文分析。
總結
以上是生活随笔為你收集整理的Spring源码阅读笔记06:bean加载之如何获取单例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 公安部:醉驾入刑以来 醉驾发生率减少70
- 下一篇: 字体图标生成网站-icon