什么是依赖传递
举例说明:
存在4个Java组件:组件A,组件B,组件C和组件D,依赖配置如下:
组件A对组件B的依赖:
<dependency>
<groupId>xxx.yyy.zzz</groupId>
<artifactId>组件B</artifactId>
<version>1.0</version>
<scope>compile</scope>
</dependency>
组件B对组件C和组件D的依赖:
<dependency>
<groupId>xxx.yyy.zzz</groupId>
<artifactId>组件C</artifactId>
<version>1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>xxx.yyy.zzz</groupId>
<artifactId>组件D</artifactId>
<version>1.0</version>
<scope>compile</scope>
</dependency>
它们的依赖关系为:组件B依赖组件C和组件D,组件A依赖组件B,这就导致组件A间接依赖组件C和组件D,组件A对组件C和组件D的依赖关系就是依赖传递产生的。
排除依赖传递的3种方式
在使用Maven作为构建工具时,要排除依赖传递有3种实现方式:
使用exclusion排除
由于依赖传递的影响导致组件A间接依赖了组件C,如果不希望组件A依赖组件C,可以在配置文件pom.xml中做依赖排除:
组件A对组件B的依赖:
<dependency>
<groupId>xxx.yyy.zzz</groupId>
<artifactId>组件B</artifactId>
<version>1.0</version>
<scope>compile</scope>
<exclusions>
<!-- 排除对组件C的依赖 -->
<exclusion>
<groupId>xxx.yyy.zzz</groupId>
<artifactId>组件C</artifactId>
</exclusion>
</exclusions>
</dependency>
使用这种方式排除依赖,通常是针对这种场景:组件B是第三方的,在项目中依赖了组件B,但是又不想依赖组件C。
设置scope属性为provided
在开发自定义组件时,如果希望依赖的组件仅仅在编译和单元测试时生效,可以设置scope属性为provided。
举例:在开发自定义组件E时,需要在编译和单元测试时依赖组件F提供的API,但是又不希望其他组件在依赖组件E时再间接依赖组件F,就可以使用该方式。
<dependency>
<groupId>xxx.yyy.zzz</groupId>
<artifactId>组件F</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
最常见的例子就是,在开发自定义组件时可能需要使用Servlet API(确保不会在编译时报错即可,运行时是使用Servlet容器提供的接口),比如:javax.servlet.http.HttpServletRequest,此时可以依赖javax.servlet-api,同时设置scope属性为provided。
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
设置optional属性为true
在开发自定义组件时,如果明确需要禁止依赖传递,可以设置optional属性为true。
举例:在开发自定义组件E时,某个接口存在多种可选的实现方式,而这些不同的实现方式又需要依赖不同的第三方组件(如组件F支持HTTP调用方式,组件G支持MQ调用方式),那么就可以在自定义组件配置文件pom.xml中声明对第三方组件的依赖是可选的。
<dependency>
<groupId>xxx.yyy.zzz</groupId>
<artifactId>组件F</artifactId>
<version>1.0</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>xxx.yyy.zzz</groupId>
<artifactId>组件G</artifactId>
<version>1.0</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
由于在组件E中对组件F和组件G的依赖都是可选的,在项目中可以根据实际需要明确添加对组件F或组件G的依赖。
实现方式总结
如上,针对不同的场景使用不同的依赖传递排除方式,总结起来就是2大类:
其一,排除第三方组件的传递依赖时使用exclusion方式
第二,自定义组件时可以使用scope或optional属性,它们的语义不同:scope属性方式强调的是被依赖的组件仅仅在编译和单元测试时使用,不需要传递依赖到运行时,通常适用于在编写底层组件时引用API,在运行时由容器提供API的场景;optional强调的是可选性,通常用于自定义组件的某个方法存在多种实现方式,不同的实现方式需要依赖不同的第三方组件,此时将第三方组件的依赖声明为“可选的”,将对第三方组件的明确依赖交给引用自定义组件的上层来选择。
【参考】
Maven中scope=provided和optional=true的区别
Maven optional关键字透彻图解
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达,在下面评论区告诉我^_^^_^