Maven依赖中option与scope provided的区别.
maven在管理依赖时,对于引入包的传递性处理.一般有
<option>true</option>
和<scope>provied</scope>
两种处理. 但是这两个的区别是什么需要简单梳理下.
作用域为 provided
作用.
一般我们在处理 Java Web
编程的时候.特别是对于 servlet-api
的引用. 一般会设置为 provided
,这应该是大部分同学第一次接触到这个标签与语义。一般我们会如下这样写maven dependency rference:
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
如果不与其它的东西混淆在一起,大家都会明白这个作用域的含义。
This is much like
compile
, but indicates you expect the JDK or a container to provide the dependency at runtime. For example, when building a web application for the Java Enterprise Edition, you would set the dependency on the Servlet API and related Java EE APIs to scopeprovided
because the web container provides those classes. A dependency with this scope is added to the classpath used for compilation and test, but not the runtime classpath. It is not transitive.`
- 这个依赖只是编译时依赖,非运行时依赖. 简单的说在编译代码的时候.这个依赖会起作用.但是在运行时,或者打包的时候.不会引入这个依赖. 而上面这个
servlet-api
就是这么一个东西. 我们在编译的时候需要它,以检查我们的代码的完整性(所有的引用的包都存在)与正确性(所有的代码都能编译通过).但是在编译完成后,这个依赖就不需要了. 这些依赖都是由运行环境所提供.比如这里说的servlet-api
将由运行容器所提供. - 另外一层含义就是,这个依赖不会被传递. (不传递并不表示不需要,只是有其它的路径可以引入.)
关于相应的不同 scope
在不同的生命周期里生效的作用机理可以参考官方,我这里放一张截图:
Each of the scopes (except for import
) affects transitive dependencies in different ways, as is demonstrated in the table below. If a dependency is set to the scope in the left column, a transitive dependency of that dependency with the scope across the top row results in a dependency in the main project with the scope listed at the intersection. If no scope is listed, it means the dependency is omitted.
compile | provided | runtime | test | |
---|---|---|---|---|
compile | compile(*) | - | runtime | - |
provided | provided | - | provided | - |
runtime | runtime | - | runtime | - |
test | test | - | test | - |
(*) Note: it is intended that this should be runtime scope instead, so that all compile dependencies must be explicitly listed. However, if a library you depend on extends a class from another library, both must be available at compile time. For this reason, compile time dependencies remain as compile scope even when they are transitive.
所以针对上面所述的结论不传递是一个已经加工过了的结论.上面表中的含义为:当我们一级依赖引入一个包.并设置为左列定义的scope类型时.它引入的二级依赖的类型如顶行所定义的时候, 那这个间接引入的包的依赖类型由左列和上列同时决定. 举一下例子:
- 一个包:
package-a
通过provided
依赖类型被引入,那间接依赖为任意类型都会被改写为provided
,如最上一行的最左边的compile
类型(指二级间接依赖为compile
),一级依赖引入类型为:provided
时。这个compile
会被改写为provided
,换言之:所有一级依赖引入的包,其二级依赖都会被改写为provided
,但是有例外;- 反过来从最上面的行中的
provided
和test
来看,这两种依赖的包都不会被传递,不管以怎样的一级依赖被引入进来。
结论:
provided
类型的依赖:
- 不会被传递, 无论在被一级引入的时候使用的是任何作用域都是不会传递的。 这个特性有时可惜被用来管理组件包的依赖上。这样可以比较好的限制无用的依赖被传递。但是这不一定是一个好的实践。
- 从语义上来说,这个含义是这个依赖是在编译时需要。而非
runtime
需要,同时其含义provided
并不是说这个依赖不用,只是说是已经提供好。需要注意差别。
Option
选项为 true
时
这个更多的是对传递性的说明。 也就是说一个包 c
对于 b
来说是一个可选功能,那在 a
工程依赖 b
时,c不会被主动引入。(也就是不依赖)
“Project B has many features but during the development of some features we have used some capabilities of Project C . However, those features are optional, that means you don’t have to use them in your project. Therefore, you don’t need Project C in your classpath unless you want to use those features of Project B that depends on Project C”
如上引用: 说明的是一个组件有很多的功能,或者说是:feature , 有很多 feature 是可能不适用的,或者说是可选的对于工程B的功能X,这个功能是可选的.同时这个可选的功能依赖了工程C. 那这个可选 依赖C
就可以定义为 option=true
, 此时a在依赖b的时候,c不会被引用进来.如果你想引用C,那需要手工的再次添加进来.
结论
- 两者在传递依赖表现出来的特性是一样的.但是其语义是不一样的.
provided
更多的是表明这个依赖由运行环境提供.在我编译后这个依赖路径就不需要了. 实际这个依赖是被需要的,只是由其它的运行环境来保证.或者由其它的路径导入.option
更多的是强调是可选功能, 可选功能在被传递依赖的时候,不会被传递. 至于是否是真的依赖需要开发者人工确认,依赖就手工导入这个被间接引入的C,如果不依赖就不用管了.- 两都都能够达到依赖不被传递的目的.但是使用上需要进行简单的区分.