Maven dependencyManagement vs. dependencies Tags – Maven依赖性管理与依赖性标签

最后修改: 2021年 9月 20日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we will review two important Maven tags — dependencyManagement and dependencies.

在本教程中,我们将回顾两个重要的Maven标签 – dependencyManagement dependencies

These features are especially useful for multi-module projects.

这些功能对多模块项目特别有用。

We’ll review the similarities and differences of the two tags, and we’ll also look at some common mistakes that developers make when using them that can cause confusion.

我们将回顾这两个标签的异同,我们还将看看开发者在使用它们时犯的一些常见错误,这些错误会导致混淆。

2. Usage

2.使用情况

In general, we use the dependencyManagement tag to avoid repeating the version and scope tags when we define our dependencies in the dependencies tag. In this way, the required dependency is declared in a central POM file.

一般来说,当我们在dependencyManagement标签中定义我们的依赖关系时,我们使用versionscope标签来避免重复。通过这种方式,所需的依赖关系被声明在一个中央POM文件中。

2.1. dependencyManagement

2.1.依赖性管理

This tag consists of a dependencies tag which itself might contain multiple dependency tags. Each dependency is supposed to have at least three main tags: groupId, artifactId, and version. Let’s see an example:

这个标签由一个dependencies标签组成,它本身可能包含多个dependency标签。每个dependency都应该至少有三个主要标签。groupId, artifactId,version。让我们看一个例子。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>
    </dependencies>
</dependencyManagement>

The above code just declares the new artifact commons-lang3, but it doesn’t really add it to the project dependency resource list.

上面的代码只是声明了新的工件commons-lang3,但它并没有真正把它添加到项目的依赖资源列表中。

2.2. dependencies

2.2. 依赖性

This tag contains a list of dependency tags. Each dependency is supposed to have at least two main tags, which are groupId and artifactId.

这个标签包含一个dependency标签的列表。每个依赖关系应该至少有两个主要标签,即groupIdartifactId。组名工件名

Let’s see a quick example:

让我们看一个快速的例子。

<dependencies>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.12.0</version>
    </dependency>
</dependencies>

The version and scope tags can be inherited implicitly if we have used the dependencyManagement tag before in the POM file:

如果我们之前在POM文件中使用了dependencyManagement标签,那么versionscope标签可以被隐式继承。

<dependencies>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
    </dependency>
</dependencies>

3. Similarities

3.相似性

Both of these tags aim to declare some third-party or sub-module dependency. They complement each other.

这两个标签都是为了声明一些第三方或子模块的依赖性。它们相互补充。

In fact, we usually define the dependencyManagement tag once, preceding the dependencies tag. This is used in order to declare the dependencies in the POM file. This declaration is just an announcement, and it doesn’t really add the dependency to the project.

事实上,我们通常会在dependencyManagement标签之前,定义一次dependencies标签。这样做是为了在POM文件中声明依赖关系。这个声明只是一个公告,它并没有真正将依赖关系添加到项目中。

Let’s see a sample for adding the JUnit library dependency:

让我们看一个添加JUnit库依赖的例子。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

As we can see in the above code, there is a dependencyManagement tag that itself contains another dependencies tag.

正如我们在上面的代码中看到的,有一个dependencyManagement标签,它本身包含另一个dependencies标签。

Now, let’s see the other side of the code, which adds the actual dependency to the project:

现在,让我们看看代码的另一面,它将实际的依赖关系添加到项目中。

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
    </dependency>
</dependencies>

So, the current tag is very similar to the previous one. Both of them would define a list of dependencies. Of course, there are small differences which we will cover soon.

所以,当前的标签与之前的标签非常相似。它们都会定义一个依赖关系的列表。当然,也有一些小的区别,我们很快就会介绍。

The same groupId and artifactId tags are repeated in both code snippets, and there is a meaningful correlation between them: Both of them refer to the same artifact.

相同的groupIdartifactId标签在两个代码片段中都有重复,而且它们之间存在着有意义的关联。它们都指的是同一个工件。

As we can see, there is not any version tag present in our later dependency tag. Surprisingly, it’s valid syntax, and it can be parsed and compiled without any problem. The reason can be guessed easily: It will use the version declared by dependencyManagement.

我们可以看到,在我们后面的version标签中没有任何dependency标签。令人惊讶的是,这是有效的语法,它可以被解析和编译,没有任何问题。原因可以很容易猜到。它将使用dependencyManagement所声明的版本。

4. Differences

4.差异

4.1. Structural Difference

4.1.结构差异

As we covered earlier, the main structural difference between these two tags is the logic of inheritance. We define the version in the dependencyManagement tag, and then we can use the mentioned version without specifying it in the next dependencies tag.

正如我们之前所介绍的,这两个标签之间的主要结构差异是继承的逻辑。我们在dependencyManagement标签中定义了版本,然后我们可以在下一个dependencies标签中使用提到的版本,而无需指定它。

