1. 简介
最近在处理一个SpringBoot多模块项目的时候遇到一个问题,一个pom中只能有一个parent。java
使用SpringBoot把SpringBoot设置为parent以后,项目自己就不能作为父项目添加子模块module了。mysql
怎么处理?使用dependencyManagement。spring
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring.boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
dependencyManagement为何有效?sql
在SpringBoot中咱们常常使用依赖不带版本为何也能够?api
2. dependencyManagement
dependencyManagement其实主要不是为了解决继承问题,而是为了解决依赖版本混乱问题。服务器
dependencyManagement主要用于多模块项目的父项目中。maven
它的原理是:ide
当maven发现dependencies中的某个dependency没有设置版本号version,它就会从它的父项目开始,在它的祖先项目中查找dependencyManagement中配置的dependency,直到找到一个有版本号version的依赖,使用该version。spring-boot
从名字也能够看出dependencyManagement不是为了定义依赖,而是为了管理可能的依赖。有点绕,说个结论,就是若是在子模块中没有使用dependencyManagement定义的依赖,这些依赖的jar包就最终不会被打在输出的jar包中。测试
3. 为何使用SpringBoot不少依赖能够不用配置版本号
若是你看SpringBoot的pom就会发现它的父项目是:
<groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId>
spring-boot-dependencies中基本啥都没干,就定义了默认的依赖和版本了。
spring-boot-dependencies的pom大体就像下面这个样子的:
有兴趣的朋友能够看一下这个pom中定义了哪些依赖,及其使用的版本。
4. 依赖管理
像SpringBoot同样,咱们在多模块项目中也能够这样玩,首先找出多个模块的共同依赖,而后把他上移到父模块的dependencyManagement,像这样:
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring.boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>${guava.version}</version> </dependency> </dependencies> </dependencyManagement>
依赖上移以后,子模块的pom中要移除这些依赖,不然会覆盖定义在父项目中的dependencyManagement中的依赖。
dependencyManagement中的dependencies下的依赖不能直接被子模块继承,必须显式申明。直接在dependencies下的依赖能够被子项目继承。
# 分析哪些依赖使用了可是没有显式定义,哪些依赖定义了没有使用 mvn dependency:analyze # 分析依赖层级关系 mvn dependency:tree # 查看有效依赖 mvn help:effective-pom
5. scope
5.1 compile
默认的依赖范围就是compile,没有scope或者scope为comile的依赖表示编译、运行、测试的时候都须要这个依赖的jar包。
5.2 provided
表示环境已经提供了,因此打包的时候就不会将scope为provided的依赖打到输出的jar包中。
最典型的例子是servlet-api,由于这个依赖已经包含在像Tomcat这样的Servlet服务器中了,因此打包的时候就不须要将这个依赖再打包到输出jar包中了。
<dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency>
5.3 runtime
若是一个依赖的scope为runtime,表示编译的时候不能引用这个依赖的jar包。
还有编译的时候不须要运行的时候须要的jar包?
SPI相关的都是。主要是让面向接口变成,而不要直接去使用实现类,如使用java.sql.Driver,而不是com.mysql.cj.jdbc.Driver。
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> <scope>runtime</scope> </dependency>
5.4 test
scope为test的依赖表示,这个包只是在测试阶段使用,打包的时候这些依赖不会打在输出的jar包中。
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency>
5.5 system
system主要是为了引入一些没有经过maven发布的私有的三方jar包。
这些jar包的特色是:
- 没有发布,因此不能经过maven中央仓库找到
- 是第三方的,因此不能使用本身的私服引入
- 只有jar包
固然你能够把这些jar包加在classpath中,可是对于maven项目来讲很差管理。
这个时候,就能够使用scope为system的依赖了,只须要指定这些jar包在系统中的路径就能够了。
<dependency> <groupId>vip.mycollege</groupId> <artifactId>tools</artifactId> <version>1.0.0</version> <scope>system</scope> <systemPath>F:/lib/tools.jar</systemPath> </dependency>
5.6 import
import只能在dependencyManagement的dependency,而且type为pom的依赖中使用。
import主要是为了将依赖管理和依赖定义分开。
例如SpringBoot的dependencyManagement中预约义不少依赖,因此就单独弄了一个spring-boot-dependencies来管理这些依赖。
6. optional
optional是用于控制依赖传递的。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency>
optional设置为true,这个依赖不会被传递,加入在A项目中添加了这个依赖,B项目依赖A,可是B项目不会依赖spring-boot-devtools。