这段时间项目中遇到过了一些 Jar 包冲突的问题,不少是因为咱们项目模块不少的时候,用 Maven 管理不当致使的冲突问题,本文就这个问题参考网上的资料,因而总结下 Maven 中 dependencies 与 dependencyManagement 的区别。java
假设项目结构以下:apache
parent 为父模块,抽象出来管理子项目的公共依赖,为了项目的正确运行,必须让全部的子项目使用依赖项的统一版本,必须确保应用的各个项目的依赖项和版本一致,才能保证测试的和发布的是相同的结果。api
在项目的 parent 层,能够经过 dependencyManagement 元素来管理 jar 包的版本,让子项目中引用一个依赖而不用显示的列出版本号。maven
parent 中 pom.xml单元测试
<properties> <version.framework>1.0-SNAPSHOT</version.framework> <javaee-api.version>1.0-SNAPSHOT</javaee-api.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>com.zhisheng</groupId> <artifactId>framework-cache</artifactId> <version>${version.framework}</version> </dependency> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>${javaee-api.version}</version> </dependency> </dependencies> </dependencyManagement>
extendion 中的 pom.xml测试
<parent> <artifactId>parent</artifactId> <groupId>com.zhisheng</groupId> <version>0.0.1-SNAPSHOT</version> <relativePath>../parent/pom.xml</relativePath> </parent> <!--依赖关系--> <dependencies> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> </dependency> <dependency> <groupId>com.zhisheng</groupId> <artifactId>framework-cache</artifactId> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> </dependency> </dependencies>
这样作的好处:统一管理项目的版本号,确保应用的各个项目的依赖和版本一致,才能保证测试的和发布的是相同的成果,所以,在顶层 pom 中定义共同的依赖关系。同时能够避免在每一个使用的子项目中都声明一个版本号,这样想升级或者切换到另外一个版本时,只须要在父类容器里更新,不须要任何一个子项目的修改;若是某个子项目须要另一个版本号时,只须要在 dependencies 中声明一个版本号便可。子类就会使用子类声明的版本号,不继承于父类版本号。ui
咱们知道 Maven 的继承和 Java 的继承同样,是没法实现多重继承的,若是10个、20个甚至更多模块继承自同一个模块,那么按照咱们以前的作法,这个父模块的 dependencyManagement 会包含大量的依赖。若是你想把这些依赖分类以更清晰的管理,那就不可能了,import scope 依赖能解决这个问题。你能够把 dependencyManagement 放到单独的专门用来管理依赖的 POM 中,而后在须要使用依赖的模块中经过 import scope 依赖,就能够引入dependencyManagement。例如能够写这样一个用于依赖管理的 POM:编码
<project> <modelVersion>4.0.0</modelVersion> <groupId>com.zhisheng.sample</groupId> <artifactId>sample-dependency-infrastructure</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <dependencyManagement> <dependencies> <dependency> <groupId>junit</groupId> <artifactid>junit</artifactId> <version>4.8.2</version> <scope>test</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactid>log4j</artifactId> <version>1.2.16</version> </dependency> </dependencies> </dependencyManagement> </project>
而后就能够经过非继承的方式来引入这段依赖管理配置:spa
<dependencyManagement> <dependencies> <dependency> <groupId>com.zhisheng.sample</groupId> <artifactid>sample-dependency-infrastructure</artifactId> <version>1.0-SNAPSHOT</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependency> <groupId>junit</groupId> <artifactid>junit</artifactId> </dependency> <dependency> <groupId>log4j</groupId> <artifactid>log4j</artifactId> </dependency>
这样,父模块的 POM 就会很是干净,由专门的 packaging 为 pom 的 POM 来管理依赖,也契合的面向对象设计中的单一职责原则。此外,咱们还可以建立多个这样的依赖管理 POM,以更细化的方式管理依赖。这种作法与面向对象设计中使用组合而非继承也有点类似的味道。插件
相对于 dependencyManagement,全部声明在父项目中 dependencies 里的依赖都会被子项目自动引入,并默认被全部的子项目继承。
dependencies 即便在子项目中不写该依赖项,那么子项目仍然会从父项目中继承该依赖项(所有继承)
dependencyManagement 里只是声明依赖,并不实现引入,所以子项目须要显示的声明须要用的依赖。若是不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,而且没有指定具体版本,才会从父项目中继承该项,而且 version 和 scope 都读取自父 pom; 另外若是子项目中指定了版本号,那么会使用子项目中指定的jar版本。
与 dependencyManagement 相似的,咱们也可使用 pluginManagement 元素管理插件。一个常见的用法就是咱们但愿项目全部模块的使用 Maven Compiler Plugin 的时候,都使用 Java 1.8,以及指定 Java 源文件编码为 UTF-8,这时能够在父模块的 POM 中以下配置 pluginManagement:
<build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.5.1</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </pluginManagement> </build>
这段配置会被应用到全部子模块的 maven-compiler-plugin 中,因为 Maven 内置了 maven-compiler-plugin 与生命周期的绑定,所以子模块就再也不须要任何 maven-compiler-plugin 的配置了。
与依赖配置不一样的是,一般全部项目对于任意一个依赖的配置都应该是统一的,但插件却不是这样,例如你能够但愿模块 A 运行全部单元测试,模块 B 要跳过一些测试,这时就须要配置 maven-surefire-plugin 来实现,那样两个模块的插件配置就不一致了。这也就是说,简单的把插件配置提取到父 POM 的 pluginManagement 中每每不适合全部状况,那咱们在使用的时候就须要注意了,只有那些普适的插件配置才应该使用 pluginManagement 提取到父 POM 中。
关于插件 pluginManagement,Maven 并无提供与 import scope 依赖相似的方式管理,那咱们只能借助继承关系,不过好在通常来讲插件配置的数量远没有依赖配置那么多,所以这也不是一个问题。
转载自:https://zhuanlan.zhihu.com/p/31020263