在如下结构的Maven多模块项目中:
P // parent project
* A // first module
* B // second module, containing the test in question
A 的pom.xml
包含:
<profile>
<id>theProfile</id>
<build>
<resources>
<resource>
<directory>src/main/ctx/someDir</directory>
<filtering>true</filtering>
</resource>
<resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<build>
</profile>
当运行完整的项目 P 且激活此配置文件时,{em> B 测试期间src/test/resources
作为类路径的一部分的可用性方式是什么?
如果是,以何种方式,以及如何更改定义,以便给定资源
a)纯粹的附加
b)仅影响定义它们的 A 。
如果否,src/main/resources
部分是多余的吗?
答案 0 :(得分:2)
简短回答:不,不。
在流程资源阶段,项目A中的资源将被复制到A/target/classes
。配置文件唯一要做的就是将更多资源复制到target/classes
。也就是说,它还会复制(和过滤)来自src/main/ctx/someDir
的文件。
B的测试类路径保持不变。假设B依赖于A,则其测试类路径将包括A.jar,其将包括A /目标/类的内容。您可以使用mvn dependency:build-classpath
进行检查。但是,尽管类路径相同,但A的类路径条目的内容将不同。
我不确定你为什么提到src/test/resource
(我假设你错了src/test/resources
)。使用<testResources>
元素单独管理测试资源。如果你的意思是A/src/test/resources
,那么不,它们不会出现在B的测试类路径中。如果你的意思是B/src/test/resources
,那么是的,它们将出现在B的测试类路径中。因此,通过激活配置文件,它不会受到任何影响。
指定src/main/resources
不是多余的。如果您要包含<resources>
元素,则需要包含项目中包含资源的所有目录。
答案 1 :(得分:2)
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&#39的依赖关系包括A,所以它将引用A的主要工件(因为jar:jar
没有运行将指向A&#39; s ${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
] < / p>
虽然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&#39的测试类将使用类似
${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&#39>的编译类路径与以前相同。我也投入了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&C的类路径由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&#39>的类路径构造与以前相同,只是现在B看到的是.jar
而不是A&#39的编译类。所以B&#39; 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&#39; 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&#39; 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的第二次调用中我们刚刚使用单个模块recactor运行(即B是反应器中唯一的模块),现在A将从本地缓存中解析,因此我们得到的测试类路径类似于< / p>
${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相比时,您可能需要修改测试的类路径...这个没问题,因为测试类路径是不可传递的)