Maven Profiles

本文深入探讨了Maven Profiles的概念及其在构建过程中如何实现个性化配置,包括如何触发、定制与陷阱避免。重点阐述了在不同场景下使用Profiles的方法,以及如何在项目中高效地管理和组织Profiles,以保持构建过程的可移植性和团队协作性。
摘要由CSDN通过智能技术生成

原文地址:http://maven.apache.org/guides/introduction/introduction-to-profiles.html

简介

Apache Maven2.0竭尽所能让构建是可移植的。这意味着在pom.xml中配置构建内容,避免引用其它的文件(包括:继承、依赖和其它的方式),并使用本地repository来存储元数据的方式,来确保它的这一特性。

然而,有时无法做到彻底的兼容。可能我们会需要使用插件(plugins)来配置一些本地文件系统路径,也可能会有一些在依赖上的细微差别,项目的artifact也可能发生一些变化。甚至会需要根据不同的构建环境,在构造周期中(build lifecycle),引入一些不同的插件。

为处理这些场景,Maven2.0引入了build profile的概念。Profiles通过使用POM的一个子结点来指定一些内容,并可以通过多种方式来触发。Profiles通过设置一组相同名称,不同值的额外目标环境参数来达到这个目的(比如:在开发、测试和生产环境下的应用的根目录)。同样的,profiles可以方便的指定同团队成员的构建时得到不同的结果。同时,如果处理得当,在使用profiles时可以不破环项目的可移植性。在构建时,调用同一POM文件,使用-f参数,调用不同的参数和配置执行构建过程,可以更方便的进行维护。

profile的类型和定义位置

  • 每个Project
    定义在pom.xml文件中
  • 每个用户
    定义在Maven-setting中(%USER_HOME%/.m2/settings.xml)
  • 全局的
    定义在global Maven-settings中(%M2_HOME%/conf/settings.xml)

如何触发profile

一个Profile可以通过以下方式触发:

  • 明确指定
  • 通过Maven配置
  • 通过环境变量
  • 操作系统设置
  • 判断文件是否存在

详细说明

可以通过-P命令行参数来指定生效的Profiles。

该参数值为使用逗号分隔的profile-id。该参数可以指定为在当前配置中或在settings.xml文件的<activePorfile>元素中的内容profile.

mvn groupId:artifactId:goal -P profile-1,profile-2

Profiles可以在Maven Settings的<activeProfiles>中配置。该配置中包含一个或多个<activeProfile>元素,每一个都包含一个profile-id节点。

<setting>
    ...
    <activeProfiles>
        <activeProfile>profile-1</activeProfile>
    </activeProfiles>
    ...
</setting>

定义在此处的Profiles将默认在每一个project中使用。

Profiles可以根据检测构建环境来自动触发。这些内容也配置在<activation>中。通常,使用这种配置来限制JDK的版本,检查系统变量在存在和变量的值。下在这个示例将在JDK1.4及以上版本中触发:

<profiles>
    <profile>
        <activation>
            <jdk>1.4</jdk>
        </activation>
        ...
    </profile>
</profiles>

从Maven2.1开始,可以指定范围(Enforcer Version Range Syntax),下面的示例表示JDK版本为1.3, 1.4和1.5时触发:

<profiles>
  <profile>
    <activation>
      <jdk>[1.3,1.6)</jdk>
    </activation>
    ...
  </profile>
</profiles>

下面这个示例则根据操作系统来决定是否生效:

<profiles>
  <profile>
    <activation>
      <os>
        <name>Windows XP</name>
        <family>Windows</family>
        <arch>x86</arch>
        <version>5.1.2600</version>
      </os>
    </activation>
    ...
  </profile>
</profiles>

下面这个示例则在系统指定debug为任意值时生效:

<profiles>
  <profile>
    <activation>
      <property>
        <name>debug</name>
      </property>
    </activation>
    ...
  </profile>
</profiles>

下面这个示例在指定environment为test值时生效:

<profiles>
  <profile>
    <activation>
      <property>
        <name>environment</name>
        <value>test</value>
      </property>
    </activation>
    ...
  </profile>
</profiles>

可以使用如下命令使上述profile生效:

mvn groupId:artifactId:goal -Denvironment=test

从Maven3.0开始,POM中的profiles可以通过settings.xml中的激活的profiles中的参数,来决定是否激活。

下面这个示例在缺少文件时触发:

<profiles>
  <profile>
    <activation>
      <file>
        <missing>target/generated-sources/axistools/wsdl2java/org/apache/maven</missing>
      </file>
    </activation>
    ...
  </profile>
</profiles>

从Maven2.0.9开始,可以使用标签<exists><missing>。支持一些系统变量,如 user.home {env.HOME}。注意,定义在POM自身中的一些变量无法在此使用,如${project.build.director}。

