前情提要:web项目中的配置文件一般有开发环境dev,测试环境test,生产环境prd的区分,每次本地运行测试或者打包都需要手动修改web.xml或者spring.xml(因为一般各个环境的配置文件都是在这2个XML中配置加载的),很麻烦还容易忘。最近突然发现我们公司其他项目组有在maven中配置profiles,可以通过在maven插件上点击选择,直接就能打包运行所选的环境。如图 1:
研究了一波,我这边将不同环境的logback配置文件也集成到里面了,需要实现的目标是:在idea的maven插件这,只需要用鼠标打钩所需环境直接打包就可以使用所选环境的properties配置文件和logback.xml文件。
实现过程记录一下:
1.配置文件结构
src/main/resources/dev 目录是开发环境的配置文件
src/main/resources/prd 目录是生产环境的配置文件
src/main/resources/test 目录是测试环境的配置文件
各个环境的jdbc.properties里的数据库配置都不同,每个logback.xml日志的打印级别,appender输出都有所不同(dev只输出控制台,prd需要输出文件等)。
2.pom.xml文件添加如下配置:
<build>
<!--要打包的资源文件,结合profile中的env标签-->
<resources>
<resource>
<!--目录为src/main/resources主目录时,处理后的资源文件输出到本身所在的目录-->
<directory>src/main/resources</directory>
<!-- 只处理如下配置中包含的资源类型-->
<includes>
<include>**logback.xml</exclude>
</excludes>
<!--目标处理主资源目下的资源文件时,是否对主资源目录开启资源过滤-->
<filtering>false</filtering>
</resource>
<resource>
<!--目录不为src/main/resources主目录时,处理后的资源文件默认输出到主目录,
也可以使用targetPath来指定输出到哪个目录-->
<directory>src/main/resources/entry/${env}</directory>
<includes>
<include>**logback.xml</include>
</includes>
<!-- 默认${build.outputDirectory}目录下,如配置src则表示${build.outputDirectory}/src-->
<!-- <targetPath>src</targetPath>--> <!--此处不指定,默认输出主目录 -->
<!--是否进行过滤-->
<filtering>false</filtering>
</resource>
</resources>
</build>
<!-- 打包环境配置 开发环境dev 测试环境test 正式环境prd -->
<profiles>
<profile>
<!--不同环境Profile的唯一id-->
<id>dev</id>
<!--未指定环境时,默认打包dev-->
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<!--env标签(名字随便起),自定义字段可以有多个-->
<!-- 这里为每个profile都定义一个名为env的properties,可以在配置文件里被引用,
也可以结合pom文件里的resource和filter属性,作为文件名的一部分或者文件夹名的一部分-->
<env>dev</env>
</properties>
</profile>
<profile>
<id>test</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<env>test</env>
</properties>
</profile>
<profile>
<id>prd</id>
<properties>
<env>prd</env>
</properties>
</profile>
</profiles>
resources标签:
maven默认是将src/main/resources下的所有配置文件都会打包,打包后的结构也不会变,这样的话无法实现通过勾选图1中的dev,prd,test环境来加载对应的配置文件,因为每个配置文件的路径都不同,切换环境的话还得在加载配置文件的XML中修改路径。所以这里我们使用resources标签来控制打包后配置文件的结构。
resources标签表示maven生命周期的process-resources阶段执行maven-resources-plugin插件的resources目标,此处配置了两次resources,所以resources目标会执行两次
第一次是将主目录src/main/resources下的除了logback.xml以外所有xml都打包,结果就是将config下的spring.xml和spring-mvc.xml打包,打包出来依旧在config目录下。
第二次是根据profiles标签的配置,动态的将src/main/resources/entry/dev目录,src/main/resources/entry/prd目录,src/main/resources/entry/test目录
下的jdbc.properties和logback.xml打包至主目录,也就是src/main/resources(打包后在WEB-INF/classes/)下。图1里勾选的哪个环境,就打包哪个目录下的2个文件。
profiles标签:
profiles配置是用来区分环境,三个profile表示三个环境,profile的id标签的值就是图1里的勾选框,properties下的env标签是自定义标签,名字随便起,作用就是properties下的标签类似于map键值对, <env>dev</env>就表示env=dev,要引用值可以使用${env},引用{env}就等于dev。引用的值可以作为文件名的一部分或者文件夹名的一部分来使用。在resources我是作为文件夹名来使用的。
那么为什么要这样配置resources标签和profiles标签呢?
首先按照原始结构,之前如果我打dev环境的包,我的jdbc.properties在spring.xml中的引用肯定要写成:
<context:property-placeholder location="classpath:entry/dev/jdbc.properties"/>
logback.xml是在web.xml中要写成:
<listener> <listener-class>ch.qos.logback.ext.spring.web.LogbackConfigListener</listener-class> </listener> <context-param> <param-name>logbackConfigLocation</param-name> <param-value>classpath:entry/dev/logback.xml</param-value> </context-param>
如果我要切换prd环境就必须手动修改路径,entry/dev/改为entry/prd/,很麻烦。
但是我使用上面的resources标签和profiles标签打完包后的配置文件结构如图所示:
jdbc.properties和logback.xml文件是根据我在图1里的maven插件中勾选的环境,将对应的文件夹下的配置文件打包到主目录(classes目录)的,spring.xml和spring-mvc.xml依然在本来的config目录下。
那么我就可以这样写(只读主目录的配置文件,因为主目录的配置文件就是根据图1勾选的环境所打包出来的配置文件):jdbc.properties在spring.xml中
<!-- jdbc配置 jdbc.properties文件maven会根据配置打包在classpath下,此处匹配不到不影响-->
<context:property-placeholder location="classpath:jdbc.properties"/>
然后logback.xml是在web.xml中
<listener>
<listener-class>ch.qos.logback.ext.spring.web.LogbackConfigListener</listener-class>
</listener>
<context-param>
<param-name>logbackConfigLocation</param-name>
<param-value>classpath:logback.xml</param-value>
</context-param>
这样就实现了在maven插件中勾选环境就可以打包出对应环境的配置文件。
注意一点:上面配置spring.xml中的classpath:jdbc.properties和web.xml中的classpath:logback.xml会显示找不到(按住ctrl鼠标也点不进去),这个不影响,虽然编译器找不到,但是打包之后对应的目录下会有配置文件,项目可以运行,没有任何问题。