maven dependency conflicts, dependency mediation, dependency delivery and dependency scope

dependency transitive

The current project introduces a dependency, and the dependencies of this dependency will also be imported into the project. More accurately, mavenit will resolve direct dependencies POM, and introduce those necessary indirect dependencies into the current project in the form of transitive dependencies.

Why is it called ' necessary indirect dependency '? This is because not all indirect dependencies will be imported. This has to talk about the scope mavenof dependence .

Dependency scope

mavenIntroducing dependencies is not to jarcopy the package into the project, but to jardownload the package to the local warehouse, and then introduce specific packages classpathinto the project through formulation. Managed 3 sets , namelyjarmavenclasspathCompile classpath, test classpath, run classpath.

The dependency range is used to control the 3 classpaths. The dependency range of maven is:

Dependency scope illustrate
compile compile dependency scope (default) . Valid for all classpaths. Example: spring-core
test Test dependent scope. Only valid for test classpath. Example: junit
provided A dependent scope has been provided. Valid for compile and test classpaths. Example: servlet-api
runtime Runtime depends on scope. Valid for testing and running classpath. Example: JDBC driver
system System dependent scope. Valid for compile and test classpaths. Explicitly specified via systemPath.
import Import dependent scopes. It will not affect the classpath.

In addition to controlling the classpath, dependency scope also affects dependency delivery. If A depends on B and B depends on C, then A is the first direct dependency on B. B is the second direct dependency on C. A is a transitive dependency on C. The conclusion is: the scope of the first direct dependence and the scope of the second direct dependence determine the scope of the transitive dependence.

Use the table on "Maven Combat" to illustrate:

The first directly depends on the second directly depends on compile test provided runtime
compile compile - - runtime
test test - - test
provided provided - provided provided
runtime runtime - - runtime

The first column is the first direct dependency, the first row is the second direct dependency, and the middle indicates the range of transitive dependencies.

Dependency Conflicts and Dependency Mediation

It is because of the dependency transfer that the possibility of dependency conflicts is brought about. For example, A->X(1.0), A->B->X(2.0) . A directly depends on version 1.0 of X, and B, which A depends on, depends on version 2.0 of X. If the dependency scope is appropriate, the X that depends on B will also be passed to the A project. The versions of the two Xs are inconsistent, which creates a dependency conflict.

When a dependency conflict occurs, maven will not directly prompt an error, but use a set of rules to proceedRely on mediation. There are two rules:

  1. The closest path is preferred.
  2. The first declarer takes precedence.

The dependency path refers to the length from the project to the dependency. For example, the length of A->X(1.0) is 1, and the length of A->B->X(2.0) is 2, so the 1.0 version of X will be used eventually.

What if both paths are the same? For example, A->B->X(2.0) and A->C->X(3.0), the length of these two dependency paths is 2, so which one to use? This requires the second rule, which is to use whichever is declared first.

In most cases, maventhis automatic dependency mediation can help us solve the problem. But sometimes we have to manually handle dependency conflicts. This kind of conflict may not be different versions of the same dependency (this dependency mediation can handle it), but two dependencies that cannot appear at the same time. For example slf4j-log4j, logbackthese two dependencies cannot appear at the same time, but because their coordinates are different, maven will not align them for processing. At this time, we need to manuallyexclude dependenciesup.

Excluding dependencies
The following example is an example of excluding dependencies. When excluding dependencies, it isNo need to specify the version

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.5.3</version>
    <exclusions>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring</artifactId>
        </exclusion>
    </exclusions>
</dependency>

This kind of exclusion is very convenient. If there are many same indirect dependencies that need to be excluded, it will be more troublesome. You can refer to: " Global exclusion " of maven implementation dependencies

Check for dependency conflicts
Because maven uses dependency mediation when a dependency conflict occurs, there will be no prompts. So how do we check? There are two methods.

The first is to mvn dependency:tree -Dverboselist all dependencies of the project as well as transitive dependencies using For duplicate and conflicting dependencies, and will be omitted for duplicateprompted omitted for conflict with x.x.x.

The second method is to use maven's enforcer plugin. Add to the project POM:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-enforcer-plugin</artifactId>
            <version>1.4.1</version>
            <executions>
                <execution>
                    <id>enforce</id>
                    <configuration>
                        <rules>
                            <dependencyConvergence/>
                        </rules>
                    </configuration>
                    <goals>
                        <goal>enforce</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

In this way, when compiling with maven, if there is a dependency conflict, there will be an error message:

[ERROR]
Dependency convergence error for org.slf4j:slf4j-api:1.6.1 paths to dependency are:
+-org.myorg:my-project:1.0.0-SNAPSHOT
  +-org.slf4j:slf4j-jdk14:1.6.1
    +-org.slf4j:slf4j-api:1.6.1
and
+-org.myorg:my-project:1.0.0-SNAPSHOT
  +-org.slf4j:slf4j-nop:1.6.0
    +-org.slf4j:slf4j-api:1.6.0

Guess you like

Origin blog.csdn.net/qq_44732146/article/details/129705585