咱们知道,maven经过依赖的坐标来查找依赖,并经过必定的规则来自动管理依赖。本篇文章将经过对坐标和依赖的讲解,来告诉咱们maven管理依赖的原理与过程,并介绍如何经过一些工具来实现依赖的优化。java
咱们一般会经过下面的方式来引入一个依赖spring
<dependency>
<groupId>xxx.xx.xx</groupId>
<artifactId>xx</artifactId>
<version>1.1</artifactId>
</dependency>
复制代码
groupId,artifactId,version就是一个依赖的坐标,但它只是maven查找依赖所须要必要坐标,其实坐标还包括classfier和extension。下面咱们来详细介绍一下每个坐标元素的含义:sql
maven依赖调解有两条很是明确的规则: 路径最短优先 优先定义优先 举个例子以下:apache
root
+--a:1
+--c:1
+--b:1
+--c:2
+--d:1
+--a:2
复制代码
pathLength(a:1)=1,pathLength(a:2)=2,所以a:2就会被自动exclude掉,maven不会将该版本的jar包下载至本地。 c:1和c:2的路径长度均为1,但因为c:1定义在前,会被自动引入,c:2就会被exclude掉。 注:这里你们可能会有一些疑问,c:2引入的d:1也会被exclude掉吗?答案是确定的。这种简单粗暴的的规则,极大简化了maven管理依赖的成本。api
maven有三类classpath(经过classpath查找加载相应资源),编译期classpath,测试期classpath及运行期classpath。maven 在编译,测试,运行期间所须要的资源是有所不一样的,因此在管理maven 依赖时,也会按照对应的scope进行不一样行为的管理。bash
maven有如下几种scope: compile:一般状况下,咱们并不会手动设置scope的范围,默认的就是compile,此scope下的依赖对三类classpath均有效。jvm
<dependency>
<groupId>sun.jdk</groupId>
<artifactId>tools</artifactId>
<version>1.5.0</version>
<scope>system</scope>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
<dependency>
<groupId>javax.sql</groupId>
<artifactId>jdbc-stdext</artifactId>
<version>2.0</version>
<scope>system</scope>
<systemPath>${java.home}/lib/rt.jar</systemPath>
</dependency>
复制代码
classpath(编译) | classpath(测试) | classpath(运行) | 示例 | |
---|---|---|---|---|
compile | Y | Y | Y | spring-core |
test | Y | JUnit | ||
provided | Y | Y | servlet-api | |
runtime | Y | Y | JDBC | |
system | Y | Y |
你们看到这里可能会有疑惑,scope如何影响依赖传递。 一个简单的计算方式:scope(上层依赖)&scope(间接依赖),即直接依赖和间接依赖的交集 好比A(runtime)→B(test) 则该B依赖只会对测试期有效maven
dependencyManagement 是maven 2.0.6加入的标签,它的出现的缘由在于推进pom文件的良好管理。主要做用能够总结为两个方面:ide
When referring to artifacts whose poms have transitive dependencies the project will need to specify versions of those artifacts as managed dependencies. Not doing so will result in a build failure since the artifact may not have a version specified. (This should be considered a best practice in any case as it keeps the versions of artifacts from changing from one build to the next)工具
maven 依赖的一个最佳实践:全部的transive依赖都要显示地声明版本,防止不一样编译行为形成的编译结果不一样
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>maven</groupId>
<artifactId>X</artifactId>
<packaging>pom</packaging>
<name>X</name>
<version>1.0</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>test</groupId>
<artifactId>a</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>b</artifactId>
<version>1.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
复制代码
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>maven</groupId>
<artifactId>Y</artifactId>
<packaging>pom</packaging>
<name>Y</name>
<version>1.0</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>test</groupId>
<artifactId>a</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>c</artifactId>
<version>1.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
复制代码
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>maven</groupId>
<artifactId>Z</artifactId>
<packaging>pom</packaging>
<name>Z</name>
<version>1.0</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>maven</groupId>
<artifactId>X</artifactId>
<version>1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>maven</groupId>
<artifactId>Y</artifactId>
<version>1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
复制代码
Z同时引入了X与Y,X与Y同时都引入了依赖a,根据优先定义优先,则会引入X中a也就是1.1版本。 须要注意的是,即使X中再引入其它bom,也会优先使用X中的,而不会采用路径长度最短优先的原则。 咱们看一下项目使用:
<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>com.test</groupId>
<artifactId>test</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>maven</groupId>
<artifactId>X</artifactId>
<version>1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>maven</groupId>
<artifactId>Y</artifactId>
<version>1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>a</artifactId>
<version>1.3</version>
</dependency>
</dependencies>
</project>
复制代码
若是在一个项目中显示定义了a,根据显示定义优先,此pom将不会引入X,Y中定义的a,所以,此时的版本应为1.3 应该注意的是,不只仅会引入bom中版本,还会使用bom中的其它元素,好比exclusion,scope,type