Maven的依赖作用域和依赖传递
在Java项目开发中,Maven是我们最常用的依赖管理和构建工具了!我们常常通过添加dependency
节点,就能够很方便地加入依赖,而不需要我们自己去手动下载jar
文件并引入。
今天主要是来总结一下在Maven中依赖的作用域和传递。
1,依赖作用域
通过在每个dependency
中设定scope
字段,即可声明其作用域,例如:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
<!-- 声明作用域 -->
<scope>provided</scope>
</dependency>
上面我们就设定了lombok
这个依赖的作用域为provided
。
常用的作用域字段值及其意义如下:
compile
这是默认的scope
(即你不写scope
字段的话,这个依赖作用域就是compile
),表示依赖在编译、测试和运行时都是可用的,并且会参与项目的打包过程,该依赖会传递给依赖该模块的其他模块provided
表示依赖在编译和测试时是可用的,但该依赖不会参与程序运行阶段,即程序运行时无法调用该依赖中的类,它不会参与项目的打包过程,也不会传递给其他模块runtime
表示依赖仅在运行时是可用的,但在编译和测试时不需要,它会传递给依赖该模块的其他模块,但不会参与项目的打包过程test
表示依赖只在测试和运行时使用,不会参与项目的打包过程,也不会传递给其他模块
可见一个Maven项目,从编译到运行会经历三个阶段:编译 → 测试 → 运行
不同作用域在三个阶段的可见性如下表:
编译时可用 | 测试时可用 | 运行时可用 | |
---|---|---|---|
compile | √ | √ | √ |
provided | √ | √ | x |
runtime | x | √ | √ |
test | x | √ | x |
2,作用域和打包
我们常常会使用maven-assembly-plugin
插件,让我们在打包的时候将所有的依赖都打包至最后的jar
文件中,使得jar
文件可以直接运行。
不过真的是所有的依赖都会被打包到最后的jar
中吗?
其实并不是,在使用maven-assembly-plugin
插件插件时,默认只有scope
为compile
和runtime
的依赖才会被包含在最终的结果中。
因此,为了减小最终jar
的大小,我们应当将运行时不需要的依赖设置为provided
或者test
,当然这也是根据用途选择。
例如lombok
依赖会在编译的时候生成getter
和setter
的代码,但是运行的时候这个依赖就不需要了,因此它常常被设定为provided
。
但是在Spring Boot开发中就不一样了,Spring Boot工程中,使用的是spring-boot-maven-plugin
,这个插件也能完成同样的目的,即打包时将所有的依赖全部打包到一个jar
中,但是这个插件会将所有的依赖都打包进去,无论其scope
是什么。
不过,我们可以在这个插件中进行配置,声明打包时需要排除的依赖,例如:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<!-- 打包时排除lombok依赖 -->
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
3,依赖的传递
事实上,在Maven中,依赖也是会传递的,我们先创建一个名为first
的项目,并引入lombok
依赖如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gitee.swsk33</groupId>
<artifactId>first</artifactId>
<version>1.0.0</version>
<properties>
<java.version>17</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- 引入lombok依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
</dependency>
</dependencies>
</project>
这是项目first
的pom.xml
文件,其groupId
为com.gitee.swsk33
,其artifactId
为first
,其版本为1.0.0
,现在在其工程目录下执行mvn clean install
安装至本地仓库使得待会可以引用它。
现在在新建项目second
,并引用上述的first
作为依赖,如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gitee.swsk33</groupId>
<artifactId>second</artifactId>
<version>1.0.0</version>
<properties>
<java.version>17</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- 引用first项目 -->
<dependency>
<groupId>com.gitee.swsk33</groupId>
<artifactId>first</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>
好的,现在展开IDEA左侧栏的外部库部分,看看second
项目的依赖:
可见second
项目仅仅是引入了first
项目,但为什么外部库中包含了lombok
依赖呢?这是因为first
依赖lombok
,而second
依赖first
时,lombok
也被传递给了second
。
同样地,如果现在又有一个项目third
依赖second
呢?那么third
也会间接依赖lombok
,也可以使用lombok
中的类。
当然,依赖并不总是会传递的,有下列因素会影响依赖传递。
(1) scope
作用域
scope
不仅仅代表这个依赖的作用域,也会影响依赖的传递,只有scope
为compile
和runtime
的依赖是会传递的。
假设现在把上述first
项目中的lombok
依赖scope
改成provided
或者test
,然后重新执行mvn clean install
,你就会发现在second
的依赖中,就看不到lombok
了!
(2) optional
字段
除了scope
之外,还可以设定依赖的optional
字段,当设定为true
时代表这个依赖是可选的,那么这时无论其scope
是什么,这个依赖都不会传递。默认情况下,即不声明依赖的optional
字段时,它的值是false
。
现在将first
中的lombok
依赖的optional
字段声明为true
:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
<optional>true</optional>
</dependency>
然后重新mvn clean install
,再次打开second
项目,你就会发现lombok
依赖就没有传递过来了!
所以如果在制作外部库需要其他人引用的时候,我们可以将一些仅仅是外部库需要使用但是其它项目不一定要使用的依赖的optional
设定为true
,避免其他开发者引入你的外部库时发生依赖冲突。
转载自:https://juejin.cn/post/7239585610858823739