基于 springboot + maven 开发,这里整顿一波多模块(module)我的项目的开发治理。

1. 聚合与继承

多模块的我的项目构造,根本离不开聚合继承两种maven治理形式。二者不是相悖的,很多我的项目构造是二者组合在一起治理的。

1.1. 聚合

目标

能够一次构建多个模块的我的项目。

当一个我的项目中有多个须要构建的模块我的项目时,如果每个模块独自构建,太费工作量。最好能够基于某个模块一次构建配置的所有模块,这就是聚合。

利用形式

先确定一个专门用于打包的maven我的项目,针对该我的项目pom 文件做以下的非凡解决:

  • <packaging> 值为 pom。(后续会讲 packaging 值的区别)
  • 基于<modules> 申明须要打包的所有模块,来实现模块的聚合。

1.2. 继承

1、目标

缩小反复的配置。

继承比拟好了解,相似于java类的继承,子模块能够主动继承父模块的一些属性。在maven我的项目中,能够把多个子模块独特的配置放到父模块中,那么子模块就不须要反复保护配置了。

2、利用形式

先确定一个父模块我的项目,针对该我的项目pom 文件做以下的非凡解决:

  • <packaging> 值为 pom。(后续会讲 packaging 值的区别)
  • 子模块中须要申明:(1)<parent> 为父模块的信息;(2)<relativePath>为父模块 pom 的相对路径。当我的项目构建时,Maven会首先依据 <relativePath> 查看父POM,如果找不到,再从本地仓库查找。
3、配置中可继承的元素
  • groupId :项目组 ID ,我的项目坐标的外围元素;
  • version :我的项目版本,我的项目坐标的外围元素;
  • properties :自定义的 Maven 属性;
  • dependencies :我的项目的依赖配置;
  • dependencyManagement :醒目的依赖治理配置;
  • repositories :我的项目的仓库配置;
  • build :包含我的项目的源码目录配置、输入目录配置、插件配置、插件治理配置等;
  • reporting :包含我的项目的报告输入目录配置、报告插件配置等;
  • description :我的项目的形容信息;
  • organization :我的项目的组织信息;
  • inceptionYear :我的项目的开创年份;
  • url :我的项目的 url 地址
  • develoers :我的项目的开发者信息;
  • contributors :我的项目的贡献者信息;
  • distributionManagerment :我的项目的部署信息;
  • issueManagement :缺点跟踪零碎信息;
  • ciManagement :我的项目的继续继承信息;
  • scm :我的项目的版本控制信息;
  • mailingListserv :我的项目的邮件列表信息;
4、dependencies和dependencyManagement(plugins与pluginManagement)

(1)dependencies

如果父我的项目pom中定义的是独自的 dependencies,则代表援用对应的所有依赖项。其所有子项目的pom中,就算没有引入父我的项目中定义的依赖,也主动会继承父我的项目pom文件 dependencies 中的所有依赖项。

(2)dependencyManagement

父我的项目pom中只是申明依赖,并不实现引入,因而子项目须要显示的申明须要的依赖。当父我的项目中申明过一些依赖我的项目,但如果不在子项目中申明依赖,是不会从父我的项目中继承的。

另外,只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父我的项目中继承该项,并且version和scope都读取自父pom;
如果子项目中指定了版本号,那么会应用子项目中指定的version和scope版本。

个别举荐用 dependencyManagement,因为配置起来更灵便,子项目应该按需配置须要的依赖项,以及可自定义版本号。但 dependency 也有它的作用,看理论状况搭配了。

pluginspluginManagement 的关系就如同 dependenciesdependencyManagement,这里就不多说了。

代码不可被继承

要留神,后面讲的继承都是 pom 文件配置中的元素可被继承。但父模块中的代码是不能够被继承的。

如果你说,想和子模块依赖公共的配置一样,想将子模块公共调用的代码放到父模块中,这样子模块就能公共调用了。非放父模块也行,能够在子模块中引入 build-helper-maven-plugin 等插件,将父模块的代码门路手动增加到子模块,如上面配置插件:

    <properties>        <main.basedir>${project.basedir}/..</main.basedir>        <shared.srcdir>${project.basedir}/src</shared.srcdir>    </properties>    ... ...    <build>        <plugins>                <plugin>                    <groupId>org.codehaus.mojo</groupId>                    <artifactId>build-helper-maven-plugin</artifactId>                    <version>${build-helper-maven-plugin.version}</version>                    <inherited>true</inherited>                    <executions>                        <execution>                            <id>add-source</id>                            <phase>generate-sources</phase>                            <goals>                                <goal>add-source</goal>                            </goals>                            <configuration>                                <sources>                                    <source>${shared.srcdir}/main/java</source>                                </sources>                            </configuration>                        </execution>                        <execution>                            <id>add-test-source</id>                            <phase>generate-sources</phase>                            <goals>                                <goal>add-test-source</goal>                            </goals>                            <configuration>                                <sources>                                    <source>src/it/java</source>                                    <source>${shared.srcdir}/test/java</source>                                </sources>                            </configuration>                        </execution>                        <execution>                            <id>add-test-resource</id>                            <phase>generate-resources</phase>                            <goals>                                <goal>add-test-resource</goal>                            </goals>                            <configuration>                                <resources>                                    <resource>                                        <directory>src/it/resources</directory>                                    </resource>                                    <resource>                                        <directory>${shared.srcdir}/test/resources</directory>                                    </resource>                                </resources>                            </configuration>                        </execution>                    </executions>                </plugin>        </plugins>    </build>

