分模块打包实战

Maven 分模块打包实战

核心概念

在多模块项目中,不同模块的打包方式和目标不同:

  • 父模块:不打包,仅用于聚合
  • 公共模块:打包成普通 JAR,供其他模块依赖
  • 服务模块:打包成普通 JAR 或可执行 JAR
  • 启动模块:打包成可执行 JAR,包含所有依赖

打包类型对比

打包类型 packaging 产物 适用场景 大小
POM pom 无 JAR 父模块、聚合模块 -
普通 JAR jar 仅包含本模块代码 公共模块、被依赖模块 小(几十 KB - 几 MB)
可执行 JAR jar 包含所有依赖 启动模块、独立应用 大(几十 MB - 几百 MB)
WAR war Web 应用包 部署到 Tomcat 等容器 中等

父模块打包配置

基本配置

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- 父模块 pom.xml -->
<project>
<groupId>com.example</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging> <!-- 必须是 pom -->

<modules>
<module>my-common</module>
<module>my-service</module>
<module>my-app</module>
</modules>
</project>

特点

  • packaging 必须是 pom
  • 不会生成 JAR 文件
  • 执行 mvn package 时会构建所有子模块

公共模块打包配置

公共模块(如 common、domain、repository)被其他模块依赖,只需打包成普通 JAR。

基本配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!-- my-common/pom.xml -->
<project>
<parent>
<groupId>com.example</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0</version>
</parent>

<artifactId>my-common</artifactId>
<packaging>jar</packaging> <!-- 默认就是 jar,可省略 -->

<build>
<plugins>
<!-- Maven JAR 插件(默认已配置) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

打包产物

1
2
my-common/target/
└── my-common-1.0.0.jar # 只包含本模块编译的 class 文件

使用方式

1
2
3
4
5
6
7
8
# 打包并安装到本地仓库
mvn clean install

# 其他模块通过依赖引用
<dependency>
<groupId>com.example</groupId>
<artifactId>my-common</artifactId>
</dependency>

启动模块打包配置

启动模块需要打包成可执行 JAR,包含所有依赖,可独立运行。

方式一:Spring Boot Maven Plugin(推荐)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<!-- my-app/pom.xml -->
<project>
<parent>
<groupId>com.example</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0</version>
</parent>

<artifactId>my-app</artifactId>
<packaging>jar</packaging>

<dependencies>
<!-- 依赖其他模块 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>my-service</artifactId>
</dependency>

<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<!-- Spring Boot 打包插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<!-- 指定主类(可选,自动检测) -->
<mainClass>com.example.MyApplication</mainClass>
<!-- 排除某些依赖(可选) -->
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

关键配置

  • repackage goal:将依赖打包到 JAR 中
  • 自动配置 MANIFEST.MF 中的 Main-Class
  • 使用 Spring Boot 的类加载器

打包产物

1
2
3
my-app/target/
├── my-app-1.0.0.jar # 可执行 JAR(50-100 MB)
└── my-app-1.0.0.jar.original # 原始 JAR(只有本模块代码)

运行

1
java -jar target/my-app-1.0.0.jar

方式二:Maven Assembly Plugin(自定义打包)

适用于非 Spring Boot 项目或需要自定义打包结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<build>
<plugins>
<!-- Assembly 插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.example.Main</mainClass>
</manifest>
</archive>
<descriptorRefs>
<!-- 预定义的打包方式 -->
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

打包产物

1
target/my-app-1.0.0-jar-with-dependencies.jar

运行

1
java -jar target/my-app-1.0.0-jar-with-dependencies.jar

方式三:Maven Shade Plugin(合并依赖)

适用于需要解决依赖冲突或重命名包的场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<build>
<plugins>
<!-- Shade 插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<transformers>
<!-- 指定主类 -->
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.example.Main</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>
<!-- 排除签名文件 -->
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

特点

  • 可以重命名包(relocate)避免冲突
  • 可以合并 META-INF 下的配置文件
  • 生成的 JAR 替换原始 JAR

瘦 JAR + lib 目录方式

有些场景下不希望所有依赖打包到一个 JAR 中,可以采用瘦 JAR + lib 目录的方式。

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<build>
<plugins>
<!-- 复制依赖到 lib 目录 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<includeScope>runtime</includeScope>
</configuration>
</execution>
</executions>
</plugin>

