先行一步
VMware 提供培訓和認證,助你加速進步。
瞭解更多得益於我們的可插拔理念以及實現中的大量辛勤工作,Spring IoC 容器(與 Spring 的其餘大部分元件一樣)極其靈活。
常常被忽視的一點是,Spring 配置不必侷限於 XML,儘管 XML 格式是最常用的。Spring 擁有自己的內部元資料格式,即 BeanDefinition 介面及其子介面。代表 IoC 容器例項的 BeanFactory 和 ApplicationContext 實現由這種 Java 元資料驅動,並且與元資料解析(通常由 BeanDefinitionReader 實現執行)完全分離。
BeanDefinition 元資料最初並非為終端開發者設計。在 Spring 2.0 中,NamespaceHandlers(處理 XML 擴充套件名稱空間的類)生成 BeanDefinition 元資料,並且我們引入了 BeanDefinitionBuilder,帶有流暢的 API 使其更容易。但生成 BeanDefinition 元資料仍然屬於基礎設施編碼的範疇,而不是你在編寫業務邏輯和定義常規 Spring Bean 時每天要做的事情。
今天,我想描述一種在 Java 程式碼中定義 Bean 的新選項,它*是*面向終端使用者(開發者)而不是基礎設施提供者。這目前是 Spring 核心的里程碑版本附加元件,但可能會進入 Spring 主體。
我們先來看一個例子
@Configuration
public class MyConfig {
@Bean
public Person rod() {
return new Person("Rod Johnson");
}
@Bean(scope = Scope.PROTOTYPE)
public Book book() {
Book book = new Book("Expert One-on-One J2EE Design and Development");
book.setAuthor(rod()); // rod() method is actually a bean reference !
return book;
}
}
@Configuration 註解將此物件標識為一個特殊的配置類。每個 @Bean 方法都定義一個 Bean。Bean 的名稱就是方法的名稱。可以使用註解定義額外的別名,但最好從方法而不是註解中選取名稱,因為這意味著編譯器可以確保消除歧義。
Bean 在 Java 程式碼中透過建構函式、屬性或任意方法呼叫進行配置。請注意,對另一個 Bean 方法的呼叫建立了從“book”Bean 到“rod”Bean 的依賴關係。但這比在沒有框架支援的情況下在 Java 中例項化物件具有關鍵優勢:例如
透過將其與實現相同結果的 XML 定義進行比較,可能會更容易理解正在發生的事情,XML 定義如下
<bean id="rod" class="Person" scope="singleton">
<constructor-arg>Rod Johnson</constructor-arg>
</bean>
<bean id="book" class="Book" scope="prototype">
<constructor-arg>Expert One-on-One J2EE Design and Development</constructor-arg>
<property name="author" ref="rod"/>
</bean>
儘管它基於註解,但這種 Java 配置機制在使用註解方面是獨特的,我見過註解不包含在核心業務邏輯中,而是包含在單獨的配置類中。實際上,它是一種配置的 DSL。因此,它保留了 Spring 的非侵入性承諾:你無需更改 Java 程式碼即可使用它。
配置類類似於 XML Bean 定義檔案,因此 @Configuration 註解包含一些與 <beans> 元素相似的選項,例如預設的自動裝配或延遲初始化。例如
@Configuration(defaultAutowire = Autowire.BY_TYPE, defaultLazy = Lazy.FALSE)
public class DataSourceConfiguration extends ConfigurationSupport {
}
@Bean 註解允許設定作用域和延遲初始化等選項,就像使用 <bean> 元素一樣。預設作用域是 Singleton,與 XML 相同。
這種 Java 配置風格具有一些有趣的特點。例如
<li>Because configurations are Java classes, they can participate in inheritance relationships. For example, you could define a superclass that demands some abstract @Beans to be implemented in subclasses.</li>
<li>It creates a new visibility option. An @Bean method can be protected, it which case it benefits from the usual characteristics of the Spring component, but is not visible externally--that is it not injectable and cannot be obtained by calling getBean() on the IoC context.</li>
我在向人們展示這一點(現在已經一年多了)的經驗是,他們有時需要一些時間來理解它,但通常最終都會非常熱情。
這*不是*為了取代 Spring 的 XML 格式。就像 Spring 2.0 擴充套件名稱空間以及自 Spring 1.0 以來就可能使用的屬性檔案一樣,它是一個額外的選項。複雜的應用程式需要多種型別的配置,Spring 旨在為配置提供最佳的整體解決方案。我們將繼續探索其他形式的配置。
你通常會混合使用 Java 和 XML 配置。在同一個應用程式上下文中,你可以使用任意數量的 Java 配置類。
以下示例使用 XML Bean 定義來定義一個 MyConfig Bean(如上所示),它可以像任何普通 Bean 一樣被注入。ConfigurationPostProcessor 處理所有帶有 @Configuration 註解的 Bean,生成必要的 Bean 定義。
<beans>
<bean class="..MyConfig"/>
<bean class="org.springframework.beans.factory.java.ConfigurationPostProcessor"/>
<bean class="SomeRandomBean">
<property...
</bean>
</beans>
當然,你可以在同一個 XML 中包含普通的舊式 Bean 定義,就像示例中的“SomeRandomBean”。你也可以使用 Java 配置和現有的 XML 配置構建上下文。
Costin 還實現了一個方便的應用程式上下文,它使用萬用字元從 classpath 中載入類,如下所示
ApplicationContext oneConfig = new AnnotationApplicationContext(SimpleConfiguration.class.getName());
ApplicationContext aBunchOfConfigs = new AnnotationApplicationContext("**/configuration/*Configuration.class");
類使用 ASM 進行檢查,而無需載入它們。在未來的版本中,我們可能會提供額外的自動檢測場景。
該版本在此處。Costin Leau 現在是專案負責人。程式碼應被視為 Alpha 質量。我們包含了一個修改後的 Spring Pet Store 示例,但毫無疑問,將在實際專案的使用中吸取教訓。
Costin 和我很樂意收到您對該功能的反饋意見。
這段程式碼將何去何從?好吧,這取決於你。它確實需要反饋(歡迎提出建議),所有可能的範圍(和實現改進)將透過實際使用而顯現出來,任何技術都是如此。目前它不在路線圖上,但如果它能激起足夠的興趣,可能會進入未來版本的 Spring 核心。
此外,它還需要一個響亮的名字。歡迎提出建議!
遺憾的是,從那時起我只斷斷續續地處理過這個問題,沒有時間做得更多,所以還沒有把它達到可以釋出的程度。幸運的是,Spring Modules 的負責人兼 Spring 大師 Costin Leau 自今年年初加入 Interface21 以來,有更多時間進行 Spring 編碼,他已經挺身而出,推進了這項工作。
該實現不需要對 Spring 核心進行任何修改。正如我所說,IoC 容器具有高度的靈活性。如果你有興趣,它將配置物件視為一個工廠 Bean,每個 Bean 定義都由該物件上的一個例項工廠方法支援:這是一個自 Spring 1.1 以來就可用的機制。它對配置例項進行了一些位元組碼操作,目前使用 CGLIB,以確保對單例範圍 @Bean 方法的重複呼叫始終返回同一個物件。