maven仲裁机制_Maven 基础知识(二)依赖机制

传递依赖

maven通过读取分析工程依赖的其他工程的pom文件,自动的把依赖工程对应的依赖(包括这些工程自身的依赖以及从父工程继承到的依赖)加入到当前工程的依赖里面。

传递依赖机制虽然可以让我们方便的引入项目需要的全部依赖,但很容易就会使我们工程的依赖变的庞大复杂,并且引入的依赖很可能会同时依赖一个jar包的不同版本。因此maven在传递依赖机制中加入了一些机制来管理最终加入到工程中的依赖项

依赖仲裁(Dependency mediation)

依赖范围(Dependency scope)

依赖管理(Dependency management)

排除依赖(Excluded dependencies)

选择性依赖(Optional dependencies)

依赖仲裁

当在依赖树中出现同一个依赖的多个版本时,依赖仲裁 用来决定最终采用哪个版本。

maven采用选择 最近 的机制来决定最终的版本号, 最近 指的是在工程的依赖树中距离当前的工程路径最短,这就是为什么我们可以通过在当前工程中声明一个特定依赖,从而复盖传递过来的依赖的原因。如果两个依赖在依赖树中的距离一样,则选择 最先 声明的。

场景1 工程A有如下依赖树A├── B│ └── C│ └── D 2.0└── E └── D 1.0

此时对于D的依赖,有两条路径 A -> B -> C -> D 2.0 和 A -> E -> D 1.0,因为第二条的路径短,所以最终选择 D 1.0

场景2 工程A有如下依赖树A├── B│ └── C│ └── D 2.0└── E └—— F └—— D 3.0

此时对于D的依赖有两条 A -> B -> C -> D 2.0 和 A -> E -> F -> D 3.0,此时两条路径一样长,选择先声明的,所以最终选择D 2.0

根据 依赖仲裁 的机制,当我们在自己的工程中明确写明一个依赖的版本时,就可以确保这就是最终采用的版本。但是有一个例外就是 硬性需求(Hard requirements)优先级总是高于 软需求(Soft requirement) 。

依赖范围

classpath

在说明 依赖范围 的作用之前,先简单了解一下maven的执行环境信息。maven在执行不同命令如compile、test,或者是在一个构建的不同phase,会利用不同的classpath对代码执行编译、测试、运行,默认预设了如下四种classpath

compile classpath

runtime classpath

test classpath

plugin classpath

其中 plugin classpath 是插件执行的path,正常应用开发中不会涉及到。另外三种path则和我们息息相关。

可以通过在 pom. 文件中追加如下plugin查看具体工程的各个classpath,org.apache.maven.pluginsmaven-antrun-plugin1.7compilecompilerun

scope

依赖范围 就是用来控制依赖在哪一个classpath中使用,同时限定哪些依赖可以向后传递。在maven中,依赖总共有六种scope

compile(编译)

compile 是默认的scope,当依赖没有明确指定scope时,maven会自动设置成compile 。会出现在所有环境里面(测试、编译、运行)。会向后进行传递。

provided(提供)

provided表示运行环境会提供这个依赖,例如servlet-api相关的依赖,因为在servelet容器中已经有了,所以在其中运行应用时就不需要这个依赖。会出现在编译、测试环境下,但是不会出现在运行环境中。不会向后传递。

runtime(运行)

runtime表示运行时依赖,指在编译时不需要,在运行时需要的依赖。例如数据库连接的具体实现mysql-connector-java。会出现在运行、测试环境下,但是不会出现在编译环境中。会向后传递。

test(测试)

test表示在应用正常运行时不需要这个依赖,只在编译测试代码和执行测试用例时需要。例如JUnit和Mockito相关的依赖。出现在测试环境中,不出现在编译和运行环境中。不会向后传递。

system(系统)

不推荐使用

system 和 provided范围比较像,也是由运行环境提供,但是一般指用来区分不同操作系统下的依赖。可通过systemPath来具体指定依赖的位置.会出现在编译、测试环境下,但是不会出现在运行环境中。不会向后传递。

import

import类型的依赖只能出现在模块中,用来引入pom类型的工程。其效果相当于是把这个依赖用它引入的pom工程中有效的中的依赖列表替换掉,具体例子参考Dependency Management。因为是用在模块中,所以import依赖不会影响真正的依赖传递。

对于及联依赖,可以用如下表来说明

compile

provided

runtime

test

compile

compile

-

runtime

provided

provided

-

provided

runtime

runtime

-

runtime

test

test

-

test

左边一列是我们工程直接依赖对应的scope

上边一列是我们直接依赖的工程对应依赖的scope

交叉的部分是我们工程中对依赖的依赖对应的scope

只有compile和runtime可以向后传递

最后追加一个依赖的例子org.yamlsnakeyaml1.17junitjunit4.12testmysqlmysql-connector-java8.0.19runtimejavax.servletservlet-api2.3provided

对应的各个环境的pathcompile classpath: /Users/chengaofeng/ideaspace/maven-learn/maven-test/target/classes:/Users/chengaofeng/.m2/repository/org/yaml/snakeyaml/1.17/snakeyaml-1.17.jar:/Users/chengaofeng/.m2/repository/javax/servlet/servlet-api/2.3/servlet-api-2.3.jar runtime classpath: /Users/chengaofeng/ideaspace/maven-learn/maven-test/target/classes:/Users/chengaofeng/.m2/repository/org/yaml/snakeyaml/1.17/snakeyaml-1.17.jar:/Users/chengaofeng/.m2/repository/mysql/mysql-connector-java/8.0.19/mysql-connector-java-8.0.19.jar:/Users/chengaofeng/.m2/repository/com/google/protobuf/protobuf-java/3.6.1/protobuf-java-3.6.1.jar test classpath: /Users/chengaofeng/ideaspace/maven-learn/maven-test/target/test-classes:/Users/chengaofeng/ideaspace/maven-learn/maven-test/target/classes:/Users/chengaofeng/.m2/repository/org/yaml/snakeyaml/1.17/snakeyaml-1.17.jar:/Users/chengaofeng/.m2/repository/junit/junit/4.12/junit-4.12.jar:/Users/chengaofeng/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar:/Users/chengaofeng/.m2/repository/mysql/mysql-connector-java/8.0.19/mysql-connector-java-8.0.19.jar:/Users/chengaofeng/.m2/repository/com/google/protobuf/protobuf-java/3.6.1/protobuf-java-3.6.1.jar:/Users/chengaofeng/.m2/repository/javax/servlet/servlet-api/2.3/servlet-api-2.3.jar

依赖管理

依赖管理 的第一个用处是用来将依赖信息进行集中化管理。

当我们有许多工程继承自一个parent时,最常见的做法是把这些工程的依赖信息统一放在父pom的dependencyManagement中,在子工程中只指定依赖的group和artifactId,这样就可以保证所有工程中依赖相同的版本。当需要修改版本时,只用修改父pom里面dependencyManagement中的定义,所有子模块就自动依赖到修改后的版本。

例:

Project A: ... group-aartifact-a1.0group-cexcluded-artifactgroup-aartifact-b1.0barruntime

Project B: ... group-cartifact-b1.0warruntimegroup-aartifact-b1.0barruntime

A工程 和 B工程有一个相同的依赖 group-a:artifact-b:1.0,另外各自都有一个特有的依赖。如果用 依赖管理 ,可以将依赖信息放到如下所示的父pom中 ... group-aartifact-a1.0group-cexcluded-artifactgroup-cartifact-b1.0warruntimegroup-aartifact-b1.0barruntime

之后 A工程的pom可以变成下面的内容 ... group-a .........

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值