本人初来乍到,最近研究如何搭maven框架,那么在maven项目中重中之重就是如何配父模块的pom文件。为了支持不同环境下使用不同的配置文件,有多重多样的方式,之前了解过可以在工程构建打包阶段选择配置文件,运行阶段进行配置文件选择,感兴趣的可以查阅:https://blog.csdn.net/halfclear/article/details/80067998;
以上两种方式其实还是要把properties文件打包进去,这种方式其实还不够友好,在工程构建打包阶段选择配置文件方式下进一步通过过滤替换的方式来实现;
目前普遍流行的是以下三种方式:
(1)不同环境同一套xml配置文件模板的场景:不同环境下配置不同的properties文件,共用同一套spring配置,通过不同环境下的properties配置文件替换掉spring中的${key}的方式;
(2)不同环境不同xml配置文件的场景:另一种就是不同环境下使用不同 ×××-spring.xml 配置文件,这种情况下需要指定环境来拿取×××-spring.xml;
(3)(1)与(2)相结合使用的场景:在某场景下(1)(2)单独使用并不能满足需求,比如在开发及测试环境下,数据库的读写操作都是用同一个数据库,而在生产环境下,读操作使用一个数据库,写操作用到另一个数据库,那么不同环境下对于数据库的 ds-spring.xml 的配置套路就不同了。
比如我们以dev/sit/prod三种环境进行讲解
在父模块下建立vars包来放三种环境下的properties文件,文件中主要以key-value的方式来存储数据
dev
true
../${project.parent.artifactId}/vars/vars.dev.properties
sit
../${project.parent.artifactId}/vars/vars.sit.properties
prod
../${project.parent.artifactId}/vars/vars.sit.properties
${basedir}/src/main/resources
true
${basedir}/src/test/resources
上面是pom文件中的配置不同环境下的properties文件,根据单词filter可以猜到这个配置是干嘛了.他的工作过程就是在打包的时候通过key-value对来过滤
从这里介绍的方法可以看出, 配置文件中的参数是在打包的时候才会被真正填充进去的, 那么对于那种希望在Eclipse中调试的项目怎么办.(例如用Jetty插件来调试Maven项目的时候, 并不会将项目打包后来执行, 而是直接运行src/main/webapp作为项目root路径。所以在开发 调试的时候,可以在配置文件的目录中放上完整的配置文件,里面的填充需要的参数,这位就可以顺利进行调试了, 并且不影响打包。
这种场景其实讲解第三种场景说明就很明了,其实就是resources下根据不同环境分包dev/sit/prod三种包,每个包下面存放该环境下的配置文件,该文件中不包含占位符,全部都是直接拿来就可以使用的配置文件,方式如下:
由于每个环境下的配置文件中不包含占位符,所以不需要(一)中通过过滤替换占位符的环节,仅指定maven项目的打包执行环境,这种情况下不需要在
dev
dev
true
sit
sit
prod
prod
${basedir}/src/main/resources/${package.environment}/
${basedir}/src/test/resources/${package.environment}
通过与(一)中对比,resource标签中少了
这种是最常使用的模式,即能满足各个环境通用配置文件模板的使用,又能满足不同环境个性化配置文件的需要,目录结构如下:
从图中可以看出,对于通用的配置文件的参数properties文件是放在父模块下,以key-value方式存储,用于打包时过滤替换占位符,个性化的配置放在各个模块下,不放在resources文件下,resources下主要存放通用配置文件,先把代码贴出来再做解释
dev
DEV
true
../${project.parent.artifactId}/vars/vars.dev.properties
sit
SIT
../${project.parent.artifactId}/vars/vars.sit.properties
prod
PROD
../${project.parent.artifactId}/vars/vars.prod.properties
org.apache.maven.plugins
maven-war-plugin
${project.artifactId}
src/main/webapp
true
**/*.html
**/*.js
**/*.css
**/*.xml
**/*.jsp
src/main/web-env/${envName}
true
WEB-INF/
org.apache.maven.plugins
maven-compiler-plugin
3.8.0
1.8
UTF-8
org.apache.maven.plugins
maven-resources-plugin
2.6
false
$[*]
UTF-8
maven-surefire-plugin
2.12.4
src/test/testng.xml
org.codehaus.mojo
sonar-maven-plugin
3.2
${basedir}/src/main/resources
true
${basedir}/src/test/resources
为了更详细的解释这种模式,先来看看一下的一些问题,原来想把以下的问题单独写个分享,但是为了理解的连贯性,所以就一并放到一起了。
从代码中可以看出,其实 资源文件的配置 可以有两种方法:
- 一是在
元素下添加 进行配置。 - 另一种是在
的 子元素中配置maven-resources-plugin等处理资源文件的插件。 那么这两种方式有什么区别吗?
首先我们先了解一下编译和打包阶段的细节问题
我们主要从eclipse中maven目录结构、target文件夹目录结构以及eclipse下tomcat项目目录结构入手作对比来理解。
编译阶段
src/main/java和src/test/java
这两个目录中的所有*.java文件会分别在comile和test-comiple阶段被编译,编译结果分别放到了target/classes和targe/test-classes目录中,但是这两个目录中的其他文件都会被忽略掉。
src/main/resouces和src/test/resources
这两个目录中的文件也会分别被复制到target/classes和target/test-classes目录中。
打包阶段 target/classes
打包插件默认会把这个目录中的所有内容打入到jar包或者war包中。(没有进行特殊的配置,Maven会按照标准的目录结构查找和处理各种类型文件,如果有特殊配置,target下可能会包含target\m2e-wtp\web-resources的路径文件,这个在以下文章中会详细讲解)
编译阶段:
元素下添加 进行配置的都会被复制到target/classes下,而 的 子元素中配置maven-resources-plugin等处理资源文件的插件的方式会被复制到target\m2e-wtp\web-resources路径下(该路径是eclipse空间下)。 接下来我们通过代码来验证,将非src\main\resources的资源包放到
元素下添加 进行配置,如下:
${basedir}/src/main/resources true src/main/web-env/${envName} true 最后编译完成target目录结构如下:
src/main/web-env/${envName}路径下的文件被复制到target/classes下,即使通过
去指定路径,也依然是在classes下延伸的路径而已。
src/main/web-env/${envName} true WEB-INF/ 同理:在
的 子元素中配置maven-resources-plugin等处理资源文件的插件的方式只会被复制到target\m2e-wtp\web-resources路径下,不管路径如何指定,这里要注意的是,一定要指定在WEB-INF文件夹下,因为不指定的话,最终打包不到WEB-INF包下,如下:
打包阶段:
下图是maven项目编译完成后的target目录结构,项目在tomcat上发布后,
通过上图分析 编译 -->项目tomcat发布过程:
① 当项目进行编译时,会把src/main/webapp直接照搬进了target\m2e-wtp\web-resources下,修改时间会更新为当前时间;
② 通过eclipse中tomcat下的clean操作,会把src/main/webapp直接照搬进了apache-tomcat-7.0.88\webapps\xxxx项目下;同时,target\m2e-wtp\web-resources下的文件会覆盖掉apache-tomcat-7.0.88\webapps\xxxx项目下同名的文件(通过修改时间来看的话),而且target下的classes文件会直接搬到apache-tomcat-7.0.88\webapps\xxxx项目\WEB-INF下,其中freemarker是在编译时过滤而没有搬到arget\m2e-wtp\web-resources下的文件,在tomcat下的日期仍然是第一次tomcat clean时候的日期,而lib始终是最新的更新日期。
总结:先把src/main/webapp照搬进来,如果存在则不替换,不存在新增,若存在src/main/webapp中没有的则删除,然后再将target\m2e-wtp\web-resources下的文件搬进来进行替换相同的文件
还有一点特别要注意相同路径的问题,下面通过一个例子说明:
对于不同环境特有的配置文件,在打包的时候也想和其他配置文件打包到一起,如图所示,spring-ds.xml是不同环境下特有的配置文件,但是对于打包之后的某一个环境下其实和其他的配置文件没有什么区别,所以这个时候就想把他们打包在一起
可以通过路径的设置来达到该目的
org.apache.maven.plugins maven-war-plugin ${project.artifactId} src/main/web-env/${envName}/spring true WEB-INF/classes/conf/spring ../${project.parent.artifactId}/web-env/${envName} true WEB-INF/ 将路径改为WEB-INF\classes下的同其他配置文件路径相同的路径,这样编译后的路径就是如下图
当tomcat clean的时候,target/classes下的路径会被放在WEB-INF下,其实就是和上图路径重合到一起了,所以两路文件就会被放到一起了,如下图
到此编译打包的路径问题就讲完了,其实我这边并没有使用到打包来做解释,仅仅是通过tomcat的clean操作来作比较而已!
通过编译打包的介绍,应该就理解(三)方式的用处了吧!
这里其实有想要多说两句,在web.xml中加载配置文件的路径又是根据哪个目录来的呢?
我感觉这个应该很好理解啊,web.xml是在tomcat(服务器)启动时加载这些配置文件,那就说这些路径是根据tomcat下的项目目录路径来的。
classpath 路径在每个J2ee项目中都会用到,即WEB-INF下面的classes目录,所以对于spring-ds.xml并非在classes下,所以路径自然不是用classpath来使用。