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 是 a<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}
so
$ 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 上运行时,您可能需要修改测试的类路径......这可以作为测试类路径是不可传递的)