`

转关于maven可选依赖和排除依赖的学习

阅读更多
原文地址:http://qa.taobao.com/?p=7351

      

      了解可选依赖和排除依赖的功能,能够帮助我们更好的理解依赖是什么、怎样使用、如何工作和何时最适宜应用。其中,排除依赖是作为依赖的基本概念而不是处于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层上?

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

相关推荐

    Maven中的依赖

    5. **仓库**:Maven依赖的存储库,包括本地仓库(默认在用户目录下)和远程仓库(如中央仓库mvnrepository.com)。当本地仓库没有所需依赖时,Maven会尝试从远程仓库下载。 6. **排除依赖(exclude)**:有时候我们...

    Java Maven导入Spring依赖

    Java使用Maven导入Spring依赖

    IDEA最新版2020.1的maven工程本地依赖仓库无法使用问题(已解决)

    "IDEA最新版2020.1的maven工程本地依赖仓库无法使用问题解决方案" ...本文详细介绍了IDEA最新版2020.1的maven工程本地依赖仓库无法使用问题的解决方案,提供了详细的解决步骤和注意事项,帮助读者快速解决这个问题。

    maven依赖+继承+聚合

    首先,我们来讨论"Maven依赖"。在Java开发中,一个项目往往需要引用其他库或者框架来完成特定功能。Maven通过在`pom.xml`文件中声明依赖(dependencies)来管理这些外部库。依赖声明包括groupId、artifactId和...

    maven 中引入依赖的包

    在Java开发领域,Maven是一个不可或缺的构建工具,它通过管理项目依赖关系,简化了项目的构建、测试和部署过程。本文将深入探讨如何在Maven项目中引入依赖的包,并结合相关源码和工具,帮助开发者更好地理解和使用这...

    关于maven的资源依赖介绍

    在软件开发领域,Maven 是一个广泛使用的项目管理和综合工具,尤其在Java世界里,它极大地简化了构建、依赖管理和项目文档的生成。本篇文章将深入介绍 Maven 的资源依赖及其相关概念,帮助开发者更好地理解和使用 ...

    maven仓库中关于Hadoop的一些依赖

    总之,Hadoop和Hive在大数据处理中扮演着重要角色,它们的Maven依赖是开发相关项目的基础。正确配置和管理这些依赖,能够确保项目的顺利运行,提高开发效率。而理解这些依赖的功能和作用,有助于更好地利用Hadoop和...

    maven依赖小例子

    在这个名为“maven依赖小例子”的源码中,你可以看到如何实际配置和使用Maven依赖的示例。通过分析源码,你可以更好地理解Maven POM.xml文件的结构和依赖管理的工作方式。在实际开发中,熟练掌握Maven依赖管理不仅能...

    maven_package 依赖包(完整)

    在本"maven_package"压缩包中,包含了完整的Maven依赖包,这些包广泛适用于各种Java项目,确保了项目的正常运行和高效开发。比如,提到了"log4j-1.2.17.jar",这是一个著名的日志处理框架,对于系统日志记录至关重要...

    Maven的依赖验证项目

    【Maven的依赖验证项目】是一个关于Maven项目管理和依赖管理的实践案例,它与CSDN博主songdeitao的一篇文章《Maven依赖管理详解》相关联。在这个项目中,我们将深入理解Maven如何处理项目的依赖关系,以及如何有效地...

    Maven运行依赖实例

    总结,"Maven运行依赖实例"是一个关于如何使用Maven工具来管理和运行具有依赖关系的Java项目的教程。通过阅读提供的博客文章和分析`runWithDependent`文件,学习者可以深化对Maven的理解,并提升其在实际开发中的...

    各种maven需要的lib依赖.rar

    各种maven需要的lib依赖.rar各种maven需要的lib依赖.rar各种maven需要的lib依赖.rar各种maven需要的lib依赖.rar各种maven需要的lib依赖.rar各种maven需要的lib依赖.rar各种maven需要的lib依赖.rar各种maven需要的lib...

    dubbo项目maven依赖

    在IT行业中,Dubbo是一个非常重要的分布式服务框架,...通过理解Dubbo和Maven的工作原理,以及排查和解决编译问题的方法,你将能够成功地从源码编译出Apache Dubbo项目。记住,持续学习和实践是成为IT行业大师的关键。

    Geoserver maven 依赖

    本篇将深入探讨"GeoServer Maven依赖"这一主题,以及如何在Java环境中使用Maven构建GeoServer相关的项目。 首先,Maven是Apache软件基金会的一个项目,它通过一个项目对象模型(Project Object Model,POM)来管理...

    Maven离线依赖包v2

    Maven是Java开发中广泛使用的构建工具,它通过项目对象模型(Project Object Model,POM)来管理项目的构建、报告和依赖关系。"Maven离线依赖包v2"指的是一个包含Maven仓库中多种库的压缩文件集合,主要用于在没有...

    ​实现maven项目中多版本依赖兼容使用解决方案

    总结来说,解决Maven依赖冲突需要深入理解Maven的依赖管理和类加载机制。在本案例中,通过修改冲突依赖的类路径,可以实现多版本依赖的共存,但这种方式并不适用于所有场景,因此在实际应用中应谨慎考虑。在可能的...

    Maven 依赖详细理解.pdf

    依赖范围(scope)是Maven依赖管理的一个重要概念。scope定义了依赖项的使用范围,主要有以下几个选项:compile、provided、runtime和test。compile表示依赖项在编译时需要,provided表示依赖项在编译和测试时需要,但...

    Maven本地仓库依赖环境

    在IT行业中,Maven是一个非常重要的构建工具,主要用于管理Java项目的构建、报告和依赖关系。在JavaWeb开发中,Maven扮演着核心角色,帮助开发者有效地处理库的依赖关系,使得项目构建过程更加标准化和自动化。本文...

    Maven 多项目依赖关系

    Maven使用一个统一的配置方式,使得项目间的依赖关系清晰明了,便于维护和更新。本文将深入探讨Maven如何处理多项目依赖关系,并结合标签“源码”和“工具”,探讨其在实际开发中的应用。 一、Maven项目结构与POM....

    MAVEN(spring5.0)全套依赖

    Maven是一款强大的Java项目管理工具,它通过XML格式的配置文件(pom.xml)来管理项目的构建、报告和依赖关系。在Spring 5.0框架的开发中,Maven扮演着至关重要的角色,帮助开发者集成各种库和组件,简化项目的构建...

Global site tag (gtag.js) - Google Analytics