Spring IOC 高級特性

介紹

通過對 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 自動裝配功能等。

Spring IOC 容器的 lazy-init 屬性實現預實例化

通過前面對 IOC 容器的實現和工作原理分析知道 IOC 容器的初始化過程就是對 Bean 定義資源的定位、載入和註冊,此時容器對 Bean 的依賴注入並沒有發生,依賴注入主要是在應用程序第一次向容器索取 Bean 時,通過 getBean 方法的調用完成。當Bean定義資源的<Bean>元素中配置了lazy-init屬性時,容器將會在初始化的時候對所配置的Bean進行預實例化,Bean 的依賴注入在容器初始化的時候就已經完成。這樣,當應用程序第一次向容器索取被管理的 Bean 時,就不用再初始化和對 Bean 進行依賴注入了,直接從容器中獲取已經完成依賴注入的現成 Bean,可以提高應用第一次向容器獲取 Bean 的性能。下面通過代碼分析容器預實例化的實現過程:

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 進行處理的地方。

finishBeanFactoryInitialization 處理預實例化 Bean

當 Bean 定義資源被載入 IOC 容器之後,容器將 Bean 定義資源解析爲容器內部的數據結構BeanDefinition 註冊到容器中 , AbstractApplicationContext 類中的finishBeanFactoryInitialization 方法對配置了預實例化屬性的 Bean 進行預初始化過程,源碼如下:

//對配置了 lazy-init 屬性的 Bean 進行預實例化處理
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	//這是 Spring3 以後新加的代碼,爲容器指定一個轉換服務(ConversionService)
	//在對某些 Bean 屬性進行轉換時使用
	// Initialize conversion service for this context.
	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 提供。

DefaultListableBeanFactory 對配置 lazy-init 屬性單態 Bean 的預實例化

public void preInstantiateSingletons() throws BeansException {
	if (this.logger.isDebugEnabled()) {
		this.logger.debug("Pre-instantiating singletons in " + this);
	}
	// 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.
	List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
	// Trigger initialization of all non-lazy singleton beans...
	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>() {
						@Override
						public Boolean run() {
							return ((SmartFactoryBean<?>) factory).isEagerInit();
						}
					}, getAccessControlContext());
				}
				else {
					isEagerInit = (factory instanceof SmartFactoryBean &&
							((SmartFactoryBean<?>) factory).isEagerInit());
				}
				if (isEagerInit) {
					//調用 getBean 方法,觸發容器對 Bean 實例化和依賴注入過程
					getBean(beanName);
				}
			}
			else {
				getBean(beanName);
			}
		}
	}
	...
}

通過對 lazy-init 處理源碼的分析,我們可以看出,如果設置了 lazy-init 屬性,則容器在完成 Bean定義的註冊之後,會通過 getBean 方法,觸發對指定 Bean 的初始化和依賴注入過程,這樣當應用第一次向容器索取所需的 Bean 時,容器不再需要對 Bean 進行初始化和依賴注入,直接從已經完成實例化和依賴注入的 Bean 中取一個現成的 Bean,這樣就提高了第一次獲取 Bean 的性能。

FactoryBean 的實現

在 Spring 中,有兩個很容易混淆的類:BeanFactoryFactoryBean
BeanFactory:Bean 工廠,是一個工廠(Factory),我們 Spring IOC 容器的最頂層接口就是這個BeanFactory,它的作用是管理 Bean,即實例化、定位、配置應用程序中的對象及建立這些對象間的依賴。
FactoryBean:工廠 Bean,是一個 Bean,作用是產生其他 bean 實例。通常情況下,這種 bean 沒有什麼特別的要求,僅需要提供一個工廠方法,該方法用來返回其他 bean 實例。通常情況下,bean 無須自己實現工廠模式,Spring 容器擔任工廠角色;但少數情況下,容器中的 bean 本身就是工廠,其作用是產生其它 bean 實例。
當用戶使用容器本身時,可以使用轉義字符”&”來得到 FactoryBean 本身,以區別通過 FactoryBean產生的實例對象和 FactoryBean 對象本身。在 BeanFactory 中通過如下代碼定義了該轉義字符:

String FACTORY_BEAN_PREFIX = "&";

