在构建之后处理 Maven 项目的依赖项
Handle the dependencies of a Maven Project after the build
所以我的问题涉及 Maven 项目中使用的依赖项。我可以使用 maven-shade-plugin
构建一个只有一个 pom 的小项目。所以它包含我使用它的所有依赖项,也可以构建为可执行 JAR。但是,具有以下结构的更大项目会发生什么:
+- myProject
+- pom.xml ... <packaging>pom, aggregator (<modules>) of frontend & backend
|
+- frontend
| +- pom.xml ... <parent>myProject, <packaging>pom, aggregator (<modules>) of window & ***
| |
| +- window
| | +- pom.xml ... <parent>frontend
| |
| +- ***
| +- pom.xml ... <parent>frontend
|
+- backend
+- pom.xml ... <parent>myProject, <packaging>pom, aggregator (<modules>) of database & ***
|
+- database
| +- pom.xml ... <parent>backend
|
+- ***
+- pom.xml ... <parent>backend
其中 window
和 database
只是 frontend
和 backend
中的示例项目,可能包含更多项目。
当我构建这样的东西时,我也可以使用 shade
方法,但我对此有疑问。这是否意味着在父级 myProject
中有一些依赖项集(带有 dependencyManagement),这些依赖项集被 frontend
和/或 backend
中的许多不同项目使用,例如,每一个构建到 JAR 时的那些项目分别包含那些依赖项(例如 JUnit,并且都包含它自己)?当一些项目相互依赖时,例如 window
依赖于 database
,因为 databse
是一个依赖项,所以它被构建到 window
的 JAR 中,然后两者分别会包含他们自己的依赖项(都有 JUnit jar),尽管他们可以使用相同的引用而不是拥有自己的引用?我是不是混淆了什么,或者以这种方式构建它是个坏主意吗?
是否有首选或“更好”的方法来构建这样的东西?
首先,这种方法被称为多模块构建,它非常适合此类事情。
Wouldn't that mean that when in the parent myProject are some dependencies set (with dependencyManagement) which get used by many different projects inside frontend and or backend for example,
对dependencyManagement
的意思有误解。在 dependencyManagement
中定义工件意味着您可以定义一个 dependency
而无需在您的模块之一(window、数据库)中提供版本号。
dependencyManagement
的目的是在中央位置(通常是多模块构建 (myProject
) 的根目录中“管理”使用的依赖项列表。
让我们从一个例子开始。您在 dependencyManagement 中定义如下工件:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apiguardian</groupId>
<artifactId>apiguardian-api</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
</dependencyManagement>
现在您想使用这个工件(换句话说,jar 文件中的 classes)。这不会向您的项目添加依赖项。其中 none 个。
所以现在要真正使用它,您必须在 pom.xml
文件之一中定义一个 dependency
。例如 window
看起来像这样:
<dependencies>
<dependency>
<groupId>org.apiguardian</groupId>
<artifactId>apiguardian-api</artifactId>
</dependency>
</dependencies>
这将起到真正的作用。这意味着在构建模块 window
期间,此依赖项(jar 文件)将在 class 路径上可用,并且您可以编译使用 classes 的 classes的依赖。您现在可以将此依赖项添加到您的多个模块中(请记住不要定义版本)。
经过一段时间的开发您想升级此神器的版本。这可以通过简单地更改 dependencyManagement
位置(仅一个位置)中的版本以及将使用该版本的所有模块来轻松实现。
所以第二个误会。由 Maven(以及其他人)构建的 jar NOT 包含它的依赖项。
包含依赖项的 jar 称为 fat-jar
、shaded-jar
或 jar-with-dependencies
或 executable-jar
(略有不同),通常不会创建,也不应该创建被用作其他人使用的依赖项。
And when some projects depend on each other for example window depends on database , that because databse is a dependecy it gets build into the JAR of window which then both seperately would contain the their own
如前所述,默认情况下 jar 不包含依赖项(而且永远不应该包含)。
如果您在多模块构建的模块之间建立依赖关系,那没关系,从技术上讲,结果是在构建 and/or 测试期间在 class 路径上找到依赖关系。
所以另一件事就是你已经提到的测试依赖关系。我以 assertj 库为例。工件本身将被定义为您可能已经在 dependencyManagement
中猜到的,如前所述。这意味着我们将这个工件添加到 dependencyManagement。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.19.0</version>
</dependency>
<dependency>
<groupId>org.apiguardian</groupId>
<artifactId>apiguardian-api</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
</dependencyManagement>
所以现在您想在您的模块之一中使用 assertj
部分,但仅用于测试。我们增强了模块的 dependency
部分...因为我们必须编写一些如下所示的测试:
<dependencies>
<dependency>
<groupId>org.apiguardian</groupId>
<artifactId>apiguardian-api</artifactId>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
所以您在这里看到的最重要的东西是 <scope>test</scope>
。这意味着依赖关系仅在单元测试期间“可见”。这意味着默认情况下位于 src/test/java
中的测试代码。所以在每个模块中你必须使用 assertj 你必须添加这个依赖(使用范围测试)。
所以最后你想构建一个前端和后端的可执行 jar。
通常的方法是创建一个单独的模块 frontend-app
和 backend-app
来生成可执行的 jar 文件。首先,您必须在 frontend-app
中定义使用的模块。这看起来像这样:
<dependencies>
<dependency>
<groupId>...</groupId>
<artifactId>window</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>...</groupId>
<artifactId>supplemental modules for frontend</artifactId>
</dependency>
...
</dependencies>
非常重要的是要看到给定的版本是由占位符 ${project.version}
完成的,它会自动替换为项目的定义版本。 ${project.version}
的用法表明该依赖项是由您自己的多模块构建构建的。
这些依赖项对于模块的正确构建顺序是绝对必要的。通过使用依赖项,Maven 可以自动确定正确的构建顺序。
当然,您必须进行配置以创建可执行 jar。这可以通过 maven-shade-plugin 或 maven-assembly-plugin(基于用例)来完成。如果这是一种 Spring 引导项目,您应该为此目的使用 spring-boot-maven-plugin。
如果您需要在此模块中编写一些集成测试,您还必须为此添加适当的依赖项。
默认情况下,通常的模块不会生成 shaded/fat jar。通常没有理由这样做。
所以我的问题涉及 Maven 项目中使用的依赖项。我可以使用 maven-shade-plugin
构建一个只有一个 pom 的小项目。所以它包含我使用它的所有依赖项,也可以构建为可执行 JAR。但是,具有以下结构的更大项目会发生什么:
+- myProject
+- pom.xml ... <packaging>pom, aggregator (<modules>) of frontend & backend
|
+- frontend
| +- pom.xml ... <parent>myProject, <packaging>pom, aggregator (<modules>) of window & ***
| |
| +- window
| | +- pom.xml ... <parent>frontend
| |
| +- ***
| +- pom.xml ... <parent>frontend
|
+- backend
+- pom.xml ... <parent>myProject, <packaging>pom, aggregator (<modules>) of database & ***
|
+- database
| +- pom.xml ... <parent>backend
|
+- ***
+- pom.xml ... <parent>backend
其中 window
和 database
只是 frontend
和 backend
中的示例项目,可能包含更多项目。
当我构建这样的东西时,我也可以使用 shade
方法,但我对此有疑问。这是否意味着在父级 myProject
中有一些依赖项集(带有 dependencyManagement),这些依赖项集被 frontend
和/或 backend
中的许多不同项目使用,例如,每一个构建到 JAR 时的那些项目分别包含那些依赖项(例如 JUnit,并且都包含它自己)?当一些项目相互依赖时,例如 window
依赖于 database
,因为 databse
是一个依赖项,所以它被构建到 window
的 JAR 中,然后两者分别会包含他们自己的依赖项(都有 JUnit jar),尽管他们可以使用相同的引用而不是拥有自己的引用?我是不是混淆了什么,或者以这种方式构建它是个坏主意吗?
是否有首选或“更好”的方法来构建这样的东西?
首先,这种方法被称为多模块构建,它非常适合此类事情。
Wouldn't that mean that when in the parent myProject are some dependencies set (with dependencyManagement) which get used by many different projects inside frontend and or backend for example,
对dependencyManagement
的意思有误解。在 dependencyManagement
中定义工件意味着您可以定义一个 dependency
而无需在您的模块之一(window、数据库)中提供版本号。
dependencyManagement
的目的是在中央位置(通常是多模块构建 (myProject
) 的根目录中“管理”使用的依赖项列表。
让我们从一个例子开始。您在 dependencyManagement 中定义如下工件:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apiguardian</groupId>
<artifactId>apiguardian-api</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
</dependencyManagement>
现在您想使用这个工件(换句话说,jar 文件中的 classes)。这不会向您的项目添加依赖项。其中 none 个。
所以现在要真正使用它,您必须在 pom.xml
文件之一中定义一个 dependency
。例如 window
看起来像这样:
<dependencies>
<dependency>
<groupId>org.apiguardian</groupId>
<artifactId>apiguardian-api</artifactId>
</dependency>
</dependencies>
这将起到真正的作用。这意味着在构建模块 window
期间,此依赖项(jar 文件)将在 class 路径上可用,并且您可以编译使用 classes 的 classes的依赖。您现在可以将此依赖项添加到您的多个模块中(请记住不要定义版本)。
经过一段时间的开发您想升级此神器的版本。这可以通过简单地更改 dependencyManagement
位置(仅一个位置)中的版本以及将使用该版本的所有模块来轻松实现。
所以第二个误会。由 Maven(以及其他人)构建的 jar NOT 包含它的依赖项。
包含依赖项的 jar 称为 fat-jar
、shaded-jar
或 jar-with-dependencies
或 executable-jar
(略有不同),通常不会创建,也不应该创建被用作其他人使用的依赖项。
And when some projects depend on each other for example window depends on database , that because databse is a dependecy it gets build into the JAR of window which then both seperately would contain the their own
如前所述,默认情况下 jar 不包含依赖项(而且永远不应该包含)。
如果您在多模块构建的模块之间建立依赖关系,那没关系,从技术上讲,结果是在构建 and/or 测试期间在 class 路径上找到依赖关系。
所以另一件事就是你已经提到的测试依赖关系。我以 assertj 库为例。工件本身将被定义为您可能已经在 dependencyManagement
中猜到的,如前所述。这意味着我们将这个工件添加到 dependencyManagement。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.19.0</version>
</dependency>
<dependency>
<groupId>org.apiguardian</groupId>
<artifactId>apiguardian-api</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
</dependencyManagement>
所以现在您想在您的模块之一中使用 assertj
部分,但仅用于测试。我们增强了模块的 dependency
部分...因为我们必须编写一些如下所示的测试:
<dependencies>
<dependency>
<groupId>org.apiguardian</groupId>
<artifactId>apiguardian-api</artifactId>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
所以您在这里看到的最重要的东西是 <scope>test</scope>
。这意味着依赖关系仅在单元测试期间“可见”。这意味着默认情况下位于 src/test/java
中的测试代码。所以在每个模块中你必须使用 assertj 你必须添加这个依赖(使用范围测试)。
所以最后你想构建一个前端和后端的可执行 jar。
通常的方法是创建一个单独的模块 frontend-app
和 backend-app
来生成可执行的 jar 文件。首先,您必须在 frontend-app
中定义使用的模块。这看起来像这样:
<dependencies>
<dependency>
<groupId>...</groupId>
<artifactId>window</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>...</groupId>
<artifactId>supplemental modules for frontend</artifactId>
</dependency>
...
</dependencies>
非常重要的是要看到给定的版本是由占位符 ${project.version}
完成的,它会自动替换为项目的定义版本。 ${project.version}
的用法表明该依赖项是由您自己的多模块构建构建的。
这些依赖项对于模块的正确构建顺序是绝对必要的。通过使用依赖项,Maven 可以自动确定正确的构建顺序。
当然,您必须进行配置以创建可执行 jar。这可以通过 maven-shade-plugin 或 maven-assembly-plugin(基于用例)来完成。如果这是一种 Spring 引导项目,您应该为此目的使用 spring-boot-maven-plugin。
如果您需要在此模块中编写一些集成测试,您还必须为此添加适当的依赖项。
默认情况下,通常的模块不会生成 shaded/fat jar。通常没有理由这样做。