Maven的坐标为各种构件引入了秩序,任何一个构件都必须明确的定义自己的坐标,maven的坐标包括如下的元素:
groupId: 定义当前Maven项目隶属的实际项目
artifactId: 该元素定义实际项目中的一个Maven项目或模块
version: 该元素定义Maven项目当前所处的版本
packaging: 该元素定义Maven项目的打包方式
classifier: 该元素用来帮助定义构建输出的一些附属构件
注:groupId、artifactId、version、packaging是必须定义的,classifier是不能被直接定义的,因为附属构件不是项目直接默认生成的,而是由附加的插件帮助生成的。
依赖:
Maven在编译项目主代码的时候需要使用编译classpath
Maven在编译和执行测试的时候会使用测试classpath
Maven在实际运行项目的时候又会使用运行classpath
依赖范围就是用来控制依赖与这三种classpath(编译classpath、测试classpath、运行classpath)的关系
Maven的5种依赖范围:
compile: 编译依赖范围(默认),对于编译、测试、运行三种classpath都有效,如:spring-core
test: 测试依赖范围, 只对测试classpath有效。典型范例:Junit
provided: 已提供依赖范围 对于编译和测试classpath有效,但在运行时无效。典型范例:servlet-api
runtime: 运行时依赖范围 对于测试和运行classpath有效,但在对编译主代码时无效。典型范例:JDBC
system: 系统依赖范围,本地的Maven仓库之外的类库文件
传递性依赖
简单的说,一般项目中出现问题多数是因为重复的引用或者引用了较低版本的依赖,或者是他们的依赖范围发生了变化。
举个例子来理解传递性依赖:
我们创建了一个Maven Project-----learnDependency,然后我们引入了spring-core这个依赖,然后我们打开spring-core的pom.xml发现,spring-core也有自己的依赖:commons-logging,而且该依赖没有声明依赖范围,那么默认的就是compile,所以这时我们就可以说:commons-logging也是learnDependency的一个依赖,这时我们就将这种依赖称之为传递性依赖,commons-logging是learnDependency的一个传递性依赖。有了传递性依赖,我们就可以在使用的时候不去考虑我们引入的依赖到底是否需要其它依赖,和是否引入多余的依赖,Maven 会解析各个直接依赖的pom,将必要的间接依赖引入到项目中。
假设:A依赖于B,B依赖于C,那么我们就说A对于B是第一直接依赖,B对于C是第二直接依赖,A对于C是传递性依赖。
因为依赖是有依赖范围的,那么对于这种传递性依赖Maven又是如何界定其依赖范围的呢?
(1)当第二直接依赖的范围是compile的时候,传递性依赖的范围与第一直接依赖的范围一致;
(2)当第二直接依赖的范围是test的时候,依赖不会得以传递
(3)当第二直接依赖的范围是provided的时候,只传递第一依赖范围也为provided的依赖,且传递性依赖的范围同样是provided;
(4)当第二直接依赖的范围是runtime的时候,传递性依赖的范围与第一直接依赖的范围一致,但compile除外,此时传递性依赖范围为runtime
maven引入依赖的两个原则:
(1)路径就近原则,如a->c->d1.0。另一依赖:b->d2.0,则会选d2.0
(2)声明顺序前面的优先级高。a->c1.0 。 b->c2.0,则a先定义取c1.0
因为上面的原则,所以有时候会出现依赖冲突的问题。
有很多同一项目的不同模块,这些依赖的版本都是相同的,则可以使用properties定义属性,${}引用。
优化依赖:
mvn dependency : list 查看当前项目的已解析依赖
mvn dependency : tree 查看当前项目的依赖树
mvn dependency : analyze 得出
Used undeclared dependencies: 表示项目中使用到的,但是没有显示声明的依赖
Unused declared dependencies: 表示项目中未使用的,但显示声明的依赖
注:dependency : analyze只会分析编译主代码和测试代码需要用到的依赖,一些执行测试和运行时需要的依赖它无法发现