IOC容器的高階特性
1.通過前面4節對Spring IoC容器的原始碼分析,我們已經基本上了解了Spring IoC容器對Bean定義資源的定位、讀入和解析過程,同時也清楚了當使用者通過getBean方法向IoC容器獲取被管理的Bean時,IoC容器對Bean進行的初始化和依賴注入過程,這些是Spring IoC容器的基本功能特性。Spring IoC容器還有一些高階特性,如使用lazy-init屬性對Bean預初始化、FactoryBean產生或者修飾Bean物件的生成、IoC容器初始化Bean過程中使用BeanPostProcessor後置處理器對Bean宣告週期事件管理和IoC容器的autowiring自動裝配功能等。
2.Spring IoC容器的lazy-init屬性實現預例項化:
通過前面我們對IoC容器的實現和工作原理分析,我們知道IoC容器的初始化過程就是對Bean定義資源的定位、載入和註冊,此時容器對Bean的依賴注入並沒有發生,依賴注入主要是在應用程式第一次向容器索取Bean時,通過getBean方法的呼叫完成。
當Bean定義資源的<Bean>元素中配置了lazy-init屬性時,容器將會在初始化的時候對所配置的Bean進行預例項化,Bean的依賴注入在容器初始化的時候就已經完成。這樣,當應用程式第一次向容器索取被管理的Bean時,就不用再初始化和對Bean進行依賴注入了,直接從容器中獲取已經完成依賴注入的現成Bean,可以提高應用第一次向容器獲取Bean的效能。
下面我們通過程式碼分析容器預例項化的實現過程:
(1).refresh()
先從IoC容器的初始會過程開始,通過前面文章分析,我們知道IoC容器讀入已經定位的Bean定義資源是從refresh方法開始的,我們首先從AbstractApplicationContext類的refresh方法入手分析,原始碼如下:
//容器初始化的過程,讀入Bean定義資源,並解析註冊 public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. //呼叫容器準備重新整理的方法,獲取容器的當時時間,同時給容器設定同步標識 prepareRefresh(); // Tell the subclass to refresh the internal bean factory. //告訴子類啟動refreshBeanFactory()方法,Bean定義資原始檔的載入從子類的refreshBeanFactory()方法啟動 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. //為BeanFactory配置容器特性,例如類載入器、事件處理器等 prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. //為容器的某些子類指定特殊的BeanPost事件處理器 postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. //呼叫所有註冊的BeanFactoryPostProcessor的Bean invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. //為BeanFactory註冊BeanPost事件處理器. //BeanPostProcessor是Bean後置處理器,用於監聽容器觸發的事件 registerBeanPostProcessors(beanFactory); // Initialize message source for this context. //初始化資訊源,和國際化相關. initMessageSource(); // Initialize event multicaster for this context. //初始化容器事件傳播器 initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. //呼叫子類的某些特殊Bean初始化方法 onRefresh(); // Check for listener beans and register them. //為事件傳播器註冊事件監聽器. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. //初始化所有剩餘的單例Bean. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. //初始化容器的生命週期事件處理器,併發布容器的生命週期事件 finishRefresh(); } catch (BeansException ex) { // Destroy already created singletons to avoid dangling resources. //銷燬以建立的單態Bean destroyBeans(); // Reset 'active' flag. //取消refresh操作,重置容器的同步標識. cancelRefresh(ex); // Propagate exception to caller. throw ex; } } }
在refresh方法中ConfigurableListableBeanFactorybeanFactory = obtainFreshBeanFactory();啟動了Bean定義資源的載入、註冊過程,而finishBeanFactoryInitialization方法是對註冊後的Bean定義中的預例項化(lazy-init=false,Spring預設就是預例項化,即為true)的Bean進行處理的地方。
(2).finishBeanFactoryInitialization處理預例項化Bean:
當Bean定義資源被載入IoC容器之後,容器將Bean定義資源解析為容器內部的資料結構BeanDefinition註冊到容器中,AbstractApplicationContext類中的finishBeanFactoryInitialization方法對配置了預例項化屬性的Bean進行預初始化過程,原始碼如下:
//對配置了lazy-init屬性的Bean進行預例項化處理
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
//這是Spring3以後新加的程式碼,為容器指定一個轉換服務(ConversionService)
//在對某些Bean屬性進行轉換時使用
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
//為了型別匹配,停止使用臨時的類載入器
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes.
//快取容器中所有註冊的BeanDefinition元資料,以防被修改
beanFactory.freezeConfiguration();
// Instantiate all remaining (non-lazy-init) singletons.
//對配置了lazy-init屬性的單態模式Bean進行預例項化處理
beanFactory.preInstantiateSingletons();
}
ConfigurableListableBeanFactory是一個介面,其preInstantiateSingletons方法由其子類DefaultListableBeanFactory提供。
(3).DefaultListableBeanFactory對配置lazy-init屬性單態Bean的預例項化:
//對配置lazy-init屬性單態Bean的預例項化
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isInfoEnabled()) {
this.logger.info("Pre-instantiating singletons in " + this);
}
List<String> beanNames;
//在對配置lazy-init屬性單態Bean的預例項化過程中,必須多執行緒同步,以確保資料一致性
synchronized (this.beanDefinitionMap) {
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
beanNames = new ArrayList<String>(this.beanDefinitionNames);
}
for (String beanName : beanNames) {
//獲取指定名稱的Bean定義
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//Bean不是抽象的,是單態模式的,且lazy-init屬性配置為false
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
//如果指定名稱的bean是建立容器的Bean
if (isFactoryBean(beanName)) {
//FACTORY_BEAN_PREFIX=”&”,當Bean名稱前面加”&”符號
//時,獲取的是產生容器物件本身,而不是容器產生的Bean.
//呼叫getBean方法,觸發容器對Bean例項化和依賴注入過程
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
//標識是否需要預例項化
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
//一個匿名內部類
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
public Boolean run() {
return ((SmartFactoryBean<?>) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
//呼叫getBean方法,觸發容器對Bean例項化和依賴注入過程
getBean(beanName);
}
}
else {
//呼叫getBean方法,觸發容器對Bean例項化和依賴注入過程
getBean(beanName);
}
}
}
}
通過對lazy-init處理原始碼的分析,我們可以看出,如果設定了lazy-init屬性,則容器在完成Bean定義的註冊之後,會通過getBean方法,觸發對指定Bean的初始化和依賴注入過程,這樣當應用第一次向容器索取所需的Bean時,容器不再需要對Bean進行初始化和依賴注入,直接從已經完成例項化和依賴注入的Bean中取一個執行緒的Bean,這樣就提高了第一次獲取Bean的效能。
3.FactoryBean的實現:
在Spring中,有兩個很容易混淆的類:BeanFactory和FactoryBean。
BeanFactory:Bean工廠,是一個工廠(Factory),我們Spring IoC容器的最頂層介面就是這個BeanFactory,它的作用是管理Bean,即例項化、定位、配置應用程式中的物件及建立這些物件間的依賴。
FactoryBean:工廠Bean,是一個Bean,作用是產生其他bean例項。通常情況下,這種bean沒有什麼特別的要求,僅需要提供一個工廠方法,該方法用來返回其他bean例項。通常情況下,bean無須自己實現工廠模式,Spring容器擔任工廠角色;但少數情況下,容器中的bean本身就是工廠,其作用是產生其它bean例項。
當用戶使用容器本身時,可以使用轉義字元”&”來得到FactoryBean本身,以區別通過FactoryBean產生的例項物件和FactoryBean物件本身。在BeanFactory中通過如下程式碼定義了該轉義字元:
StringFACTORY_BEAN_PREFIX = "&";
如果myJndiObject是一個FactoryBean,則使用&myJndiObject得到的是myJndiObject物件,而不是myJndiObject產生出來的物件。
(1).FactoryBean的原始碼如下:
//工廠Bean,用於產生其他物件
public interface FactoryBean<T> {
//獲取容器管理的物件例項
T getObject() throws Exception;
//獲取Bean工廠建立的物件的型別
Class<?> getObjectType();
//Bean工廠建立的物件是否是單態模式,如果是單態模式,則整個容器中只有一個例項
//物件,每次請求都返回同一個例項物件
boolean isSingleton();
}
2). AbstractBeanFactory的getBean方法呼叫FactoryBean:
在我們分析Spring Ioc容器例項化Bean並進行依賴注入過程的原始碼時,提到在getBean方法觸發容器例項化Bean的時候會呼叫AbstractBeanFactory的doGetBean方法來進行例項化的過程,原始碼如下:
//真正實現向IOC容器獲取Bean的功能,也是觸發依賴注入功能的地方
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
//根據指定的名稱獲取被管理Bean的名稱,剝離指定名稱中對容器的相關依賴
//如果指定的是別名,將別名轉換為規範的Bean名稱
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
//先從快取中取是否已經有被建立過的單態型別的Bean
//對於單例模式的Bean整個IOC容器中只建立一次,不需要重複建立
Object sharedInstance = getSingleton(beanName);
//IOC容器建立單例模式Bean例項物件
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
//如果指定名稱的Bean在容器中已有單例模式的Bean被建立
//直接返回已經建立的Bean
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//獲取給定Bean的例項物件,主要是完成FactoryBean的相關處理
//注意:BeanFactory是管理容器中Bean的工廠,而FactoryBean是
//建立建立物件的工廠Bean,兩者之間有區別
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
...
}
//獲取給定Bean的例項物件,主要是完成FactoryBean的相關處理
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.
//容器已經得到了Bean例項物件,這個例項物件可能是一個普通的Bean,
//也可能是一個工廠Bean,如果是一個工廠Bean,則使用它建立一個Bean例項物件,
//如果呼叫本身就想獲得一個容器的引用,則指定返回這個工廠Bean例項物件
//如果指定的名稱是容器的解引用(dereference,即是物件本身而非記憶體地址),
//且Bean例項也不是建立Bean例項物件的工廠Bean
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,或者指定名稱是容器的解引用,
//呼叫者向獲取對容器的引用,則直接返回當前的Bean例項
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
//處理指定名稱不是容器的解引用,或者根據名稱獲取的Bean例項物件是一個工廠Bean
//使用工廠Bean建立一個Bean的例項物件
Object object = null;
if (mbd == null) {
//從Bean工廠快取中獲取給定名稱的Bean例項物件
object = getCachedObjectForFactoryBean(beanName);
}
//讓Bean工廠生產給定名稱的Bean物件例項
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
//如果從Bean工廠生產的Bean是單態模式的,則快取
if (mbd == null && containsBeanDefinition(beanName)) {
//從容器中獲取指定名稱的Bean定義,如果繼承基類,則合併基類相關屬性
mbd = getMergedLocalBeanDefinition(beanName);
}
//如果從容器得到Bean定義資訊,並且Bean定義資訊不是虛構的,
//則讓工廠Bean生產Bean例項物件
boolean synthetic = (mbd != null && mbd.isSynthetic());
//呼叫FactoryBeanRegistrySupport類的getObjectFromFactoryBean方法,
//實現工廠Bean生產Bean物件例項的過程
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
在上面獲取給定Bean的例項物件的getObjectForBeanInstance方法中,會呼叫FactoryBeanRegistrySupport類的getObjectFromFactoryBean方法,該方法實現了Bean工廠生產Bean例項物件。
Dereference(解引用):一個在C/C++中應用比較多的術語,在C++中,”*”是解引用符號,而”&”是引用符號,解引用是指變數指向的是所引用物件的本身資料,而不是引用物件的記憶體地址。
(3). AbstractBeanFactory生產Bean例項物件:
AbstractBeanFactory類中生產Bean例項物件的主要原始碼如下:
//Bean工廠生產Bean例項物件
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
//Bean工廠是單態模式,並且Bean工廠快取中存在指定名稱的Bean例項物件
if (factory.isSingleton() && containsSingleton(beanName)) {
//多執行緒同步,以防止資料不一致
synchronized (getSingletonMutex()) {
//直接從Bean工廠快取中獲取指定名稱的Bean例項物件
Object object = this.factoryBeanObjectCache.get(beanName);
//Bean工廠快取中沒有指定名稱的例項物件,則生產該例項物件
if (object == null) {
//呼叫Bean工廠的getObject方法生產指定Bean的例項物件
object = doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);
//將生產的例項物件新增到Bean工廠快取中
this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
}
return (object != NULL_OBJECT ? object : null);
}
}
//呼叫Bean工廠的getObject方法生產指定Bean的例項物件
else {
return doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);
}
}
//呼叫Bean工廠的getObject方法生產指定Bean的例項物件
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 {
//實現PrivilegedExceptionAction介面的匿名內建類
//根據JVM檢查許可權,然後決定BeanFactory建立例項物件
object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
//呼叫BeanFactory介面實現類的建立物件方法
return factory.getObject();
}
}, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
//呼叫BeanFactory介面實現類的建立物件方法
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.
//創建出來的例項物件為null,或者因為單態物件正在建立而返回null
if (object == null && isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
//為創建出來的Bean例項物件新增BeanPostProcessor後置處理器
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;
}
從上面的原始碼分析中,我們可以看出,BeanFactory介面呼叫其實現類的getObject方法來實現建立Bean例項物件的功能。
(4).工廠Bean的實現類getObject方法建立Bean例項物件:
FactoryBean的實現類有非常多,比如:Proxy、RMI、JNDI、ServletContextFactoryBean等等,FactoryBean介面為Spring容器提供了一個很好的封裝機制,具體的getObject有不同的實現類根據不同的實現策略來具體提供,我們分析一個最簡單的AnnotationTestFactoryBean的實現原始碼:
public class AnnotationTestBeanFactory implements FactoryBean<IJmxTestBean> {
private final FactoryCreatedAnnotationTestBean instance = new FactoryCreatedAnnotationTestBean();
public AnnotationTestBeanFactory() {
this.instance.setName("FACTORY");
}
//AnnotationTestBeanFactory產生Bean例項物件的實現
public IJmxTestBean getObject() throws Exception {
return this.instance;
}
public Class<? extends IJmxTestBean> getObjectType() {
return FactoryCreatedAnnotationTestBean.class;
}
public boolean isSingleton() {
return true;
}
}
其他的Proxy,RMI,JNDI等等,都是根據相應的策略提供getObject的實現。這裡不做一一分析,這已經不是Spring的核心功能,有需要的時候再去深入研究。
4.BeanPostProcessor後置處理器的實現:
BeanPostProcessor後置處理器是Spring IoC容器經常使用到的一個特性,這個Bean後置處理器是一個監聽器,可以監聽容器觸發的Bean宣告週期事件。後置處理器想容器註冊以後,容器中管理的Bean就具備了接收IoC容器事件回撥的能力。
BeanPostProcessor的使用非常簡單,只需要提供一個實現介面BeanPostProcessor的實現類,然後在Bean的配置檔案中設定即可。
(1).BeanPostProcessor的原始碼如下:
public interface BeanPostProcessor {
//為在Bean的初始化前提供回撥入口
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
//為在Bean的初始化之後提供回撥入口
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
這兩個回撥的入口都是和容器管理的Bean的生命週期事件緊密相關,可以為使用者提供在Spring IoC容器初始化Bean過程中自定義的處理操作。
(2).AbstractAutowireCapableBeanFactory類對容器生成的Bean新增後置處理器:
BeanPostProcessor後置處理器的呼叫發生在Spring IoC容器完成對Bean例項物件的建立和屬性的依賴注入完成之後,在對Spring依賴注入的原始碼分析過程中我們知道,當應用程式第一次呼叫getBean方法(lazy-init預例項化除外)向Spring IoC容器索取指定Bean時觸發Spring IoC容器建立Bean例項物件並進行依賴注入的過程,其中真正實現建立Bean物件並進行依賴注入的方法是AbstractAutowireCapableBeanFactory類的doCreateBean方法,主要原始碼:
//真正建立Bean的方法
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
// Instantiate the bean.
//封裝被建立的Bean物件
.......
try {
//將Bean例項物件封裝,並且Bean定義中配置的屬性值賦值給例項物件
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
//初始化Bean物件
//在對Bean例項物件生成和依賴注入完成以後,開始對Bean例項物件
//進行初始化 ,為Bean例項物件應用BeanPostProcessor後置處理器
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) {
//獲取指定名稱的已註冊的單例模式Bean物件
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
//根據名稱獲取的已註冊的Bean和正在例項化的Bean是同一個
if (exposedObject == bean) {
//當前例項化的Bean初始化完成
exposedObject = earlySingletonReference;
}
//當前Bean依賴其他Bean,並且當發生迴圈引用時不允許新建立例項物件
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
//獲取當前Bean所依賴的其他Bean
for (String dependentBean : dependentBeans) {
//對依賴Bean進行型別檢查
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.
//註冊完成依賴注入的Bean
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
//為應用返回所需要的例項物件
return exposedObject;
}
從上面的程式碼中我們知道,為Bean例項物件新增BeanPostProcessor後置處理器的入口的是initializeBean方法。
(3).initializeBean方法為容器產生的Bean例項物件新增BeanPostProcessor後置處理器:
同樣在AbstractAutowireCapableBeanFactory類中,initializeBean方法實現為容器建立的Bean例項物件新增BeanPostProcessor後置處理器,原始碼如下:
//初始容器建立的Bean例項物件,為其新增BeanPostProcessor後置處理器
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
//JDK的安全機制驗證許可權
if (System.getSecurityManager() != null) {
//實現PrivilegedAction介面的匿名內部類
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
//為Bean例項物件包裝相關屬性,如名稱,類載入器,所屬容器等資訊
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
//對BeanPostProcessor後置處理器的postProcessBeforeInitialization
//回撥方法的呼叫,為Bean例項初始化前做一些處理
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
//呼叫Bean例項物件初始化的方法,這個初始化方法是在Spring Bean定義配置
//檔案中通過init-method屬性指定的
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
//對BeanPostProcessor後置處理器的postProcessAfterInitialization
//回撥方法的呼叫,為Bean例項初始化之後做一些處理
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
BeanPostProcessor是一個介面,其初始化前的操作方法和初始化後的操作方法均委託其實現子類來實現,在Spring中,BeanPostProcessor的實現子類非常的多,分別完成不同的操作,如:AOP面向切面程式設計的註冊通知介面卡、Bean物件的資料校驗、Bean繼承屬性/方法的合併等等,我們以最簡單的AOP切面織入來簡單瞭解其主要的功能。
(4).AdvisorAdapterRegistrationManager在Bean物件初始化後註冊通知介面卡:
AdvisorAdapterRegistrationManager是BeanPostProcessor的一個實現類,其主要的作用為容器中管理的Bean註冊一個面向切面程式設計的通知介面卡,以便在Spring容器為所管理的Bean進行面向切面程式設計時提供方便,其原始碼如下:
//為容器中管理的Bean註冊一個面向切面程式設計的通知介面卡
public class AdvisorAdapterRegistrationManager implements BeanPostProcessor {
//容器中負責管理切面通知介面卡註冊的物件
private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) {
this.advisorAdapterRegistry = advisorAdapterRegistry;
}
//BeanPostProcessor在Bean物件初始化前的操作
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//沒有做任何操作,直接返回容器建立的Bean物件
return bean;
}
//BeanPostProcessor在Bean物件初始化後的操作
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof AdvisorAdapter){
//如果容器建立的Bean例項物件是一個切面通知介面卡,則向容器的註冊
this.advisorAdapterRegistry.registerAdvisorAdapter((AdvisorAdapter) bean);
}
return bean;
}
}
其他的BeanPostProcessor介面實現類的也類似,都是對Bean物件使用到的一些特性進行處理,或者向IoC容器中註冊,為建立的Bean例項物件做一些自定義的功能增加,這些操作是容器初始化Bean時自動觸發的,不需要認為的干預。
5.Spring IoC容器autowiring實現原理:
Spring IoC容器提供了兩種管理Bean依賴關係的方式:
a. 顯式管理:通過BeanDefinition的屬性值和構造方法實現Bean依賴關係管理。
b. autowiring:Spring IoC容器的依賴自動裝配功能,不需要對Bean屬性的依賴關係做顯式的宣告,只需要在配置好autowiring屬性,IoC容器會自動使用反射查詢屬性的型別和名稱,然後基於屬性的型別或者名稱來自動匹配容器中管理的Bean,從而自動地完成依賴注入。
通過對autowiring自動裝配特性的理解,我們知道容器對Bean的自動裝配發生在容器對Bean依賴注入的過程中。在前面對Spring IoC容器的依賴注入過程原始碼分析中,我們已經知道了容器對Bean例項物件的屬性注入的處理髮生在AbstractAutoWireCapableBeanFactory類中的populateBean方法中,我們通過程式流程分析autowiring的實現原理:
(1). AbstractAutoWireCapableBeanFactory對Bean例項進行屬性依賴注入:
應用第一次通過getBean方法(配置了lazy-init預例項化屬性的除外)向IoC容器索取Bean時,容器建立Bean例項物件,並且對Bean例項物件進行屬性依賴注入,AbstractAutoWireCapableBeanFactory的populateBean方法就是實現Bean屬性依賴注入的功能,其主要原始碼如下:
//將Bean屬性設定到生成的例項物件上
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
//獲取容器在解析Bean定義資源時為BeanDefiniton中設定的屬性值
PropertyValues pvs = mbd.getPropertyValues();
...
//依賴注入開始,首先處理autowire自動裝配的注入
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
//對autowire自動裝配的處理,根據Bean名稱自動裝配注入
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
...
}
//對不是autowiring的屬性進行依賴注入
}
(2).Spring IoC容器根據Bean名稱或者型別進行autowiring自動依賴注入:
//根據名稱對屬性進行自動依賴注入
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
//對Bean物件中非簡單屬性(不是簡單繼承的物件,如8中原始型別,字串,URL等都是簡單屬性)進行處理
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
//如果Spring IOC容器中包含指定名稱的Bean
if (containsBean(propertyName)) {
//呼叫getBean方法向IoC容器索取指定名稱的Bean例項,迭代觸發屬性的初始化和依賴注入
Object bean = getBean(propertyName);
//為指定名稱的屬性賦予屬性值
pvs.add(propertyName, bean);
//指定名稱屬性註冊依賴Bean名稱,進行屬性依賴注入
registerDependentBean(propertyName, beanName);
if (logger.isDebugEnabled()) {
logger.debug("Added autowiring by name from bean name '" + beanName +
"' via property '" + propertyName + "' to bean named '" + propertyName + "'");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
"' by name: no matching bean found");
}
}
}
}
//根據型別對屬性進行自動依賴注入
protected void autowireByType(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
//獲取使用者定義的型別轉換器
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
//存放解析的要注入的屬性
Set<String> autowiredBeanNames = new LinkedHashSet<String>(4);
//對Bean物件中非簡單屬性(不是簡單繼承的物件,如8中原始型別,字元
//URL等都是簡單屬性)進行處理
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
try {
//獲取指定屬性名稱的屬性描述器
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
// Don't try autowiring by type for type Object: never makes sense,
// even if it technically is a unsatisfied, non-simple property.
//不對Object型別的屬性進行autowiring自動依賴注入
if (!Object.class.equals(pd.getPropertyType())) {
//獲取屬性的setter方法
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
// Do not allow eager init for type matching in case of a prioritized post-processor.
//檢查指定型別是否可以被轉換為目標物件的型別
boolean eager = !PriorityOrdered.class.isAssignableFrom(bw.getWrappedClass());
//建立一個要被注入的依賴描述
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
//根據容器的Bean定義解析依賴關係,返回所有要被注入的Bean物件
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
//為屬性賦值所引用的物件
pvs.add(propertyName, autowiredArgument);
}
for (String autowiredBeanName : autowiredBeanNames) {
//指定名稱屬性註冊依賴Bean名稱,進行屬性依賴注入
registerDependentBean(autowiredBeanName, beanName);
if (logger.isDebugEnabled()) {
logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" +
propertyName + "' to bean named '" + autowiredBeanName + "'");
}
}
//釋放已自動注入的屬性
autowiredBeanNames.clear();
}
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
}
}
}
通過上面的原始碼分析,我們可以看出來通過屬性名進行自動依賴注入的相對比通過屬性型別進行自動依賴注入要稍微簡單一些,但是真正實現屬性注入的是DefaultSingletonBeanRegistry類的registerDependentBean方法。
(3).DefaultSingletonBeanRegistry的registerDependentBean方法對屬性注入:
//為指定的Bean注入依賴的Bean
public void registerDependentBean(String beanName, String dependentBeanName) {
//處理Bean名稱,將別名轉換為規範的Bean名稱
String canonicalName = canonicalName(beanName);
//多執行緒同步,保證容器內資料的一致性
//先從容器中:bean名稱-->全部依賴Bean名稱集合找查詢給定名稱Bean的依賴Bean
synchronized (this.dependentBeanMap) {
//獲取給定名稱Bean的所有依賴Bean名稱
Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
if (dependentBeans == null) {
//為Bean設定依賴Bean資訊
dependentBeans = new LinkedHashSet<String>(8);
this.dependentBeanMap.put(canonicalName, dependentBeans);
}
//向容器中:bean名稱-->全部依賴Bean名稱集合新增Bean的依賴資訊
//即,將Bean所依賴的Bean新增到容器的集合中
dependentBeans.add(dependentBeanName);
}
//從容器中:bean名稱-->指定名稱Bean的依賴Bean集合找查詢給定名稱Bean的依賴Bean
synchronized (this.dependenciesForBeanMap) {
Set<String> dependenciesForBean = this.dependenciesForBeanMap.get(dependentBeanName);
if (dependenciesForBean == null) {
dependenciesForBean = new LinkedHashSet<String>(8);
this.dependenciesForBeanMap.put(dependentBeanName, dependenciesForBean);
}
//向容器中:bean名稱-->指定Bean的依賴Bean名稱集合新增Bean的依賴資訊
//即,將Bean所依賴的Bean新增到容器的集合中
dependenciesForBean.add(canonicalName);
}
}
通過對autowiring的原始碼分析,我們可以看出,autowiring的實現過程:
a. 對Bean的屬性迭代呼叫getBean方法,完成依賴Bean的初始化和依賴注入。
b. 將依賴Bean的屬性引用設定到被依賴的Bean屬性上。
c. 將依賴Bean的名稱和被依賴Bean的名稱儲存在IoC容器的集合中。
Spring IoC容器的autowiring屬性自動依賴注入是一個很方便的特性,可以簡化開發時的配置,但是凡是都有兩面性,自動屬性依賴注入也有不足,首先,Bean的依賴關係在配置檔案中無法很清楚地看出來,對於維護造成一定困難。其次,由於自動依賴注入是Spring容器自動執行的,容器是不會智慧判斷的,如果配置不當,將會帶來無法預料的後果,所以自動依賴注入特性在使用時還是綜合考慮。