Maven解读:强大的依赖体系
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解读:强大的依赖体系的更多相关文章
- Maven解读:项目依赖管理如何优化
Github地址:https://github.com/zwjlpeng/Maven_Detail Maven最大的好处莫过于其强大的依赖管理系统,在Pom配置文件中指定项目需要的Jar包的坐标,Ma ...
- Maven(2)-坐标和依赖
本文简要介绍Maven里面的坐标(coodinate)以及maven依赖管理(Dependency) 一.坐标 先来个截图: 在上图peoject栏目有groupId,artifactId,versi ...
- maven 打包含有第三方依赖的 jar 包
maven 打包含有第三方依赖的 jar 包:mvn assembly:assembly
- maven的中传递依赖,maven的依赖管理(转)
在maven的pom文件中 <dependencies> <dependency> <groupId>junit</groupId> <artif ...
- Maven核心概念之依赖,聚合与继承
一.依赖 我们项目中依赖的jar包可以通过依赖的方式(dependencies元素下添加dependency子元素)引入. <dependency> <groupId>juni ...
- Maven之——坐标和依赖(上)
Maven之--坐标和依赖(上) 1. Maven坐标概念 Maven通过构件的坐标来在Maven仓库中定位到详细的构件.Maven的坐标元素包含groupId.artifactId.versi ...
- maven添加oracle jdbc依赖
maven添加oracle jdbc依赖 由于Oracle授权问题,Maven不提供Oracle JDBC driver,为了在Maven项目中应用Oracle JDBC driver,必须手动添加到 ...
- 【Maven】---坐标与依赖
Maven坐标与依赖 最近想深度学习下maven,找到一本书叫<Maven实战>,这本书讲的确实很好,唯一遗憾的是当时maven教学版本是3.0.0的,而目前已经到了3.5.4了,版本存在 ...
- 用Maven快速生成带有依赖的可执行jar包
一.背景 最近项目在做微服务的拆分,那么我们想让我们的容器启动更加的轻量级,所以我们选择放弃tomcat等容器,而是通过maven生成带有指定依赖的可执行jar包的方式进行处理,本文我将分享如何通过m ...
随机推荐
- 8.Generics 泛型(Dart中文文档)
这篇翻译的不好 如果你看API文档中的数组篇,你会发现类型一般写成List.<...>的写法表示通用类型的数组(未明确指定数组中的数据类型).通常情况泛型类型用E,T,S,K,V表示. W ...
- uliweb的模版
uliweb模版的文件名是与函数名相同的 以test为例: ***@Android:~/ablog# vim apps/blog/templates/test.html 编辑test.html的内容 ...
- WPF 自定义ComboBox样式,自定义多选控件
原文:WPF 自定义ComboBox样式,自定义多选控件 一.ComboBox基本样式 ComboBox有两种状态,可编辑和不可编辑状态.通过设置IsEditable属性可以切换控件状态. 先看基本样 ...
- django学习笔记(4)
Part 4: Forms and generic views ====> Write a simple form$ edit polls\templates\polls\detail.html ...
- extern "C" 的用意
extern "C" 修饰符只有在C++代码的时候才用到. C++编译器通常会对变量名和函数名进行改编,这样在链接的时候会出现问题. 假如: 1.用C++编写的Dll,在编译成Dl ...
- UWP 剪贴板 Clipboard
Clipboard使用Windows.ApplicationModel.DataTransfer.Clipboard 设置文本 DataPackage dataPackage = new DataPa ...
- 并行Linq
有时候我们对大批量数据进行处理,此时并行linq就起作用了. 并行查询 对于以下查询可以耗时会非常大,如下: ; var r = new Random(); , arraySize).Select(x ...
- How to create a custom action type with a custom control (BarCheckItem), associated with it
https://www.devexpress.com/Support/Center/Example/Details/E1977/how-to-create-a-custom-action-type-w ...
- 宝塔中mysql数据库命名小坑
今天在通过宝塔新建网站,添加mysql数据库,名字中间有下划线,发现能够创建成功,但是实际链接后,是没有这个数据库的.是宝塔的原因还是liunx服务器的原因? 不支持下划线的数据库名字吗? 比如 bo ...
- 文件的上传和下载--SpringMVC
文件的上传和下载是项目开发中最常用的功能,例如图片的上传和下载.邮件附件的上传和下载等. 接下来,将对Spring MVC环境中文件的上传和下载进行详细的讲解. 一.文件上传 多数文件上传都是通过表单 ...