maven使用问题积累

写在前面

Maven是一个项目管理和综合工具,能让我们很轻松完成项目构建和自动化测试。本篇以问答的形式对近来被问到过的maven的相关问题做下总结,谨做为知识积累,供大家查阅。后续工作过程中如果大家有遇到这方面的其他问题,欢迎一起补充完善~~

maven的依赖传递

Q1: 父pom中使用 声明了A、B的依赖,版本设置为1.0。 版本同为1.0,A、B、C三个项目中,B依赖A,C同时依赖A、B,项目C继承父POM,同时在其项目的pom中加入B依赖,version为2.0。B 2.0 也继承了父pom,同时在其项目的pom中有A 2.0的依赖。这种情况下,对项目C执行mvn package,发现项目C的jar lib中包含的A为1.0版本,B为2.0版本。何解?

A1: 这个问题与maven 的传递性依赖有关,先看官方文档对于传递性依赖的定义及其规则中文文档可参考,但具体释义建议以官方文档为准。

传递性依赖是maven2.0以后出现的新的特性。当你的项目依赖库A,而库A又依赖库B和库C时,传递性依赖使得你项目添加A依赖时,就能帮你把A依赖的其他库B和C也隐式添加到你的项目中,从而避免去寻找所有依赖。该特性依靠解析远端仓库的依赖库的项目文件得以实现的。传递性依赖没有嵌套深度的限制,但是当出现循环依赖的时候会报错。
传递性依赖使得包含的依赖库得以很快增长,因为这个原因,依赖性做了一些限制性规定,来确定选择哪些依赖库。

  • 依赖调解:当依赖库存在多个版本时,遵循最小路径原则,在2.0.9版本以后,如果遇到路径相同的依赖库,遵循最先声明原则。
    最小路径原则,即存在两个不同版本的库时,优先选择依赖树中路径最短的版本。
    如果,A、B、C、D依赖关系 A -> B -> C -> D 2.0,而A -> E -> D 1.0,则在构建A时,D1.0会被使用。因为A -> E -> D中从A到D的路径更短。如果需要使用依赖A,应直接使用在pom中显示添加D2.0的依赖。

  • 依赖管理:在传递性依赖或者当没有指定依赖版本时,项目作者可以通过依赖管理直接指定依赖的版本。在前述的例子中,A未直接依赖D,但D是A的依赖库。这时,A可以将D做为依赖管理部分的一个依赖,使用 ,在D可能会被引入的时候,控制D的版本。

  • 依赖范围 – 你可以指定只在当前编译范围内包含合适的依赖
  • 排除依赖 如果项目X依赖于项目Y,项目Y又依赖项目Z,项目X的所有者可以使用”exclusion”元素来显式排除项目Z
  • 可选依赖 – 如果项目Y依赖项目Z,项目Y的所有者可以使用”optional”元素来指定项目Z作为X的可选依赖。那么当项目X依赖项目Y时,X只依赖Y并不依赖Y的可选依赖Z。

依赖管理部分,官方文档给予了更为详细的解释,并给出了一些示例,结合示例,归纳了两条原则:

  1. 在传递性依赖中,依赖管理的优先级高于依赖调解
  2. 当前pom中依赖声明的优先级高于父pom的依赖声明

以上内容均从官方文档获得。从依赖调解和依赖管理两部分内容看,问题中的C->B->A, C通过依赖传递获得A的依赖,而在C的父pom中使用dependencyManagement管理确定了A的版本,所以按照依赖管理原则,A的版本为1.0,而B因为在C项目的pom中有声明version,以项目自身pom为准,B的版本为2.0。

maven compiler使用相关

Q2: 本地安装了多个jdk版本,希望maven compile在编译一些项目时使用特定版本的jdk,而非缺省jdk版本。

A2:问题可以分为两种情况解答:

  • 本地如果为有桌面系统,可使用IDE工具,建议按照IDE工具的配置方法来设置项目编译使用的JDK版本及编译级别。
    以IDEA为例,先设置java编译器,file->setting->java compile,以jdk1.8为例,设置如下:

setting文件设置javac

setting属性设置完成后,进入file->project structure->project 设置项目的sdk及编译级别
project sdk设置

file->project structure ->modules 设置各模块的sdk及编译级别
各module的编译级别

各module依赖sdk

  • 本地如果为linux环境且无可视化界面,可按照maven官方提供的文档来设置项目所需要javac的绝对路径,具体配置
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <project>
    [...]
    <build>
    [...]
    <plugins>
    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.7.0</version>
    <configuration>
    <verbose>true</verbose>
    <fork>true</fork>
    <executable><!-- path-to-javac --></executable>
    <compilerVersion>1.7</compilerVersion>
    </configuration>
    </plugin>
    </plugins>
    [...]
    </build>
    [...]
    </project>

当然,此处指定的javac版本仅用于maven compiler插件,其他插件仍使用默认jdk版本。 path-to-javac 为本地javac的绝对安装路径, 可以写成硬编码,不过建议最好利用环境变量或者maven的setting.xml文件将该路径做成可配置项。可参考:

1
<executable>${JAVA_1_7_HOME}/bin/javac</executable>

未完待续……