This article is part of the Maven source Code Parsing series: How does dependency mediation work? The sixth chapter mainly introduces the principle of dependencyManagement version locking.

Please read the rest of the series, in order, at juejin.cn/post/703292…

scenario

We specify version 2.0 of X directly as dependencyManagement in the root module MavenencyDemo. Also, A depends on C, and C depends on X (1.0). Let’s see if ultimately A depends on X (1.0) or X (2.0).

Root module mavenDependencyDemo pom.xml file contents:


      
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>mavenDependencyDemo</artifactId>
    <packaging>pom</packaging>
    <version>1.0</version>
    <modules>
        <module>A</module>
        <module>B</module>
        <module>C</module>
        <module>D</module>
        <module>X</module>
    </modules>
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.example</groupId>
                <artifactId>X</artifactId>
                <version>2.0</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>
Copy the code

The pom.xml of A reads as follows:


      
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>mavenDependencyDemo</artifactId>
        <groupId>org.example</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>A</artifactId>
    <version>1.0</version>

    <dependencies>
        <dependency>
            <groupId>org.example</groupId>
           <artifactId>C</artifactId>
            <version>1.0</version>
        </dependency>
    </dependencies>

</project>
 
Copy the code

Take a look at the dependency tree using the command MVN dependency: tree-dverbose:

[INFO] Scanning for projects... [the INFO] [INFO] -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- < org. Example: A > -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- [INFO] Building A 1.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- Maven-dependency plugin:2.8:tree (default-cli) @a -- [INFO] org.example:A:jar:1.0 [INFO] - Org. Example: C: jar: 1.0: the compile (INFO) - org. Example: X: jar: 2.0: the compile (version managed from 1.0) [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- [INFO] Total time: 1.410 s [INFO] Finished at: 2021-11-20T16:31:03+08:00 [INFO] ------------------------------------------------------------------------Copy the code

You can see that X (2.0) is used, the X (2.0) specified in dependencyManagement.

Another line of key information is printed:

(version managed from 1.0) 
Copy the code

Later, we will use this key information to find the corresponding source code.

Before reading the source code, let’s to the Maven website maven.apache.org/guides/intr… Explore and find a sentence:

Dependency management – this allows project authors to directly specify the versions of artifacts to be used when they are encountered in transitive dependencies or in dependencies where no version has been specified.

DependencyManagement specifies a version of a dependencyManagement statement:

  1. Specify the version of the dependency to be passed (even if the dependency has a custom version, it will be overridden);
  2. Specify the version of a direct dependency when no version is specified.

Of course, if there is no specified version of the dependency declared using dependencyManagement, the custom version of the dependency passed will be in effect.

DependencyManagement specifies the version of the dependency to be delivered (if the dependency has a custom version, it will be overridden), which is the concept of version locking.

The source code

Maven-dependency tree = maven-dependency tree = maven-dependency tree

It is controlled by getPremanagedVersion, so let’s go inside and see what it does:

DependencyManagement () this method is used to obtain the version number before the version number defined in dependencyManagement is updated.

We can see that there are two assignments (this. XXX is just a simple set method), so we can both set breakpoints and debug again:

As you can see, Is the core in the project DependencyTreeResolutionListener realized Maven Org, apache maven. An artifact. Resolver. ResolutionListener# includeArtifact method.

Going back to the Maven core project, see where the includeArtifact method is called:

Keep going up the call chain,

C (X (1.0)); C (X (1.0));

DependencyManagement = X (2.0) if the managedVersions version has a value (it didn’t have one before) :

Let’s redebug and explore to see if managedVersions did something. Let’s go back to the recursive method.

As you can see, when parsing C dependent X (1.0), it is “managed”, i.e. the version is changed to 2.0.

Obviously, the version number is managedVersions.

Now that we know how X (1.0) is changed to X (2.0), where does managedVersions come from?

Let’s continue down the call chain:

As you can see, dependency: Tree is the “birthplace” of magenedVersions, which is why it is called a core plug-in. So we according to the prompt the call stack, and then to the plug-in project org.. Apache maven. Shared.. The dependency tree. DefaultDependencyTreeBuilder# buildDependencyTree look at:

As you can see from project:

So we need to continue to see where Project was born:

Here we see that the project was passed from the Maven-dependency plugin, so let’s go to the TreeMojo and continue debugging:

Maven core project: Maven core project:

Scroll up to find that project is obtained from session:

At this point, we find an inclusion relationship: Session -> currentProject -> managedVersionMap. There are a lot of assignments. If you are not familiar with the source code, we will break all setCurrentProject and setManagedVersionMap locations to see where assignments are made. Finally we found this:

At this point, we have the source code for resolving the dependency version defined in dependencyManagement.

summary

DependencyManagement defines a dependencyManagement version of a dependency. If a dependency is resolved, the version defined by dependencyManagement will be used.