基于多模块的maven项目

目前Java的开发基本都已经依赖于maven对项目进行构建和依赖管理。虽然gradle也逐渐被更多的人开始使用,但就目前来说maven的使用率还是比较高的。 并且,随着微服务的流行在maven的多模块的需求也逐渐增加,也同样能够提升maven工程的代码复用。所以,这里对于maven的多模块项目做一个配置相关的介绍。

多模块的简单介绍

maven作为一个用于管理项目依赖及构建的工具被广泛应用于java的工程中,同时被诸如Eclipse,IntelliJ IDEA等集成开发环境所支持。 采用maven的优势在于能够不依赖于开发环境对工程进行构建,并能对第三方依赖做统一的管理。而对于maven的多模块工程而言,能够提升工程代码的复用, 以及在微服务这类应用场景中,对各个微服务独立于maven仓库的支持作自定义包的使用。

这种应用场景下,maven工程由一个位于顶层目录的parent工程构成,各个子模块分别再其下进行生成。多模块项目中的模块也能够是一个多模块的项目。 在构建时,应该位于parent工程所在的目录执行maven命令。

根工程的pom.xml文件

<?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>xyz.bezalel.nebula</groupId>
    <artifactId>parnet</artifactId>
    <packaging>pom</packaging>
    <version>1.0.0</version>
    <modules>
        <module>nebula-app</module>
        <module>common</module>
    </modules>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
    </dependencies>
</project>

以上的配置文件定义了一个多模块的maven项目,注意作为根的pom.xml文件中,packaging标签所使用的是pom,而不是传统的jar或者war等。 同时,在配置文件中定义了其有两个子模块nebula-appcommon。而在根工程中所定义的对lombok的依赖,将被其子工程所继承。

子模块的pom.xml文件

在之parent的pom.xml文件所在的目录下,新建nebula-app与common目录作为其子工程所在的文件夹。

common模块的pom.xml文件

以下为common工程目录内的pom.xml配置文件,由于其继承于xyz.bezalel.nebula,因此其groupId可以省略。

<?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>parnet</artifactId>
        <groupId>xyz.bezalel.nebula</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>common</artifactId>
</project>

nebula-app模块的pom.xml文件

以下为nebula工程目录内的pom.xml配置文件,根据定义其依赖于另一个common模块,此处需要按照标准的第三方包的方式定义其依赖模块。

<?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>parnet</artifactId>
        <groupId>xyz.bezalel.nebula</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>nebula-app</artifactId>
    <dependencies>
      <dependency>
        <groupId>xyz.bezalel.nebula</groupId>
        <artifactId>common</artifactId>
        <version>1.0.0</version>
      </dependency>
    </dependencies>
</project>

多模块的maven项目编译与打包

对于编译与打包,需要在parent的pom.xml文件所在的目录下,执行maven命令。

mvn clean compile package

针对spring boot的多模块项目

由于maven的项目结构是一个树的结构,因此maven项目不能有多个parent。因此,spring boot的根工程pom.xml需要设置其parent为 spring-boot-starter-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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.5.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
    <groupId>xyz.bezalel.nebula</groupId>
    <artifactId>parnet</artifactId>
    <packaging>pom</packaging>
    <version>1.0.0</version>
    <modules>
        <module>nebula-app</module>
        <module>common</module>
    </modules>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
    </dependencies>

</project>

而对于其子模块中,如果不需要打包的模块,则不需要添加对应的spring-boot-maven-plugin,只有需要将其打包成jar执行的包才需要。 例如本示例中的nebula-app需要打包成可执行的jar文件,则其配置文件如下。

<?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>parnet</artifactId>
        <groupId>xyz.bezalel.nebula</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>nebula-app</artifactId>
    <dependencies>
      <dependency>
        <groupId>xyz.bezalel.nebula</groupId>
        <artifactId>common</artifactId>
        <version>1.0.0</version>
      </dependency>
    </dependencies>
    <build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

总结及说明

对于maven来说xml的编写的确很繁琐且冗余,xml格式的情况着实有些尴尬。相比于诸如bson等二进制数据,它的可读性的确提高了, 但相应的体积也解析复杂度也提高,而与toml或者json等数据格式比较,xml的可读性又显得累赘,而且解析速度也是toml这些更高。 所以,xml着实位于一个高不成低不就的位置。

对于spring boot的多模块项目,原本使用 spring-boot:run 可以执行,但现在由于其依赖问题将不能执行了。虽然有其他资料声称,对parent 工程执行mvn install可以解决,但这样做是把你的工程安装到本地的仓库中,如此而行的结果是:你调试时执行的代码与你编写的代码可能不是一个。 意思就是,你调试时调用的是你位于本地仓库中之前install的工程,而你修改后的内容由于没有被install,所以可能不会被执行。 因此,对于spring boot的各个应用,在继承开发环境中需要以普通的Java应用来执行,而不能通过maven的spring-boot:run来执行。