背景

针对旧项目的改造。

test-service
test-integration
test-util

依赖关系如下:

+-----------------+
|  test-service   |
+--------+--------+
         |
         v
+-----------------+
| test-integration|
+--------+--------+
         |
         v
+-----------------+
|   test-util     |
+-----------------+

test-serivce 有一个 facade 接口,期望迁移到 bat 系统中。

那么要如何实现呢?

思路1-复制

这是最常见的一种方式,直接复制对应的代码到 bat 系统中。

好处:对原系统的影响最小,也最简单灵活

缺点:如果后续逻辑调整,需要修改2个地方。

思路2-打包为公共 jar

可以把依赖的部分打包为 jar,然后新的项目中使用。

优点:只需要改一个地方,保障功能的一致性。

缺点:对于打包和项目的维护管理提出一定的要求。且存在各种依赖等,比较复杂。

最后方案

最后选择了一个项目折中的方案。

service 如果全部打包依赖的太多,且只关注其中的一个接口,这部分采用复制+修改的方式。

integration 层相对比较稳定,且代码比较复杂,所以期望直接把 integration 打包为公共 jar。

多模块依赖的难题

难题

不同于简单的 facade,facade 的依赖一般非常少。

直接和当前项目断开依赖,作为一个独立的模块,指定打包就行。

integration 层涉及到大量的包依赖,全部复制过来特别多、且需要梳理。

所以希望像在原来的项目中一样,打包的时候可以直接获取到对应的依赖包版本。

snapshot 问题

一般的项目都是 1.0-SNAPSHOT,跟着主 pom.xml 版本走。

但是提供的 jar 必须是稳定的,就像我们日常的 facade 一样,不然会导致后续更新产线的包不稳定的问题。

传递依赖问题

不同于单个的 facade 模块,实际上我们依赖的这种包都需要处理。

上传到 nexus 中去。

+-----------------+
| test-integration|
+--------+--------+
         |
         v
+-----------------+
|   test-util     |
+-----------------+

解决方案

目录结构

为了演示 maven 多模块,我们尽可能的简化。

│   pom.xml
├───test-integration
│   │   pom.xml
├───test-service
│   │   pom.xml
└───test-util
    │   pom.xml

主 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>org.example</groupId>
    <artifactId>maven-multi-model-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <modules>
        <module>test-service</module>
        <module>test-integration</module>
        <module>test-util</module>
    </modules>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.example</groupId>
                <artifactId>test-service</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
            <dependency>
                <groupId>org.example</groupId>
                <artifactId>test-integration</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
            <dependency>
                <groupId>org.example</groupId>
                <artifactId>test-util</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

test-util pom

<?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.example</groupId>
        <artifactId>maven-multi-model-demo</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>test-util</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

</project>

test-integration pom

<?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.example</groupId>
        <artifactId>maven-multi-model-demo</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>test-integration</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>test-util</artifactId>
        </dependency>
    </dependencies>

</project>

test-service pom

<?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.example</groupId>
        <artifactId>maven-multi-model-demo</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>test-service</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>test-integration</artifactId>
        </dependency>
    </dependencies>

</project>

snapshot 问题

我们首先来解决 snapshot 的问题

主 pom

指定对应的 snapshot 版本

<properties>
        <test-integration.version>20250926-SNAPSHOT</test-integration.version>
        <test-util.version>20250926-SNAPSHOT</test-util.version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>test-integration</artifactId>
            <version>${test-integration.version}</version>
        </dependency>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>test-util</artifactId>
            <version>${test-util.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

在 test-integration 和 test-util 中指定版本

<version>20250926-SNAPSHOT</version>

测试

mvn clean install

如下:

[INFO] maven-multi-model-demo 1.0-SNAPSHOT ................ SUCCESS [  0.284 s]
[INFO] test-util 20250926-SNAPSHOT ........................ SUCCESS [  5.696 s]
[INFO] test-integration 20250926-SNAPSHOT ................. SUCCESS [  0.136 s]
[INFO] test-service 1.0-SNAPSHOT .......................... SUCCESS [  0.146 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

可以看到对应的2个模块,已经是我们的指定版本了。

nexus 上传问题

因为整个项目特别大,我们不可能把全部丢上去,比如在根目录中

mvn clean deploy

就会把整个项目都上传到 nexus 中,但是我们并不想这样。

指定方式

好在 maven 是支持指定打包的范围的。

我们可以在主 pom.xml 中添加如下的内容:

    <profiles>
        <profile>
            <id>default</id>
            <modules>
                <module>test-service</module>
                <module>test-integration</module>
                <module>test-util</module>
            </modules>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
        </profile>
        <profile>
            <id>moduleConfig</id>
            <modules>
                <module>test-integration</module>
                <module>test-util</module>
            </modules>
            <activation>
                <activeByDefault>false</activeByDefault>
            </activation>
        </profile>
    </profiles>

意思是,默认还是和以前一样,前模块。

不过我们可以通过下面的命令,触发指定的模块本地打包,上传 deploy 也是同理。

mvn clean install -P moduleConfig

测试

[INFO] maven-multi-model-demo 1.0-SNAPSHOT ................ SUCCESS [  0.314 s]
[INFO] test-util 20250926-SNAPSHOT ........................ SUCCESS [  1.072 s]
[INFO] test-integration 20250926-SNAPSHOT ................. SUCCESS [  0.160 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

可以看到这个除了主 pom 信息,只有我们指定的模块。

小结

感觉这种拆分方式,其实还是比较麻烦的。

还是要结合实际的应用场景,选择适合自己项目的方式。