文档章节

maven项目对象模型(二)

万建宁
 万建宁
发布于 09/18 23:15
字数 2988
阅读 15
收藏 0

1.4.4.传递性依赖

一个传递性依赖就是一个依赖的依赖。如果project-a依赖于project-b,而后者接着依赖于project-c,那么project-c就是被认为是project-a的传递性依赖。如果project-c依赖于project-d,那么project-d也被认为是project-a的传递性依赖。Maven的优势之一就是它能够管理传递性依赖,并且能够帮助开发者屏蔽掉跟踪所有编译期和运行期依赖细节。有了传递性依赖机制。在使用Spring Framework 的时候就不用去考虑它依赖了那些包,也不用担心一如多余的依赖。Maven会解析各个直接依赖的POM,将那些必须的间接依赖,以传递性依赖的形式引入到当前的项目中。

Maven建立一个依赖图,并且处理一些可能发生的冲突和重叠。

§传递性依赖的范围


依赖范围不仅可以控制依赖与三种classpath的关系,还对传递性依赖产生影响如下表

如果project-a包含一个project-b的测试范围依赖,后者包含一个对于project-c的编译范围依赖。project-c将会是project-a的测试范围传统依赖。

从表中发现这样的规律:当第二个直接依赖范围是compile的时候,传递性依赖的范围与第一直接依赖的范围一致;当第二个直接依赖范围是test的时候,传递性依赖不会得以传递;当第二个直接依赖范围是provided的时候,只传递第一直接依赖范围为provided的依赖。且传递性依赖的范围同样为provided;当第二直接依赖范围是runtime的时候,依赖性传递的范围与第一直接依赖的范围一致,但compile列外,此时传递性依赖的范围为runtime。

1.4.5.依赖版本界限

不是必须为依赖声明摸个特定的版本,可以指定一个满足需求的依赖版本界限。例如:项目依赖JUnit3.8或以上的版本,或者说依赖于JUnit1.2.10和1.2.14之间的某个版本。可以使用如下的字符来围绕一个或者多个版本号,开实现版本界限(,)不包含量词,[, ]包含量词。例如想访问JUnit任意大于等于3.8但小于4.0版本的

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>[3.8,4.0)</version>

<scope>test</scope>

</dependency>

如果想要依赖任意不大于3.8.1的版本,可以只指定一个上包含边界。

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>[,3.8.1]</version>ex-de

<scope>test</scope>

</dependency>

在逗号前面或者后面的版本不是必须的,这种空缺意味着正无穷或者负无穷。

注意:当生命一个“正常的”版本如JUnit3.8.2,最好表述成“允许任何版本,最好是3.8.2”。当检测到版本冲突的时候,Maven会使用冲突算法来选择最好的版本。如果指定[3.8.2],它意味只有3.8.2会被使用,没有其它地方依赖地使用了一个版本[3.8.1],就会得到一个构建失败的报告,说明有版本冲突。要保守党的使用它,只有在确实需要的时候才使用。正好的做法是通过dependencyManagement来解决冲突。

1.4.6.依赖调解

Maven引入的传递性依赖机制,一方面大大简化和方便了依赖声明,另一方面,大部分情况下只需要关心项目的直接依赖,而不用考虑这些直接依赖会引入那些传递性依赖。但是有时候,当传递性依赖造成问题的时候,需要清楚地知道该传递性依赖是从哪条依赖路径引入的。例如:项目A有这样的依赖关系:A -> B -> C -> X(1.0), A-> D -> X(2.0),X是A的传递性依赖,但是两条依赖路径上有两个版本的X,那么哪个X会被Maven解析使用呢?两个版本都被解析显然是不对的,因为会造成依赖重复,因此必须选择一个。Maven依赖调解的第一个原则是:路径最近者优先。该例中X(1.0)的路径长度为3,而X(2.0)路径长度为2,因此X(2.0)会被解析使用。

