1. 程式人生 > >spring原始碼分析四 bean的載入第一步

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載入的第一步完成了。

在這裡插入圖片描述