一、scopeprovided概述
在Maven的依赖管理范畴中,scopeprovided代表依赖关系的一种“范畴”,与被依赖项目的编译构建不带来实际用处的依赖关系,通常以optional或provided为属性。
换句话说,scopeprovided设定的依赖关系只在编译期和测试期中生效,并在运行时被丢弃。这意味着,该依赖项只在项目的编译和测试中有效。
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>
在上面的代码例子中,与servlet-api相关联的依赖项的作用仅限于编译和测试,在运行时不会被打包。如果用户所在的容器已经包含了servlet-api的库,就不必将它打包进war文件中,因此该依赖此时可用于编译,但不用于部署。
二、scopeprovided的使用场景
1.与Java标准库相关的依赖库
与应用程序运行环境相关的库,比如Java标准库,即使没有将其作为Maven依赖项导入,Java运行时环境也将它们提供给应用程序。
例如,如果我们想要为servlet应用程序设置ContextPath,则只需要导入web.xml文件就可以了,这样就可以通过web服务器运行和测试应用程序。在这种情况下,servlet-api与Java标准库相关,因此我们可以将其声明为provided,而不必将其打包到生产环境中:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
2.减少部署时的依赖项
当项目打算部署时,我们通常会将其从测试环境中移植到生产环境中。在此过程中,需要将我们已经编译过的代码移植到生产环境,并将所有依赖库(除Java标准库之外)放在一个classpath中。一般来说,同样的依赖包会被多个依赖库中所使用,无需重复下载或者打包到多个部署包中。因此为了提高效率,最好将所有这些依赖项打包在一个单独的文件中,让所有应用程序都可以共享它们而不用重复下载。
这就是scopeprovided的另一个用例:它能帮助我们仅将必须部署的依赖项打包到生产环境中,而不会重复打包在它们依赖的多个模块中。我们可以使用该范畴来告诉Maven,一些依赖仅在JAR打包时有效,而不是在WAR或EAR打包时有效。
3.与插件相关的范畴
Maven插件是Maven生态系统中非常重要的一部分,Maven插件通常也会有自己的宿主环境(如Jetty或Tomcat)。在某些情况下,插件可能需要一些额外的依赖项来执行其任务。为了提供这些支持,将这些插件的依赖项声明为插件的scopeprovided是有意义的,因为它将允许这些依赖项在插件代码运行时被查找到,但不会被打包进用户项目中。
<plugins>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.31.v20200723</version>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</plugin>
</plugins>
三、范畴unused的缺陷
相对于范畴provided的优点, unused的范畴不仅编译时用不到,并且test范畴通常代表着较大的测试代码,而且通常不需要在运行时打包。因此,它的适用范围通常更小。
然而,unused范畴的一个缺陷是无法自动删除所有未使用的依赖项,一些用户仍然有一些未删除的垃圾文件,这会使项目变得丑陋,难以维护。
结论
范畴provided是作为Maven支持库中最常用的范畴之一。在依赖管理中,scopeprovided 常见的使用场景是:与Java标准库相关的依赖库、减少部署时的依赖项、与插件相关的范畴。unused的范畴与之相比,它的使用范围通常更小,且不能自动删除未使用的依赖项,将文件留下来会使项目难以维护,变得丑陋。