下面这个示例将默认被调用:

<profiles>
  <profile>
    <id>profile-1</id>
    <activation>
      <activeByDefault>true</activeByDefault>
    </activation>
    ...
  </profile>
</profiles>

该profile将自动的被调用,在没有指定其它profile的情况下。通过命令行或者激活配置指定profile时,所有的默认profile将不会被触发。

禁止profile

从Maven2.0.10开始,可以使用’!’或’-‘来禁止profile的触发:

mvn groupId:artifactId:goal -P !profile-1,!profile-2

可用使用该处理来禁止默认的profile和通过配置来激活的profile。

哪些内容可以使用哪种类型的profile来定制

我们已经说明过在哪里指定profiles和如何激活它们,它们对熟悉如何指定profile内容有密切的联系。与其它内容一样,profile的配置也不简单。

根据配置profile位置的不同,配置选项也有一定的区别。

在外部配置Profiles

严格意义上来说,在外部指定profiles(如settings.xml,profiles.xml)是不可移植的。任何可能高度改变构建结果的配置都被限制仅可配置在POM文件自身中。如一些改变代码仓库的配置,但不可改变构建输出的路径。因此,我们仅可以在这部分配置中修改<repositories><pluginRepositories>和一些附加的<properties>

<properties>可以指定一些自定义的键值,并在处理POM时使用。如可以指定${profile.provided.path}。

在POM中定义Profiles

在POM中指定profiles,会有更多的选项。相对应的,在这种类型的profile中,只可以修改本项目和子模块。使用这种方式配置,可以更好的保持可移植性,可以增加更多的说明,让使用者使用这些内容。

在POM中定义的Profiles可以使用以下的元素:

  • <repositories>
  • <pluginRepositories>
  • <dependencies>
  • <plugins>
  • <properties>
  • <reporting>
  • <modules>
  • <dependencyManagement>
  • <distributionManagement>
  • 和一些build的子元素:
    • <defaultGoal>
    • <resource>
    • <testResources>
    • <finalName>

<profile>以外的POM元素

profiles无法修改在结点之外的POM元素,因为当POM发布到存储仓库时,运行时的修改是无法保证同步的,可以导致构建时得到完全不一样的结果。尽管使用这些外部的配置,产生的问题是有限的。另一个原因是POM可能复用父POM的一些信息。

外部的文件,如settings.xml和profiles.xml同样不可修改POM-profiles之外的内容。让我们详细的说明下这个过程。当一个有效的POM上传到远程的仓库时,任何人都可能下载并构建这个Maven项目。假如,我们可以依赖一些重要的profiles,或者一些元素在settings.xml中。这时,一些我们无法预期的人就无法构建项目。同时我们需要考虑如何将settings.xml共享给其它人。请记住,过多的配置文件容易引起混乱,并给维护带来困难。如果它是构建的数据,则应当被包含在POM中。Maven2的一个目标就是将构建所需的内容维持在一个文件中,或者POM文件层次结构中。

Profile 陷阱

我们已经提到使用profile可能对项目可移植性破坏的可能性。也给出了破坏项目可移植性的案例。接下来会再使用一个章节来讨论,如何避免使用Profile的误区。

在使用Profiles时应当注意两个问题。一是外部参数,通常在是在plugin配置中。这些会破坏项目的可移植性。另一个是自定义profile定义不完整。

外部参数

外部参数指在pom.xml之外定义一些参数。最常见的是POM中plugin配置。当缺少这些细小的参数时,构建会失败。例如,在settings.xml中指定appserver paths,并在pom中使用该字段,则团队中其它成员没有在settings.xml中指定该参数时,会构建失败。如下:
pom.xml

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.myco.plugins</groupId>
        <artifactId>spiffy-integrationTest-plugin</artifactId>
        <version>1.0</version>
        <configuration>
          <appserverHome>${appserver.home}</appserverHome>
        </configuration>
      </plugin>
      ...
    </plugins>
  </build>
  ...
</project>

~/.m2/settings.xml

<settings>
  ...
  <profiles>
    <profile>
      <id>appserverConfig</id>
      <properties>
        <appserver.home>/path/to/appserver</appserver.home>
      </properties>
    </profile>
  </profiles>

  <activeProfiles>
    <activeProfile>appserverConfig</activeProfile>
  </activeProfiles>
  ...
</settings>

当你配置好这些内容后,可以成功构建integration-test。但当你同事构建integration-test时,会失败。

此时,你的项目完全不可移植。使用在pom.xml中内置profile的方式则可以解决这个问题。同时Maven提供的丰富的项目层级支持,可以在团队级别的配置或类似文件中,通过<pluginManagement>标签来指定这些配置。

另外的答案可能是开发环境的规范。然而,它可能会妥协于Maven给生产力带来的提升。

