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 中的一个普通配置类:
@Configurationpublic class AppConfig {@Autowiredprivate DataSource dataSource;@Beanpublic AccountRepository accountRepository() {return new JdbcAccountRepository(dataSource);}@Beanpublic 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/xdbjdbc.username=sajdbc.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;@Beanpublic DataSource dataSource() {return new DriverManagerDataSource(url, username, password);}}
properties-config.xml
<beans><context:property-placeholder location="classpath:/com/acme/jdbc.properties"/></beans>
jdbc.propertiesjdbc.url=jdbc:hsqldb:hsql://localhost/xdbjdbc.username=sajdbc.password=
public static void main(String[] args) {ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);TransferService transferService = ctx.getBean(TransferService.class);// ...}
