我们常见的 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版本。
声明,以上代码经过测试!