如果 myJndiObject 是一個 FactoryBean,則使用&myJndiObject 得到的是 myJndiObject 對象,而
不是 myJndiObject 產生出來的對象。

FactoryBean 的源碼

//工廠 Bean,用於產生其他對象
public interface FactoryBean<T> {
	//獲取容器管理的對象實例
	T getObject() throws Exception;

	//獲取 Bean 工廠創建的對象的類型
	Class<?> getObjectType();

	//Bean 工廠創建的對象是否是單態模式,如果是單態模式,則整個容器中只有一個實例
	//對象,每次請求都返回同一個實例對象
	boolean isSingleton();
}

AbstractBeanFactory 的 getBean 方法調用 FactoryBean

在前面分析 Spring IOC 容器實例化 Bean 並進行依賴注入過程的源碼時,提到在 getBean 方法觸發容器實例化 Bean 的時候會調用 AbstractBeanFactory 的 doGetBean 方法來進行實例化的過程中,會調用getObjectForBeanInstance()獲取給定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);
				// 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 {
							object = postProcessObjectFromFactoryBean(object, beanName);
						}
						catch (Throwable ex) {
							throw new BeanCreationException(beanName,
									"Post-processing of FactoryBean's singleton object failed", ex);
						}
					}
					//將生產的實例對象添加到 Bean 工廠緩存中
					this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
				}
			}
			return (object != NULL_OBJECT ? object : null);
		}
	}
	//調用 Bean 工廠的 getObject 方法生產指定 Bean 的實例對象
	else {
		Object object = doGetObjectFromFactoryBean(factory, beanName);
		if (object != null && shouldPostProcess) {
			try {
				object = postProcessObjectFromFactoryBean(object, beanName);
			}
			catch (Throwable ex) {
				throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
			}
		}
		return object;
	}
}
//調用 Bean 工廠的 getObject 方法生產指定 Bean 的實例對象
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
		throws BeanCreationException {
	Object object;
	try {
		if (System.getSecurityManager() != null) {
			AccessControlContext acc = getAccessControlContext();
			try {
				//實現 PrivilegedExceptionAction 接口的匿名內置類
				//根據 JVM 檢查權限,然後決定 BeanFactory 創建實例對象
				object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
					@Override
					public Object run() throws Exception {
							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");
	}
	return object;
}

從上面的源碼分析中,可以看出,BeanFactory 接口調用其實現類的 getObject 方法來實現創建Bean 實例對象的功能。

工廠 Bean 的實現類 getObject 方法創建 Bean 實例對象

FactoryBean 的實現類有非常多,比如:Proxy、RMI、JNDI、ServletContextFactoryBean 等等,FactoryBean 接口爲 Spring 容器提供了一個很好的封裝機制,具體的 getObject 有不同的實現類根據不同的實現策略來具體提供,分析一個最簡單的 AnnotationTestFactoryBean 的實現源碼:

public class AnnotationTestBeanFactory implements FactoryBean<FactoryCreatedAnnotationTestBean> {

   private final FactoryCreatedAnnotationTestBean instance = new FactoryCreatedAnnotationTestBean();

   public AnnotationTestBeanFactory() {
      this.instance.setName("FACTORY");
   }

   @Override
   // AnnotationTestBeanFactory產生Bean實例對象的實現
   public FactoryCreatedAnnotationTestBean getObject() throws Exception {
      return this.instance;
   }

   @Override
   public Class<? extends IJmxTestBean> getObjectType() {
      return FactoryCreatedAnnotationTestBean.class;
   }

   @Override
   public boolean isSingleton() {
      return true;
   }

}

其他的Proxy,RMI,JNDI 等等,都是根據相應的策略提供 getObject 的實現。這裏不做一一分析,這已經不是 Spring 的核心功能,有需要的時候再去深入研究。

BeanPostProcessor 後置處理器的實現

BeanPostProcessor 後置處理器是 Spring IOC 容器經常使用到的一個特性,這個 Bean 後置處理器是一個監聽器,可以監聽容器觸發的 Bean 聲明週期事件。後置處理器向容器註冊以後,容器中管理的 Bean就具備了接收 IOC 容器事件回調的能力。
BeanPostProcessor 的使用非常簡單,只需要提供一個實現接口 BeanPostProcessor 的實現類,然後在 Bean 的配置文件中設置即可。

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 過程中自定義的處理操作。

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 						@Nullable Object[] args)
throws BeanCreationException {
	//創建 Bean 實例對象
	...
	Object exposedObject = bean;
	try {
		//對 Bean 屬性進行依賴注入
		populateBean(beanName, mbd, instanceWrapper);
		//在對 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);
			}
		}
	...
	//爲應用返回所需要的實例對象
	return exposedObject;
}

從上面的代碼中知道,爲 Bean 實例對象添加 BeanPostProcessor 後置處理器的入口的是initializeBean 方法。

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>() {
			@Override
			public Object run() {
				invokeAwareMethods(beanName, bean);
				return null;
			}
		}, getAccessControlContext());
	}
	else {
		//爲 Bean 實例對象包裝相關屬性,如名稱,類加載器,所屬容器等信息
		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 後置處理器實例對象初始化之前的處理方法
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
		throws BeansException {
	Object result = existingBean;
	//遍歷容器爲所創建的 Bean 添加的所有 BeanPostProcessor 後置處理器
	for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
		//調用 Bean 實例所有的後置處理中的初始化前處理方法,爲 Bean 實例對象在
		//初始化之前做一些自定義的處理操作
		result = beanProcessor.postProcessBeforeInitialization(result, beanName);
		if (result == null) {
			return result;
		}
	}
	return result;
}
//調用 BeanPostProcessor 後置處理器實例對象初始化之後的處理方法
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
		throws BeansException {
	Object result = existingBean;
	//遍歷容器爲所創建的 Bean 添加的所有 BeanPostProcessor 後置處理器
	for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
		//調用 Bean 實例所有的後置處理中的初始化後處理方法,爲 Bean 實例對象在
		//初始化之後做一些自定義的處理操作
		result = beanProcessor.postProcessAfterInitialization(result, beanName);
		if (result == null) {
			return result;
		}
	}
	return result;
}

