环境与profile
在开发软件的时候,有一个很大的挑战就是将应用程序从一个环境迁移到另外一个环境。在开发阶段中,某些环境相关做法可能并不适合迁移到生产环境中,甚至即便迁移过去也无法正常工作。数据库配置,加密算法以及外部系统的集成是跨环境部署时会发生变化的几个典型例子。
比如,考虑一下数据库配置。在开发环境中,我们可能会使用嵌入式数据库,并预先加载测试数据。例如,在Spring配置类中,我们可能会在一个带有@Bean注解的方法上使用EmbeddedDatabaseBuilder;
@Bean(destroyMethod="shutdown")
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().addScript("classpath:schema.sql")
.addScript("classpath:test-data.sql").build();
}
这会创建一个类型为javax.sql.DataSource的bean是如何创建出来的才是最有意思的。使用EmbeddedDatabaseBuilder会搭建一个嵌入式的Hypesonic数据库,它的模式(schema)定义在schema.sql中,测试数据则是通过test-data加载的。
当你在开发环境中运行集成测试或者启动应用进行手动测试的时候,这个DataSourse是很有用的 。每次启动它的时候都能让数据库处于一种给定的状态。
尽管EmbeddedDatabaseBuilder创建的DataSourse非常适用于开发环境。但是对于生产环境来说,这会是一个糟糕的选择。在生产环境的配置中,你可能会希望使用JNDI从容器中获取一个DataSource。在这种场景中,如下的@Bean方法会更加合适:
@Bean
public DataSource dataSource() {
JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
jndiObjectFactoryBean.setJndiName("jdbc/myDS");
jndiObjectFactoryBean.setResourceRef(true);
jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);
return (DataSource) jndiObjectFactoryBean.getObject();
}
通过JNDI获取DataSourse能够让容器决定该如何创建这个DataSourse,甚至包括切换为容器管理的连接池。即便如此,JNDI管理的DataSourse更加适合于生产环境,对于简单的集成和开发测试环境来说,这会带来不必要的复杂性。
同时,在QA环境中,你可以选择完全不同的DataSourse配置,可以配置为Commons DBCP连接池。
显然,在这里展示三个版本的dataSourse()方法的互不相同。虽然它们都会生成一个类似为javax.sql.DataSourse的bean,但它们的相似点也仅限于此了。每个方法都使用了完全不同的策略来生成DataSourse bean。
这些例子表现了在不同的环境下某个bean会有所不同。我们必须要有一种方法来配置DataSourse,使其在每种环境下都会选择最合适的配置。
其中一种方式就是在单独的配置类(或xml文件)中配置每个bean,然后再构建阶段(可能会使用Maven的profiles)确定要将哪一个配置编译到可部署的应用中。这种方式的问题在于要为每种环境重新构建应用。
值得庆幸的是,Spring所提供的解决方案并不需要重新构建。