Github地址:https://github.com/zwjlpeng/Maven_Detail

Maven最大的好处就是能够很方便的管理项目对第三方Jar包的依赖,只需在Pom文件中添加几行配置文件,就可以将第三方的Jar包纳入自已项目的类路径下,在Pom配置文件中我们也可以指定第三方Jar包的版本号,表明依赖第三方某一版本的Jar包,因此通过Maven管理项目的依赖,我们可以很容易的对项目依赖的第三方Jar包进行升级,升级过程中需要我们做的仅仅是更改配置文件->重新mvn package即可,是不是so easy~,想想通过传统方式搭建的Web工程,当我们为了解决低版本Spring中的BUG【如版本3.2.3中,当我们设置了@RequestParam(value="username", required=false)注解后,传入参数为空时,系统却抛出异常~】时,不得不升级Spring的版本时,我们需要怎么做?需要到Spring官网下载高版本,然后将相应的Jar包添加到工程的Build Path下,重新编译工程,当一个Jar包需要升级时,估且可以忍受,但是当多了,我想大概也只能呵呵了...

当很多人从一个软件迁移到另一个软件并不再回头的时候,就值得我们注意了...

直接依赖/间接依赖

Maven中最容易理解的就是直接依赖,A项目的运行需要有B项目的存在,这就是一个直接依赖,当B项目的运行需要有C项目的存在时,这里就存在A项目对C项目的一个间接依赖,A项目要想成功运行,在其类路径下必须要存在B项目和C项目,当然使用Maven我们不需要关注这种间接依赖,Maven会帮我们处理,如我们的项目中需要spring-core,在Pom文件中我们只需要添加如下配置,再看看我们的类路径是不是存在了spring-core-4.1.4.RELEASE.jar/commons-logging-1.2.jar两个Jar包,其中这个commons-logging-1.2.jar包就是通过间接依赖加入类路径下的~

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>

再看看spring-core-4.1.4.RELEASE.jar里面的Pom文件,在这个Pom文件中将对commons-logging-1.2.jar依赖设置为Compile并且非可选,下是是其Pom.xml文件

<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>net.sf.jopt-simple</groupId>
<artifactId>jopt-simple</artifactId>
<version>4.8</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.4</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>

在这个Pom.xml文件中,只有这个Jar包是必须的,其他依赖均是可选的(Optional)依赖,在Maven中可选依赖是不会进行传递的,为什么要有可选依赖呢?例如,一个持久层模块不但可以持久化Oracle数据库,也可以持久化Mysql数据库,那么在这个持化层框架中应该对应了两份代码,一份是关于Oracle持久化的处理,一份是关于Mysql持久化的处理,如果将持久层模块的Oracle与Mysql驱动均设置为非可选依赖,那么依赖这个持久层框架的项目类路径中将同时出现Mysql以及Oracle的驱动Jar包,如果真的这样,你会不会感觉到这种设计很奇葩~,因此Maven中Optional关键字就诞生了~~~

重复引入的处理?

在什么情况下,会出现依赖的重复引入呢?

场景一:项目A依赖于项目B与项目C,项目B与项目C均依赖于项目D,这时项目中就会出现两份D项目(有可能B项目与C项目依赖的D项目的版本还不一样~),这种情况下,Maven是如何处理的呢?

规则,第一声明者优化

这种情况下,Maven处理方法,是完全依赖于项目B与项目C在Pom.xml文件中声明的顺序,哪个声明在前就使用哪个项目的D依赖,如下是一个典型的例子~

<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-common</artifactId>
<version>0.99.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.1.4.RELEASE</version>
</depend

上面Pom配置文件中最终依赖的commons-logging为commons-logging-1.1.3.jar,但是当我们调整配置文件依赖的顺序,变成如下配置时,commons-logging的版本又变为了commons-logging-1.2.jar,结论是完全符合第一声明者优化的原则

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-common</artifactId>
<version>0.99.0</version>
</dependency>

场景二:一个Pom文件中声明了对一个项目的高低版本的依赖

