領先一步
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);
看啊,沒有轉型! 也沒有基於字串的查找。 當然,這會引發一個問題,「如果 context 中配置了兩個或多個 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:修復了 sample web.xml 中的拼字錯誤。]