4.2. Behavioral Difference

4.2.行为上的差异

dependencyManagement is just a declaration, and it does not really add a dependency. The declared dependencies in this section must be later used by the dependencies tag. It is just the dependencies tag that causes real dependency to happen. In the above sample, the dependencyManagement tag will not add the junit library into any scope. It is just a declaration for the future dependencies tag.

dependencyManagement只是一个声明,它并没有真正添加一个依赖关系。本节中声明的dependencies必须在以后被dependencies标签使用。只是dependencies标签导致了真正的依赖关系的发生。在上面的例子中,dependencyManagement标签不会将junit库加入任何范围。它只是对未来的dependencies标签的一个声明。

5. Real-World Example

5.现实世界的例子

Nearly all Maven-based open-source projects use this mechanism.

几乎所有基于Maven的开源项目都使用这种机制。

Let’s see an example from the Maven project itself. We see the hamcrest-core dependency, which exists in the Maven project. It’s declared first in the dependencyManagement tag, and then it is imported by the main dependencies tag:

让我们看看来自Maven项目本身的例子。我们看到hamcrest-core依赖,它存在于Maven项目中。它首先在dependencyManagement标签中声明,然后被主dependencies标签导入。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
            <version>2.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.hamcrest</groupId>
        <artifactId>hamcrest-core</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

6. Common Use Cases

6.常见用例

A very common use case for this feature is a multi-module project.

这个功能的一个非常常见的用例是一个多模块项目。

Imagine we have a big project which consists of different modules. Each module has its own dependencies, and each developer might use a different version for the used dependencies. Then it could lead to a mesh of different artifact versions, which can also cause difficult and hard-to-resolve conflicts.

想象一下,我们有一个由不同模块组成的大项目。每个模块都有自己的依赖关系,每个开发者都可能使用不同的版本来处理所使用的依赖关系。那么,这可能会导致不同工件版本的网状结构,这也会导致困难和难以解决的冲突。

The easy solution for this problem is definitely using the dependencyManagement tag in the root POM file (usually called the “parent”) and then using the dependencies in the child’s POM files (sub-modules) and even the parent module itself (if applicable).

这个问题的简单解决方案肯定是在根POM文件(通常称为 “父”)中使用dependencyManagement 标签,然后在子POM文件(子模块)甚至父模块本身(如果适用)中使用dependencies

If we have a single module, does it make sense to use this feature or not? Although this is very useful in multi-module environments, it can also be a rule of thumb to obey it as a best practice even in a single-module project. This helps the project readability and also makes it ready to extend to a multi-module project.

如果我们有一个单一的模块,使用这个功能是否有意义?尽管这在多模块环境中非常有用,但即使在单模块项目中,也可以作为一个经验法则,将其作为一个最佳实践来遵守。这有助于项目的可读性,也使得它可以扩展到一个多模块项目。

7. Common Mistakes

7.常见错误

One common mistake is defining a dependency just in the dependencyManagement section and not including it in the dependencies tag. In this case, we will encounter compile or runtime errors, depending on the mentioned scope.

一个常见的错误是仅仅在dependencyManagement部分定义了一个依赖关系,而没有将其纳入dependencies标签。在这种情况下,我们将遇到编译或运行时错误,这取决于所提到的范围

Let’s see an example:

让我们看一个例子。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>
        ...
    </dependencies>
</dependencyManagement>

Imagine the above POM code snippet. Then suppose we’re going to use this library in a sub-module source file:

想象一下上面的POM代码片断。然后假设我们要在一个子模块源文件中使用这个库。

import org.apache.commons.lang3.StringUtils;

public class Main {

    public static void main(String[] args) {
        StringUtils.isBlank(" ");
    }
}

This code will not compile because of the missing library. The compiler complains about an error:

由于缺少库,这段代码将无法编译。编译器会抱怨说有错误。

[ERROR] Failed to execute goal compile (default-compile) on project sample-module: Compilation failure
[ERROR] ~/sample-module/src/main/java/com/baeldung/Main.java:[3,32] package org.apache.commons.lang3 does not exist

To avoid this error, it’s enough to add the below dependencies tag to the sub-module POM file:

为了避免这个错误,只要在子模块的POM文件中加入下面的dependencies标签即可。

<dependencies>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
    </dependency>
</dependencies>

8. Conclusion

8.结语

In this tutorial, we compared Maven’s dependencyManagement and dependencies tags. Then, we reviewed their similarities and differences and saw how they work together.

在本教程中,我们比较了Maven的dependencyManagementdependencies标签。然后,我们回顾了它们的异同,并了解了它们如何协同工作。

As usual, the code for these examples is available over on GitHub.

像往常一样,这些例子的代码可以在GitHub上找到over