规则,使用最后声明者,示例如下

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<!-- 版本一 -->
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<!-- 版本二 -->
<version>4.1.4.RELEASE</version>
</dependency>

最终spring-core-4.1.4.RELEASE.jar的版本号为4.1.4,但当将版本一与版本二的顺序调换后,则项目类路径下依赖的Jar包就会变成2.0.6

场景三:A项目依赖于B项目,B项目依赖于D项目,A项目依赖于C项目,C项目依赖于E项目,E项目又依赖于D项目,简化一下,即A->B->D/A->C->E->D,这时项目中也会由于传递依赖,引入了对D项目的两次依赖

规则:最短路径优先

在场景三中,由于A项目从B项目得到对D项目的依赖路径要比从C项目中获取D项目依赖的路径要短,说起来太转口了~,因此会优先采用从B项目中得到的D依赖,如下是一个示例~

这个在开源项目中,找了半天也没有找到很好的例子

Maven中的依赖范围

什么是依赖范围,依赖范围指明了第三方Jar包在类路径中的可见性,当我们向项目中添加了依赖,默认的依赖范围是Compile

Maven中具体的几种编译范围如下

compile:默认的编译范围,表示该Jar包在编译、运行、测试类路径中均可见

test:表示该Jar包仅在测试类路径中可见,正式发布打包时,里面没有该Jar包

provided:表示该Jar包在运行时由服务器提供,该Jar包对于编译和测试classpath有效,但在运行时无效,即发布时,最终打包的项目中不会含有该Jar包。典型范例:servlet-api

runtime:运行时依赖范围,对于测试和运行classpath有效,但在对编译主代码时无效。典型范例:JDBC

system:系统依赖范围,使用system范围的依赖必须通过systemPath元素显示地指定依赖文件的路径,不依赖Maven仓库解析,但是这样会对项目的移植性造成严重的影响,如下是使用系统依赖的一个典型例子

<dependency>
<artifactId>com.netease</artifactId>
<groupId>httpclient</groupId>
<version>1.0</version>
<scope>system</scope>
<systemPath>E:\source\Crawer\lib\commons-httpclient-3.1_2.jar</systemPath>
</dependency

在上面配置文件中,真正有作用的一句就是systemPath,其他的可以随意配置,没什么影响~,经过上面的配置后,可以发现项目的classpath中已经出现了commons-httpclient-3.1_2.jar包

作用system指定依赖范围,该依赖范围会出现在编译、测试、运行时的类路径下

import:这个范围maven 2.0.9以上才支持,据说是为了支持继承,没用过~~~

传递性依赖的依赖范围处理

传递性会导致依赖范围的变更,如A项目对B项目的依赖范围是compile,B项目对C项目的依赖范围是provided,那么最终A项目对C项目的依赖范围是啥子呢?以下是Maven官方给的一个表格

  compile provided runtime test
compile compile  runtime
provided provided provided 
runtime  runtime  runtime
test test   test

在这个表格中第一列代表的是一级依赖,第一行代表的是二级依赖,如表格中的红包部分,A项目对B项目的依赖范围是provided,B项目对C项目的依赖是compile,那么最终A项目对C项目的依赖是provided,在表格中-代表的是在传递性依赖中该依赖会被忽略

好了现在可以回答刚才提的问题,A项目对B项目是compile,B项目对C项目是provided那么最终的结果是A项目不对C项目进行依赖~

解答,A项目对B项目有依赖,说明B项目必须要在A项目的编译路径下,B项目对C项目是provided说明该依赖是由容器来提供的,在正式的发布包中B项目是不包含C项目的Jar包,因此A项目对B项目依赖后,会认为C项目是由容器提供,因此会忽略该依赖,默认认为容器中有,此时也不会报错,因为B项目已经编译打包了~

