Spring 的 @Configuration 类支持的目的并不是要 100% 完全取代 Spring XML。一些设施,如 Spring XML 命名空间,仍然是配置容器的理想方式。在 XML 方便或必要的情况下,你有一个选择:要么通过使用例如 ClassPathXmlApplicationContext以 「以 XML 为中心 」的方式实例化容器,要么通过使用AnnotationConfigApplicationContext 和 @ImportResource 注解来根据需要导入 XML,以 「以 Java 为中心」 的方式实例化它。
以 XML 为中心的 @Configuration 类的使用
从 XML 引导 Spring 容器并以临时的方式包含 @Configuration 类可能是更好的做法。例如,在一个使用Spring XML 的大型现有代码库中,根据需要创建 @Configuration 类并从现有的 XML 文件中包含它们是比较容易的。在本节后面,我们将介绍在这种 「以XML为中心 」的情况下使用 @Configuration 类的选项。
将 @Configuration 类声明为普通的 Spring 元素
记住,@Configuration 类最终是容器中的 Bean 定义。在这个系列的例子中,我们创建了一个名为 AppConfig 的 @Configuration 类,并将其作为 <bean/>
定义包含在 system-test-config.xml 中。因为 <context:annotation-config/>
被打开了,所以容器会识别 @Configuration
注解并正确处理 AppConfig 中声明的 @Bean 方法。
下面的例子展示了 Java 中的一个普通配置类:
@Configuration
public class AppConfig {
@Autowired
private DataSource dataSource;
@Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository(dataSource);
}
@Bean
public TransferService transferService() {
return new TransferService(accountRepository());
}
}
下面的示例显示了一个样例 system-test-config.xml 文件的一部分:
<beans>
<!-- 启用注解助理 @Autowired and @Configuration -->
<context:annotation-config/>
<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
<bean class="com.acme.AppConfig"/>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
下面的示例显示了一个可能的 jdbc.properties 文件:
jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
jdbc.username=sa
jdbc.password=
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/com/acme/system-test-config.xml");
TransferService transferService = ctx.getBean(TransferService.class);
// ...
}
:::info
在 system-test-config.xml 文件中,AppConfig <bean/>
并没有声明一个 id 元素。虽然这样做是可以接受的,但考虑到没有其他 Bean 会引用它,而且它也不可能被明确地从容器中获取名字,所以这样做是不必要的。同样地,DataSource Bean 只按类型自动连接,所以严格来说不需要明确的 bean id。
:::
使用 <context:component-scan/>
来拾取 @Configuration 类
因为 @Configuration 是用 @Component 元注解的,所以 @Configuration 注解的类自动成为组件扫描的候选对象。使用与前面例子中描述的相同场景,我们可以重新定义 system-test-config.xml 以利用组件扫描。注意,在这种情况下,我们不需要明确声明 <context:annotation-config/>
,因为<context:component-scan/>
可以实现同样的功能。
下面的示例显示了修改后的 system-test-config.xml 文件:
<beans>
<!-- picks up and registers AppConfig as a bean definition -->
<context:component-scan base-package="com.acme"/>
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
以 **@Configuration**
类为中心使用 XML 与 @ImportResource
在 @Configuration 类是配置容器的主要机制的应用中,仍然可能需要至少使用一些 XML。在这些情况下,你可以使用 @ImportResource 并只定义你需要的 XML。这样做实现了 「以 Java 为中心 」的配置容器的方法,并使 XML 保持在最低限度。下面的例子(包括一个配置类、一个定义 bean 的 XML 文件、一个属性文件和主类)显示了如何使用 @ImportResource 注解来实现 「以 Java 为中心 」的配置,并根据需要使用 XML。
@Configuration
@ImportResource("classpath:/com/acme/properties-config.xml") // 导入了 xml 配置
public class AppConfig {
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource dataSource() {
return new DriverManagerDataSource(url, username, password);
}
}
properties-config.xml
<beans>
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
</beans>
jdbc.properties
jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
jdbc.username=sa
jdbc.password=
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
TransferService transferService = ctx.getBean(TransferService.class);
// ...
}