文章目录
解决jar包冲突
依赖类型
直接依赖
项目中直接导入的jar包,就是该项目的直接依赖包。
传递依赖
项目中没有直接导入的jar包,通过项目直接依赖的jar包传递到项目中。
例一
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
</dependencies>
虽然项目只导入了spring-context
这一个jar包,但是它所依赖的jar包都会被导入,这便是传递依赖,如下图所示。
此处只声明了spring-context
的坐标,但是它依赖的jar包都被导入到maven项目中了,它们的关系如下图所示。
jar包冲突发生场景
在导入下面两个坐标的时候,spring-context
会直接导入5.0.2.RELEASE
版本,它相关的传递依赖(其中之一spring-core
)也会导入这个版本。但是这里手动导入了spring-beans
,且版本为4.2.3.RELEASE
,这个版本会直接覆盖掉通过传递依赖导入的spring-beans
的5.0.2.RELEASE
版本,而高版本的某些功能在低版本没有,这就可能导致项目的开发出现问题。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
有三种解决方式可以解决jar包冲突。
方式一:第一声明原则
说明
哪个jar包的坐标在靠上的位置,这个jar包就是先声明的。先声明的jar包坐标下的依赖包,可以优先进入项目中。
例一
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
spring-beans依赖spring-core,spring-context也依赖spring-core,但是spring-beans先声明的jar包坐标,所以即使spring-context
有spring-core
的传递依赖,也会先导入spring-core
的4.2.3版本,下图为上面例一代码关于第一声明原则的图片说明。
方式二:路径近者优先原则
说明
直接依赖路径比传递依赖路径近,所以最终导入的jar包是直接依赖。
例一
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
虽然spring-context有传递依赖spring-beans,且它的版本为5.0.2.RELEASE
,但是后面手动导入了spring-beans
,所以最终进入项目的是spring-beans
的4.2.3.RELEASE
版本的jar包。
方式三:直接排除法
说明
通过配置exclusions标签来排除某个jar包的依赖包,内部可以不写版本号,版本号默认和这个jar包一致。
例一
通过exclusion标签,直接排除了
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.2.3.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
图中使用的spring-core
版本为5.0.2.RELEASE
,说明直接排除起了作用。
三种方式比较
方式一要求需要的jar包必须按照先后顺序优先导入,方式二需要再重复写一遍jar包坐标,方式三写法简单,不用顾忌先后顺序,推介使用方式三。
pom文件内部标签
dependencyManagement
概念:jar包版本锁定。
说明:
-
maven工程是可以分父子依赖关系的。凡是依赖别的项目后,拿到的别的项目的依赖包,都属于传递依赖。
-
比如:当前A项目,被B项目依赖。那么我们项目中所有jar包都会传递到B项目中。
B项目开发者,如果再在项目中导入一套ssm框架的jar包,对于项目是直接依赖,那么直接依赖的jar包就会把我们项目传递过去的jar包覆盖掉。
-
为了防止以上情况的出现。可以把A项目中主要jar包的坐标锁住,那么其他依赖该项目的项目中,即便是有同名jar包直接依赖,也无法覆盖。
例一:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
注意:dependencyManagement标签内部只是将jar包锁定,并不会导入jar包,要想导入jar包,必须在dependencyManagement
标签外部的<dependencies>
标签中声明jar包坐标。
properties
作用:统一管理jar包版本
好处:方便快速更改版本,方便开发人员对项目进行维护。
例一:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.0.2.RELEASE</spring.version>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<mysql.version>5.1.6</mysql.version>
<mybatis.version>3.4.5</mybatis.version>
</properties>
build
内部可以声明要使用的插件
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
</plugin>
</plugins>
</build>
maven工程拆分与聚合的思想
maven基础应用
- 传统的ssm框架整合的项目我们要在每个项目中都放置一套ssm框架的jar包。
- 如果是maven的ssm工程。有十个,我们只需要一套jar包。真正项目中只用放置jar的坐标即可。
maven高级应用
普通项目分三层:dao、service、controller。使用maven对模块的拆分和聚合可以解决代码重用问题,同时便于维护。
例一
需求:看订单操作
-
买家:买家要看到订单,必须要把数据库中订单数据查询出来。dao层的任务。
-
卖家:卖家要看订单,必须要把数据库中订单数据查询出来。dao层的任我。
maven解决代码可重用和便于维护问题上是这么解决的:
maven把一个完整的项目,分成不同的独立模块,这些模块都有各自独立的坐标。哪个地方需要其中某个模块,就直接引用该模块的坐标即可。
今后如果公司开发一个新项目,我们先考虑问题不是dao,service,utils,domain如何编写,我们要考虑的是,dao,service,utils,domain这些模块是否已经存在,如果存在直接引用。
以上说的就是maven拆分的思想。
项目和模块的区别
- 工程不等于完整的项目,模块也不等于完整的项目。一个完整的项目看的是代码,代码完整,就可以说这是一个完整的项目,和此项目是工程和模块没有关系。
- 独立性
- 工程天生只能使用自己内部资源,工程天生是独立的。后天可以和其他工程或模块建立关联关系。
- 模块天生不是独立的,模块天生是属于父工程的,模块一旦创建,所有父工程的资源都可以使用。
- 关系
- 父子工程直接,子模块天生继承父工程,可以使用父工程所有资源。
- 子模块之间天生是没有任何关系的。(可以通过导入坐标的方式建立模块间的依赖关系)
- 继承与依赖
- 父子工程直接不用建立关系,继承关系是先天的,不需要手动建立。
- 平级直接的引用叫依赖,依赖不是先天的,依赖是需要后天建立的。
传递下来的包能否使用
传递依赖可用表:
使用maven拆分聚合思想对项目结构重新设计
PS:这种拆分聚合思想在公司中应用更多。