<!-- JAR 插件配置 classpath -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.example.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>

打包产物

1
2
3
4
5
6
7
target/
├── my-app-1.0.0.jar # 瘦 JAR(只有本模块代码,几百 KB)
└── lib/ # 依赖目录
├── my-common-1.0.0.jar
├── my-service-1.0.0.jar
├── spring-boot-3.2.0.jar
└── ...

运行

1
2
3
4
5
# 方式 1:直接运行(MANIFEST.MF 已配置 classpath)
java -jar target/my-app-1.0.0.jar

# 方式 2:手动指定 classpath
java -cp "target/my-app-1.0.0.jar:target/lib/*" com.example.Main

优点

  • 更新单个模块时,只需替换对应的 JAR
  • 依赖可复用,多个应用共享
  • JAR 文件小,传输快

缺点

  • 部署时需要保持目录结构
  • 不如单 JAR 方便

常用打包命令

基本命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 清理 + 打包(跳过测试)
mvn clean package -DskipTests

# 清理 + 打包 + 安装到本地仓库
mvn clean install

# 只打包特定模块
mvn clean package -pl my-app

# 打包模块及其依赖
mvn clean package -pl my-app -am

# 打包多个模块
mvn clean package -pl my-common,my-service

# 跳过某个模块
mvn clean package -pl !my-test

# 并行构建(加速)
mvn clean package -T 4

多环境打包

使用 Maven Profile 实现多环境打包:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!-- 父 POM 中定义 profiles -->
<profiles>
<!-- 开发环境 -->
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<env>dev</env>
<spring.profiles.active>dev</spring.profiles.active>
</properties>
</profile>

<!-- 测试环境 -->
<profile>
<id>test</id>
<properties>
<env>test</env>
<spring.profiles.active>test</spring.profiles.active>
</properties>
</profile>

<!-- 生产环境 -->
<profile>
<id>prod</id>
<properties>
<env>prod</env>
<spring.profiles.active>prod</spring.profiles.active>
</properties>
</profile>
</profiles>

打包命令

1
2
3
4
5
6
7
8
9
10
11
# 开发环境(默认)
mvn clean package

# 测试环境
mvn clean package -Ptest

# 生产环境
mvn clean package -Pprod

# 同时激活多个 profile
mvn clean package -Ptest,docker

资源过滤

1
2
3
4
5
6
7
8
9
10
11
12
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>application.yml</include>
<include>application-${env}.yml</include>
</includes>
</resource>
</resources>
</build>

打包优化

1. 排除不必要的依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- 排除 provided scope 的依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope> <!-- 编译时需要,运行时不需要 -->
</dependency>

<!-- 排除传递依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>

2. 依赖分析

1
2
3
4
5
6
7
8
9
10
11
# 查看依赖树
mvn dependency:tree

# 分析依赖冲突
mvn dependency:tree -Dverbose

# 查看直接依赖
mvn dependency:list

# 分析未使用的依赖
mvn dependency:analyze

3. 压缩 JAR 包

1
2
3
4
5
6
7
8
9
10
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<compress>true</compress>
<index>true</index>
</archive>
</configuration>
</plugin>

4. 跳过不必要的步骤

1
2
3
4
5
6
7
8
# 跳过测试
mvn clean package -DskipTests

# 跳过测试编译和执行
mvn clean package -Dmaven.test.skip=true

# 跳过 Javadoc 生成
mvn clean package -Dmaven.javadoc.skip=true

Docker 镜像打包

方式一:Dockerfile + Maven 打包

1. Maven 打包可执行 JAR

1
mvn clean package -DskipTests

2. 编写 Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 多阶段构建(推荐)
FROM eclipse-temurin:17-jdk-alpine AS builder
WORKDIR /app

# 复制 Maven 配置和源码
COPY pom.xml .
COPY my-common ./my-common
COPY my-service ./my-service
COPY my-app ./my-app

# Maven 打包
RUN ./mvnw clean package -DskipTests

# 运行阶段
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app

# 复制构建产物
COPY --from=builder /app/my-app/target/my-app-1.0.0.jar app.jar

# 暴露端口
EXPOSE 8080

# 启动命令
ENTRYPOINT ["java", "-jar", "app.jar"]

简化版(本地已打包)

