TL;DR A) 不; B) 否;如果你的 <resources> 是 <resources combine.children="append"> 那么你可以省略它,但正如所写,否
长答案
如果您从根目录运行构建,并假设 B 依赖于 A
您获得的类路径取决于您将整个反应器推进到的阶段。
如果该阶段在生命周期的 package 阶段之前,则类路径将引用 ${project.build.outputDirectory} 目录以获取反应器内的依赖项
如果阶段处于生命周期的package 阶段或之后,类路径将引用构建的 JAR 文件,例如${project.build.directory}/${project.build.finalName}.jar
所以给你一些具体的例子:
$ mvn compile
这在 P 中没有任何作用,因为 P 是 <packaging>pom</packaging>,并且默认情况下,打包不会将任何 [类路径相关] 插件绑定到 install 之前的生命周期阶段。
当我们点击 A 时,它会在编译类路径中列出 A 的所有依赖项,因为这些都不是来自反应器,它们将从本地缓存中解析(即~/.m2/repository)所以如果 A 使用 log4j,你将有一个编译类路径,如
${JAVA_HOME}/lib/rt.jar:~/.m2/repository/log4j/log4j/1.2.16/log4j-1.2.16.jar
我们没有指定编译后的阶段,所以不会调用需要测试类路径的插件,所以此时不相关。
现在我们移动到 B。B 的依赖项包括 A,因此它将引用 A 的主要工件(因为 jar:jar 尚未运行将指向 A 的 ${project.build.outputDirectory})B 的编译类路径看起来有点东西像这样
${JAVA_HOME}/lib/rt.jar:~/.m2/repository/log4j/log4j/1.2.16/log4j-1.2.16.jar
:./A/target/classes
[注意:当我们从 P 目录调用时,当前目录是 P 的 ${basedir},所以 B 的 ${basedir} 的值将是 ./B]
虽然 B 自己的依赖项可能会根据其 pom 中依赖项的顺序以及是否对传递依赖项应用排除或版本覆盖来改变类路径
好的。这很容易让我们开始......接下来我们将生命周期提升到test 阶段
$ mvn test
P的故事和以前一样
A 的编译故事与以前相同。当我们达到test-compile 阶段时,测试将使用以下类路径编译(假设使用 junit 进行测试)
${JAVA_HOME}/lib/rt.jar:~/.m2/repository/log4j/log4j/1.2.16/log4j-1.2.16.jar
:./A/target/classes:~/.m2/repository/junit/junit/4.10/junit-4.10.jar
[我的元素排序可能有点错误,因为我需要深入研究 mvn -X 来确认,但主体是正确的]
当我们进入test 阶段时,surefire:test 将构建测试类路径。默认情况下,它将测试依赖项放在非测试依赖项之前,但它是可配置的。所以 A 的测试类将使用类似这样的类路径执行
${JAVA_HOME}/lib/rt.jar:./A/target/test-classes:~/.m2/repository/junit/junit/4.10/junit-4.10.jar
:~/.m2/repository/log4j/log4j/1.2.16/log4j-1.2.16.jar:./A/target/classes
这允许使用测试类路径中的匹配资源来覆盖生产默认值以使代码可测试等。
B 的编译类路径和以前一样。我还认为 B 依赖于不同版本的 JUnit。 test-compile 类路径应该不足为奇
${JAVA_HOME}/lib/rt.jar:~/.m2/repository/log4j/log4j/1.2.16/log4j-1.2.16.jar
:./A/target/classes:./B/target/classes
:~/.m2/repository/junit/junit/4.11/junit-4.11.jar
现在事情变得有趣了,B 的类路径是由surefire 构造的(同样可以修改测试范围依赖项的顺序,因此假设您使用的是默认值)。 A 的测试类路径是不可传递的,因此不会暴露给 B。
${JAVA_HOME}/lib/rt.jar:./B/target/test-classes
:~/.m2/repository/junit/junit/4.11/junit-4.11.jar
:~/.m2/repository/log4j/log4j/1.2.16/log4j-1.2.16.jar
:./A/target/classes:./B/target/classes
最后,让我们深入到package 阶段,看看它如何影响类路径。
$ mvn package
P 和以前一样。
A 实际上和以前一样,因为它的依赖项都不是来自反应器内部。但这里的关键是,当jar:jar 在package 阶段运行时,它会替换暴露的类路径……这将影响 B 如何看待 A。
B 的类路径的构造与以前相同,只是现在 B 看到 A 的 .jar 而不是 A 的编译类。所以 B 的 compile 类路径将是
${JAVA_HOME}/lib/rt.jar:~/.m2/repository/log4j/log4j/1.2.16/log4j-1.2.16.jar
:./A/target/A-1.0-SNAPSHOT.jar
B 的 test-compile 类路径看起来像这样
${JAVA_HOME}/lib/rt.jar:~/.m2/repository/log4j/log4j/1.2.16/log4j-1.2.16.jar
:./A/target/A-1.0-SNAPSHOT.jar:./B/target/classes
:~/.m2/repository/junit/junit/4.11/junit-4.11.jar
B 的 test 类路径将如下所示:
${JAVA_HOME}/lib/rt.jar:./B/target/test-classes
:~/.m2/repository/junit/junit/4.11/junit-4.11.jar
:~/.m2/repository/log4j/log4j/1.2.16/log4j-1.2.16.jar
:./A/target/A-1.0-SNAPSHOT.jar:./B/target/classes
现在只是给你最后的图片
$ mvn install -DskipTests
$ mvn test -f B/pom.xmml
在 Maven 的第二次调用中,我们仅使用单个模块反应器运行(即 B 是反应器中的唯一模块),现在 A 将从本地缓存中解析,因此我们得到类似的测试类路径
${JAVA_HOME}/lib/rt.jar:./B/target/test-classes
:~/.m2/repository/junit/junit/4.11/junit-4.11.jar
:~/.m2/repository/log4j/log4j/1.2.16/log4j-1.2.16.jar
:~/.m2/repository/com/mydomain/myproject/A/1.0-SNAPSHOT/A-1.0-SNAPSHOT.jar
:./B/target/classes
现在希望这已经在一定程度上阐明了 Maven 类路径的奥秘。
您的个人资料是如何混入其中的……好吧,它们对您的类路径没有任何作用。他们所做的是将文件复制到${project.build.outputDirectory。
当 A 到达process-resources 阶段时,它会将所有定义的resources 复制到${project.build.outputDirectoy} 所以
$ mvn package -PtheProfile
将构造完全相同的类路径但./A/src/main/ctx/someDir 中的文件将通过过滤复制到 A 的 ${project.build.outputDirectoy},同时保留它们的目录结构,./A/src/main/resources 中的文件将被复制到A 的${project.build.outputDirectoy} 没有过滤,同时保留其目录结构。然后当我们到达package 阶段时,jar:jar 将再次将所有这些文件吞入.jar。
我希望这个答案可以帮助您更好地了解正在发生的事情......我也希望您开始了解为什么使用配置文件来影响构建的工件会导致头痛,例如
$ mvn clean install -PtheProfile -DskipTests
$ mvn test -f B/pom.xml
会有不同的结果
$ mvn clean install -DskipTests
$ mvn test -f B/pom.xml
由于本地存储库缓存不知道在将工件安装到本地存储库时哪些配置文件处于活动状态,因此第一种情况会构建与第二种情况不同的 A.jar...
但这更多地暗示了您将来可能会遇到的问题,以及为什么我们提倡坚持使用 Maven 方式并避免使用配置文件来修改传递公开的类路径或构建的工件。使用配置文件来修改 test 类路径非常有用(例如,当测试在 JDK1.5、JDK1.6 和 JDK1.7 上运行时,您可能需要修改测试的类路径......这没关系因为测试类路径是不可传递的)