这的做法比拟麻烦,还不如定义一个公共的模块,将须要多模块复用的代码都放入该模块中。而后在子模块的pom中援用公共模块的依赖即可。前面的例子中会有这种体现(demo-comm)。

1.3. 聚合与继承比拟

聚合是为了不便疾速构建我的项目,而继承是为了打消反复配置。

相同点:打包形式都是pom,除了pom文件之外没有其余理论的内容。

不同点:聚合是聚合模块通过module援用被聚合模块,而继承是子模块通过parent援用父模块。

理论我的项目中通常把聚合和继承联合起来一起应用。parent我的项目既是聚合模块,也是父模块。

2. 多模块示例

上面会举一个多模块我的项目的简略例子,便于理解外围的配置过程。

2.1. 代码构造

示例的maven我的项目就叫 demo-service。删掉了 src目录,父pom 中定义的 artifactId 为 demo-parent。上面简略列了三个子模块:

  • demo-api: 对外提供Http API的可启动模块。
  • demo-mqc: MQ生产端的可启动模块。
  • demo-comm:被其余子模块公共依赖的不可启动模块。

代码构造如下:

.├── HELP.md├── demo-api│   ├── HELP.md│   ├── demo-api.iml│   ├── mvnw│   ├── mvnw.cmd│   ├── pom.xml│   └── src│       └── main│           ├── java│           │   └── pers│           │       └── kerry│           │           └── demoapi│           │               ├── DemoApiApplication.java│           │               └── controller│           │                   └── DemoController.java│           └── resources│               └── application.properties├── demo-comm│   ├── HELP.md│   ├── demo-comm.iml│   ├── mvnw│   ├── mvnw.cmd│   ├── pom.xml│   └── src│       └── main│           ├── java│           │   └── pers│           │       └── kerry│           │           └── democomm│           │               ├── config│           │               │   └── DemoConfig.java│           │               ├── mapper│           │               │   └── DemoMapper.java│           │               └── service│           │                   └── DemoService.java│           └── resources│               ├── application.properties│               └── mapper│                   └── DemoMapper.xml├── demo-mqc│   ├── HELP.md│   ├── demo-mqc.iml│   ├── mvnw│   ├── mvnw.cmd│   ├── pom.xml│   └── src│       └── main│           ├── java│           │   └── pers│           │       └── kerry│           │           └── demomqc│           │               ├── DemoMqcApplication.java│           │               └── consumer│           │                   └── DemoConsumer.java│           └── resources│               └── application.properties├── demo-service.iml├── mvnw├── mvnw.cmd└── pom.xml

当然还能够基于业务再做模块细分,如:

  • 横向:(1)可减少 demo-socket 服务解决长连贯;(2)可减少 demo-job 服务解决如 xxl-job 之类的服务。
  • 纵向:(1)demo-api 如果有多个业务 api,能够在下面在提炼一层 api-apps 模块(demo-parent -> api-apps -> order-api、log-api);(2)公共模块的服务如果可细分,不心愿其余模块依赖全量的公共模块代码,也能够提炼一层 comm-apps(demo-parent -> comm-apps -> order-comm、log-comm)。

