第五章:坐标和依赖
1.每个依赖中可以包含的元素有:
- groupId,artifactId,version: 这三个元素是Maven项目最重要的元素。Maven需要根据这三个坐标找到需要的依赖。
- type:依赖的类型,对应所依赖的项目所定义的packaging。一般此元素不必声明,默认为jar
- scope:依赖范围,后面会详细讲解
- optional:标记依赖是否可选
- exclusions:用来排除依赖性传递
2.依赖范围:
需要知道的是:Maven在编译,测试,运行使用的是不同的classpath(编译classpath,测试classpath,运行classpath)
注:这里的classpath和J2EE中的WEB-INI的classpath不是同一个概念。此处的classpath是javac命令编译的时候,-classpath参数
依赖范围是用来控制Maven项目所引入的依赖于这三种classpath的关系。
Maven有一下集中依赖范围:
- compile(默认):编译依赖范围。此范围对于编译、测试、运行三种classpath都有效
- test:测试依赖范围。此范围只对于测试classpath有效,典型的例子:JUnit
- provided:已提供依赖范围。此范围对于编译、测试两种classpath有效,典型例子api (注:第一次看到此范围,一直不明白为什么叫provided范围,后来再次看,理解到有时候项目是在一个容器里面运行的,而这个容器已经提供了项目运行所需要的api。比如:Servlet、jre和jdk的区别一样provided:已提供范围全称应该叫运行时api已经提供的范围。)
- runtime:运行时依赖。此范围对于测试、运行classpath有效,编译的时候无效。典型例子:JDBC (注:为什么runtime不只是对运行时有效?)
- system(尽量别用):系统范围依赖。此范围对于编译、测试两种classpath有效。与provided区别:使用system依赖必须通过systemPath元素显式指定依赖文件的路径,由于路径一般是与本机系统绑定的,可能对系统移植带来一定的问题,因此谨慎使用
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.7</version> <scope>system</scope> <systemPath>${java.home}/lib/rt.jir</systemPath> </dependency>
- import:导入依赖范围,该依赖范围不会对classpath产生实际影响。后续详细介绍。
依赖范围 |
对于编译classpath有效 | 对于测试classpath有效 | 对于运行时classpath有效 | 例子 |
compile test provided runtime system |
Y - Y - Y |
Y Y Y Y Y |
Y - - Y - |
spring-core JUnit servlet-api JDBC驱动 本地的Maven仓库之外的类库文件 |
3.依赖传递
传统不使用Maven的项目中,往往需要手动的下载相关依赖,但是由于依赖可能又会依赖其他的类库,层层引入,因此可能会引入很多其他的不必要的依赖。
或者是之引入一个简单的依赖,这个依赖不包含其他的依赖,然后根据出错的信息,依次引入其他的依赖,这种方法,更加麻烦。
Maven传递性依赖机制可以很好的解决这一个问题。
看例子:
account-email 引入了一个org.springframework:spring-core:2.5.6依赖,同时spring-core包含了一个commons-logging依赖,对于commons-logging依赖,默认使用的依赖范围为compile,同时对于spring-core,account-email声明的依赖也是compile。
那么commons-logging便成为account-email的传递依赖。
传递依赖和依赖范围:
compile | test | provided | runtime | |
compile test provided runtime |
compile test provided runtime |
- - - - |
- - -(书上是provided,官方为-) - |
runtime test provided runtime |
(最左边一列表示第一依赖范围,最上边一行表示第二依赖范围)
想一想为什么要这样设计?