原文地址 译者:Tyrianhtml
依赖机制是Maven最为用户熟知的特性之一,同时也是Maven所擅长的领域之一。单个项目的依赖管理并不难,
可是当你面对包含数百个模块的多模块项目和应用时,Maven能帮你保证项目的高度控制力和稳定性。java
大纲:web
传递性依赖是Maven2.0的新特性。假设你的项目依赖于一个库,而这个库又依赖于其余库。你没必要本身去找出全部这些依赖,你只须要加上你直接依赖的库,Maven会隐式的把这些库间接依赖的库也加入到你的项目中。这个特性是靠解析从远程仓库中获取的依赖库的项目文件实现的。通常的,这些项目的全部依赖都会加入到项目中,或者从父项目继承,或者经过传递性依赖。
传递性依赖的嵌套深度没有任何限制,只是在出现循环依赖时会报错。
传递性依赖会致使包含库的依赖图增加的很是大。为了解决这个问题,Maven也提供了额外的机制,能让你指定哪些依赖会被包含:redis
依赖范围会影响传递性依赖,同时也会影响项目构建任务中使用的classpath。
Maven有如下6种依赖范围:spring
每类依赖范围(除了import)经过不一样方式影响传递性依赖,具体以下表所示。最左侧一列表明了直接依赖范围,最顶层一行表明了传递性依赖的范围,行与列的交叉单元格就表示最终的传递性依赖范围。表中的“-“表示该传递性依赖将会被忽略。sql
compile | provided | runtime | test | |
compile | compile(*) | – | runtime | – |
provided | provided | – | provided | – |
runtime | runtime | – | runtime | – |
test | test | – | test | – |
(*)注意:这里原本应该是compile范围,那样的话compile范围都必须显式指定-然而,有这样一种状况,你依赖的、继承自其它库中的类的库必须在编译时可用。考虑到这个缘由,即便在依赖性传递状况下,编译时依赖仍然是compile范围。mongodb
Maven提供了一个机制来集中管理依赖信息,叫作依赖管理元素”<dependencyManagement>”。假设你有许多项目继承自同一个公有的父项目,那能够把全部依赖信息放在一个公共的POM文件,而且在子POM中简单第引用该构件便可。经过一些例子能够更好的解释这个机制。下面是两个继承自同一个父项目的POM:apache
项目A编程
<project>
…
<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>group-c</groupId>
<artifactId>excluded-artifact</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-b</artifactId>
<version>1.0</version>
<type>bar</type>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>api
项目B
<project>
…
<dependencies>
<dependency>
<groupId>group-c</groupId>
<artifactId>artifact-b</artifactId>
<version>1.0</version>
<type>war</type>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-b</artifactId>
<version>1.0</version>
<type>bar</type>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
这两个POM都依赖于同一个模块,同时每一个POM又各自依赖于一个无关的模块。父项目的POM详细信息以下所示:
<project>
…
<dependencyManagement>
<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
<version>1.0</version><exclusions>
<exclusion>
<groupId>group-c</groupId>
<artifactId>excluded-artifact</artifactId>
</exclusion>
</exclusions></dependency>
<dependency>
<groupId>group-c</groupId>
<artifactId>artifact-b</artifactId>
<version>1.0</version>
<type>war</type>
<scope>runtime</scope>
</dependency><dependency>
<groupId>group-a</groupId>
<artifactId>artifact-b</artifactId>
<version>1.0</version>
<type>bar</type>
<scope>runtime</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
这样两个子项目的POM文件就简单多了。
<project>
…
<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
</dependency><dependency>
<groupId>group-a</groupId>
<artifactId>artifact-b</artifactId>
<!– This is not a jar dependency, so we must specify type. –>
<type>bar</type>
</dependency>
</dependencies>
</project><project>
…
<dependencies>
<dependency>
<groupId>group-c</groupId>
<artifactId>artifact-b</artifactId>
<!– This is not a jar dependency, so we must specify type. –>
<type>war</type>
</dependency><dependency>
<groupId>group-a</groupId>
<artifactId>artifact-b</artifactId>
<!– This is not a jar dependency, so we must specify type. –>
<type>bar</type>
</dependency>
</dependencies>
</project>
注意:在这两个POM文件的依赖中,咱们必须指定<type/>元素。由于与依赖管理元素匹配的依赖引用最小信息集是{groupId, artifactId, type, classfier}。许多状况下,依赖指向的jar不须要指定classfier。由于默认type是jar,默认classfiler为空,因此咱们能够把信息集设置为{groupId, artifactId}。
依赖管理元素第二个很是有用的功能是控制传递性依赖中构件的版本。例子以下
项目A:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>maven</groupId>
<artifactId>A</artifactId>
<packaging>pom</packaging>
<name>A</name>
<version>1.0</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>test</groupId>
<artifactId>a</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>b</artifactId>
<version>1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>c</artifactId>
<version>1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>d</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
项目B:
<project>
<parent>
<artifactId>A</artifactId>
<groupId>maven</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>maven</groupId>
<artifactId>B</artifactId>
<packaging>pom</packaging>
<name>B</name>
<version>1.0</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>test</groupId>
<artifactId>d</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>test</groupId>
<artifactId>a</artifactId>
<version>1.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>c</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
当在maven中有项目依赖B时,无论它们的pom文件中指定的版本是什么,构件a,b,c和d的版本都是1.0。
依赖管理的标签详细描述信息能够从这里获取项目描述符引用
这个章节描述的特性只在Maven2.0.9及以后的版本才有。这意味着更早版本的Maven不会解析包含import元素的pom文件。所以在使用该特性前,你必须慎重考虑。若是你打算使用这个特性,咱们建议你使用enforcer插件来强制使用Maven2.0.9及以上版本。
前面的例子描述了怎么经过继承来指定管理的依赖。然而,这对于更大的项目一般会更复杂,由于一个项目只能继承自一个父项目。为了解决这个问题,项目能够导入其余项目的管理依赖,这能够经过声明依赖一个包含值为”import”的<scope>元素的构件来实现。
项目B:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>maven</groupId>
<artifactId>B</artifactId>
<packaging>pom</packaging>
<name>B</name>
<version>1.0</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>maven</groupId>
<artifactId>A</artifactId>
<version>1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>d</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>test</groupId>
<artifactId>a</artifactId>
<version>1.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>c</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
假设A就是上一个例子中定义的POM,那么最终的结果也是一致的。除了在B中定义的d模块,全部A的管理依赖都会导入到B中。
项目X:
<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>
项目Y:
<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>
项目Z:
<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。在这里,会使用1.1版本的a,由于X先被声明,而且a没有在Z的依赖管理中声明。
这个过程是递归进行的。假如X导入了另外的POM,Q,那么当解析Z的时候,全部Q的管理依赖看上去就都像在X中定义的同样。
当定义一个用于构建多项目的包含一些相关构件的依赖“库”时,导入依赖就十分有效。从“库”中引用一个或多个构件到项目中,是一种很常见的作法。然而,
保持项目中使用的依赖版本与库中发布的版本一致会有点麻烦。下面的模式描述了怎么生成一个供其它项目使用的“物料清单”(BOM)。
项目的根元素是BOM pom文件。它定义了库中建立的全部构件版本。其它要使用该库的项目必须将该pom导入到其pom文件中的<dependencyManagement>元素中。
<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>bom</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<properties>
<project1Version>1.0.0</project1Version>
<project2Version>1.0.0</project2Version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.test</groupId>
<artifactId>project1</artifactId>
<version>${project1Version}</version>
</dependency>
<dependency>
<groupId>com.test</groupId>
<artifactId>project2</artifactId>
<version>${project1Version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>parent</module>
</modules>
</project>
parent子项目将BOM pom做为它的父项目。这是一个简单的多项目pom。
<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>bom</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<properties>
<project1Version>1.0.0</project1Version>
<project2Version>1.0.0</project2Version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.test</groupId>
<artifactId>project1</artifactId>
<version>${project1Version}</version>
</dependency>
<dependency>
<groupId>com.test</groupId>
<artifactId>project2</artifactId>
<version>${project1Version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>parent</module>
</modules>
</project>
接下来是真正的pom文件。
<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>
<parent>
<groupId>com.test</groupId>
<version>1.0.0</version>
<artifactId>parent</artifactId>
</parent>
<groupId>com.test</groupId>
<artifactId>project1</artifactId>
<version>${project1Version}</version>
<packaging>jar</packaging><dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
</dependencies>
</project><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>
<parent>
<groupId>com.test</groupId>
<version>1.0.0</version>
<artifactId>parent</artifactId>
</parent>
<groupId>com.test</groupId>
<artifactId>project2</artifactId>
<version>${project2Version}</version>
<packaging>jar</packaging><dependencies>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</dependency>
</dependencies>
</project>
下面的例子说明了怎么在项目中使用“库”,而没必要指定依赖模块的版本。
<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>use</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging><dependencyManagement>
<dependencies>
<dependency>
<groupId>com.test</groupId>
<artifactId>bom</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.test</groupId>
<artifactId>project1</artifactId>
</dependency>
<dependency>
<groupId>com.test</groupId>
<artifactId>project2</artifactId>
</dependency>
</dependencies>
</project>
最后,当建立引入依赖的项目时,须要注意如下几点:
系统范围的依赖应该是一直可用,而且Maven不会去仓库中查找。系统范围依赖一般是指JDK或者VM提供的依赖。因此,系统依赖适用于这种状况:之前能够单独获取,但如今是由JDK提供的依赖。典型的例子就是JDBC标准扩展或者Java认证和受权服务(JAAS)。一个简单的例子以下:
<project>
…
<dependencies>
<dependency>
<groupId>javax.sql</groupId>
<artifactId>jdbc-stdext</artifactId>
<version>2.0</version>
<scope>system</scope>
<systemPath>${java.home}/lib/rt.jar</systemPath>
</dependency>
</dependencies>
…
</project>
若是你的构件依赖于JDK的tools.jar,那么系统路径的值以下所示:
<project>
…
<dependencies>
<dependency>
<groupId>sun.jdk</groupId>
<artifactId>tools</artifactId>
<version>1.5.0</version>
<scope>system</scope>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
</dependencies>
…
</project>
原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文连接地址: 《Maven官方文档》-Maven依赖机制简介
Software Engineerat TP-LINK