Location>code7788 >text

maven pass dependencies and prioritization with examples, difficult to top also have to be on the yah!

Popularity:570 ℃/2024-08-07 08:29:30

Happy Moment

I want to buy a motorcycle, but I don't have enough money. I want to borrow some from my dad.

Me: Dad, I want to buy a motorcycle, it's easy to commute to work.

Dad: Your cousin fell off his motorcycle last month, don't you know? You still want to buy a motorcycle?

Me: I'm sorry, I'm not buying

Boss: That's right, just ride your cousin's car, why buy a new one?

你是认真的吗

Let's start with a question.

with respect tomaven The dependence of the (dependencyI'm sure we all know a little bit about it.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="/POM/4.0.0"
         xmlns:xsi="http:///2001/XMLSchema-instance"
         xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.">
    <modelVersion>4.0.0</modelVersion>

    <groupId></groupId>
    <artifactId>spring-boot-2_7_18</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId></groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.18</version>
    </parent>

    <properties>
        <>8</>
        <>8</>
        <>UTF-8</>
    </properties>

    <dependencies>
        <dependency>
            <groupId></groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
</project>

Isn't it reasonable and logical to introduce whatever you depend on? Let's take a look at thelog dependencies

log依赖

I used idea's Maven Helper plugin, a good maven dependency analysis tool.

At this point, are you in doubt: don't you just rely on thespring-boot-starter-webHow come there's all kinds oflog of dependence?

And then I'm in Add a line in the middle, just add a line

新加一行

at this timelog Dependency has changed from what it was before.

log依赖变化

What's this for?

You think it doesn't matter, but the following exception occurs when you actually start it (see the cause:SpringBoot2.7 or capricious, just does not support Logback1.3, you can do anything about it!

SLF4J: Failed to load class "org.".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http:///#StaticLoggerBinder for further details.
Exception in thread "main" : org/slf4j/impl/StaticLoggerBinder
	at (:304)
	at (:118)
	at (:238)
	at (:220)
	at (:178)
	at (:171)
	at (:145)
	at (:133)
	at (:79)
	at $starting$0(:56)
	at (:1249)
	at (:120)
	at (:56)
	at (:299)
	at (:1300)
	at (:1289)
	at (:16)
Caused by: : org.
	at (:381)
	at (:424)
	at $(:331)
	at (:357)
	... 17 more

And then you're confused.

怎么会这样

Let's tweak it.

pom去掉springboot日志

at this timelog Relies on the following

logback1.3.14依赖的slf4j怎么是1.7.36

Maybe that's okay with you guys, I'll quote it again for you;logback1.3.14 dependentslf4j The version is2.0.7

logback1.3.14依赖slf4j2.0.7

then (in that case)slf4j1.7.36 Where is it from and why isn't it2.0.7 ?

With this barrage of questions down, I'm asking if you're panicking, but don't you panic, because I'm going to make a move!

transferential dependence

Before the birth of maven, adding jar dependencies can be a big headache, you need to manually add all the jars, it is easy to miss, and then according to the exceptions to make up for the missing jar; many experienced veterans will be categorized, such as the introduction of Spring need to add which several jars, the introduction of the POI need to add which several jars, but it is still easy to miss; while the maven pass-through dependency mechanism is a good solution to this problem. maven's pass-through dependency mechanism solves this problem very well

What is transitive dependence, going back to our original case

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="/POM/4.0.0"
         xmlns:xsi="http:///2001/XMLSchema-instance"
         xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.">
    <modelVersion>4.0.0</modelVersion>

    <groupId></groupId>
    <artifactId>spring-boot-2_7_18</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId></groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.18</version>
    </parent>

    <properties>
        <>8</>
        <>8</>
        <>UTF-8</>
    </properties>

    <dependencies>
        <dependency>
            <groupId></groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
</project>

Intuitively it looks like it only relies on thespring-boot-starter-webLibyan Arab Jamahiriyaspring-boot-starter-web also has its own dependencies, which maven resolves, and so on. maven introduces those necessary indirect dependencies into the current project as pass-through dependencies

传递性依赖

concern

not rely onspring-boot-starter-webHow come there's all kinds oflog of dependence?

Is it clear?

Dependency Priority

The pass-through dependency mechanism greatly simplifies dependency declarations and is very developer-friendly. For example, if we need to use spring's web functionality, we can simply introduce the

<dependency>
	<groupId></groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

It's ok, isn't it so easy? But there are some problems, for example, project P has two transitive dependencies as follows

P -> A -> B -> C(1.0)

P -> D -> C(2.0)

So which C will be introduced into the P project by maven? At this point, maven enables its first principle

Shortest path first

Here.trails refers to the length of the pass dependency, a pass dependency has a length of 1, a P to C (1.0) pass dependency has a length of 3, and a P to C (2.0) pass dependency has a length of 2. Therefore, C (2.0) will be introduced by maven into the P project, while C (1.0) will be ignored

Shortest path first does not solve all problems, for example, project P has two transitive dependencies as follows

P -> B -> C(1.0)

P -> D -> C(2.0)

The length of both passed dependencies is 2, so who does maven bring in? Starting with maven 2.0.9, maven adds the second principle

Priority of the first statement

processShortest path first If B is declared before D, then C(1.0) will be introduced to P by maven and C(2.0) will be ignored.

Let's look at it again.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="/POM/4.0.0"
         xmlns:xsi="http:///2001/XMLSchema-instance"
         xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.">
    <modelVersion>4.0.0</modelVersion>

    <groupId></groupId>
    <artifactId>spring-boot-2_7_18</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId></groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.18</version>
    </parent>

    <properties>
        <>8</>
        <>8</>
        <>UTF-8</>
        <>1.3.14</>
    </properties>

    <dependencies>
        <dependency>
            <groupId></groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
</project>

The logback at this point

log依赖变化

Why 1.3.14 and not 1.2.12, which actually involvesCustom Properties which is somewhat similar to override in java; 1.2.12 is a custom property declared in a parent dependency (spring-boot-starter-parent) of a parent dependency (spring-boot-dependencies) of the

logback1.2.12

And the custom attributes we declare ourselves<>1.3.14</> Just in time to cover it.1.2.12So maven uses1.3.14

Is that the last question? Let's review the question, which reads as follows

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="/POM/4.0.0"
         xmlns:xsi="http:///2001/XMLSchema-instance"
         xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.">
    <modelVersion>4.0.0</modelVersion>

    <groupId></groupId>
    <artifactId>spring-boot-2_7_18</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId></groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.18</version>
    </parent>

    <properties>
        <>8</>
        <>8</>
        <>UTF-8</>
        <>1.3.14</>
    </properties>

    <dependencies>
        <dependency>
            <groupId></groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-logging</artifactId>
                    <groupId></groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId></groupId>
            <artifactId>logback-classic</artifactId>
            <version>${}</version>
        </dependency>
    </dependencies>
</project>

Dependency at this time

logback1.3.14依赖的slf4j怎么是1.7.36

Why is slf4j 1.7.36 and not 2.0.7 in logback?Custom Properties prioritization

The prioritization of custom attributes follows the same first and second principles of maven dependency passing

Inherited from grandpa (spring-boot-dependencies) be1.7.36

slf4j1.7.36

is equivalent to its own, the length of the pass dependency is 0, and logback inherits it from its parent (2.0.7)

slf4j2.0.7

The pass dependency length is 1, so maven uses the1.7.36 rather than2.0.7The easiest way to change it is as follows

<properties>
	<>8</>
	<>8</>
	<>UTF-8</>
	<>1.3.14</>
	<>2.0.7</>
</properties>

summarize

  1. maven's dependency passing is a very powerful feature, so don't wonder if you've ever had a situation where you've introduced one dependency and brought in too many.

  2. maven dependency prioritization follows two principles

    First principle: shortest path first

    Second principle: precedence of the first statement

    The second principle is applied only in cases handled by the first principle; custom attributes also follow these two principles