1
2
3
4
5
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY my-app/target/my-app-1.0.0.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

3. 构建镜像

1
2
3
4
5
# 构建镜像
docker build -t my-app:1.0.0 .

# 运行容器
docker run -d -p 8080:8080 my-app:1.0.0

方式二:Jib Maven Plugin(无需 Dockerfile)

Jib 是 Google 开源的 Maven/Gradle 插件,无需 Dockerfile 即可构建 Docker 镜像。

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<build>
<plugins>
<!-- Jib 插件 -->
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>3.4.0</version>
<configuration>
<!-- 基础镜像 -->
<from>
<image>eclipse-temurin:17-jre-alpine</image>
</from>
<!-- 目标镜像 -->
<to>
<image>my-app</image>
<tags>
<tag>1.0.0</tag>
<tag>latest</tag>
</tags>
</to>
<!-- 容器配置 -->
<container>
<jvmFlags>
<jvmFlag>-Xms512m</jvmFlag>
<jvmFlag>-Xmx1024m</jvmFlag>
</jvmFlags>
<ports>
<port>8080</port>
</ports>
<mainClass>com.example.MyApplication</mainClass>
<creationTime>USE_CURRENT_TIMESTAMP</creationTime>
</container>
</configuration>
</plugin>
</plugins>
</build>

构建命令

1
2
3
4
5
6
7
8
# 构建到本地 Docker
mvn compile jib:dockerBuild

# 构建并推送到 Docker Hub
mvn compile jib:build

# 构建到 tar 文件
mvn compile jib:buildTar

优点

  • 无需安装 Docker
  • 无需编写 Dockerfile
  • 构建速度快(增量构建)
  • 自动优化镜像分层

方式三:Spring Boot Maven Plugin 构建镜像

Spring Boot 2.3+ 内置了镜像构建功能(使用 Cloud Native Buildpacks)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<name>my-app:${project.version}</name>
<env>
<BP_JVM_VERSION>17</BP_JVM_VERSION>
</env>
</image>
</configuration>
</plugin>
</plugins>
</build>

构建命令

1
2
3
4
5
# 构建镜像
mvn spring-boot:build-image

# 推送镜像
mvn spring-boot:build-image -Dspring-boot.build-image.publish=true

实战案例

场景 1:微服务项目打包

1
2
3
4
5
6
microservices-project/
├── pom.xml # 父 POM
├── common/ # 公共模块(普通 JAR)
├── user-service/ # 用户服务(可执行 JAR)
├── order-service/ # 订单服务(可执行 JAR)
└── gateway/ # 网关(可执行 JAR)

父 POM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<properties>
<spring-boot.version>3.2.0</spring-boot.version>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<pluginManagement>
<plugins>
<!-- 统一配置 Spring Boot 插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>

公共模块 POM(common)

1
2
<artifactId>common</artifactId>
<!-- 不需要任何打包插件,默认打包成普通 JAR -->

服务模块 POM(user-service)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<artifactId>user-service</artifactId>

<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>common</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<!-- 使用父 POM 中配置的 Spring Boot 插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

打包命令

1
2
3
4
5
6
7
8
# 打包所有服务
mvn clean package -DskipTests

# 只打包用户服务
mvn clean package -pl user-service -am -DskipTests

# 生产环境打包
mvn clean package -Pprod -DskipTests

产物

1
2
3
4
common/target/common-1.0.0.jar                     # 普通 JAR
user-service/target/user-service-1.0.0.jar # 可执行 JAR
order-service/target/order-service-1.0.0.jar # 可执行 JAR
gateway/target/gateway-1.0.0.jar # 可执行 JAR

场景 2:框架项目打包(供第三方使用)

1
2
3
4
5
6
rag-framework/
├── pom.xml # 父 POM
├── rag-core/ # 核心模块(普通 JAR)
├── rag-store-pgvector/ # 实现模块(普通 JAR)
├── rag-spring-boot-starter/ # Starter(普通 JAR)
└── rag-app/ # 示例应用(可执行 JAR)

核心模块和实现模块

1
2
3
4
5
6
7
<!-- rag-core/pom.xml -->
<artifactId>rag-core</artifactId>
<!-- 不需要特殊配置,打包成普通 JAR -->

