maven中的依赖机制简介
依赖管理是maven的一大特征,对于一个简单的项目,对依赖的管理并不是什么困难的事,但是如果这个项目依赖的库文件达到几十个甚至于上百个的时候就不是一个简单的问题了。在这个时候maven对于依赖管理的作用就显露出来了。下面主要讨论几个方面的内容:传递性依赖,依赖范围,依赖管理,系统依赖,可选依赖
传递性依赖:
传递性依赖是在maven2中添加的新特征,这个特征的作用就是你不需要考虑你依赖的库文件所需要依赖的库文件,能够将依赖模块的依赖自动的引入。例如我们依赖于spring的库文件,但是spring本身也有依赖,如果没有传递性依赖那就需要我们了解spring项目依赖,然后也要添加到我们的项目中。
由于没有限制依赖的数量,如果出现循环依赖的时候会出现问题,这个时候有两种方式处理,一种是通过build-helper-maven-plugin插件来规避,另一种就是重构两个相互依赖的项目。
通过传递性依赖,项目的依赖结构能够很快生成。但是因为这个新的特性会有一些其他的特性被添加进来来限制由于传递性依赖所引入的包。
依赖调节:如果在一个项目里面出现不同的模块,依赖了一个项目的不同版本的时候判断依赖的版本。maven2.0的时候仅仅支持最近原则也就是在依赖树中的最靠近项目的版本作为依赖版本。到了maven2.0.9的时候又提出了一个最先声明原则,也就是在项目中被最早声明的被判断为依赖的版本。
依赖管理:在传递性依赖或者没有指定版本的依赖的情况下,断定依赖的版本。
依赖范围:决定依赖在构建的那个阶段起作用。
排除依赖:在标签中可以明确的排除某个依赖。
可选依赖:标签这个依赖是可选的。
依赖范围
maven有三套classpath(编译classpath,运行classpath,测试classpath)分别对应构建的三个阶段。依赖范围就是控制依赖与这三套classpath的关系。依赖范围有六种:
compile:编译依赖范围,在三个classpath都有效。
test:测试依赖范围,在编译代码和运行代码是无效。
provided:以提供的依赖范围,在编译和测试的时候有效,在运行的时候无效。例如servlet-api,因为容器已经提供,在运行的时候是不需要的。
runtime:运行时依赖范围,仅在测试和运行的时候有效。例如jdbc只有在测试和运行的时候才有效。
system:系统依赖范围,与provided范围一致,但是依赖是通过系统变量来指定依赖,不利于移植。
import(在maven2.0.9后支持):导入依赖范围,对三个classpath没有实际影响。
依赖范围影响传递性依赖。假如a依赖于b,b依赖于c,那么第一个为第一个依赖,第二个为第二依赖。左边第一列是第一依赖,第一行是第二依赖。
compile | provided | runtime | test | |
compile | compile | - | runtime | - |
provided | provided | - | provided | - |
runtime | runtime | - | runtime | - |
test | test | - | test | - |
依赖管理
依赖管理是一个集中的依赖信息的一种方式。它可以提供一个将依赖信息放置在一个公共的POM中让子POM继承。但是它只是起到限制的作用并不会引入实际依赖。
下面提供两个例子
A项目
1: <project>
2: ...
3: <dependencies>
4: <dependency>
5: <groupId>group-a</groupId>
6: <artifactId>artifact-a</artifactId>
7: <version>1.0</version>
8: <exclusions>
9: <exclusion>
10: <groupId>group-c</groupId>
11: <artifactId>excluded-artifact</artifactId>
12: </exclusion>
13: </exclusions>
14: </dependency>
15: <dependency>
16: <groupId>group-a</groupId>
17: <artifactId>artifact-b</artifactId>
18: <version>1.0</version>
19: <type>bar</type>
20: <scope>runtime</scope>
21: </dependency>
22: </dependencies>
23: </project>
B项目
1: <project>
2: ...
3: <dependencies>
4: <dependency>
5: <groupId>group-c</groupId>
6: <artifactId>artifact-b</artifactId>
7: <version>1.0</version>
8: <type>war</type>
9: <scope>runtime</scope>
10: </dependency>
11: <dependency>
12: <groupId>group-a</groupId>
13: <artifactId>artifact-b</artifactId>
14: <version>1.0</version>
15: <type>bar</type>
16: <scope>runtime</scope>
17: </dependency>
18: </dependencies>
19: </project>
可以这两个pom里面有公共依赖,可以提到一个公共的父类POM中
1: <project>
2: ...
3: <dependencyManagement>
4: <dependencies>
5: <dependency>
6: <groupId>group-a</groupId>
7: <artifactId>artifact-a</artifactId>
8: <version>1.0</version>
9:
10: <exclusions>
11: <exclusion>
12: <groupId>group-c</groupId>
13: <artifactId>excluded-artifact</artifactId>
14: </exclusion>
15: </exclusions>
16:
17: </dependency>
18:
19: <dependency>
20: <groupId>group-c</groupId>
21: <artifactId>artifact-b</artifactId>
22: <version>1.0</version>
23: <type>war</type>
24: <scope>runtime</scope>
25: </dependency>
26:
27: <dependency>
28: <groupId>group-a</groupId>
29: <artifactId>artifact-b</artifactId>
30: <version>1.0</version>
31: <type>bar</type>
32: <scope>runtime</scope>
33: </dependency>
34: </dependencies>
35: </dependencyManagement>
36: </project>
通过这种做法,项目A和项目B的POM文件可以被简化
项目A
1: <project>
2: ...
3: <dependencies>
4: <dependency>
5: <groupId>group-a</groupId>
6: <artifactId>artifact-a</artifactId>
7: </dependency>
8:
9: <dependency>
10: <groupId>group-a</groupId>
11: <artifactId>artifact-b</artifactId>
12: <!-- This is not a jar dependency, so we must specify type. -->
13: <type>bar</type>
14: </dependency>
15: </dependencies>
16: </project>
项目B
1: <project>
2: ...
3: <dependencies>
4: <dependency>
5: <groupId>group-c</groupId>
6: <artifactId>artifact-b</artifactId>
7: <!-- This is not a jar dependency, so we must specify type. -->
8: <type>war</type>
9: </dependency>
10:
11: <dependency>
12: <groupId>group-a</groupId>
13: <artifactId>artifact-b</artifactId>
14: <!-- This is not a jar dependency, so we must specify type. -->
15: <type>bar</type>
16: </dependency>
17: </dependencies>
18: </project>
下面的例子是对于传递性依赖中版本控制
项目A
1: <project>
2: <modelVersion>4.0.0</modelVersion>
3: <groupId>maven</groupId>
4: <artifactId>A</artifactId>
5: <packaging>pom</packaging>
6: <name>A</name>
7: <version>1.0</version>
8: <dependencyManagement>
9: <dependencies>
10: <dependency>
11: <groupId>test</groupId>
12: <artifactId>a</artifactId>
13: <version>1.2</version>
14: </dependency>
15: <dependency>
16: <groupId>test</groupId>
17: <artifactId>b</artifactId>
18: <version>1.0</version>
19: <scope>compile</scope>
20: </dependency>
21: <dependency>
22: <groupId>test</groupId>
23: <artifactId>c</artifactId>
24: <version>1.0</version>
25: <scope>compile</scope>
26: </dependency>
27: <dependency>
28: <groupId>test</groupId>
29: <artifactId>d</artifactId>
30: <version>1.2</version>
31: </dependency>
32: </dependencies>
33: </dependencyManagement>
34: </project>
项目B
1: <project>
2: <parent>
3: <artifactId>A</artifactId>
4: <groupId>maven</groupId>
5: <version>1.0</version>
6: </parent>
7: <modelVersion>4.0.0</modelVersion>
8: <groupId>maven</groupId>
9: <artifactId>B</artifactId>
10: <packaging>pom</packaging>
11: <name>B</name>
12: <version>1.0</version>
13: <dependencyManagement>
14: <dependencies>
15: <dependency>
16: <groupId>test</groupId>
17: <artifactId>d</artifactId>
18: <version>1.0</version>
19: </dependency>
20: </dependencies>
21: </dependencyManagement>
22: <dependencies>
23: <dependency>
24: <groupId>test</groupId>
25: <artifactId>a</artifactId>
26: <version>1.0</version>
27: <scope>runtime</scope>
28: </dependency>
29: <dependency>
30: <groupId>test</groupId>
31: <artifactId>c</artifactId>
32: <scope>runtime</scope>
33: </dependency>
34: </dependencies>
35: </project>
当运行项目B的时候,a,b,c,d都是version1.0。
首先a,c被显式的声明,然后是b在parent中的依赖管理中设定。然后是d虽然在parent中有但是在本项目中也有定义,本项目优先于父项目,所有也是version1.0。
导入依赖
这个特性是在maven2.0.9中被添加的。在上面的例子中提供了一种通过继承的方式来管理依赖。下面提供一种导入的方式来引入依赖管理。通过设定scope为import来实现。
项目B
1: <project>
2: <modelVersion>4.0.0</modelVersion>
3: <groupId>maven</groupId>
4: <artifactId>B</artifactId>
5: <packaging>pom</packaging>
6: <name>B</name>
7: <version>1.0</version>
8: <dependencyManagement>
9: <dependencies>
10: <dependency>
11: <groupId>maven</groupId>
12: <artifactId>A</artifactId>
13: <version>1.0</version>
14: <type>pom</type>
15: <scope>import</scope>
16: </dependency>
17: <dependency>
18: <groupId>test</groupId>
19: <artifactId>d</artifactId>
20: <version>1.0</version>
21: </dependency>
22: </dependencies>
23: </dependencyManagement>
24: <dependencies>
25: <dependency>
26: <groupId>test</groupId>
27: <artifactId>a</artifactId>
28: <version>1.0</version>
29: <scope>runtime</scope>
30: </dependency>
31: <dependency>
32: <groupId>test</groupId>
33: <artifactId>c</artifactId>
34: <scope>runtime</scope>
35: </dependency>
36: </dependencies>
37: </project>
下面我们给出一个导入两个项目的时的例子。
X项目
1: <project>
2: <modelVersion>4.0.0</modelVersion>
3: <groupId>maven</groupId>
4: <artifactId>X</artifactId>
5: <packaging>pom</packaging>
6: <name>X</name>
7: <version>1.0</version>
8: <dependencyManagement>
9: <dependencies>
10: <dependency>
11: <groupId>test</groupId>
12: <artifactId>a</artifactId>
13: <version>1.1</version>
14: </dependency>
15: <dependency>
16: <groupId>test</groupId>
17: <artifactId>b</artifactId>
18: <version>1.0</version>
19: <scope>compile</scope>
20: </dependency>
21: </dependencies>
22: </dependencyManagement>
23: </project>
Y项目
1: <project>
2: <modelVersion>4.0.0</modelVersion>
3: <groupId>maven</groupId>
4: <artifactId>Y</artifactId>
5: <packaging>pom</packaging>
6: <name>Y</name>
7: <version>1.0</version>
8: <dependencyManagement>
9: <dependencies>
10: <dependency>
11: <groupId>test</groupId>
12: <artifactId>a</artifactId>
13: <version>1.2</version>
14: </dependency>
15: <dependency>
16: <groupId>test</groupId>
17: <artifactId>c</artifactId>
18: <version>1.0</version>
19: <scope>compile</scope>
20: </dependency>
21: </dependencies>
22: </dependencyManagement>
23: </project>
Z项目
1: <project>
2: <modelVersion>4.0.0</modelVersion>
3: <groupId>maven</groupId>
4: <artifactId>Z</artifactId>
5: <packaging>pom</packaging>
6: <name>Z</name>
7: <version>1.0</version>
8: <dependencyManagement>
9: <dependencies>
10: <dependency>
11: <groupId>maven</groupId>
12: <artifactId>X</artifactId>
13: <version>1.0</version>
14: <type>pom</type>
15: <scope>import</scope>
16: </dependency>
17: <dependency>
18: <groupId>maven</groupId>
19: <artifactId>Y</artifactId>
20: <version>1.0</version>
21: <type>pom</type>
22: <scope>import</scope>
23: </dependency>
24: </dependencies>
25: </dependencyManagement>
26: </project>
在这个例子中Z导入了X,Y,那么两个里面都有a,但是由于先导入X,所有a是1.1的版本。导入是递归的,如果X还导入了一个项目Q, 那么Q也会被导入到Z。
需要注意的地方,不要导入当前POM的子POM,因为它无法定位。
系统依赖
常常被用来告知jdk和虚拟机中提供的依赖。
例一:
1: <project>
2: ...
3: <dependencies>
4: <dependency>
5: <groupId>javax.sql</groupId>
6: <artifactId>jdbc-stdext</artifactId>
7: <version>2.0</version>
8: <scope>system</scope>
9: <systemPath>${java.home}/lib/rt.jar</systemPath>
10: </dependency>
11: </dependencies>
12: ...
13: </project>
例二:
1: <project>
2: ...
3: <dependencies>
4: <dependency>
5: <groupId>sun.jdk</groupId>
6: <artifactId>tools</artifactId>
7: <version>1.5.0</version>
8: <scope>system</scope>
9: <systemPath>${java.home}/../lib/tools.jar</systemPath>
10: </dependency>
11: </dependencies>
12: ...
13: </project>
可选依赖
可选依赖使用的情况是对于某个依赖来说系统只有在某个特定的情况下使用到它。例如数据库驱动,有mysql的,oracle的。只有在我们使用到mysql的时候才会被使用。
使用方式
1: <project>
2: ...
3: <dependencies>
4: <!-- declare the dependency to be set as optional -->
5: <dependency>
6: <groupId>sample.ProjectA</groupId>
7: <artifactId>Project-A</artifactId>
8: <version>1.0</version>
9: <scope>compile</scope>
10: <optional>true</optional> <!-- value will be true or false only -->
11: </dependency>
12: </dependencies>
13: </project>
依赖排除
对于某些因为某些原因被导入而你又不想引入的依赖进行排除。
1: <project>
2: ...
3: <dependencies>
4: <dependency>
5: <groupId>sample.ProjectA</groupId>
6: <artifactId>Project-A</artifactId>
7: <version>1.0</version>
8: <scope>compile</scope>
9: <exclusions>
10: <exclusion> <!-- declare the exclusion here -->
11: <groupId>sample.ProjectB</groupId>
12: <artifactId>Project-B</artifactId>
13: </exclusion>
14: </exclusions>
15: </dependency>
16: </dependencies>
17: </project>