2.2. pom配置(demo-parent)

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 https://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.6.3</version>        <relativePath/> <!-- lookup parent from repository -->    </parent>    <groupId>pers.kerry</groupId>    <artifactId>demo-parent</artifactId>    <version>${revision}</version>    <name>demo-parent</name>    <description>demo-service</description>    <packaging>pom</packaging>    <properties>        <java.version>1.8</java.version>        <revision>0.0.1-SNAPSHOT</revision>        <main.basedir>${project.basedir}</main.basedir>        <spring-boot-starter.version>2.6.3</spring-boot-starter.version>        <lombok.version>1.18.24</lombok.version>        <rocketmq.version>2.2.0</rocketmq.version>        <flatten-maven-plugin.version>1.2.7</flatten-maven-plugin.version>        <maven-antrun-plugin.version>3.0.0</maven-antrun-plugin.version>    </properties>    <modules>        <module>demo-api</module>        <module>demo-mqc</module>        <module>demo-comm</module>    </modules>    <dependencyManagement>        <dependencies>            <dependency>                <groupId>pers.kerry</groupId>                <artifactId>demo-comm</artifactId>                <version>${project.version}</version>            </dependency>            <dependency>                <groupId>org.springframework.boot</groupId>                <artifactId>spring-boot-starter-web</artifactId>                <version>${spring-boot-starter.version}</version>            </dependency>            <dependency>                <groupId>org.projectlombok</groupId>                <artifactId>lombok</artifactId>                <version>${lombok.version}</version>            </dependency>            <dependency>                <groupId>org.apache.rocketmq</groupId>                <artifactId>rocketmq-spring-boot-starter</artifactId>                <version>${rocketmq.version}</version>            </dependency>        </dependencies>    </dependencyManagement>    <build>        <pluginManagement>            <plugins>                <plugin>                    <groupId>org.codehaus.mojo</groupId>                    <artifactId>flatten-maven-plugin</artifactId>                    <version>${flatten-maven-plugin.version}</version>                    <configuration>                        <updatePomFile>true</updatePomFile>                        <flattenMode>clean</flattenMode>                    </configuration>                    <executions>                        <execution>                            <id>flatten</id>                            <phase>process-resources</phase>                            <goals>                                <goal>flatten</goal>                            </goals>                        </execution>                        <execution>                            <id>flatten-clean</id>                            <phase>clean</phase>                            <goals>                                <goal>clean</goal>                            </goals>                        </execution>                    </executions>                </plugin>                <plugin>                    <groupId>org.apache.maven.plugins</groupId>                    <artifactId>maven-antrun-plugin</artifactId>                    <version>${maven-antrun-plugin.version}</version>                    <inherited>true</inherited>                    <executions>                        <execution>                            <phase>validate</phase>                            <goals>                                <goal>run</goal>                            </goals>                            <configuration>                                <target>                                    <mkdir dir="${main.basedir}/.git/hooks"/>                                </target>                            </configuration>                        </execution>                    </executions>                </plugin>            </plugins>        </pluginManagement>    </build></project>
2. pom配置剖析

在示例中,就是一个聚合与继承合二为一的构造,具体分析 pom 非凡元素如下:

  • packaging:无论是聚合还是继承,都要求父模块或聚合构建模块中该值为pom
  • properties:可定义变量,变量值能够是 ${project.basedir} 这类maven内置变量,也能够是依赖包版本这类常量。倡议在 properties 中对立保护所有 <version>,便于变量对立治理。
  • modules:作为聚合构造的我的项目,须要通过 modules 来申明须要构建的模块。例如,如果正文掉 <module>demo-api</module>,在 demo-parent 门路执行 mvn package 命令时,就不会打包 demo-api 的模块。
  • dependencyManagement:配置 dependencyManagement,意味着父模块只做申明,子模块能够按需援用所须要的依赖项。
  • dependency:demo-comm:demo-comm 作为公共依赖的模块,因为会有多个子模块会依赖。可间接在父模块中申明(基于dependencyManagement形式),定义好 version。这样须要用到中子模块间接申明即可,不必再定义版本号。
  • src:倡议删除,起因后面有说。
  • spring-boot-maven-plugin:倡议删除,该插件是构建 springboot 非凡 jar包的,该模块打包形式是pom,用不上。

2.3. pom配置(demo-comm)

1、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 https://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelVersion>4.0.0</modelVersion>    <parent>        <groupId>pers.kerry</groupId>        <artifactId>demo-parent</artifactId>        <version>${revision}</version>        <relativePath>../pom.xml</relativePath>    </parent>    <groupId>pers.kerry</groupId>    <artifactId>demo-comm</artifactId>    <name>demo-comm</name>    <description>demo-comm</description>    <packaging>jar</packaging>    <properties>        <main.basedir>${project.basedir}/..</main.basedir>    </properties>    <dependencies>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <dependency>            <groupId>org.projectlombok</groupId>            <artifactId>lombok</artifactId>        </dependency>    </dependencies>    </project>
2. pom配置剖析
  • packaging:尽管 demo-comm 中只是代码,并没有可启动的fat jar(内置tomcat 的 springboot程序)。但代码需供其余模块调用,仍然是须要配置为 jar类型。
  • properties:继承了父模块中的属性,可自定义本人个性的属性值。
  • dependency:因为只须要2个依赖项,所以只须要引入父模块中2个即可。如果版本没特殊要求,可不非凡申明,继承自父模块定义的version。
  • 启动类:因为无需启动,倡议删除无用的启动类。
  • spring-boot-maven-plugin:和启动项一样,因为无需启动,也无需应用 spring-boot-maven-plugin 将我的项目打包成 fat jar。这个插件是创立 springboot 我的项目时默认生成的插件,但这里必须删除掉,否则在我的项目构建时会报错。因为该插件在打包我的项目时,生成的jar(fat jar)包构造和一般jar构造不同,会导致其余模块依赖该模块代码时报错。