<!-- rag-store-pgvector/pom.xml -->
<artifactId>rag-store-pgvector</artifactId>
<!-- 打包成普通 JAR,供用户按需引入 -->

发布到 Maven 仓库

1
2
3
4
5
6
7
8
# 构建并安装到本地
mvn clean install

# 部署到私有仓库(需配置 distributionManagement)
mvn clean deploy

# 发布到 Maven 中央仓库(需配置 GPG 签名等)
mvn clean deploy -P release

用户使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- 用户项目 pom.xml -->
<dependencies>
<!-- 引入核心 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>rag-core</artifactId>
<version>1.0.0</version>
</dependency>

<!-- 按需引入实现 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>rag-store-pgvector</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>

常见问题

Q1: Spring Boot 打包后 JAR 很大怎么办?

A: 几种优化方式:

  1. 排除不必要的依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <exclusions>
    <exclusion>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    </exclusion>
    </exclusions>
    </dependency>
  2. 使用瘦 JAR + lib 目录

    1
    2
    3
    4
    5
    6
    7
    <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
    <layout>ZIP</layout>
    </configuration>
    </plugin>
  3. 使用 Docker 分层构建

    • 依赖层单独缓存,不需要每次都打包

Q2: 多模块打包时出现 “Could not resolve dependencies” 错误?

A: 原因和解决方法:

  1. 模块未安装到本地仓库

    1
    2
    # 先 install 依赖的模块
    mvn clean install -pl common -am
  2. 版本不一致

    • 检查子模块版本是否与父 POM 一致
    • 使用 ${project.version} 引用
  3. 构建顺序错误

    • Maven 会自动计算依赖顺序
    • 使用 -am 参数构建依赖模块

Q3: 如何在打包时指定不同的配置文件?

A: 使用 Maven Profile + 资源过滤:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<profiles>
<profile>
<id>dev</id>
<properties>
<config.file>application-dev.yml</config.file>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<config.file>application-prod.yml</config.file>
</properties>
</profile>
</profiles>

<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>

打包:

1
mvn clean package -Pprod

Q4: 如何生成源码 JAR 和 Javadoc JAR?

A: 用于发布到 Maven 仓库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<build>
<plugins>
<!-- 源码 JAR -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>

<!-- Javadoc JAR -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

Q5: 打包时如何跳过某些模块?

A: 使用 -pl! 排除:

1
2
3
4
5
# 跳过测试模块
mvn clean package -pl !test-module

# 只打包指定模块
mvn clean package -pl user-service,order-service

打包最佳实践

1. 模块职责清晰

模块类型 打包方式 发布
公共模块 普通 JAR install 到本地仓库
服务模块 普通 JAR 或可执行 JAR 看是否独立运行
启动模块 可执行 JAR 部署

2. 统一管理插件版本

在父 POM 的 pluginManagement 中统一配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
</plugin>
</plugins>
</pluginManagement>

3. 使用 Profile 管理多环境

1
2
3
4
5
6
7
8
9
10
11
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>prod</id>
</profile>
</profiles>

4. 优化构建速度

1
2
3
4
5
6
7
8
# 并行构建
mvn clean package -T 4

# 跳过测试
mvn clean package -DskipTests

# 离线模式(使用本地缓存)
mvn clean package -o

5. 依赖管理

1
2
3
4
5
6
7
8
# 定期分析依赖
mvn dependency:analyze

# 检查版本冲突
mvn dependency:tree -Dverbose

# 清理未使用的依赖
mvn dependency:purge-local-repository

总结

打包方式 适用场景 命令 产物大小
普通 JAR 公共模块、被依赖模块 mvn package
可执行 JAR(Spring Boot) 启动模块、微服务 mvn package
瘦 JAR + lib 需要分离依赖的场景 mvn package 小 + lib 目录
Docker 镜像 容器化部署 mvn jib:dockerBuild 镜像

关键点

  • 父模块 packaging=pom,不打包
  • 公共模块打包成普通 JAR,install 到本地仓库
  • 启动模块使用 Spring Boot Maven Plugin 打包成可执行 JAR
  • 使用 Profile 管理多环境配置
  • 使用 -pl-am 精确控制打包范围

分模块打包实战
https://zmmmmy.github.io/2026/01/12/分模块打包实战/
作者
ZhiMy
发布于
2026年1月12日
许可协议