spring原始碼分析四 bean的載入第一步
分析:org.springframework.beans.factory.support.AbstractBeanFactory中
doGetBean的方法:
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException
從快取中獲取bean的程式碼塊如下:
1. transformedBeanName(name)
final String beanName = transformedBeanName(name);
transformedBeanName方法如下:
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
BeanFactoryUtils.transformedBeanName(name) 方法如下:
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
-- 如果 name 不是以 & 開頭的 直接返回
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
return name;
}
-- 如果 name 是以 & 開頭的,擷取掉&,再返回
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
do {
beanName = beanName. substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
});
}
public String canonicalName(String name) 程式碼如下:
public String canonicalName(String name) {
String canonicalName = name;
// Handle aliasing...
String resolvedName;
do {
-- aliasMap 快取的是 別名的 集合
-- 這裡將傳遞的別名轉換為 真正的名字
-- 如果沒有別名,則直接返回
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
綜上:final String beanName = transformedBeanName(name); 的功能是先擷取掉&(如果有的話),並通過別名(如果傳遞的引數為別名)找到真正的名字。
接下來:從快取獲取bean:重點
程式碼如下: Object sharedInstance = getSingleton(beanName);追蹤進去,發現再 DefaultSingletonBeanRegistry.java 類中有:
@Override
@Nullable
public Object getSingleton(String beanName) {
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) {
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;
}
1. 該方法的作用是:返回給定名字的已經註冊過的原始的單例例項
2. singletonObjects是個map, 快取的是的 單例的名字->單例物件,Object singletonObject = this.singletonObjects.get(beanName); 是從快取中獲取單例。
3. 如果快取中沒有物件,並且該beanName是要當前要建立的單例的名字,
isSingletonCurrentlyInCreation(beanName) 解釋見下面
/**
* Return whether the specified singleton bean is currently in creation
* (within the entire factory).
* @param beanName the name of the bean
*/
public boolean isSingletonCurrentlyInCreation(String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName);
}
這裡:singletonsCurrentlyInCreation 快取的當前要建立的Bean的所有的名字
/** Names of beans that are currently in creation. */
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
4. synchronized (this.singletonObjects) 鎖定全域性變數,防止併發問題出現
5. singletonObject = this.earlySingletonObjects.get(beanName); earlySingletonObjects 快取的早期的單例物件,(beanName -> bean)
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
為什麼會有這個判斷:如果這個Bean正在載入,則不處理
7. if (singletonObject == null && allowEarlyReference) 如果當前的bean不是正在載入,並且 允許早期的引用建立 (allowEarlyReference whether early references should be created or not,allowEarlyReference的作用:是否應該建立早期的引用 early references)這裡為true,為了解決迴圈依賴的問題
8. ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);singletonFactories 快取的是單例工廠,(beanName -> ObjectFactory)程式碼如下。 當某些地方需要提前初始化的時候則會呼叫 addBeanFactory方法將對應的ObjectFactory初始化策略儲存再singletonFactories 中
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
9. 如果單例工廠不為空,從工廠獲取物件,再將獲取到的物件快取到earlySingletonObjects中,再將單例工廠移除singletonFactories。
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
回到文章最開始doGetBean的方法:
程式碼先貼出來:
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
如果快取中獲取到了物件,並且沒有引數:那麼執行
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
為什麼有這行程式碼:getObjectForBeanInstance使用的頻率很高,無論是從快取中載入bean還是根據不同的scope策略載入bean。總之,我們得到bean的例項後要做的第一件事情就是呼叫這個方法來檢測一下正確性,其實就是檢測當前bean是否是FactoryBean型別的Bean,如果是,那麼需要呼叫該bean對應的FactoryBean的getObject()的方法作為返回值。
無論是從快取中載入bean還是根據不同的scope策略載入bean,都只是最原始的bean狀態,並不一定是我們想要的Bean。例如:我們都對需要對工廠bean進行處理,那麼這裡得到的其實是工程bean的初始狀態,但是我們真正需要的是工廠bean中定義的factory-method方法中的返回的bean,而getObjectForBeanInstance方法就是完成這個工作。
接下來分析這行程式碼:
通過方法的描述我們知道:該方法可能返回bean本身,也可能返回bean對應的FactoryBean,具體看原始碼分析:
下面我們看上圖的最後一個方法:
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
方法的描述是:從暴露出來的指定的FactoryBean中獲取物件
原始碼分析如下圖:
分析doGetObjectFromFactoryBean方法:這個邏輯比較簡單。
再次分析 protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) 這個方法:
spring再獲取到object物件之後,並沒有直接返回,而是做了後續處理,呼叫了 object = postProcessObjectFromFactoryBean(object, beanName); 方法,程式碼如下:
分析原始碼如下:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.java
@Override
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
return applyBeanPostProcessorsAfterInitialization(object, beanName);
}
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
我們發現,這裡是對獲取到的object物件坐的後續處理。實際呼叫的postProcessAfterInitialization方法,在實際開發中可以針對此特性設計自己的業務邏輯。
到這裡把bean載入的第一步完成了。