【发布时间】:2015-03-07 06:01:39
【问题描述】:
我需要使用同一个父 pom 文件支持多种类型的客户端构建。我面临的挑战是不同的客户将使用略有不同的库。例如,一个客户端可能使用 SQL 服务器,而另一个客户端可能使用 MySQL。这是一个简单的示例,但其他库可能包括那些可能需要我们内部没有但我们的客户会拥有的许可证的库。在内部不排除它们会导致 maven 不再构建,因为库不会出现在我们的存储库中。我最初的想法是在我们的父 pom 中为每个客户端创建一个配置文件,然后在这些配置文件中定义仅用于该客户端的任何依赖项。这些配置文件将由缺少属性或由具有特定值的属性激活。当涉及多个模块时,特别是当一个孩子是另一个孩子的依赖时,我对解决依赖关系的方式有疑问。我认为问题的症结在于触发配置文件的变量在解决过程中的某个时间点未设置,但请允许我举一个简单的例子:
父 pom:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>../child-a</module>
<module>../child-b</module>
</modules>
<profiles>
<profile>
<id>client-a</id>
<activation>
<property>
<name>!clientbuild</name>
</property>
</activation>
<dependencies>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>sqljdbc4</artifactId>
<version>4.0</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>client-b</id>
<activation>
<property>
<name>clientbuild</name>
<value>clientb</value>
</property>
</activation>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
</dependency>
</dependencies>
</profile>
</profiles>
</project>
我在我的父 pom 中定义了 client-a 和 client-b 配置文件。在没有“clientbuild”属性的情况下应该激活client-a 配置文件,当“clientbuild”属性设置为“clientb”时应该激活“client-b”配置文件。如果我在父级上运行依赖项:树并在我的 Maven 用户“setting.xml”文件中指定“clientb”,我会得到以下信息:
--- maven-dependency-plugin:2.8:tree (default-cli) @ parent ---
com.test:parent:pom:0.0.1-SNAPSHOT
\- mysql:mysql-connector-java:jar:5.1.34:compile
--- maven-dependency-plugin:2.8:tree (default-cli) @ child-a ---
com.test:child-a:jar:0.0.1-SNAPSHOT
\- mysql:mysql-connector-java:jar:5.1.34:compile
--- maven-dependency-plugin:2.8:tree (default-cli) @ child-b ---
com.test:child-b:jar:0.0.1-SNAPSHOT
+- com.test:child-a:jar:0.0.1-SNAPSHOT:compile
| \- com.microsoft.sqlserver:sqljdbc4:jar:4.0:compile
\- mysql:mysql-connector-java:jar:5.1.34:compile
“parent”和“child-a”项目具有正确的依赖关系,但“child-b”具有来自两个配置文件的依赖关系。从树中我可以看到包含了不正确的依赖项,因为 maven 认为“child-a”具有 sqljdbc 的依赖项。我的信念是,在构建时,maven 会从父 pom 中获取“child-a”并解决它的依赖关系,而不使用我在 maven“settings.xml”文件中设置的“clientbuild”属性。有没有办法让 maven 在整个依赖解析过程中使用“clientbuild”属性?
通过各种实验,我已经确定是否要删除“!clientbuild”并将其替换为对某个值的检查(然后在我的 settings.xml 中指定该值),或者如果我没有激活要求并使用 -P 手动触发配置文件我得到了想要的结果。不幸的是,我们不能强制我们的第一个客户端在构建过程中使用 -P 或指定任何其他参数,因此使用“clientbuild”属性的缺失是我目前可以对“client-a”使用的唯一激活检查。此外,如果我将此检查替换为“activeByDefault”,则在将“clientb”作为属性添加到“settings.xml”文件时,我会得到与上述相同的行为。
因此,考虑到所有这些,我的问题是:我正在尝试做的事情是否可能?我知道我的要求很不寻常。理想情况下,我希望始终在构建期间指定配置文件,但不幸的是,这对我们的客户来说是不可能的。
简而言之,我需要默认激活一个包含某些依赖项的配置文件,但是如果由属性激活,这些依赖项将被另一个配置文件中的另一组依赖项替换。此外,当属于同一父级的某些模块相互依赖时,这需要工作,如上所示。任何人都有这方面的经验或有任何我可以尝试的替代方法?
作为最后一个脚注,我使用的是 Eclipse(特别是 Spring Tool Suite)和它附带的嵌入式 Maven 3。
编辑(子 POM 和 settings.xml): 根据要求,这里是 child-a 和 child-b 的 POM。当我尝试将“clientbuild”属性应用为“clientb”时,我还包含了我的用户 settings.xml 文件。
child-a POM:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.test</groupId>
<artifactId>parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>child-a</artifactId>
<packaging>jar</packaging>
</project>
child-b POM:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.test</groupId>
<artifactId>parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>child-b</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.test</groupId>
<artifactId>child-a</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
clientb“clientbuild”属性激活时的settings.xml:
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<pluginGroups>
</pluginGroups>
<proxies>
</proxies>
<servers>
</servers>
<mirrors>
</mirrors>
<profiles>
<profile>
<id>client-profile</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<clientbuild>clientb</clientbuild>
</properties>
</profile>
</profiles>
</settings>
我还尝试设置标签以激活我的 settings.xml 中的“客户端构建”配置文件,而不是使用 activeByDefault 标签,但这产生了相同的结果。
编辑 2(澄清关系和使用 JVM 参数): 澄清一下,client-a/client-b 配置文件对 child-a/child-b 模块之间的关系没有影响。无论配置文件如何,这种关系都是 child-b 依赖于 child-a。 client-a/client-b 配置文件唯一影响的是 sqljdbc 或 mysql-connector-java 是否作为依赖项添加到 parent。
至于在命令行中使用的 clientbuild 变量。传递 -Dclientbuild=clientb 将生成所需的依赖关系树。
--- maven-dependency-plugin:2.8:tree (default-cli) @ parent ---
com.test:parent:pom:0.0.1-SNAPSHOT
\- mysql:mysql-connector-java:jar:5.1.34:compile
--- maven-dependency-plugin:2.8:tree (default-cli) @ child-a ---
com.test:child-a:jar:0.0.1-SNAPSHOT
\- mysql:mysql-connector-java:jar:5.1.34:compile
--- maven-dependency-plugin:2.8:tree (default-cli) @ child-b ---
com.test:child-b:jar:0.0.1-SNAPSHOT
+- com.test:child-a:jar:0.0.1-SNAPSHOT:compile
\- mysql:mysql-connector-java:jar:5.1.34:compile
但是,我想要/需要使用 settings.xml 的原因是因为使用命令行参数,在修复手动 maven 构建的同时,并不能解决 Eclipse 的嵌入式 Maven 仍然会像我一样解决依赖关系的事实ve 显示在上面的初始依赖项中:树输出(child-b 将具有两个配置文件的依赖项,而不仅仅是 client-b 配置文件)。这本身是可以接受的(即使行为不符合预期),但是由于许可和其他原因,我们没有激活配置文件中不应该(来自客户端配置文件)的一些依赖项原因。如果两个配置文件的依赖关系都存在,它将导致 Eclipse 中出现许多缺少工件的错误。
【问题讨论】:
-
可以为 child-a 和 b 模块添加描述符吗?
-
@tmarwen 我添加了 child-a 和 child-b POM 以及 Eclipse 在尝试使用激活“client-b”配置文件时使用的 settings.xml 文件“clientbuild”属性。
-
我不确定我是否完全理解 child-a/child-b 模块和 client-a/client-b 配置文件之间的关系。如果 child-a 仅在 client-a 配置文件处于活动状态时应该是一个模块,那么您应该将模块声明本身移动到配置文件中,并将依赖项移动到模块中。如果不是这种情况,您能否验证当 clientbuild 变量直接在命令行(-Dclientbuild=clientb)而不是 settings.xml 中给出时,您是否得到相同的行为?询问是因为您的设置对我来说总体上看起来不错。
-
@kaqqao 澄清一下,client-a/client-b 配置文件对 child-a/child-b 模块之间的关系没有影响。无论配置文件如何,这种关系都是 child-b 依赖于 child-a。 client-a/client-b 配置文件唯一影响的是 sqljdbc 或 mysql-connector-java 是否作为依赖项添加到父级。由于篇幅太长,在下一条评论中继续...
-
@kaqqao 至于在命令行中使用的 clientbuild 变量。传递 -Dclientbuild=clientb 将生成所需的依赖关系树。我想要/需要使用 settings.xml 的原因是因为使用命令行参数,在修复手动 maven 构建时,并不能解决 Eclipse 的嵌入式 Maven 仍然会解决我上面显示的依赖项的事实(子-b 将具有两个配置文件的依赖项)。如果两个配置文件的依赖关系都存在,它将导致 Eclipse 中出现许多缺少工件的错误,因为我们不会拥有所有客户端的工件。