BeanPostProcessor 是一個接口,其初始化前的操作方法和初始化後的操作方法均委託其實現子類來實現,在 Spring 中,BeanPostProcessor 的實現子類非常的多,分別完成不同的操作,如:AOP 面向切面編程的註冊通知適配器、Bean 對象的數據校驗、Bean 繼承屬性/方法的合併等等,我們以最簡單的 AOP 切面織入來簡單瞭解其主要的功能。

AdvisorAdapterRegistrationManager 在 Bean 對象初始化後註冊通知適配器

AdvisorAdapterRegistrationManager 是 BeanPostProcessor 的一個實現類,其主要的作用爲容器中管理的 Bean 註冊一個面向切面編程的通知適配器,以便在 Spring 容器爲所管理的 Bean 進行面向切面編程時提供方便,其源碼如下:

//爲容器中管理的 Bean 註冊一個面向切面編程的通知適配器
public class AdvisorAdapterRegistrationManager implements BeanPostProcessor {
    //容器中負責管理切面通知適配器註冊的對象
    private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
    public AdvisorAdapterRegistrationManager() {
    }
    public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) {
        //如果容器創建的 Bean 實例對象是一個切面通知適配器,則向容器的註冊
        this.advisorAdapterRegistry = advisorAdapterRegistry;
    }
    //BeanPostProcessor 在 Bean 對象初始化後的操作
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
    //BeanPostProcessor 在 Bean 對象初始化前的操作
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof AdvisorAdapter) {
            this.advisorAdapterRegistry.registerAdvisorAdapter((AdvisorAdapter)bean);
        }
        //沒有做任何操作,直接返回容器創建的 Bean 對象
        return bean;
    }
}

其他的 BeanPostProcessor 接口實現類的也類似,都是對 Bean 對象使用到的一些特性進行處理,或者向 IOC 容器中註冊,爲創建的 Bean 實例對象做一些自定義的功能增加,這些操作是容器初始化 Bean時自動觸發的,不需要認爲的干預。

Spring IOC 容器 autowiring 實現原理

Spring IOC 容器提供了兩種管理 Bean 依賴關係的方式:

  • 顯式管理:通過 BeanDefinition 的屬性值和構造方法實現 Bean 依賴關係管理
  • autowiring:Spring IOC 容器的依賴自動裝配功能,不需要對 Bean 屬性的依賴關係做顯式的聲明,只需要在配置好 autowiring 屬性,IOC 容器會自動使用反射查找屬性的類型和名稱,然後基於屬性的類型或者名稱來自動匹配容器中管理的 Bean,從而自動地完成依賴注入。

