Maven依赖中option与scope provided的区别.

  |   0 评论   |   1,200 浏览

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 scope provided 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.

compileprovidedruntimetest
compilecompile(*)-runtime-
providedprovided-provided-
runtimeruntime-runtime-
testtest-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,但是有例外;
  • 反过来从最上面的行中的providedtest来看,这两种依赖的包都不会被传递,不管以怎样的一级依赖被引入进来

结论:

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”

-- 引用自: Difference Between optionaltrue and provided

如上引用: 说明的是一个组件有很多的功能,或者说是:feature , 有很多 feature 是可能不适用的,或者说是可选的对于工程B的功能X,这个功能是可选的.同时这个可选的功能依赖了工程C. 那这个可选 依赖C就可以定义为 option=true , 此时a在依赖b的时候,c不会被引用进来.如果你想引用C,那需要手工的再次添加进来.

结论

  • 两者在传递依赖表现出来的特性是一样的.但是其语义是不一样的.
    • provided更多的是表明这个依赖由运行环境提供.在我编译后这个依赖路径就不需要了. 实际这个依赖是被需要的,只是由其它的运行环境来保证.或者由其它的路径导入.
    • option更多的是强调是可选功能, 可选功能在被传递依赖的时候,不会被传递. 至于是否是真的依赖需要开发者人工确认,依赖就手工导入这个被间接引入的C,如果不依赖就不用管了.
  • 两都都能够达到依赖不被传递的目的.但是使用上需要进行简单的区分.

评论

发表评论


取消