groupId,artifactId和version:依赖的基本坐标,对于任何一个依赖来讲,基本坐标是最重要的,Maven根据坐标才能找到须要的依赖
type: 依赖的类型,对应于项目坐标定义的packaging。大部分状况下,该元素没必要声明,其默认值是jar
scope: 依赖的范围,下面会进行详解
optional: 标记依赖是否可选
exclusions: 用来排除传递性依赖,下面会进行详解
大部分依赖声明只包含基本坐标。java
maven依赖分为传递依赖,可选依赖,排除依赖,归类依赖。spring
Maven在编译主代码的时候须要使用一套classpath,在编译和执行测试的时候会使用另外一套classpath,实际运行项目的时候,又会使用一套classpath。sql
依赖范围就是用来控制依赖与这三种classpath(编译classpath、测试classpath、运行classpath)的关系,Maven有如下几种依赖范围:apache
compile: 编译依赖范围。若是没有指定,就会默认使用该依赖范围。使用此依赖范围的Maven依赖,对于编译、测试、运行三种classpath都有效。api
test: 测试依赖范围。使用此依赖范围的Maven依赖,只对于测试classpath有效,在编译主代码或者运行项目的使用时将没法使用此类依赖。典型的例子就是JUnit,它只有在编译测试代码及运行测试的时候才须要。app
provided: 已提供依赖范围。使用此依赖范围的Maven依赖,对于编译和测试classpath有效,但在运行时无效。典型的例子是servlet-api,编译和测试项目的时候须要该依赖,但在运行项目的时候,因为容器已经提供,就不须要Maven重复地引入一遍。maven
runtime: 运行时依赖范围。使用此依赖范围的Maven依赖,对于测试和运行classpath有效,但在编译主代码时无效。典型的例子是JDBC驱动实现,项目主代码的编译只须要JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才须要实现上述接口的具体JDBC驱动。ide
system: 系统依赖范围。该依赖与三种classpath的关系,和provided依赖范围彻底一致。可是,使用system范围依赖时必须经过systemPath元素显式地指定依赖文件的路径。因为此类依赖不是经过Maven仓库解析的,并且每每与本机系统绑定,可能形成构建的不可移植,所以应该谨慎使用。systemPath元素能够引用环境变量,如:测试
<dependency> <groupId>javax.sql</groupId> <artifactId>jdbc-stdext</artifactId> <version>2.0</version> <scope></scope> <systemPath>${java.home}/lib/rt.jar</systemPath> </dependency>
import(Maven 2.0.9及以上): 导入依赖范围。该依赖范围不会对三种classpath产生实际的影响,稍后会介绍到。spa
A->B A依赖B,B->C B依赖C,则A和C之间存在传递依赖,依赖范围控制着传递依赖产生的影响。如account-email对于spring-core的依赖范围是compile,spring-core对于commons-logging的依赖范围是compile,那么account-email对于commons-logging这一传递性依赖的范围也就是compile。
假设A依赖B,B依赖C,咱们说A对于B是第一直接依赖,B对于C是第二直接依赖,A对于C是传递性依赖。第一直接依赖的范围和第二直接依赖的范围决定了传递性依赖的范围,以下图,最左边一列表示第一直接依赖范围,最上面一行表示第二直接依赖范围,中间交叉单元格表示传递性依赖范围。
传递依赖深度不一样
A->B->C->X(1.0)
A->D->X(2.0)
因为只能引入一个版本的包,此时Maven按照最短路径选择导入x(2.0)。
传递依赖深度相同
A->B->X(1.0)
A->D->X(2.0)
路径长度一致,则优先选择pom文件中先声明的,此时导入x(1.0)。
有时候咱们不想让依赖传递,那么可配置该依赖为可选依赖,将元素optional设置为true便可,例如:
<dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.1</version> <optional>true<optional> </dependency>
那么依赖该项目的另以项目将不会获得此依赖的传递。
当咱们引入第三方jar包的时候,不免会引入传递性依赖,有些时候这是好事,然而有些时候咱们不须要其中的一些传递性依赖。
好比上例中的项目,咱们不想引入传递性依赖commons-logging,咱们可使用exclusions元素声明排除依赖,exclusions能够包含一个或者多个exclusion子元素,所以能够排除一个或者多个传递性依赖。须要注意的是,声明exclusions的时候只须要groupId和artifactId,而不须要version元素,这是由于只须要groupId和artifactId就能惟必定位依赖图中的某个依赖。换句话说,Maven解析后的依赖中,不可能出现groupId和artifactId相同,可是version不一样的两个依赖。
以下是一个排除依赖的例子:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>2.5.6</version> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency>
若是咱们项目中用到不少关于Spring Framework的依赖,它们分别是org.springframework:spring-core:2.5.6, org.springframework:spring-beans:2.5.6,org.springframework:spring-context:2.5.6,它们都是来自同一项目的不一样模块。所以,全部这些依赖的版本都是相同的,并且能够预见,若是未来须要升级Spring Framework,这些依赖的版本会一块儿升级。所以,咱们应该在一个惟一的地方定义版本,而且在dependency声明引用这一版本,这一在Spring Framework升级的时候只须要修改一处便可。
<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.mycompany.app</groupId> <artifactId>my-app-simple</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>my-app-simple</name> <properties> <springframework.version>2.5.6</springframework.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${springframework.version}</version> </dependency> </dependencies> </project>