通過對 autowiring 自動裝配特性的理解,我們知道容器對 Bean 的自動裝配發生在容器對 Bean 依賴注入的過程中。在前面對 Spring IOC 容器的依賴注入過程源碼分析中,我們已經知道了容器對 Bean實例對象的屬性注入的處理髮生在 AbstractAutoWireCapableBeanFactory 類中的 populateBean方法中,我們通過程序流程分析 autowiring 的實現原理:

AbstractAutoWireCapableBeanFactory 對 Bean 實例進行屬性依賴注入

應用第一次通過 getBean 方法(配置了 lazy-init 預實例化屬性的除外)向 IOC 容器索取 Bean 時,容器創建 Bean 實例對象 , 並且 對 Bean 實 例對象進行屬性依賴注入 ,AbstractAutoWireCapableBeanFactory 的 populateBean 方法就是實現 Bean 屬性依賴注入的功能,其主要源碼如下:

//將 Bean 屬性設置到生成的實例對象上
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
	PropertyValues pvs = mbd.getPropertyValues();
	if (bw == null) {
		if (!pvs.isEmpty()) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
		}
		else {
			// Skip property population phase for null instance.
			return;
		}
	}
	// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
	// state of the bean before properties are set. This can be used, for example,
	// to support styles of field injection.
	boolean continueWithPropertyPopulation = true;
	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
					continueWithPropertyPopulation = false;
					break;
				}
			}
		}
	}
	if (!continueWithPropertyPopulation) {
		return;
	}
	//獲取容器在解析 Bean 定義資源時爲 BeanDefiniton 中設置的屬性值
	PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
	//對依賴注入處理,首先處理 autowiring 自動裝配的依賴注入
	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.
		//根據 Bean 名稱進行 autowiring 自動裝配處理
		if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
			autowireByName(beanName, mbd, bw, newPvs);
		}
		// Add property values based on autowire by type if applicable.
		//根據 Bean 類型進行 autowiring 自動裝配處理
		if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
			autowireByType(beanName, mbd, bw, newPvs);
		}
		pvs = newPvs;
	}
	...
}

Spring IOC 容器根據 Bean 名稱或者類型進行 autowiring 自動依賴注入

//根據類型對屬性進行自動依賴注入
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 != 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 方法。

DefaultSingletonBeanRegistry 的 registerDependentBean 方法對屬性注入

//爲指定的 Bean 注入依賴的 Bean
public void registerDependentBean(String beanName, String dependentBeanName) {
	// A quick check for an existing entry upfront, avoiding synchronization...
	//處理 Bean 名稱,將別名轉換爲規範的 Bean 名稱
	String canonicalName = canonicalName(beanName);
	Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
	if (dependentBeans != null && dependentBeans.contains(dependentBeanName)) {
		return;
	}
	// No entry yet -> fully synchronized manipulation of the dependentBeans Set
	//多線程同步,保證容器內數據的一致性
	//先從容器中:bean 名稱-->全部依賴 Bean 名稱集合找查找給定名稱 Bean 的依賴 Bean
	synchronized (this.dependentBeanMap) {
		//獲取給定名稱 Bean 的所有依賴 Bean 名稱
		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 的實現過程:
1.對 Bean 的屬性代調用 getBean 方法,完成依賴 Bean 的初始化和依賴注入。
2.將依賴 Bean 的屬性引用設置到被依賴的 Bean 屬性上。
3.將依賴 Bean 的名稱和被依賴 Bean 的名稱存儲在 IOC 容器的集合中。
Spring IOC 容器的 autowiring 屬性自動依賴注入是一個很方便的特性,可以簡化開發時的配置,但是凡是都有兩面性,自動屬性依賴注入也有不足,首先,Bean 的依賴關係在配置文件中無法很清楚地看出來,對於維護造成一定困難。其次,由於自動依賴注入是 Spring 容器自動執行的,容器是不會智能判斷的,如果配置不當,將會帶來無法預料的後果,所以自動依賴注入特性在使用時還是綜合考慮。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章