应用场景
在java项目的开发过程中,配置文件中相关配置项的值是应不同的执行环境所变化的,并且这种变化也可能是事前未知的。
纵向变化-执行者
一种是随着执行者的不同而不同,譬如说开发人员开发过程中debug的环境(简称dev)、个人CI与单元测试环境(ut)、团队CI环境、测试环境可能使用不同类型的数据库和执行环境。
横向变化-时间
另外一种是随着时间的变化而变化的。例如在笔者所服务的公司,通过使用模板机VM的方式提供带系统、数据库和基础数据的开发测试环境给大家使用,但是随着版本不断上线,模板机VM会不断被更新。在模板机被更新后,需要重新clone环境并使用,这时如IP等信息基本都会有变化,因此即使是如团队CI环境,可能也会需要变化。
解决方案1- profile
通过maven profile来针对横向变化的部分来形成一个个profile,在运行时动态选择即可。
解决方案2 - filter
在maven profile的基础上,针对临时变化的部分,可以通过filter在runtime动态指定环境的参数值。
利用spring框架自身提供的profile机制
最终的解决方案
针对公司现有java类产品的开发框架(springMvc),使用了如下的方式
1、将src/main/resouces下的配置文件复制到src/test/resouces下,对需要参数化的配置项的值进行参数化修改。
key=123 修改为key=${key}
2、在pom.xml中建立dev/ut/ci/qa等profile
<profiles>
<profile>
<id>dev</id>
<!-- 默认激活开发配制,使用app_dev.properties来替换设置过虑的资源文件中的${key} -->
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<filters>
<filter>src/test/resources/app_dev.properties</filter>
</filters>
</build>
</profile>
<profile>
<id>ut</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<filters>
<filter>src/test/resources/app_ut.properties</filter>
</filters>
</build>
</profile>
</profiles>
3、在pom.xml的<build/>部分加入filter,指定需要被替换的参数文件
<build>
<testResources>
<!-- filter global.properties frameworkConfig.properties -->
<testResource>
<directory>src/test/resources</directory>
<includes>
<include>frameworkConfig.properties</include>
<include>cfc_config.properties</include>
</includes>
<filtering>true</filtering>
</testResource>
<!-- inlcude other files like root-context.xml-->
<testResource>
<directory>src/test/resources</directory>
<excludes>
<exclude>frameworkConfig.properties</exclude>
<exclude>cfc_config.properties</exclude>
<exclude>app_*.properties</exclude>
</excludes>
<filtering>true</filtering>
</testResource>
</testResources>
</build>
这里有个坑要注意,一般在网上搜来的都是profile/filter介绍都是关于<resource/>标签的,其实对应的是src/main/resouces目录。如果要操作src/test/resources目录,则需要使用<testResources/>标签。
4、在src/test/resouces下建立类似app_dev/app_qa等配置文件,文件中填写相应的配置项的值。
如:key=123
5、在pom.xml的<build/> 的filter中增加exclude部分来剔除4中的配置文件,以免污染构建后的二进制文件夹。
<exclude>app_*.properties</exclude>
6、如果有临时变化,不需要通过commit到代码库中,则可以在运行时,通过类似
mvn test -Pdev -Dkey=666
的方式来动态修改key的值。
为什么不用配置中心
笔者所在的公司也建设了配置中心,所有系统在启动时都需要通过配置中心来获取对应配置项中的值。在其设计过程中,除了prod环境外,也规划了dev/qa等环境。 由于配置中心是一个web服务,对于多个开发/测试人员,如果在同时针对某个系统进行开发/测试,但使用不同的环境,其在配置中心的配置项的值也不同,如果使用同一个配置中心,则会造成配置项的值冲突。
现实中,也是通过模板机来部署多套配置中心来规避上述问题。但是在开发/单元测试/集成测试的过程中,我们希望配置值能跟随代码库进行配置管理。
With the above configuration, both main/resources and test/resources folders are treated as resources while the second one should be treated as test resources. Because of that, the resources:resources goal handles not only the config.xml but also test-config.xml and both lands in target/classes properly filtered.
Because of default definition, the other goal resources:testResources copies test-config.xml to target/test-classes without applying the filters (as by default filtering is disabled).