Maven之坐标和依赖_jerry_dyy的博客-CSDN博客
Maven之聚合与继承_jerry_dyy的博客-CSDN博客
Maven之生命周期和插件_jerry_dyy的博客-CSDN博客
坐标:
Maven依靠坐标来实现构件的唯一性。
Maven坐标元素包括:groupId、artifactId、version、packaging、classifier。
只要提供正确的坐标,Maven就可以从仓库中找到正确的构件。
groupId: 一般是域名的倒置;
artifactId: 一般以实际项目名称作为前缀,模块名作为后缀,就像:nexus-indexer,foo-core;
version: 定义版本,Maven定义了一套完整的版本规范,以及快照(SNAPSHOT)的概念;
packaging:打包方式,默认值为Jar;
classifer: 帮助定义构件输出一些附属构件,比如xxx-javadoc.jar(Java文档),xxx-sources.jar(源代码)。
其中groupId、artifactId、version是必须定义的,packaging是可选的,而classifer是不能直接定义的。
构件的文件名与坐标相对应,一般规则是:artifactId-version[-classfier].packaging。
Maven仓库的布局基于Maven坐标。
依赖:
project下的dependencies可以包含多个dependency元素。
每个dependency包含的元素有:
groupId、artifactId、version:依赖的基本坐标;
type: 依赖的类型,对应于项目坐标定义的packaging,默认值为Jar;
scope: 依赖的范围;
optional: 标记依赖是否可选;
exclusions: 用来排除传递性依赖。
依赖的范围:
三套Classpath: 编译主代码的时候需要使用一套classpath,编译和执行测试代码的时候会使用另外一套classpath,实际运行Maven项目的时候又会使用一套classpath。
依赖范围就是用来控制依赖与这三种classpath(编译classpath、测试classpath、运行classpath)的关系:
Compile: 编译依赖范围,默认使用该编译范围,对于编译、测试、运行三种classpath都有效;
Test: 测试依赖范围,只对于测试classpath有效,例如JUnit,它只有在编译测试代码以及运行测试的时候才需要;
Provided: 已提供依赖范围,对于编译和测试classpath有效,但在运行时无效,例如servlet-api;
Runtime: 运行时依赖范围,对于测试和运行classpath有效,但在编译主代码时无效,例如JDBC驱动;
System: 系统依赖范围,该依赖与三种classpath的关系,和provided一致。但是使用system依赖范围时必须通过systemPath元素显示地指定依赖文件的路径,往往与本地绑定,可能造成构件的不可移植,应该谨慎使用;
Import: 导入依赖范围,该依赖范围不会对三种classpath产生实际的影响,只有type为pom的时候,使用该依赖范围用于引入dependencyManagement。
传递性依赖:
A依赖了B,B依赖了C,那么C就是A的传递性依赖。
有了传递性依赖,Maven就会解析各个直接依赖的POM,将那些必要的间接依赖,以传递性依赖的形式引入到当前项目中。
依赖范围对传递性依赖产生影响:
最左边一列表示第一直接依赖范围,最上面一行表示第二直接依赖范围。
Compile | Test | Provided | Runtime | |
Compile | compile | -- | -- | runtime |
Test | test | -- | -- | test |
Provided | provided | -- | provided | provided |
Runtime | runtime | -- | -- | runtime |
依赖调解:
第一原则:路径最近者优先:
A->B->C->X(1.0), A->D->X(2.0),两个不同版本的X,因为X(2.0)路径长度短,所以会被解析使用。
第二原则:第一声明者优先:
在路径长度相等的前提下,在POM中依赖声明的顺序决定了谁会被解析使用。A->B->Y(1.0), A->C->Y(2.0),在该例中,如果B的依赖声明在C之前,那么Y(1.0)将会被解析使用。
可选依赖:
如果路径中出现可选依赖(optional),那么依赖将不会传递了:
A>B, B->X(可选), B->Y(可选),由于X、Y是可选依赖,依赖将不会得以传递,也就是说,X、Y将不会对A有任何影响。
最佳实践:
排除依赖:dependency中声明exclusions,exclusions中有一个或多个exclusion,exclusion中只需要groupId、artifactId即可。
归类依赖:定义properties元素,定义xxx.version,然后在需要的地方引用${xxx.version},避免出错。
优化依赖:Maven会自动解析所有项目的直接依赖和间接依赖,并根据规则正确判断每个依赖的范围,对于一些依赖冲突,也能进行调解,以确保任何一个构件只有唯一的版本在依赖中存在。在这些工作之后,得到的那些依赖被称为已解析依赖。
查看已解析依赖列表:mvn dependency:list
查看已解析依赖树:mvn dependency:tree
依赖分析:mvn dependency:analyze
可以分析那些依赖是使用到了,但是没有显示声明:当升级对应的直接依赖之后,相关的传递性依赖版本也有可能发生辩护,不易察觉,因此,最好直接声明项目中直接用到的任何依赖。
那些依赖是没有使用到,但是直接声明了的:只会分析编译主代码和测试代码需要用到的依赖,一些执行测试和运行时需要的依赖它发现不了。