您的位置:首页 > 其它

maven可选依赖和排除依赖

2016-05-06 13:45 447 查看
了解可选依赖和排除依赖的功能,能够帮助我们更好的理解依赖是什么、怎样使用、如何工作和何时最适宜应用。其中,排除依赖是作为依赖的基本概念而不是处于pom层。

一、 可选依赖

当一个项目不适合分割成多个子模块的时候,我们可以使用可选依赖。它的思想在于某些依赖只应用于某些功能,而且当没有该功能时也不存在该依赖。理想状况下,一个功能可能被划分为一个子模块,该子模块是一个只有核心功能的项目,由于当你要使用这个子工程的功能的时候,你会需要它的全部,所以这个子工程只含有非可选性依赖。

然而,如果工程不可被分割,这些依赖被声明为可选。如果一个用户想要使用和可选性依赖相关的功能,他们必须要在工程中重新声明可选性依赖。也许可选依赖和排除依赖不是解决问题的最好方法,但是不失为一种有效的解决方案。

1. 为何使用可选依赖

声明可选依赖不仅对于节省空间/内存等是重要的,而且对于使用一个工程的时候控制实际依赖的列表也是非常重要的。因为jar包最终可能编译成WAR、EAR、EJB等等,包含错误的jar包可能产生违反许可证协议、导致类路径错误等问题。

2.如何使用optional标记

在你的依赖声明中简单地将<optional>标记设置成true,就能将一个依赖声明为可选的。示例如下
<project>

...

<dependencies>

<!-- declare the dependency to be set as optional -->

<dependency>

<groupId>sample.ProjectA</groupId>

<artifactId>Project-A</artifactId>

<version>1.0</version>

<scope>compile</scope>

<optional>true</optional> <!-- value will be true or false only -->

</dependency>

</dependencies>

</project>


3.可选依赖是如何工作的?
Project-A -> Project-B


如上图所以projectA依赖projectB,当A在它的pom中声明B作为它的可选依赖时,这个关系会一直保持。 这就像在通常的构建中,projectB会被加到它的类路径中。
Project-X -> Project-A


但是当另外一个工程projectX在它的pom中声明A作为其依赖时,可选性依赖这时就发挥作用了。你会发现projectB并不存在projectX的类路径中。如果X的类路径要包含B那么需要在你的pom中直接进行声明。

4.例子:

让我们假设现在有这样一个和Hibernate有类似功能的工程X2,支持多种诸如MySQL, postgre, oracle等数据库驱动/依赖,所有这些驱动/依赖是X2但不是你的工程所需要的,所以一种比较可行的方法就是X2将这些驱动/依赖声明为可选的。这样,无论任何时候当你的工程在pom中声明X2作为直接依赖,X2所支持的这些驱动/依赖都不会被自动加到你工程的类路径中,相反地,你必须要直接声明需要使用的数据库驱动/依赖。

二、 排除依赖

由于maven2.x会传递解析依赖,所以很有可能一些你不需要的依赖也会包含在工程类路径中。例如,一些你依赖的工程可能没有正确的声明它们的依赖集。为了解决这种特殊情况,maven2.x已经引入了显式排除依赖的概念。排除是设置在pom中指定的依赖上,并且有指定的groupId和artifactId来标注。当你构建工程时,该物件不会像解析加载依赖一样被加载到你工程的类路径中。

1. 如何使用排除依赖

我们在pom中的<dependency>段下面加上<exclusions>标签。
<project>

...

<dependencies>

<dependency>

<groupId>sample.ProjectA</groupId>

<artifactId>Project-A</artifactId>

<version>1.0</version>

<scope>compile</scope>

<exclusions>

<exclusion>  <!-- declare the exclusion here -->

<groupId>sample.ProjectB</groupId>

<artifactId>Project-B</artifactId>

</exclusion>

</exclusions>

</dependency>

</dependencies>

</project>


2.排除依赖是如何工作的并且在何时使用它(作为最后一种解决方法)
Project-A

-> Project-B

-> Project-D <! -- This dependency should be excluded -->

-> Project-E

-> Project-F

-> Project C


如上图所示,Project-A依赖Project-B和C,Project-B依赖Project-D,Project-D依赖Project-E和F,默认的Project-A的类路径会包含:
B, C, D, E, F


如果由于我们知道Project-D的某些依赖在仓库中丢失,那么我们不想Project-D和它所有的依赖加载到Project-A的类路径中,而且也不想/不需要依赖Project-D的Project-B的功能。在这种情况下,Project-B的开发者会提供一个Project-D的 <optional>true</optional>依赖,如下:
<dependency>

<groupId>sample.ProjectD</groupId>

<artifactId>ProjectD</artifactId>