依赖调解第一原则不能解决所有问题,例如依赖关系A –> B -> Y(1.0),A -> B ->Y(2.0),Y(1.0)和Y(2.0)的依赖路径长度都是2。在Maven2.0.8及之前的版本中,这是不确定的,但是从Maven2.0.9开始,为了尽可能避免构建的不确定,Maven定义了依赖调解的第二原则:第一原则优先,在依赖路径长度相等的前提下,在POM中依赖声明的顺序决定了谁会解析使用,顺序最靠前的那个依赖被使用。如果B的依赖声明在C之前,那么Y(1.0)就会被解析使用。

1.4.7.可选依赖

假设有这样一个依赖关系,项目A依赖于项目B,项目B依赖于项目X和Y,B对于X和Y的依赖都是可选依赖:A -> B, B ->X(可选),B -> y(可选)。根据传递性依赖的定义,如果所有这三个依赖的范围都是compile,那么X,Y就是A的compile范围传递性依赖。然而,由于这里X,Y是可选依赖,依赖将不会的依传递。X,Y将不会对A有任何影响。项目B实现了两个特征,其中特征一依赖于X,特征二依赖于Y,而且这两个特征是互斥的,用户不可能同时使用两个。在编译B项目时需要两个依赖,如下:

<project>

<modelVersion>4.0.0</modelVersion>

<groupId>org.sonatype.mavenbook</groupId>

<artifactId>my-project-b</artifactId>

<version>1.0.0</version>

<dependencies>

<dependency>

<groupId>net.sf.ehcache</groupId>

<artifactId>ehcache</artifactId>

<version>1.4.1</version>

<optional>true</optional>

</dependency>

<dependency>

<groupId>swarmcache</groupId>

<artifactId>swarmcache</artifactId>

<version>1.0RC2</version>

<optional>true</optional>

</dependency>

<dependency>

<groupId>log4j</groupId>

<artifactId>log4j</artifactId>

<version>1.2.13</version>

</dependency>

</dependencies>

</project>

上述XML代码片段中,使用<optional>元素表示net.sf.ehcache和swarmcache这两个依赖为可选依赖,它们只会对当前项目B产生影响,当其它项目依赖于B的时候,这两个依赖不会被传递。因此,当A依赖于项目B的时候,那么在项目A中就要显示的声明使用哪种依赖项。

<project>

<modelVersion>4.0.0</modelVersion>

<groupId>org.sonatype.mavenbook</groupId>

<artifactId>my-application</artifactId>

<version>1.0.0</version>

<dependencies>

<dependency>

<groupId>org.sonatype.mavenbook</groupId>

<artifactId>my-project</artifactId>

<version>1.0.0</version>

</dependency>

<dependency>

<groupId>net.sf.ehcache</groupId>

<artifactId>swarmcache</artifactId>

<version>1.4.1</version>

</dependency>

</dependencies>

</project>

注意:在理想的情况下,是不应该使用可选依赖的。使用可选依赖的原因是某一个项目实现了多个特征,在面向对象设计中,有一个单一责任原则,意指一个类应该只有一项职责,而不是糅合太多的功能,这个原则在规划Maven项目的时候也同样适用。

1.4.8.排除依赖

有很多时候需要排除一个传递性依赖,就要适用exclusions元素声明排除依赖。

<dependency>

<groupId>org.sonatype.mavenbook</groupId>

<artifactId>project-a</artifactId>

<version>1.0</version>

<exclusions>

<exclusion>

<groupId>org.sonatype.mavenbook</groupId>

<artifactId>project-b</artifactId>

</exclusion>

</exclusions>

</dependency>

exclusions可以包含一个或者多个exclusion子元素。

排除并且替换一个传递性依赖。

<dependencies>

<dependency>

<groupId>org.hibernate</groupId>

<artifactId>hibernate</artifactId>

<version>3.2.5.ga</version>

<exclusions>

<exclusion>

<groupId>javax.transaction</groupId>

<artifactId>jta</artifactId>

</exclusion>

</exclusions>

</dependency>

<dependency>

<groupId>org.apache.geronimo.specs</groupId>

<artifactId>geronimo-jta_1.1_spec</artifactId>

<version>1.1</version>

</dependency>

</dependencies>

没有标记说依赖geronimo-jta_1.1_spec是一个替换,它只是正好提供了原来JTA依赖一样的API。有以下几种情况可能想要排除或者替换传递性依赖的情况:

§构建的groupId和artifactId已经改变,而当前项目需要一个传递性依赖不同名称的版本—结果是classpath中会出现同样项目的两份内容。一般来说Maven会捕获到这种冲突并且使用该项目的一个单独的版本,但是当artifactId和gruopId不一样的时候,Maven就会认为他们是两种不同的类库。

§某个构件没有在项目中被使用,而且该传递性依赖没有被标示为可选依赖的这种情况下,可能要排除这样依赖,因为它不是系统需要的东西,尽量减少应用程序发布时的类库数目。

§一个构件已经在运行时的容器中提供了,因此不应该被包含在构件中。

§为了排除一个可能是多个实现的API依赖。

1.4.9.归类依赖

有很多关于Spring Framework的依赖,它们分别是spring-aop,spring-beans,spring-context,spring-context-support,spring-core等,它们是来自同一项目的不同模块,因此,是由于这些依赖的版本都是相同的。如果将要升级Spring Framework,这些依赖的版本会一起升级。所以应该在一个唯一的地方定义一个版本,并且在dependency声明中引用这一版本,这样在升级Spring Framework的时候就只需要修改一处。

<project>

<modelVersion>4.0.0</modelVersion>

<groupId>org.sonatype.mavenbook</groupId>

<artifactId>my-project</artifactId>

<version>1.0.0-SNAPSHOT</version>

<properties>

<springframework.version>3.0.0.RELEASE</springframework.version>

</properties>

<dependencies>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-aop</artifactId>

<version>${springframework.version}</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-beans</artifactId>

<version>${springframework.version}</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

<version>${springframework.version}</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context-support</artifactId>

<version>${springframework.version}</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-core</artifactId>

<version>${springframework.version}</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-jdbc</artifactId>

<version>${springframework.version}</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-orm</artifactId>

<version>${springframework.version}</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-test</artifactId>

<version>${springframework.version}</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-tx</artifactId>

<version>${springframework.version}</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-jms</artifactId>

<version>${springframework.version}</version>

</dependency>

</dependencies>

</project>

1.4.10.依赖管理

Maven提供dependencyManagement元素既能让子模块继承到父模块的依赖配置,又能保证自模块依赖的使用灵活性。

实际的项目中,你会有许多的Maven模块,而且你往往发现这些模块有很多依赖完全相同的构建,A模块有个对spring的依赖,B模块也有,它们的依赖配置一模一样,同样的groupId, artifactId, version,或者还有exclusions,classifer。这是一种重复,重复就意味着潜在的问题,Maven提供的dependencyManagement就是用来消除这种重复的。

正确的做法是:

1. 在父模块中使用dependencyManagement配置依赖

2. 在子模块中使用dependencies添加依赖

dependencyManagement实际上不会真正引入任何依赖,dependencies才会。但是,当父模块中配置了某个依赖之后,子模块只需使用简单groupId和artifactId就能自动继承相应的父模块依赖配置。

父模块中如此声明:

<project>

<modelVersion>4.0.0</modelVersion>

<groupId>org.sonatype.mavenbook</groupId>

<artifactId>a-parent</artifactId>

<version>1.0.0</version>

...

<dependencyManagement>

<dependencies>

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

<version>5.1.2</version>

</dependency>

    ...

<dependencies>

</dependencyManagement>

</project>

子模块中如此声明:

<project>

<modelVersion>4.0.0</modelVersion>

<parent>

<groupId>org.sonatype.mavenbook</groupId>

<artifactId>a-parent</artifactId>

<version>1.0.0</version>

</parent>

<artifactId>project-a</artifactId>

...

<dependencies>

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

</dependency>

</dependencies>

</project>

依赖配置越复杂,依赖管理所起到的作用就越大,它不仅能够帮助简化配置,它还能够巩固依赖配置,也就是说,在整个项目中,对于某个构件(如mysql)的依赖配置只有一种,这样就能避免引入不同版本的依赖,避免依赖冲突。

1.4.11.优化依赖

§mvn dependency:list 此命令查看当前项目的已解析的依赖。

§mvndependency:tree 此命令查看当前项目的依赖树。

§mvndependency:analyze 此命令可以帮助分析当前项目的依赖。使用但未声明的依赖与声明但未使用的依赖。

使用以上命令可以帮助我们了解项目所有依赖的具体情况。

© 著作权归作者所有

万建宁
粉丝 3
博文 101
码字总数 190161
作品 0
西安
程序员
私信 提问
Maven的核心笔记(1)配置Maven环境变量

Maven是啥? 1.Maven是一种项目构建管理工具,自动下载架包。 2.目前主流的项目构建工具:Maven、Ant、gradle。 3.两个主要概念:坐标——构件,仓库。 一、maven的环境 1.Maven是基于项目对...

山月风成
2017/10/12
0
0
用Maven插件生成Mybatis代码

现在代码管理基本上是采用Maven管理,Maven的好处此处不多说,大家用百度搜索会有很多介绍,本文介绍一下用Maven工具如何生成Mybatis的代码及映射的文件。 一、配置Maven pom.xml 文件 在pom...

小李飞刀008
2013/10/12
32.7K
6
(一)使用IDEA创建Maven项目和Maven使用入门(配图详解)

本文详解的讲解了使用IDEA创建Maven项目,及Maven的基础入门。 1、打开IDEA,右上角选择File->New->Project 2、如图中所示选择Maven(可按自己所需添加,否则加载时速度很慢) 3、添加项目所...

青衣煮茶
2018/07/24
0
0
Win7下安装maven3.3.3步骤详细

安装步骤:1、安装maven之前,确保已经安装JDK1.6及以上版本,并配置好环境变量。2、下载maven3,最新版本是Maven3.3.3 ,下载地址:http://maven.apache.org/download.cgi3、下载apache-ma...

afreon
2016/10/08
35
0
JavaEE额外介绍

一.Maven 普通的项目需要依赖各式各样的jar包,maven是一个项目构建和管理的工具,提供了帮助管理 构建、文档、报告、依赖、scms、发布、分发的方法。可以方便的编译代码、进行依赖管理、管理...

Java_Rock
2018/01/03
0
0

没有更多内容

加载失败,请刷新页面

加载更多

【1015】LNMP架构二

【1015】LNMP架构二 三、PHP安装 PHP安装和LAMP安装PHP方法有差别,需要开启php-fpm服务 1、下载PHP7至/usr/local/src/ 切换目录:cd /usr/local/src 2、解压缩 tar -jxvf php-7.3.0.tar.gz...

飞翔的竹蜻蜓
40分钟前
4
0
浅谈Visitor访问者模式

一、前言 什么叫访问,如果大家学过数据结构,对于这点就很清晰了,遍历就是访问的一般形式,单独读取一个元素进行相应的处理也叫作访问,读取到想要查看的内容+对其进行处理就叫作访问,那么...

青衣霓裳
59分钟前
6
0
JS内嵌多个页面,页面之间如何更快捷的查找相关联的页面

假设parent为P页面, P页面有两个子页面,分别为B页面和C页面; B页面和C页面分别内嵌一个iframe,分别为:D页面和E页面 现在通过B页面的内嵌页面D的方法refreshEpage(eUrl)来加载内嵌页面E的内容...

文文1
今天
7
0
Hibernate 5 升级后 getProperties 错误

升级到 Hibernate 5 后,提示有错误: org.hibernate.engine.spi.SessionFactoryImplementor.getProperties()Ljava/util/Map; 完整的错误栈为: java.lang.NoSuchMethodError: org.hibernate......

honeymoose
今天
6
0
mysql-connector-java升级到8.0后保存时间到数据库出现了时差

在一个新项目中用到了新版的mysql jdbc 驱动 <dependency>     <groupId>mysql</groupId>     <artifactId>mysql-connector-java</artifactId>     <version>8.0.18</version> ......

ValSong
今天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部