2.4. pom配置(demo-api、demo-mqc)

1、pom.xml(demo-api)
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelVersion>4.0.0</modelVersion>    <parent>        <groupId>pers.kerry</groupId>        <artifactId>demo-parent</artifactId>        <version>${revision}</version>        <relativePath>../pom.xml</relativePath>    </parent>    <groupId>pers.kerry</groupId>    <artifactId>demo-api</artifactId>    <name>demo-api</name>    <description>demo-api</description>    <packaging>jar</packaging>    <properties>        <main.basedir>${project.basedir}/..</main.basedir>    </properties>    <dependencies>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <dependency>            <groupId>org.projectlombok</groupId>            <artifactId>lombok</artifactId>        </dependency>        <dependency>            <groupId>pers.kerry</groupId>            <artifactId>demo-comm</artifactId>        </dependency>    </dependencies>        <build>        <plugins>            <plugin>                <groupId>org.springframework.boot</groupId>                <artifactId>spring-boot-maven-plugin</artifactId>            </plugin>            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-antrun-plugin</artifactId>                <version>${maven-antrun-plugin.version}</version>                <inherited>true</inherited>                <executions>                    <execution>                        <phase>package</phase>                        <goals>                            <goal>run</goal>                        </goals>                        <configuration>                            <target>                                <copy todir="${main.basedir}/target" overwrite="true">                                    <fileset dir="${project.build.directory}">                                        <include name="*.jar"/>                                    </fileset>                                </copy>                            </target>                        </configuration>                    </execution>                </executions>            </plugin>        </plugins>    </build></project>
2、pom.xml(demo-mqc)
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelVersion>4.0.0</modelVersion>    <parent>        <groupId>pers.kerry</groupId>        <artifactId>demo-parent</artifactId>        <version>${revision}</version>        <relativePath>../pom.xml</relativePath>    </parent>    <groupId>pers.kerry</groupId>    <artifactId>demo-mqc</artifactId>    <name>demo-mqc</name>    <description>demo-mqc</description>    <packaging>jar</packaging>    <properties>        <main.basedir>${project.basedir}/..</main.basedir>    </properties>    <dependencies>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <dependency>            <groupId>org.projectlombok</groupId>            <artifactId>lombok</artifactId>        </dependency>        <dependency>            <groupId>org.apache.rocketmq</groupId>            <artifactId>rocketmq-spring-boot-starter</artifactId>        </dependency>        <dependency>            <groupId>pers.kerry</groupId>            <artifactId>demo-comm</artifactId>        </dependency>    </dependencies>    <build>        <plugins>            <plugin>                <groupId>org.springframework.boot</groupId>                <artifactId>spring-boot-maven-plugin</artifactId>            </plugin>            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-antrun-plugin</artifactId>                <inherited>true</inherited>                <executions>                    <execution>                        <phase>package</phase>                        <goals>                            <goal>run</goal>                        </goals>                        <configuration>                            <target>                                <copy todir="${main.basedir}/target" overwrite="true">                                    <fileset dir="${project.build.directory}">                                        <include name="*.jar"/>                                    </fileset>                                </copy>                            </target>                        </configuration>                    </execution>                </executions>            </plugin>        </plugins>    </build></project>
3. pom配置剖析
  • packaging:两个模块都是可执行模块,须要打包成失常内置tomcat 的 springboot fat jar的。值为 jar
  • properties:继承了父模块中的属性,可自定义本人个性的属性值。
  • dependency:因为各自功能性,引入各自真正须要的依赖项。如果版本没特殊要求,可不非凡申明,继承自父模块定义的version。
  • 启动类:须要。
  • spring-boot-maven-plugin:须要。因为两个模块都是可执行模块,须要打包成失常内置tomcat 的 springboot fat jar的。

3. 工具帮忙

3.1. Maven内置变量

后面在 properties 的介绍中,有提到 maven内置变量,上面是一些总结:

  • ${basedir}:我的项目根目录
  • ${project.build.directory}:构建目录,缺省为target
  • ${project.build.outputDirectory}:构建过程输入目录,缺省为target/classes
  • ${project.build.finalName}:产出物名称,缺省为${project.artifactId}-${project.version}
  • ${project.packaging}:打包类型,缺省为jar
  • ${project.xxx}:以后pom文件的任意节点的内容

3.2. 插件:flatten-maven-plugin

3.3. 插件:maven-antrun-plugin