概述

配置必须是环境特定的,这是生活的基本法则。如果不是这样,那就不再是配置,而是在代码中硬编码值。

对于Spring应用程序,有多种解决方案可供选择,从简单的解决方案到非常灵活、复杂的替代方案。

一个常见且直接的方法是灵活使用属性文件,以及Spring提供的第一级属性支持(如何使用属性文件)。

为了验证这个概念,本文将关注一种特定类型的属性——数据库配置。在生产环境中使用一种数据库配置,测试环境使用另一种,开发环境使用另一种,这完全合理。

2. 各个环境的*.properties*文件

让我们开始我们的验证概念:定义我们要针对的目标环境:

    • 开发环境(Dev)
    • 预发布环境(Staging)
    • 生产环境(Production)

接下来,创建三个属性文件,每个环境一个:

  • persistence-dev.properties
  • persistence-staging.properties
  • persistence-production.properties

在典型的Maven应用中,这些文件可以放在src/main/resources目录下,但在部署时,它们需要在类路径上可访问

重要的是要注意,所有属性文件都在版本控制下,使得配置更透明,可复现。这与仅仅将配置文件存储在磁盘上并指向它们的做法形成对比。

3. Spring配置

在Spring中,我们将根据环境包含正确的文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-4.0.xsd">

      <context:property-placeholder
         location="
         classpath*:*persistence-${envTarget}.properties" />

</beans>

同样,用Java配置也可以实现:

@PropertySource({ "classpath:persistence-${envTarget:dev}.properties" })

这种方法允许我们拥有多个\*.properties文件,用于特定、专注的目的。例如,在我们的案例中,持久化Spring配置导入了持久性属性,这是合理的。安全性配置会导入与安全相关的属性等。

4. 在每个环境中设置属性

最终的可部署war包将包含所有属性文件——对于持久性,是三种变体的persistence-\*.properties。由于文件实际上有不同的名称,不必担心意外包含错误的一个。我们将设置**envTarget变量**,从而从多个现有变体中选择所需的实例。

envTarget变量可以在操作系统或JVM命令行参数中设置:

-DenvTarget=dev

5. 测试和Maven

对于需要启用持久化的集成测试,我们将在pom.xml中设置envTarget属性:

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-surefire-plugin</artifactId>
   <configuration>
      <systemPropertyVariables>
         <envTarget>h2_test</envTarget>
      </systemPropertyVariables>
   </configuration>
</plugin>

对应的persistence-h2_test.properties文件可以放在src/test/resources下,这样它仅在测试时使用,不会在运行时无谓地包含和部署到war包中。

6. 进一步扩展

如果需要,可以采用几种方法为这个解决方案增加额外的灵活性。

一种方法是使用更复杂的文件名编码,不仅指定它们将使用的环境,还可以提供更多信息(如持久化提供者)。例如,我们可以使用以下类型的属性文件:persistence-h2.propertiespersistence-mysql.properties,甚至更具体:persistence-dev_h2.propertiespersistence-staging_mysql.propertiespersistence-production_amazonRDS.properties

这种命名约定的优势——这只是约定,整体方法没有变化——在于透明度。只需查看文件名,现在就更容易理解配置的作用:

  • persistence-dev_h2.properties:开发环境的持久化提供者是轻量级的内存H2数据库
  • persistence-staging_mysql.properties:预发布环境的持久化提供者是MySQL实例
  • persistence-production_amazon_rds.propertie:生产环境的持久化提供者是Amazon RDS

7. 总结

本文讨论了一种在Spring中进行环境特定配置的灵活解决方案。有关使用profile进行项目配置的另一种替代方案,请参阅此处

该解决方案的实现可在GitHub项目中找到,这是一个基于Maven的项目,导入并运行起来应该很容易。