1
这又是一个系列,一个要把Maven讲透的系列,希望能够对大家有帮助!

前言

这篇文章总结的多环境构建绝对是会在实际工作中会用到的内容。比如我现在的这家公司的Maven项目,基本上都使用了这篇文章将要总结的多环境构建。那到底什么是多环境构建呢?

我们想象一下这样的一个场景。一般我们的项目都会有开发环境、测试环境和生产环境,这些环境的数据库等配置基本上都是不一样的,那么我们在进行项目构建的时候就需要能够识别所在的环境并使用正确的配置数据。对于多个环境,我们如何能够灵活的使用不同的配置数据呢?

在Maven中,为了灵活的支持这种场景,内置了三大特性,即属性、Profile和资源过滤。下面我们将通过具体的代码示例来细说这三大特性。

Maven属性

对于Maven属性,在前面的文章我们也接触过,比如之前是这样用的:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.jellythink.BookStore</groupId>
    <artifactId>project-A</artifactId>
    <version>1.0.0</version>

    <properties>
        <springframework.version>5.1.6.RELEASE</springframework.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${springframework.version}</version>
        </dependency>
    </dependencies>
</project>

通过<properties>元素,我们可以自定义一个或多个Maven属性,然后在POM的其它地方使用${属性名称}的方式引用该属性,这种做法的最大意义在于消除重复,便于后期统一修改。但是这不是Maven属性的全部,实际上,在Maven中包含以下六类属性:

  • 内置属性
    主要有以下两个常用内置属性:

    • ${basedir}表示项目根目录,即包含pom.xml文件的目录
    • ${version}表示项目版本
  • POM属性
    我们可以使用POM属性引用POM文件中对应元素的值,比如${project.artifactId}就对应了<project><artifactId>元素的值,常用的POM属性包括:

    • ${project.build.sourceDirectory}:项目的主源码目录,默认为src/main/java/
    • ${project.build.testSourceDirectory}:项目的测试源码目录,默认为src/test/java/
    • ${project.build.directory}:项目构建输出目录,默认为target/
    • ${project.outputDirectory}:项目主代码编译输出目录,默认为target/classes/
    • ${project.testOutputDirectory}:项目测试代码编译输出目录,默认为target/test-classes/
    • ${project.groupId}:项目的groupId
    • ${project.artifactId}:项目的artifactId
    • ${project.version}:项目的version,与${version}等价
    • ${project.build.finalName}:项目打包输出文件的名称,默认为${project.artifactId}-${project.version}
这些属性都对应一个POM元素,有一些属性的默认值都是在超级POM中定义的。
  • 自定义属性
    自定义属性就是通过<properties>元素定义的属性,最开始的例子就已经讲的很明白了。
  • Settings属性
    大家还记得Maven中的settings.xml文件吗?不记得的伙伴可以去看下这篇《Maven基础教程之安装与配置》。而这个Settings属性就表示我们可以使用以settings.开头的属性引用settings.xml文件中XML元素的值,比如我们可以使用${settings.localRepository}来引用用户本地仓库的地址。
  • Java系统属性
    所有的Java系统属性都可以使用Maven属性引用,比如${user.home}指向用户的目录。我们可以使用mvn help:system查看所有的Java系统属性。
  • 环境变量属性
    所有环境变量都可以使用以env.开头的Maven属性引用。比如${env.JAVA_HOME}指向了JAVA_HOME环境变量的值。我们可以使用mvn help:system查看所有的Java系统属性。

正确的使用这些Maven属性可以帮助我们简化POM的配置和维护工作。

资源过滤

在我们开发过程中,经常会碰到这样的配置文件:

database.jdbc.driverClass = com.mysql.jdbc.driverClass
database.jdbc.connectionURL = jdbc:mysql://localhost:3306/dev
database.jdbc.username = develop
database.jdbc.password = develop-password

上面的配置数据只是对开发人员的,如果测试人员进行时,则使用的如下这样的一套配置文件:

database.jdbc.driverClass = com.mysql.jdbc.driverClass
database.jdbc.connectionURL = jdbc:mysql://localhost:3306/test
database.jdbc.username = test
database.jdbc.password = test-password

也就是说,在开发环境和测试环境,我们需要使用不同的配置文件,在没有使用Maven之前,我们都是手动的修改对应的配置数据,话又说回来了,这样很麻烦,还很容易出错。现在有了Maven,我们需要作出一点改变。

