Maven构建多模块工程
除非是简单的工程项目,实际工作中碰到的大部分Maven工程都是多模块的,各个项目模块可以独立开发,其中某些模块又可能会使用到其他的一些模块的功能,如何利用maven来构建一个多模块的工程呢?
Maven提供了继承和聚合方式用以构建多模块工程,类似于Java中的继承和聚合的概念。
项目继承结构
项目继承可以实现在父工程中创建的pom文件内容的复用。子工程可以自动继承到父工程中的pom文件属性。
比如在父工程的pom文件中定义以下属性:
<groupId>com.packt.cookbook</groupId>
<artifactId>project-with-inheritance</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
那么在子工程中添加parent定义:
<parent>
<groupId>com.packt.cookbook</groupId>
<artifactId>project-with-inheritance</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>child</artifactId>
<packaging>jar</packaging>
<name>Child Project</name>
有了以上的定义,我们就可以在子工程中使用父工程的pom文件中定义的properties和dependencies中的内容了。
NOTE:
- 父工程必须是pom类型的(packaging)
- 父工程完全不知道存在子工程,只有子工程中定义的parent元素可以指定父工程
一般而言父工程都在子工程的上一级目录中,如果父工程不在子工程的上一级目录中,子工程会继续往上在maven仓库中寻找是否有满足要求的父工程。如果需要自己指定父工程的位置,可以新增一个<relativePath>../parent/pom.xml</relativePath>
的配置。
模块聚合结构
一个父工程可以拥有很多子工程,而父工程无法明确知道其子工程。使用模块聚合可以使得父工程明确管理其子工程,而子工程又可以成为一个个独立的存在,不必明确知道其父工程的存在。
如何在父工程中定义模块呢?只需要在父工程的pom文件中定义modules元素,为每个子模块新建一个module配置即可。
<modules>
<module>admin</module>
</modules>
这种管理方式虽然简单,但是并不能继承父工程中定义好的properties和依赖,每个子模块都必须独立定义自己的依赖和属性,没有发挥maven项目管理的最大威力。
继承与聚合结合使用
如何让maven工程既有继承带来的便利性又有聚合带来的明确性呢?答案就是把这两种特性结合起来,即使用继承,又使用聚合。
例如,这里让admin模块继承maven项目,同时maven项目又使用modules元素来明确管理admin模块。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cc.adays</groupId>
<artifactId>maven</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>cc.adays.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.9</version>
<executions>
<execution>
<id>copy-dependency</id>
</execution>
</executions>
</plugin>
</plugins>
</build>
<modules>
<module>admin</module>
</modules>
</project>
在admin子模块的pom中定义parent元素。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>maven</artifactId>
<groupId>cc.adays</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>admin</artifactId>
</project>
通过这种方式,admin子元素就可以直接使用父工程中定义的依赖和属性,而父工程maven又可以明确管理其子元素,一举两得。
多模块工程的依赖管理
最后一个问题,虽然继承真心很好用,但是有时候子工程并不想拥有父工程的全部依赖,怎么办?此时就必须仰仗dependencyManagement了。通过在父工程中定义dependencyManagement,然后在子模块中选择性地使用父工程中已经定义好的依赖,就非常方便了。
举个栗子:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.10.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
这里在父工程中定义了两个依赖,一个是spring,一个是Junit,但是我们的子模块中只想使用junit,所以在子模块的pom文件中,定义:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
图片.png
这里不需要定义version和scope,因为会自动从父工程中继承而来。
相同的道理,可以使用这种方式管理maven的插件,只需要使用pluginManagement元素,具体的使用方式与依赖的管理方式是一模一样的。