Maven解读:强大的依赖体系的更多相关文章

  1. Maven解读:项目依赖管理如何优化

    Github地址:https://github.com/zwjlpeng/Maven_Detail Maven最大的好处莫过于其强大的依赖管理系统,在Pom配置文件中指定项目需要的Jar包的坐标,Ma ...

  2. Maven(2)-坐标和依赖

    本文简要介绍Maven里面的坐标(coodinate)以及maven依赖管理(Dependency) 一.坐标 先来个截图: 在上图peoject栏目有groupId,artifactId,versi ...

  3. maven 打包含有第三方依赖的 jar 包

    maven 打包含有第三方依赖的 jar 包:mvn assembly:assembly

  4. maven的中传递依赖,maven的依赖管理(转)

    在maven的pom文件中 <dependencies> <dependency> <groupId>junit</groupId> <artif ...

  5. Maven核心概念之依赖,聚合与继承

    一.依赖 我们项目中依赖的jar包可以通过依赖的方式(dependencies元素下添加dependency子元素)引入. <dependency> <groupId>juni ...

  6. Maven之——坐标和依赖(上)

    Maven之--坐标和依赖(上) 1.    Maven坐标概念 Maven通过构件的坐标来在Maven仓库中定位到详细的构件.Maven的坐标元素包含groupId.artifactId.versi ...

  7. maven添加oracle jdbc依赖

    maven添加oracle jdbc依赖 由于Oracle授权问题,Maven不提供Oracle JDBC driver,为了在Maven项目中应用Oracle JDBC driver,必须手动添加到 ...

  8. 【Maven】---坐标与依赖

    Maven坐标与依赖 最近想深度学习下maven,找到一本书叫<Maven实战>,这本书讲的确实很好,唯一遗憾的是当时maven教学版本是3.0.0的,而目前已经到了3.5.4了,版本存在 ...

  9. 用Maven快速生成带有依赖的可执行jar包

    一.背景 最近项目在做微服务的拆分,那么我们想让我们的容器启动更加的轻量级,所以我们选择放弃tomcat等容器,而是通过maven生成带有指定依赖的可执行jar包的方式进行处理,本文我将分享如何通过m ...

随机推荐

  1. WPF RichTextBox 自定义文字转超链接

    搬运自StackOverflow private void AddHyperlinkText(string linkURL, string linkName, string TextBeforeLin ...

  2. JavaWeb基础—Servlet重要对象

    一.ServletConfig对象 当servlet配置了初始化参数后(<init-param> <param-name> <param-value>),web容器 ...

  3. 2017-2018-1 20155234 实验三 实时系统及mypwd实现

    2017-2018-1 20155234实验三实时系统及mypwd实现 实验三-并发程序-1 学习使用Linux命令wc(1) 基于Linux Socket程序设计实现wc(1)服务器(端口号是你学号 ...

  4. 2017-2018-1 20155320 课堂测试(ch06)

    2017-2018-1 20155320 课堂测试(ch06) 1.(单选题 | 1 分) 下面代码中,对数组x填充后,采用直接映射高速缓存,所有对x和y引用的命中率为(D) A . 1 B . 1/ ...

  5. 20155327Exp2 后门原理与实践

    20155327Exp2 后门原理与实践 一.实验说明 任务一:使用netcat获取主机操作Shell,cron启动 (0.5分) 任务二:使用socat获取主机操作Shell, 任务计划启动 (0. ...

  6. java四舍五入

    package com.clzhang.sample; import java.math.BigDecimal; import java.math.RoundingMode; import java. ...

  7. REST API 开发

    本文我们将使用Spring MVC 4实现 CRUD Restful WebService , 通过RestTemplate写一个 REST 客户端,定义这些服务. 我们也可以通过外部的一些客户端来测 ...

  8. 自适应浏览器分辨率的javascript函数[转]

    function changeWidth(now,target) { //now是现在代码所适应的宽度,如800:target是想要达到的显示器分辨率宽度var widthStr; var flag ...

  9. 大数据中HBase集群搭建与配置

    hbase是分布式列式存储数据库,前提条件是需要搭建hadoop集群,需要Zookeeper集群提供znode锁机制,hadoop集群已经搭建,参考 Hadoop集群搭建 ,该文主要介绍Zookeep ...

  10. 我所理解的selenium之PO设计模式

    下午,花了点时间来整理UI自动化设计,就把我所理解的PO设计模式项目结构脑图整理如下,有不对的地方还望多多包涵.谢谢