为了应对不同的使用环境,我们需要将配置文件中变化的部分使用Maven属性替换,比如上面的配置文件,我们需要修改成这个样子:

database.jdbc.driverClass = ${db.driver}
database.jdbc.connectionURL = ${db.url}
database.jdbc.username = ${db.username}
database.jdbc.password = ${db.password}

我们在配置文件中定义了四个Maven属性:db.driver、db.url、db.username和db.password。接下来,我们就需要在某个地方定义这些属性。在Maven中,我们只需要使用一个额外的profile来定义这些属性就可以了。

<profiles>
    <profile>
        <id>dev</id>
        <properties>
            <db.driver>com.mysql.jdbc.driverClass</db.driver>
            <db.url>jdbc:mysql://localhost:3306/dev</db.url>
            <db.username>develop</db.username>
            <db.password>develop-password</db.password>
        </properties>
    </profile>
</profiles>

这里通过profile定义了这些属性,并使用了一个id为dev的值来区别这个profile,这样以后我们就可以针对不同的环境定义不同的profile,就可以非常的灵活。

有了属性定义,配置文件中也使用了这些属性,这样就可以了吗?不是这么简单的!我们都知道,Maven属性默认只有在POM中才会被解析。也就是说,${db.username}放到POM中会被解析成develop,但是如果放到src/main/resources/目录下的文件中,构建的时候它还是${db.username}。所以,我们需要让Maven解析资源文件中的Maven属性。

资源文件的处理其实是maven-resources-plugin的工作,但是它默认的行为只是将项目主资源文件复制到主代码编译输出目录中,将测试资源文件复制到测试代码编译输出目录中。我们只需要开启资源过滤,这个插件就能够解析资源文件中的Maven属性。

为主资源目录开启过滤:

<build>
    <!-- 为主资源目录开启过滤 -->
    <resources>
        <resource>
            <directory>${project.basedir}/src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
    
    <!-- 为测试资源目录开启过滤 -->
    <testResources>
        <testResource>
            <directory>${project.basedir}/src/main/resources</directory>
            <filtering>true</filtering>
        </testResource>
    </testResources>
</build>

我们通过mvn clean package -Pdev命令进行构建。其中-P参数表示在命令行激活一个profile。对于profile没有看懂,不要紧,下面我们再细说。构建完成后,输出目录中的数据库配置就是开发环境的配置了:

database.jdbc.driverClass = com.mysql.jdbc.driverClass
database.jdbc.connectionURL = jdbc:mysql://localhost:3306/dev
database.jdbc.username = develop
database.jdbc.password = develop-password

Maven Profile

上面说到profile,对于profile大家可能还非常的懵,这里就对profile进行详细的总结。profile是一个非常有用的功能,至少在我们公司的项目中大量使用。profile是专为不同的环境,实现无缝迁移而定制的。我们可以不同的环境配置不同的profile,比如上面提到的开发环境和测试环境两种环境下不同的配置信息,我们可以通过profile进行配置:

<profiles>
    <profile>
        <id>dev</id>
        <properties>
            <db.driver>com.mysql.jdbc.driverClass</db.driver>
            <db.url>jdbc:mysql://localhost:3306/dev</db.url>
            <db.username>develop</db.username>
            <db.password>develop-password</db.password>
        </properties>
    </profile>
    <profile>
        <id>test</id>
        <properties>
            <db.driver>com.mysql.jdbc.driverClass</db.driver>
            <db.url>jdbc:mysql://localhost:3306/test</db.url>
            <db.username>test</db.username>
            <db.password>test-password</db.password>
        </properties>
    </profile>
</profiles>

可以看到,同样的属性在两个profile中的值是不一样的;同样的,我们还可以添加更多的profile配置,比如生产配置等。接下来,我们在构建应用时,可以使用-Pdev激活dev profile,使用-Ptest激活test profile。

总结

关于Maven的多环境构建,这篇文章基本上把我工作中遇到的各种语法都进行了总结,而且这些用法也比较有代表性,希望通过我这里的总结,对大家有所帮助,在日后的工作中,大家遇到这种语法不会搞到陌生;也更希望大家在构建自己的项目中,可以使用这些用法来提升自己的工作效率。

果冻想,玩代码,玩技术!

2019年5月5日,于内蒙古呼和浩特。


图片描述


果冻想
430 声望32 粉丝