十一、环境与profile

在开发软件的时候,有一个很大的挑战就是将应用程序从一个环境迁移到另外一个环境。开发阶段中,某些环境相关做法可能并不适合迁移到生产环境中,甚至即便迁移过去也无法正常工作。数据库配置、加密算法以及与外部系统的集成是跨环境部署时会发生变化的几个典型例子。


比如,考虑一下数据库配置。在开发环境中,我们可能会使用嵌入式数据库,并预先加载测试数据。例如,在Spring配置类中,我们可能会在一个带有@Bean注解的方法上使用EmbeddedDatabaseBuilder:
十一、环境与profile_第1张图片
这会创建一个类型为javax.sql.DataSource的bean,这个bean是如何创建出来的才是最有意思的。使用EmbeddedDatabaseBuilder会搭建一个嵌入式的Hypersonic数据库,它的模式(schema)定义在schema.sql中,测试数据则是通过test-data.sql加载的。当你在开发环境中运行集成测试或者启动应用进行手动测试的时候,这个DataSource是很有用的。每次启动它的时候,都能让数据库处于一个给定的状态。

尽管EmbeddedDatabaseBuilder创建的DataSource非常适于开发环境,但是对于生产环境来说,这会是一个糟糕的选择。在生产环境的配置中,你可能会希望使用JNDI从容器中获取一个DataSource。在这样场景中,如下的@Bean方法会更加合适:

十一、环境与profile_第2张图片
通过JNDI获取DataSource能够让容器决定该如何创建这个DataSource,甚至包括切换为容器管理的连接池。即便如此,JNDI管理的DataSource更加适合于生产环境,对于简单的集成和开发测试环境来说,这会带来不必要的复杂性。同时,在QA环境中,你可以选择完全不同的DataSource配置,可以配置为Commons DBCP连接池,如下所示:

十一、环境与profile_第3张图片
显然,这里展现的三个版本的dataSource()方法互不相同。虽然它们都会生成一个类型为javax.sql.DataSource的bean,但它们的相似点也仅限于此了。每个方法都使用了完全不同的策略来生成DataSource bean。

 配置profile bean

Spring为环境相关的bean所提供的解决方案其实与构建时的方案没有太大的差别。当然,在这个过程中需要根据环境决定该创建哪个bean和不创建哪个bean。不过Spring并不是在构建的时候做出这样的决策,而是等到运行时再来确定。这样的结果就是同一个部署单元(可能会是WAR文件)能够适用于所有的环境,没有必要进行重新构建。在3.1版本中,Spring引入了bean profile的功能。要使用profile,你首先要将所有不同的bean定义整理到一个或多个profile之中,在将应用部署到每个环境时,要确保对应的profile处于激活(active)的状态。在Java配置中,可以使用@Profile注解指定某个bean属于哪一个profile。例如,在配置类中,嵌入式数据库的DataSource可能会配
置成如下所示

十一、环境与profile_第4张图片
我希望你能够注意的是@Profile注解应用在了类级别上。它会告Spring这个配置类中的bean只有在dev profile激活时才会创建。如devprofile没有激活的话,那么带有@Bean注解的方法都会被忽略掉。同时,你可能还需要有一个适用于生产环境的配置,如下所示:
十一、环境与profile_第5张图片

十一、环境与profile_第6张图片
这里有个问题需要注意,尽管每个DataSource bean都被声明在一个profile中,并且只有当规定的profile激活时,相应的bean才会被创建,但是可能会有其他的bean并没有声明在一个给定的profile范围内。没有指定profile的bean始终都会被创建,与激活哪个profile没有关系。

在XML中配置profile

十一、环境与profile_第7张图片

 激活profile

Spring在确定哪个profile处于激活状态时,需要依赖两个独立的属性:spring.profiles.active和spring.profiles.default。如果设置spring.profiles.active属性的话,那么它的值就会用来确定哪个profile是激活的。但如果没有设置spring.profiles.active属性的话,那Spring将会查找spring.profiles.default的值。如果spring.profiles.active和spring.profiles.default均没有设置的话,那就没有激活的profile,因此只会创建那些没有定义在profile中的bean。你尽可以选择spring.profiles.active和spring.profiles.default的最佳组合方式以满足需求,我将这样的自主权留给读者。我所喜欢的一种方式是使用DispatcherServlet的参数将spring.profiles.default设置为开发环境的profile,我会在Servlet上下文中进行设置(为了兼顾到ContextLoaderListener)。例如,在Web应用中,设置spring.profiles.default的web.xml文件会如下所示:

在Web应用的web.xml文件中设置默认的profile

十一、环境与profile_第8张图片
按照这种方式设置spring.profiles.default,所有的开发人员都能从版本控制软件中获得应用程序源码,并使用开发环境的设置(如嵌入式数据库)运行代码,而不需要任何额外的配置。当应用程序部署到QA、生产或其他环境之中时,负责部署的人根据情况使用系统属性、环境变量或JNDI设置spring.profiles.active即可。当设置spring.profiles.active以后,至于spring.profiles.default置成什么值就已经无所谓了;系统会
优先使用spring.profiles.active中所设置的profile。你可能已经注意到了,在spring.profiles.active和spring.profiles.default中,profile使用的都是复数形式。这意味着你可以同时激活多个profile,这可以通过列出多个profile名称,并以逗号分隔来实现。当然,同时启用dev和prod profile可能

使用profile进行测试

当运行集成测试时,通常会希望采用与生产环境(或者是生产环境的部分子集)相同的配置进行测试。但是,如果配置中的bean定义在了profile中,那么在运行测试时,我们就需要有一种方式来启用合适的profile。
Spring提供了@ActiveProfiles注解,我们可以使用它来指定运行测试时要激活哪个profile。在集成测试时,通常想要激活的是开发环境的profile。例如,下面的测试类片段展现了使用@ActiveProfiles激活dev profile:

十一、环境与profile_第9张图片

你可能感兴趣的:(Spring的核心)