Maven 自动化构建(dev, test, prod)

1. 需求描述

  • 在项目构建时,需要根据环境的不同生成不同的安装包。不希望每次通过人工修改配置。
  • 有非常多的不同的 prod 环境配置,100+。
  • 在 Maven 的多模块项目中,需要有一个完整的 properties 来定义各个不同的环境,而不是分散在各个 Module 中。
  • 不希望这些 properties 定义在 pom 中,而是需要独立出来,通过动态参数加载。
  • 最终可以通过 mvn package -Pdev, mvn package -Ptest, mvn package -Pprod 完成各种环境的构建。

项目模块假设是以下的一个结构:

<modules>
    <module>cas</module>
    <module>core</module>
    <module>web</module>
    <module>client</module>
</modules>

其中,cas,web,client 是三个 war,core 是个 jar。要完成上述目标,还需要用到 properties-maven-plugin 这个插件,可以把需要定制的 properties 放到一个外部的文件,剥离 pom,并且做到动态加载配置。

2. maven-assembly-plugin

一开始想用 maven-assembly-plugin,assembly 功能很强大,可定制的程度很高。试了一下,也可以解决上边的需求。

pom

<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
        <descriptor>src/main/assemble/package.xml</descriptor>
    </configuration>
    <executions>
        <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
</plugin>

package.xml

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">

    <id>distribution</id>
    <formats>
        <format>war</format>
    </formats>
    <includeBaseDirectory>false</includeBaseDirectory>
    <fileSets>
        <fileSet>
            <directory>${project.build.directory}/${project.build.finalName}</directory>
            <includes>
                <include>**</include>
            </includes>
            <excludes>
                <exclude>**/deploy*.xml</exclude>
            </excludes>
            <outputDirectory>/</outputDirectory>
        </fileSet>
        <fileSet>
            <directory>${project.build.directory}/${project.build.finalName}</directory>
            <includes>
                <include>**/deploy*.xml</include>
            </includes>
            <filtered>true</filtered>
            <outputDirectory>/</outputDirectory>
        </fileSet>
    </fileSets>
</assembly>

但存在的问题如下:

  • 如果使用了 assembly,那么如果在配置文件中有变量,你还是需要对 maven-war-plugin 的打包过程进行定制,否则会造成 assembly filter 起作用,war 打出的包中变量没有替换的情况。也是就是如果需要保证 mvn package 构建出的 war 是有效的,既需要定制 assembly,也需要定制 war。
  • assembly 生成的文件名默认会附加 @id@ 在文件名上,好像没有配置的方法。

综上,在这个项目中,因为没有生成不同格式发布包的要求,只需要生成 war,所以,不考虑引入 assembly ,只对 maven-war-plugin 的构建过程进行定制。

3. maven-war-plugin

在 root pom 中:

<pluginManagement>
    <plugins>
        <plugin>
            <artifactId>maven-war-plugin</artifactId>
            <version>2.1.1</version>
        </plugin>
    </plugins>
</pluginManagement>

<profiles>
    <profile>
        <id>test</id>
        <properties>
            <profile>test</profile>
        </properties>
    </profile>
</profiles>

<properties>
    <profile>dev</profile>
</properties>

在 root src 下边增加 config 目录,把相关的配置文件放到下边:

  • dev.properties
  • test.properties
  • prod1.properties
  • prod2.properties

dev 内容:

ldap.port=389
ldap.host=ldap.dev.org
ldap.searchbase=dc\=dev,dc\=org
ldap.authdn=cn\=Directory Manager
ldap.passwd=password

test 内容:

ldap.port=389
ldap.host=ldap.dev.org
ldap.searchbase=dc\=test,dc\=org
ldap.authdn=cn\=Directory Manager
ldap.passwd=password	

在 cas module pom 中:

<plugin>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
        <webResources>
            <!-- 对需要修改参数的配置文件进行配置 filtering -->
            <resource>
                <directory>src/main/webapp/WEB-INF</directory>
                <includes>
                    <include>**/deploy*.xml</include>
                </includes>
                <targetPath>WEB-INF</targetPath>
                <filtering>true</filtering>
            </resource>
        </webResources>
    </configuration>
</plugin>
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>properties-maven-plugin</artifactId>
    <version>1.0-alpha-2</version>
    <executions>
        <execution>
            <phase>initialize</phase>
            <goals>
                <goal>read-project-properties</goal>
            </goals>
            <configuration>
                <files>
                    <!-- 指向 root 目录中的配置文件,并且根据 profile 动态加载文件名 -->                    
                    <file>${basedir}/../src/config/${profile}.properties</file>
                </files>
            </configuration>
        </execution>
    </executions>
</plugin>

现在在 cas module 的根目录运行 mvn package 或者 mvn package -Ptest,可以看到需要修改的 ${ldap.host} 等已经被替换。之后只需要在每个 module 下边对相关的插件进行定制,就可以完成之前的目标。