我们常见的 Java 项目结构是这样的,
单一模块项目
实际的Java项目是这样的,
大型开源Java项目
通常一个稍大型的项目都是由多个模块组成的,比如上面著名的RPC框架Dubbo,包括了21个模块。多模块项目的依赖问题如何解决,如何更好地管理和发布多模块项目?
Maven 使用项目继承和聚合来管理多模块项目,本文将通过实例详细介绍如何使用Maven的项目继承和聚合。
maven 使用 pom .xml来管理项目,包括项目的名称、版本、依赖、打包路径等等项目信息。
什么是POM,它是英文名称 project Object Model,项目对象模型。把项目当作对象来管理,类似面向对象编程语言中的对象,可以建立继承关系,或者说父子关系,方便进行复杂项目的管理。
pom的父子关系
注意,本文的例子都比较简单,不需要使用archetype创建,按照项目结构直接创建所需要的文件即可。
项目继承
项目继承的意思是子项目或者说子模块可以继承父项目的pom配置,主要作用是将各个子项目或者子模块的相同配置提取出来,比如共同的依赖、编码、编译选项等,避免重复冗余的pom配置项。每个模块的pom.xml只需要配置本模块特有的配置项。
我们通过maven-inheritance项目来加以说明,
项目结构
maven-inheritance/ | |
├── module1 | |
│ ├── pom.xml | |
│ └── src | |
│ └── main | |
│ └── java | |
│ └── com | |
│ └── my | |
│ └── demo | |
│ └── Module1.java | |
├── module2 | |
│ ├── pom.xml | |
│ └── src | |
│ └── main | |
│ └── java | |
│ └── com | |
│ └── my | |
│ └── demo | |
│ └── Module2.java | |
└── pom.xml | |
14 directories, 5 files |
pom.xml
<project> | |
<!-- 设置pom的版本,这是必须的 --> | |
<modelVersion>4.0.0</modelVersion> | |
<groupId>com.my.demo</groupId> | |
<artifactId>demo-parent</artifactId> | |
<version>1.0</version> | |
<!-- packaging 默认值是jar,这里父级pom不需要打包,只是用来配置子模块共同的配置项,所以packaging设置为pom --> | |
<packaging>pom</packaging> | |
<!-- 子模块共同的属性 --> | |
<properties> | |
<maven.compiler.source>1.8</maven.compiler.source> | |
<maven.compiler.target>1.8</maven.compiler.target> | |
</properties> | |
<!-- 子模块共同的插件,maven-jar-plugin将模块打包成jar --> | |
< build > | |
<plugins> | |
<plugin> | |
<groupId>org.apache.maven.plugins</groupId> | |
<artifactId>maven-jar-plugin</artifactId> | |
<version>3.2.0</version> | |
</plugin> | |
</plugins> | |
</build> | |
</project> |
module1pom.xml
<project> | |
<modelVersion>4.0.0</modelVersion> | |
<!-- 指定父项目,如果父项目的pom.xml不在项目根目录,你需要使用relativePath指定 --> | |
<parent> | |
<groupId>com.my.demo</groupId> | |
<artifactId>demo-parent</artifactId> | |
<version>1.0</version> | |
<!-- <relativePath>../pom.xml</relativePath> --> | |
</parent> | |
<groupId>com.my.demo</groupId> | |
<artifactId>demo-module1</artifactId> | |
<version>1.0</version> | |
<build> | |
<plugins> | |
<plugin> | |
<artifactId>maven-jar-plugin</artifactId> | |
< configuration > | |
<archive> | |
<manifest> | |
<mainClass>com.my.demo.Module1</mainClass> | |
</manifest> | |
</archive> | |
</configuration> | |
</plugin> | |
</plugins> | |
</build> | |
</project> |
module1srcmainjavacommydemoModule1.java
package com.my.demo; | |
public class Module1 { | |
public static void main(String[] args) { | |
System.out.println("hello, module1"); | |
} | |
} |
module2pom.xml
<project> | |
<modelVersion>4.0.0</modelVersion> | |
<!-- 指定父项目,如果父项目的pom.xml不在项目根目录,你需要使用relativePath指定 --> | |
<parent> | |
<groupId>com.my.demo</groupId> | |
<artifactId>demo-parent</artifactId> | |
<version>1.0</version> | |
<!-- 默认父pom路径 --> | |
<!-- <relativePath>../pom.xml</relativePath> --> | |
</parent> | |
<groupId>com.my.demo</groupId> | |
<artifactId>demo-module2</artifactId> | |
<version>1.0</version> | |
<build> | |
<plugins> | |
<plugin> | |
<artifactId>maven-jar-plugin</artifactId> | |
<configuration> | |
<archive> | |
<manifest> | |
<mainClass>com.my.demo.Module2</mainClass> | |
</manifest> | |
</archive> | |
</configuration> | |
</plugin> | |
</plugins> | |
</build> | |
</project> |
module2srcmainjavacommydemoModule2.java
package com.my.demo; | |
public class Module2 { | |
public static void main(String[] args) { | |
System.out.println("hello, module2"); | |
} | |
} |
上面是整个maven-inheritance项目的源文件,module1和module2也比较简单。这里需要注意的就是根目录的pom.xml,里面配置了子模块共同的配置项和依赖插件,子模块的pom.xml通过<parent>标签指定了父级项目。
当需要执行编译、打包操作的时候,需要进入每个模块的根目录,执行mvn package即可,像下面这样。
PS D:demosmaven-demosmaven-inheritance> cd .module1 | |
PS D:demosmaven-demosmaven-inheritancemodule1> mvn clean package | |
PS D:demosmaven-demosmaven-inheritancemodule1> java -jar .targetdemo-module1-1.0.jar | |
hello, module1 | |
PS D:demosmaven-demosmaven-inheritancemodule1> cd ../module2 | |
PS D:demosmaven-demosmaven-inheritancemodule2> mvn clean package | |
PS D:demosmaven-demosmaven-inheritancemodule2> java -jar .targetdemo-module2-1.0.jar | |
hello, module2 |
项目继承的作用就是抽取各个项目共同的依赖和配置项,简化每个模块的配置,编译、打包需要进入每个模块分别操作。
能否所有模块统一编译和打包呢?
答案是肯定的,Maven项目聚合可以实现这个目标。
项目聚合
Maven项目聚合功能可以统一管理多个子项目或者多个子模块,统一编译、打包和发布等一系列操作。
我们通过maven-aggregation项目来加以说明,
项目结构
maven-aggregation | |
├── module1 | |
│ ├── pom.xml | |
│ └── src | |
│ └── main | |
│ └── java | |
│ └── com | |
│ └── my | |
│ └── demo | |
│ └── Module1.java | |
├── module2 | |
│ ├── pom.xml | |
│ └── src | |
│ └── main | |
│ └── java | |
│ └── com | |
│ └── my | |
│ └── demo | |
│ └── Module2.java | |
└── pom.xml | |
14 directories, 5 files |
maven-aggregation项目和maven-inheritance项目的目录结构完全一样,不同之处就在于3个pom.xml内容不同。
pom.xml
<project> | |
<modelVersion>4.0.0</modelVersion> | |
<groupId>com.my.demo</groupId> | |
<artifactId>demo-parent</artifactId> | |
<version>1.0</version> | |
<packaging>pom</packaging> | |
< modules > | |
<module>module1</module> | |
<module>module2</module> | |
</modules> | |
</project> |
module1pom.xml
<project> | |
<modelVersion>4.0.0</modelVersion> | |
<groupId>com.my.demo</groupId> | |
<artifactId>demo-module1</artifactId> | |
<version>1.0</version> | |
<properties> | |
<maven.compiler.source>1.8</maven.compiler.source> | |
<maven.compiler.target>1.8</maven.compiler.target> | |
</properties> | |
<build> | |
<plugins> | |
<plugin> | |
<artifactId>maven-jar-plugin</artifactId> | |
<version>3.2.0</version> | |
<configuration> | |
<archive> | |
<manifest> | |
<mainClass>com.my.demo.Module1</mainClass> | |
</manifest> | |
</archive> | |
</configuration> | |
</plugin> | |
</plugins> | |
</build> | |
</project> |
module2pom.xml
<project> | |
<modelVersion>4.0.0</modelVersion> | |
<groupId>com.my.demo</groupId> | |
<artifactId>demo-module2</artifactId> | |
<version>1.0</version> | |
<properties> | |
<maven.compiler.source>1.8</maven.compiler.source> | |
<maven.compiler.target>1.8</maven.compiler.target> | |
</properties> | |
<build> | |
<plugins> | |
<plugin> | |
<artifactId>maven-jar-plugin</artifactId> | |
<version>3.2.0</version> | |
<configuration> | |
<archive> | |
<manifest> | |
<mainClass>com.my.demo.Module2</mainClass> | |
</manifest> | |
</archive> | |
</configuration> | |
</plugin> | |
</plugins> | |
</build> | |
</project> |
module1和module2的Java文件内容完全一样,这里就不重复写了。这里注意一下3个pom.xml的内容,父级pom.xml通过<modules>标签来指定项目包括哪些模块,通过<module>标签指定具体的每一个模块,注意<module>标签内是子模块的目录名,而非子模块的名称。
通过下面的命令执行统一打包操作,
PS D:demosmaven-demosmaven-aggregation> mvn clean package | |
PS D:demosmaven-demosmaven-aggregation> java -jar .module1targetdemo-module1-1.0.jar | |
hello, module1 | |
PS D:demosmaven-demosmaven-aggregation> java -jar .module2targetdemo-module2-1.0.jar | |
hello, module2 |
注意这里,我执行了一次编译打包命令,module1和module2同时打包好了,可以直接运行。
混合使用
就像开头的Dubbo项目,同时使用了Maven项目继承和聚合,这样既能统一管理各个子项目的配置,也能统一各个子项目的编译打包发布流程。
你可以结合maven-inheritance和maven-aggregation项目的配置,修改对应的pom.xml,同时使用Maven项目继承和项目聚合特性。
总结
- 通过上面的文章,你可以学会Maven项目继承和项目聚合进行Java项目管理;
- 像Java的Object类以及Python的object类,是所有类的父类,pom也有Super POM,如果pom.xml没有指定parent,就是继承Super POM,感兴趣的自行了解;
- 除此之外你还可以通过文章学习到如何设置打包的main class,如何设置打包的编译选项,包括jdk版本。
声明,以上代码经过测试!