You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多模块Spring Boot项目独立模块合并至Uber JAR并按需启动指定模块的技术咨询

多模块Spring Boot合并为单一可执行Jar并按需运行的解决方案

我来给你分享一个亲测可行的方案,完美解决你把多个独立Spring Boot模块合并成单一Fat Jar,还能通过参数指定运行对应模块的需求,分几个关键步骤来实现:

1. 模块D的Maven配置(核心用Shade插件)

要把A、B、C三个模块的所有类和资源都合并到D的Jar里,Maven Shade插件是最佳选择。你需要在模块D的pom.xml里配置如下:

<build>
    <plugins>
        <!-- 可选:Spring Boot插件,用来处理可执行Jar的结构 -->
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
                <execution>
                    <id>repackage</id>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                    <configuration>
                        <!-- 指定模块D的启动类作为统一入口 -->
                        <mainClass>com.example.d.DApplication</mainClass>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <!-- Shade插件:负责合并所有依赖模块的类和资源 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.4.1</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <createDependencyReducedPom>false</createDependencyReducedPom>
                        <transformers>
                            <!-- 保留Spring Boot可执行Jar的必要结构 -->
                            <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                            <transformer implementation="org.springframework.boot.maven.PropertiesMergingResourceTransformer">
                                <resource>META-INF/spring.factories</resource>
                            </transformer>
                            <transformer implementation="org.springframework.boot.maven.ShadeResourceTransformer">
                                <mainClass>com.example.d.DApplication</mainClass>
                            </transformer>
                            <!-- 合并Spring相关的配置文件,避免覆盖 -->
                            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                <resource>META-INF/spring.handlers</resource>
                            </transformer>
                            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                <resource>META-INF/spring.schemas</resource>
                            </transformer>
                        </transformers>
                        <!-- 确保模块D里的config目录下的配置文件全部被打包 -->
                        <resourceTransformers>
                            <resourceTransformer implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
                                <includes>
                                    <include>config/**</include>
                                </includes>
                            </resourceTransformer>
                        </resourceTransformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

⚠️ 注意:如果A、B、C模块自己的pom.xml里配置了Spring Boot插件的repackage目标,记得把它们改成<skip>true</skip>,因为我们只需要模块D生成可执行Jar,其他模块作为普通依赖Jar即可。

2. 调整模块D的启动类

模块D需要一个统一的启动入口,确保能扫描到所有模块的组件。假设A、B、C的包分别是com.example.a、com.example.b、com.example.c,模块D的包是com.example.d,启动类可以这么写:

package com.example.d;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
// 扫描所有模块的包路径,保证各个模块的Bean能被加载
@ComponentScan(basePackages = {"com.example.a", "com.example.b", "com.example.c", "com.example.d"})
public class DApplication {
    public static void main(String[] args) {
        SpringApplication.run(DApplication.class, args);
    }
}

3. 确认配置文件结构

确保模块D的src/main/resources目录下的结构和你规划的一致:

src/main/resources/
├── config/
│   ├── A/
│   │   └── application-A.properties
│   ├── B/
│   │   └── application-B.properties
│   └── C/
│       └── application-C.properties
└── application.properties(可选,放所有模块共享的公共配置)

打包后,这些文件会被放在Fat Jar的classpath:/config/目录下,完全符合你需要的路径。

4. 运行验证

执行mvn clean package后,模块D的target目录下会生成可执行Jar(比如D-shade-test.jar),然后就可以用你想要的命令运行对应模块:

  • 运行模块A:
java -jar D-shade-test.jar --spring.config.location=classpath:/config/A/application-A.properties
  • 运行模块B:
java -jar D-shade-test.jar --spring.config.location=classpath:/config/B/application-B.properties

如果你想更简洁,还可以结合Spring的Profile功能:把每个模块的配置文件直接放在src/main/resources下,命名为application-A.properties,运行时只需要指定--spring.profiles.active=A,Spring会自动加载对应的配置文件,不过这需要调整配置文件的路径,看你更习惯哪种方式。

5. 额外的灵活方案(适合模块独立性强的场景)

如果每个模块都有自己的@SpringBootApplication启动类,你甚至可以不用模块D的启动类,运行时直接指定对应模块的启动类即可:

# 运行模块A,指定A的启动类和配置文件
java -jar D-shade-test.jar -Dspring.main.class=com.example.a.AApplication --spring.config.location=classpath:/config/A/application-A.properties

这种方式不需要修改模块D的启动类,对原有模块的侵入性更小。

避坑提醒

  • 资源冲突:如果A、B、C模块有同名的资源文件(比如logback.xml),Shade插件默认会覆盖,这时候要通过AppendingTransformer或者IncludeResourceTransformer来处理,确保必要的资源被保留或合并。
  • 依赖版本冲突:如果三个模块依赖不同版本的第三方库,一定要在模块D的pom.xml里统一版本,避免Jar Hell问题。

内容的提问来源于stack exchange,提问作者Suresh Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 03:29:09