不完整的自定义profile设置

除了上述可移植性的破坏,你的配置文件很可能无法涵盖所有的场景。如下面的pom.xml片段:

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.myco.plugins</groupId>
        <artifactId>spiffy-integrationTest-plugin</artifactId>
        <version>1.0</version>
        <configuration>
          <appserverHome>${appserver.home}</appserverHome>
        </configuration>
      </plugin>
      ...
    </plugins>
  </build>
  ...
</project>

现在,再考虑如下定义在pom.xml中的profiles:

<project>
  ...
  <profiles>
    <profile>
      <id>appserverConfig-dev</id>
      <activation>
        <property>
          <name>env</name>
          <value>dev</value>
        </property>
      </activation>
      <properties>
        <appserver.home>/path/to/dev/appserver</appserver.home>
      </properties>
    </profile>

    <profile>
      <id>appserverConfig-dev-2</id>
      <activation>
        <property>
          <name>env</name>
          <value>dev-2</value>
        </property>
      </activation>
      <properties>
        <appserver.home>/path/to/another/dev/appserver2</appserver.home>
      </properties>
    </profile>
  </profiles>
  ..
</project>

上面这个profile与上一个示例非常类似,并包含一些差异:显然与开发环境相关的配置,引入了一个新的profileappserverConfig-dev-2。在“env = dev”时,appserverConfig-dev将被触发。“env = dev-2”时,将触发appserverConfig-dev-2。执行:

mvn -Denv=dev-2 integration-test

将成功构建,properties将应用appserverConfig-dev-2中设置的值。执行:

mvn -Denv=dev integration-test

将成功构建,并应用appserverConfig-dev中的参数值。然而,执行:

mvn -Denv=production integration-test

时,会构建失败。因为${appserver.home}没有设置有效的路径,无法发布和测试Web应用。在编写profiles时,没有考虑到”production”这种场景。与”production”类似,”test”甚至”local”这些场景,都可能出现在integration-test的构建周期中。不完整的指定,可以有效的限制可用的目标场景。但你的团队和你的上司,可能无法注意到这些东西。当你配置profiles时,确保已经考虑到所有场景。

为不同的场景使用不同的Profile是让新团队成员遵循这些内容的关键,并让新成员快速的适应。再一次说明,确保考虑了所有的场景。

在构建时,如何指定生效的profiles

决定生效的profiles将有助于知晓构建时运行的详细profiles。我们可以使用Maven Help Plugin来获知哪个profiles将在构建时生效。

mvn help:active-profiles
mvn help:active-profiles -Denv=dev

让我们使用更多的例子,来理解active-profiles

从最后一个例子中,可以注意到有两个profiles,分别命名为:appserverConfig-devappserverConfig-dev-2,并为参数设置了不同的值。如果我们继续执行:

mvn help:active-profiles -Denv=dev

将会是设置”env=dev”参数时激活的profiles id的列表,如:

The following profiles are active:

 - appserverConfig-dev (source: pom)

如果在settings.xml中定义了profile,并设置为激活的profiles,执行后将显示:

mvn help:active-profiles

结果:

The following profiles are active:

- appserverConfig (source: settings.xml)

就像之前提到的,定义在settings.xml中的profile会被自动激活。所以我们没有指定任何激活的参数,仍然有一个激活的profile被列出。

现在,如果在settings.xml中设置了一个激活的profile,并且触发一个在POM中的profile,你认为构建时哪些profile将会生效?

mvn help:active-profiles -P appserverConfig-dev

结果如下:

The following profiles are active:

- appserverConfig-dev (source: pom)
- appserverConfig (srouce: settings.xml)

虽然列出了两个激活的profiles,我们还是无法确认哪个一profile被调用了。可以使用如下命令查看构建效果:

mvn help:effective-pom -P appserverConfig-dev

将输出生效的构建pom内容到控制台。记住,配置在settings.xml中的比配置的POM本身里的profile拥有更高的优先级。因此,此处将使用appserverConfig而不是appserverConfig-dev。如果想将输出内容写入到文件中,可以使用命令行参数-Doutput=effective-pom.xml

命令约定

到现在,你应该意识到profiles是一种原生的方式用来解决,不同目标环境下,需使用不同的路径下的配置文件来构建的问题。上文中,我们讨论了如何使用profiles来解决这些问题,以及完整考虑不同场景profiles的重要性。

同时,如何组织和管理这些profiles也是十分重要的。一个优异的程序员会努力去编写能自我解释的代码,同样,让你的profile id能准确表达它的作用,也是十分重要的。一个比较好的方式是,使用触发它的系统变量作为它的命名,例如:env-dev, env-testenv-prod。如此,就能直接的表明什么时候该触发哪一个profile。当你在测试环境时,你应当激活env-test

mvn -Denv=test <phase>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值