<version>1.0-SNAPSHOT</version>

<optional>true</optional>


</dependency>

然而,并不能达到你想要的效果。作为最后一种解决方法你仍然可以选择将它在Project-A中排除掉。如下:
<project>

<modelVersion>4.0.0</modelVersion>

<groupId>sample.ProjectA</groupId>

<artifactId>Project-A</artifactId>

<version>1.0-SNAPSHOT</version>

<packaging>jar</packaging>

...

<dependencies>

<dependency>

<groupId>sample.ProjectB</groupId>

<artifactId>Project-B</artifactId>

<version>1.0-SNAPSHOT</version>

<exclusions>

<exclusion>

        <groupId>sample.ProjectD</groupId> <!-- Exclude Project-D from Project-B -->

<artifactId>Project-D</artifactId>

</exclusion>

</exclusions>

</dependency>

</dependencies>

</project>


如果我们将Project-A部署到一个仓库中,而且Project-X声明了一个普通依赖到Project-A。那么Project-D是不是依旧从类路径中排除了?
Project-X -> Project-A


答案是yes。Project-A已经声明了它不需要Project-D,所以它不会作为Project-A的传递依赖而引入。那么考虑下图的Project-X依赖Project-Y,
Project-X -> Project-Y

         -> Project-B

-> Project-D

               ...


Project-Y依赖于Project-B,并且它有需要Project-D所支持的功能,所以不能在Project-D的依赖列表中声明排除。也可再提供一个额外的我们可以解析Project-E的仓库。在这种情况下,不能将Project-D全局排除,因为它是Project-Y的合法依赖。

在另外一种场景中,如果我们不需要的依赖是Project-E而不是Project-D,我们如何排除它呢?如下图:
Project-A

-> Project-B

-> Project-D

-> Project-E <!-- Exclude this dependency -->

-> Project-F

-> Project C


排除会影响到在依赖图上所有它的声明点以后的部分。如果你想排除Project-E而不是Project-D,可以简单的将排除指向Project-E。但是你无法将排除作用到Project-D,因为你无法改变Project-D的pom,如果你想这样,你应该用选择依赖而不是排除,或者将Project-D分成多个子工程,每个只有普通依赖。
<project>

<modelVersion>4.0.0</modelVersion>

<groupId>sample.ProjectA</groupId>

<artifactId>Project-A</artifactId>

<version>1.0-SNAPSHOT</version>

<packaging>jar</packaging>

...

<dependencies>

<dependency>

<groupId>sample.ProjectB</groupId>

<artifactId>Project-B</artifactId>

<version>1.0-SNAPSHOT</version>

<exclusions>

<exclusion>

<groupId>sample.ProjectE</groupId> <!-- Exclude Project-E from Project-B -->

<artifactId>Project-E</artifactId>

</exclusion>

</exclusions>

</dependency>

</dependencie>


3.为什么排除是依赖的基本概念,而不是在pom层上?

这主要是为了确保依赖图是可预测的,并且防止排除不该排除的依赖。如果你用到了这个最终的解决方法并且必须要把它放到排除中,你必须绝对清楚你讨厌的传递依赖中有哪些依赖会被引入。

4 依赖归类

如果我们项目中用到很多关于Spring Framework的依赖,它们分别是org.springframework:spring-core:2.5.6, org.springframework:spring-beans:2.5.6,org.springframework:spring-context:2.5.6,它们都是来自同一项目的不同模块。因此,所有这些依赖的版本都是相同的,而且可以预见,如果将来需要升级Spring Framework,这些依赖的版本会一起升级。因此,我们应该在一个唯一的地方定义版本,并且在dependency声明引用这一版本,这一在Spring Framework升级的时候只需要修改一处即可。

Xml代码

1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3. <modelVersion>4.0.0</modelVersion>

4.

5. <groupId>com.mycompany.app</groupId>

6. <artifactId>my-app-simple</artifactId>

7. <version>0.0.1-SNAPSHOT</version>

8. <packaging>jar</packaging>

9. <name>my-app-simple</name>

10. <properties>

11. <springframework.version>2.5.6</springframework.version>

12. </properties>

13.

14. <dependencies>

15. <dependency>

16. <groupId>junit</groupId>

17. <artifactId>junit</artifactId>

18. <version>3.8.1</version>

19. <scope>test</scope>

20. </dependency>

21.

22. <dependency>

23. <groupId>org.springframework</groupId>

24. <artifactId>spring-core</artifactId>

25. <version>${springframework.version}</version>

26. </dependency>

27. <dependency>

28. <groupId>org.springframework</groupId>

29. <artifactId>spring-beans</artifactId>

30. <version>${springframework.version}</version>

31. </dependency>

32. </dependencies>

33. </project>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: