領先一步
VMware 提供培訓和認證,助您加速進步。
瞭解更多今天標誌著 Spring Java 配置專案(簡稱 JavaConfig)的第三個里程碑版本釋出。該版本包含大量錯誤修復和新功能——我將在下面重點介紹一些最有趣的變化,但首先讓我快速回顧一下 JavaConfig 是什麼。
如果您有 Spring 的使用經驗,以下 XML 配置片段可能會很熟悉。我們假設正在檢視一個名為 application-config.xml 的檔案
<beans>
<bean id="orderService" class="com.acme.OrderService"/>
<constructor-arg ref="orderRepository"/>
</bean>
<bean id="orderRepository" class="com.acme.OrderRepository"/>
<constructor-arg ref="dataSource"/>
</bean>
</beans>
當然,這個XML配置最終將作為一系列指令,供Spring ApplicationContext 例項化和配置我們的Bean。
ApplicationContext ctx = new ClassPathXmlApplicationContext("application-config.xml");
OrderService orderService = (OrderService) ctx.getBean("orderService");
JavaConfig只是提供了另一種配置Spring IoC容器的機制,這次是純Java,而不是需要XML來完成工作。讓我們將上面的配置移植到JavaConfig。
@Configuration
public class ApplicationConfig {
public @Bean OrderService orderService() {
return new OrderService(orderRepository());
}
public @Bean OrderRepository orderRepository() {
return new OrderRepository(dataSource());
}
public @Bean DataSource dataSource() {
// instantiate and return an new DataSource ...
}
}
與原始XML檔案一樣,這個類僅僅是一系列指令,說明如何構建我們應用程式的各種元件。我們將把這些指令提供給一個專門設計用來讀取和執行基於Java的配置指令的 ApplicationContext 實現。
JavaConfigApplicationContext ctx = new JavaConfigApplicationContext(ApplicationConfig.class);
OrderService orderService = ctx.getBean(OrderService.class);
就是這樣!嗯,差不多。當然JavaConfig還有很多內容,但大部分功能集與Spring的XML配置所提供的功能是1:1的。關於如何使用JavaConfig的完整細節,請參閱 參考文件。如果你是JavaConfig的新手,請務必檢視 快速入門 部分。
無論如何,JavaConfig的好處是很直接的:
考慮到這一點,讓我們來看看M3版本中發生了哪些變化。
JavaConfigApplicationContext context = new JavaConfigApplicationContext(AppConfig.class);
OrderService orderService = context.getBean(OrderService.class);
看,不用型別轉換!也沒有基於字串的查詢。當然,這會引出一個問題:“如果上下文中配置了兩個或多個 OrderService 型別的物件怎麼辦?” 這種情況很容易發生,並且有多種方法可以解決。為了在本帖中簡潔起見,我將只引用那些有興趣的人檢視參考文件的 消除歧義選項 部分。
這些型別安全的 getBean() 方法也已新增到 ConfigurationSupport 基類中,使得以下操作成為可能:
@Configuration
public class ApplicationConfig extends ConfigurationSupport {
public @Bean OrderRepository orderRepository() {
return new JdbcOrderRepository(this.getBean(DataSource.class));
}
}
<web-app>
<!-- Configure ContextLoaderListener to use JavaConfigWebApplicationContext
instead of the default XmlWebApplicationContext -->
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.config.java.context.JavaConfigWebApplicationContext</param-value>
</context-param>
<!-- Configuration locations must consist of one or more comma- or space-delimited
fully-qualified @Configuration classes -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>example.RootApplicationConfig</param-value>
</context-param>
<!-- Bootstrap the root application context as usual using ContextLoaderListener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Declare a Spring MVC DispatcherServlet as usual -->
<servlet>
<servlet-name>dispatcher-servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- Configure DispatcherServlet to use JavaConfigWebApplicationContext
instead of the default XmlWebApplicationContext -->
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.config.java.context.JavaConfigWebApplicationContext</param-value>
</init-param>
<!-- Again, config locations must consist of one or more comma- or space-delimited
and fully-qualified @Configuration classes -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>example.web.WebBeansConfig</param-value>
</init-param>
</servlet>
</web-app>
在實踐中,許多人可能會希望繼續使用XML和JavaConfig的組合,尤其是在Web應用程式中。這種方法仍然有效(請參閱 組合配置方法),但對團隊來說,重要的是,如果使用者希望完全“無XML”的方法,我們必須提供這種選擇。這一改變完善了這種可能性。
@Configuration
public class FooConfig {
public @Bean Foo foo() { ... }
public @Bean Bar bar() { ... }
}
@Import(FooConfig.class)
@Configuration
public class ApplicationConfig {
public @Bean ServiceA serviceA() { ... }
}
JavaConfigApplicationContext ctx = new JavaConfigApplicationContext(ApplicationConfig.class);
// foo, bar, and serviceA beans will all be available
ctx.getBean(ServiceA.class); // works
ctx.getBean(Foo.class); // works too
這項功能只是提供了另一個工具來有效地模組化 @Configuration 類。
datasource.url=jdbc:localhost:...
datasource.username=scott
datasource.password=tiger
使用 @ResourceBundles 和 @ExternalValue,我們現在可以從JavaConfig內部訪問這些屬性。
@Configuration
@ResourceBundles("classpath:/com/acme/datasource")
public abstract class ApplicationConfig {
public @Bean OrderService orderService() {
return new OrderServiceImpl(orderRepository());
}
public @Bean OrderRepository orderRepository() {
return new JdbcOrderRepository(dataSource());
}
public @Bean DataSource dataSource() {
return new DriverManagerDataSource(url(), username(), password());
}
abstract @ExternalValue("datasource.url") String url();
abstract @ExternalValue("datasource.username") String username();
abstract @ExternalValue("datasource.password") String password();
}
這裡有幾點需要注意:看看 @ResourceBundles 註解的值為什麼不以 .properties 結尾?這是因為JavaConfig底層使用了Spring的國際化基礎設施,並會根據當前區域設定查詢 datasource.properties 的變體,例如 datasource_en.properties。另外,雖然本例將字串值提供給了 @ExternalValue 註解,但預設是根據方法名查詢屬性。因此,如果我們沒有提供 @ExternalValue("datasource.url") String url(),而是隻寫 @ExternalValue String url(),JavaConfig就會查詢名為“url”的屬性。
[更新 3/27:帖子意外刪除,故重新發布——對於已經寫過評論但被刪除的人表示歉意。] [更新 4/4:修正了示例web.xml中的一個拼寫錯誤。]