Java5的推出,加上當年基於純Java Annotation的依賴注入框架Guice的出現,使得Spring框架及其社區也“順應民意”,推出並持續完善了基於Java代碼和Annotation元信息的依賴關係綁定描述方式,即JavaConfig項目。
基於JavaConfig方式的依賴關係綁定描述基本上映射了最早的基於XML的配置方式,比如:
-
表達形式層面
基於XML的配置方式是這樣的:<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springfarmework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--bean定義--> </beans>
而基於JavaConfig的配置方式是這樣的:
@Configuration public class MockConfiguration{ //bean定義 }
任何一個標註了@Configuration的Java類定義都是一個JavaConfig配置類
-
註冊bean定義層面
基於XML的配置形式是這樣的:<bean id="mockService" class="..MockServiceImpl"> ... </bean>
而基於JavaConfig的配置形式是這樣的:
@Configuration public class MockConfiguration{ @Bean public MockService mockService(){ return new MockServiceImpl(); } }
任何一個標註了@Bean的方法,其返回值將作爲一個bean定義註冊到Spring的IoC容器,方法名將默認成爲該bean定義的id。
-
表達依賴注入關係層面
爲了表達bean與bean之間的依賴關係,在XML形式中一般是這樣的:<bean id="mockService" class="..MockServiceImpl"> <property name="dependencyService" ref="dependencyServcie"/> </bean> <bean id="dependencyServcie" class="DependencyServiceImpl"/>
而在JavaConfig中則是這樣的:
@Configuration public class MockConfiguration{ @Bean public MockService mockService(){ return new MockServiceImpl(dependencyService()); } @Bean public DependencyService dependencyService(){ return new DependencyServiceImpl(); } }
如果一個bean的定義依賴其他的bean,則直接調用對應JavaConfig類中依賴bean的創建方法就可以了。
注意:在JavaConfig形式的依賴注入過程中,我們使用方法調用的形式注入依賴,如果這個方法返回的對象實例只被一個bean依賴注入,那也還好,如果多於一個bean需要依賴這個方法調用返回的對象實例,那是不是意味着我們就會創建多個同一類型的對象實例?
從代碼表述的邏輯來看,直接上應該是會創建多個同一類型的對象實例,但實際上最終結果卻不是這樣,依賴注入的都是同一個Singleton的對象實例,那這是如何做到的?
我一開始以爲Spring框架會通過解析JavaConfig的代碼結構,然後通過解析器轉換加上反射等方式完成這一目的,但實際上Spring框架的設計和實現者採用了另一種更通用的方式,這在Spring的參考文檔中有說明,即通過攔截配置類的方法調用來避免多次初始化同一類型對象的問題,一旦擁有攔截邏輯的子類發現當前方法沒有對應的類型實例時纔會去請求父類的同一方法來初始化對象實例,否則直接返回之前的對象實例。
所以,原來Spring IoC容器中有的特性(features)在JavaConfig中都可以表述,只是換了一種形式而已,而且,通過聲明相應的Java Annotation反而“內聚”一處,變的更加簡潔明瞭了。