Maven Profile无法根据项目配置“自动激活”及复杂项目配置管理的探讨

想让某个profile“根据项目的配置自动激活”,无奈试过各种方法、策略,都不行。

下面是一个profile的标准配置:

<profiles>
<profile>
  <id>exe-jar</id>
  <activation>
    <property>
      <name>JAR-BOOT</name>
    </property>
    <file>
      <exists>${basedir}/src/main/resources/META-INF/jar.app</exists>
      <exists>profiles.xml</exists>
    </file>
  </activation>


首先,根据官方文档:

https://maven.apache.org/settings.html#Profiles

摘录如下:

Activation occurs when all specified criteria have been met, though not all are required at once.

  • jdkactivation has a built in, Java-centric check in the jdk element. This will activate if the test is run under a jdk version number that matches the prefix given. In the above example, 1.5.0_06 will match. Ranges are also supported. See the maven-enforcer-plugin for more details about supported ranges.

  • os: The os element can define some operating system specific properties shown above. See the maven-enforcer-plugin for more details about OS values.

  • property: The profile will activate if Maven detects a property (a value which can be dereferenced within the POM by ${name}) of the corresponding name=value pair.

  • file: Finally, a given filename may activate the profile by the existence of a file, or if it is missing.

The activation element is not the only way that a profile may be activated. The settings.xml file’s activeProfile element may contain the profile’s id. They may also be activated explicitly through the command line via a comma separated list after the -P flag (e.g. -P test).

To see which profile will activate in a certain build, use the maven-help-plugin.

  1. mvn help:active-profiles


profile的自动激活方式有4种。因为我是想根据项目配置来自动激活,上面这几种方式均不能达到效果。

    根据jdk、os激活,不是我想要的,pass。

    根据property激活,这个有点坑,只能是系统变量才行。mavan pom.xml里面定义的properties无法识别。

所以,这四种方式都很鸡肋,都无法做到根据项目来自动激活。

我找到了作者说的一句话:

Profile activgation is the first step of the first phase

and profile activation does not work with POM property but with CLI property

    因为系统变量,需要在打包命令,或者环境变量中设置。所以这种方法对我来说不可取(因为我想根据项目自身配置自动激活,不需要人为配置)。

    最后抱了一丝希望:根据file激活,这个也很坑。参见这个issues:

https://issues.apache.org/jira/browse/MNG-2363(我的需求跟这个描述一模一样!!)

    这个file的路径,如果是相对路径,且是在父pom.xml中设置的profiles,则file路径是针对于父pom.xml项目构建路径的绝对值。例如 profiles.xml 或 ${basedir}/profiles.xml,都是指向的父pom.xml构建时的路径,例如:D:\__SYNC2\git\jretty-pom\profiles.xml,亲测如此。这样子项目中的profiles.xml文件就不会起作用。垃圾垃圾!怎么会这样?这应该是bug吧!总之,file激活太不靠谱。


引申结论

    由于这个问题,又对Maven进行了各方面的研究,对Maven的理解也加深了。

    总结出一点:Maven不太适合多模块的复杂项目(可能大多数人的项目都不会复杂到我说的那种程度,后面有举例)。具体说起来很复杂,我简单提几点(不做详细阐述)

1、新版Maven提供了 <scope>import</scope>,但是仅能引入 dependency组件。至于其他标签都无法继承,例如build标签里面的那些,以及properties标签。这个缺点对结构复杂、继承模块非常多的项目来说很严重,就拿build标签里面的东西来说,多继承也是相当有必要的。

2、尝试用profile来解决pom.xml的多继承问题,倒是可以包含build、properties等标签,但是由于上文所述的问题,这种profile切换的功能十分鸡肋(不能根据项目的变量动态切换),它只能通过jdk、cli参数、系统变量来切换————对于多模块项目来说,并不是每个模块的build、properties配置都是一样的,有些是jar、有些是war,而通过cli参数、系统变量,只能针对单个项目去控制变量才能实现,对于多模块项目,没办法单独为每个模块指定cli参数(mvn -P参数对多模块的所有子模块生效,无法单独指定某个子模块生效,除非逐个项目执行构建,所以我说Maven适合单项目,不适合多模块项目的构建,另外当初Ant流行就是因为Ant对项目的构建更灵活,弥补了Maven的缺陷)。实际案例有很多(例如上文提到的https://issues.apache.org/jira/browse/MNG-2363案例)。所以,放弃profile。

3、既然profile无法解决pom.xml继承的问题,那么只能退而求其次,使用module-parent的项目结构,使用parent-children来实现一定程度的继承。

举个例子,我的项目比较复杂,改造前如下(简化结构):

talos-parent
    talos-api
    talos-common
    talos-app1
    talos-app2
 
 himes-parent
    himes-api
    himes-common
    himes-app1
    himes-app2

由于talos-app1、talos-app2、himes-app1……等几十个项目的pom.xml几乎是一模一样的,于是想通过继承的方式将pom.xml集中管理起来。改造后如下:

talos-parent
    talos-api
    talos-common
    talos-app-parent
        talos-app1
        talos-app2

这样一来,talos-app1和talos-app2的配置就可以继承 talos-app-parent,从而自身简化到只有一个引用声明

<project>

  <artifactId>talos-app1</artifactId>
  
  <parent>
    <groupId>com.fbank</groupId>
    <artifactId>talos-app-parent</artifactId>
    <version>1.0.0-SNAPSHOT</version>
  </parent>
  
</project>

但是,很显然,talos-app-parent的作用范围仅限于 其子module,对于himes-app1、himes-app2等其他项目无能为力

然而这并不是我期望的,talos-app和himes-app仅仅是项目不同,pom.xml其实大同小异,不能继承、非常遗憾!!(Maven的对手Gradle可以做到,它可以将片段传到远程仓库,供其他项目可以include引入


3、Maven有几个命令可以控制 module子项目的打包,但是不支持子项目嵌套。例如上面的双parent项目结构,mvn install可以一键打包所以模块。但是mvn  -pl -am这些命令参数,只能对一级模块起作用,无法控制内层的二级、三级子模块项目,而复杂的项目有二级、三级子模块很正常。


4、像Spring这样复杂的项目群,没有采用Maven来管理,看来是明智的


5、我曾经研究对比过Maven和Gradle,只能说Gradle更强大、更灵活,但是也更复杂和不可控,是一把双刃剑


结论:

  1. 如果是小团队独立项目,能忍受多个项目的Maven pom.xml内有上百行的重复,那用maven没问题。

  2. 如果是大范围的很多项目、涉及几十上百开发人员,且需要统一管理,那么用Gradle是最方便的,但是由于很多团队不会用Gradle,要推广实施并不容易。


© 2009-2020 Zollty.com 版权所有。渝ICP备20008982号