Maven项目依赖管理
我们现在已经能把项目拆分成一个个独立的模块,当在其他项目中想要使用独立出来的这些模块,只需要在其pom.xml
使用<dependency>
标签来进行jar
包的引入即可。
<dependency>
其实就是依赖,关于依赖管理里面都涉及哪些内容,如下:
- 依赖传递
- 可选依赖
- 排除依赖
我们先来理解一下什么是依赖:
依赖指当前项目运行所需的jar
,一个项目可以设置多个依赖。
格式为:
<!--设置当前项目所依赖的所有jar-->
<dependencies>
<!--设置具体的依赖-->
<dependency>
<!--依赖所属群组id-->
<groupId>org.springframework</groupId>
<!--依赖所属项目id-->
<artifactId>spring-webmvc</artifactId>
<!--依赖版本号-->
<version>5.2.15.RELEASE</version>
</dependency>
</dependencies>
1. 依赖传递与冲突问题
回到我们刚才的项目案例中,打开Maven
的面板,你会发现:
在项目所依赖的这些jar
包中,有一个比较大的区别就是有的依赖前面有箭头>
,有的依赖前面没有。
那么这个箭头所代表的含义是什么?
打开前面的箭头,你会发现这个jar
包下面还包含有其他的jar
包
你会发现maven_03_ssm_pojo
、maven_03_ssm_dao
、maven_03_ssm_service
的依赖多次被加载到Dependencies中,那么maven_03_ssm_controller
中的maven_03_ssm_pojo
、maven_03_ssm_dao
、maven_03_ssm_service
能不能使用呢?
要想验证非常简单,只需要把maven_03_ssm_controller
项目中pom.xml
关于maven_03_ssm_pojo
、maven_03_ssm_dao
的依赖注释或删除掉
在Dependencies
中移除自己所添加maven_03_ssm_pojo
、maven_03_ssm_dao
依赖后,打开UserController
的类,你会发现User
类依然存在,可以被正常使用
这个特性其实就是我们要讲解的依赖传递。
依赖是具有传递性的:
说明:A
代表自己的项目;B
,C
,D
,E
,F
,G
代表的是项目所依赖的jar
包;D1
和D2
、E1
和E2
代表是相同jar
包的不同版本
(1) A
依赖了B
和C
,B
和C
有分别依赖了其他jar
包,所以在A
项目中就可以使用上面所有jar
包,这就是所说的依赖传递
(2) 依赖传递有直接依赖和间接依赖
- 相对于
A
来说,A
直接依赖B
和C
,间接依赖了D1
,E1
,G
,F
,D2
和E2
- 相对于
B
来说,B
直接依赖了D1
和E1
,间接依赖了G
- 直接依赖和间接依赖是一个相对的概念
(3) 因为有依赖传递的存在,就会导致jar包在依赖的过程中出现冲突问题,具体什么是冲突?Maven
是如何解决冲突的?
这里所说的依赖冲突是指项目依赖的某一个jar
包,有多个不同的版本,因而造成类包版本冲突。
情况一:在maven_02_ssm
的pom.xml
中添加两个不同版本的Junit
依赖:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
通过对比,会发现一个结论
- 特殊优先:当同级配置了相同资源的不同版本,后配置的覆盖先配置的。
情况二:路径优先:当依赖中出现相同的资源时,层级越深,优先级越低,层级越浅,优先级越高
A
通过B
间接依赖到E1
A
通过C
间接依赖到E2
A
就会间接依赖到E1
和E2
,Maven
会按照层级来选择,E1
是2度,E2是3度,所以最终会选择E1
情况三:声明优先:当资源在相同层级被依赖时,配置顺序靠前的覆盖配置顺序靠后的
A
通过B
间接依赖到D1
A
通过C
间接依赖到D2
D1
和D2
都是两度,这个时候就不能按照层级来选择,需要按照声明来,谁先声明用谁,也就是说B
在C
之前声明,这个时候使用的是D1
,反之则为D2
但是对应上面这些结果,不需要刻意去记它。因为不管Maven
怎么选,最终的结果都会在Maven
的Dependencies
面板中展示出来,展示的是哪个版本,也就是说它选择的就是哪个版本,如:
如果想更全面的查看Maven
中各个坐标的依赖关系,可以点击Maven
面板中的show Dependencies
在这个视图中就能很明显的展示出jar包之间的相互依赖关系。
2. 可选依赖和排除依赖
依赖传递介绍完以后,我们来思考一个问题,
maven_02_ssm
依赖了maven_03_ssm_controller
maven_03_ssm_controller
依赖了maven_03_ssm_service
、maven_03_ssm_pojo
maven_03_ssm_service
依赖了maven_03_ssm_dao
、maven_03_ssm_pojo
maven_03_ssm_dao
依赖了maven_03_ssm_pojo
- 因为现在有依赖传递,所以
maven_02_ssm
能够使用到maven_03_ssm_pojo
的内容 - 如果说现在不想让
maven_02_ssm
依赖到maven_03_ssm_pojo
,有哪些解决方案?
说明:在真实使用的过程中,maven_02_ssm
中是需要用到maven_03_ssm_pojo
的,我们这里只是用这个例子描述我们的需求。因为有时候,maven_03_ssm_dao
出于某些因素的考虑,就是不想让别人使用自己所依赖的maven_03_ssm_pojo
。
方案一:可选依赖
- 可选依赖指对外隐藏当前所依赖的资源---不透明
在maven_03_ssm_dao
的pom.xml
,在引入maven_03_ssm_pojo
的时候,添加optional
<dependency>
<groupId>com.dcxuexi</groupId>
<artifactId>maven_03_ssm_pojo</artifactId>
<version>1.0-SNAPSHOT</version>
<!--可选依赖是隐藏当前工程所依赖的资源,隐藏后对应资源将不具有依赖传递-->
<optional>true</optional>
</dependency>
此时UserServiceI
就已经报错了,说明由于maven_03_ssm_dao
将maven_03_ssm_pojo
设置成可选依赖,导致maven_03_ssm_service
无法引用到maven_03_ssm_pojo
中的内容,导致User
类找不到。
方案二:排除依赖
- 排除依赖指主动断开依赖的资源,被排除的资源无需指定版本---不需要
前面我们已经通过可选依赖实现了阻断maven_03_ssm_pojo
的依赖传递,对于排除依赖,则指的是已经有依赖的事实,也就是说maven_03_ssm_service
项目中已经通过依赖传递用到了maven_03_ssm_pojo
,此时我们需要做的是将其进行排除,所以接下来需要修改maven_02_ssm
的pom.xml
<dependency>
<groupId>com.dcxuexi</groupId>
<artifactId>maven_03_ssm_dao</artifactId>
<version>1.0-SNAPSHOT</version>
<!--排除依赖是隐藏当前资源对应的依赖关系-->
<exclusions>
<exclusion>
<groupId>com.dcxuexi</groupId>
<artifactId>maven_03_ssm_pojo</artifactId>
</exclusion>
</exclusions>
</dependency>
这样操作后,UserService
中的User
类一样也会报错。
当然exclusions
标签带s
说明我们是可以依次排除多个依赖到的jar
包,比如maven_03_ssm_dao
中有依赖mysql-connector-java
和mybatis
,我们也可以一并将其排除。
<dependency>
<groupId>com.dcxuexi</groupId>
<artifactId>maven_03_ssm_dao</artifactId>
<version>1.0-SNAPSHOT</version>
<!--排除依赖是隐藏当前资源对应的依赖关系-->
<exclusions>
<exclusion>
<groupId>com.dcxuexi</groupId>
<artifactId>maven_03_ssm_pojo</artifactId>
</exclusion>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
<exclusion>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</exclusion>
</exclusions>
</dependency>
介绍我这两种方式后,简单来梳理下,就是
A依赖B
,B依赖C
,C
通过依赖传递会被A
使用到,现在要想办法让A
不去依赖C
- 可选依赖是在B上设置
<optional>
,A
不知道有C
的存在, - 排除依赖是在A上设置
<exclusions>
,A
知道有C
的存在,主动将其排除掉。