管理和范围

我通常在 parent-project/pom.xml中放一个 <dependencyManagement>节。这个 <dependencyManagement>部分包含对子模块的所有依赖项的声明和版本,如下所示(即没有 <scope>元素) :

<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
</dependencies>
</dependencyManagement>

在所有子模块(例如 moduleX/pom.xml)中,我有:

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

显然,在这个示例中,我为相同的依赖项多次重复 <scope>test</scope>(在每个需要 junit 的子模块中重复一次)。

我的问题是:
有关 <scope>申报的最佳做法是什么?
把它放在 <dependencyManagement>里是不是更好?
还是把它放在子模块的 <dependencies>部分更好(就像本文一样) ?为什么?
这个问题有确切的答案吗?

31535 次浏览

There is no gain in adding a single dependency to the dependency management, for any scope. All you have is the duplication. If you want to have the version configurable, add a property and use it in your dependency:

<properties>
<junit.version>4.10</junit.version>
...
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
</dependencies>

However, there are cases where the dependency management shines - when you are using boms in order to orchestrate the versions for a larger collections of artifacts, like using a certain version of a Java EE implementation:

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.jboss.bom</groupId>
<artifactId>jboss-javaee-6.0-with-tools</artifactId>
<version>${javaee6.with.tools.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
....

dependencyManagement is just here to define dependencies version for all project submodules, the only pertinent scope in this section is import for BOMs.

Scope must be defined in dependencies section.

(For a given dependency it determines the usage context. It allows to include the dependency only when it is required for execution. For example an ear will not be packaged with Java-ee dependencies (scope provided) as it will find them on the target server.)

[edit]

The first statement has an exception, the scope provided in dependencyManagement section will override defined scope in dependencies sections. see DependencyManagement to force scope

A little late to the party, but I'll add my two cents.

I recently ran into a very difficult to debug issue.
I have a parent pom for managing dependencies across multiple projects. I had it set with all the dependencies common amongst them and included groupId, artifactId, version and the most common scope.
My thinking would be that I would not have to include scope in the actual dependency section in each project if it fell in line with that most common scope.
The problem occurred when some of those dependencies showed up as transitive dependencies. For example, if:

  • A depends on B at compile scope.
  • B depends on C at compile scope.
  • C is set to provided in dependencyManagement of parent.

Then A's transitive dependency on C is determined to be provided. I'm not really sure if that makes sense or not, but it certainly is confusing.

Anyway, save yourself the hassle, and leave scope out of your dependencyManagement.

As with other answers, best practice is to exclude scope from dependencyManagement and explicitly specify it when defining the dependency. It is a rare case that you would want a different version of the same dependency in different scopes, e.g., one version when compiling your app and a different when running it -- the only case I can think of is you want to explicitly run your tests against a different version of a library in case users use that version instead of the one you specify.

If you define scope in dependencyManagement, it restricts the use of that version to ONLY the defined scope -- so any other scopes will pick up a random version of the dependency. I ran into this yesterday when we had defined junit 4.12 in dependencyManagement with test scope, but our common test framework module used junit with compile scope, so it picked up version 4.8.2 instead.