領先一步
VMware 提供培訓和認證,助您加速前進。
瞭解更多今天標誌著 Spring Java Configuration 專案(簡稱 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 中的一個拼寫錯誤。]