前言
Spring Boot 是一个非常流行的 Java 开发框架,它提供了自动配置、快速开发等诸多便利特性。在日常开发中,我们通常会使用 Maven 或 Gradle 来完成项目构建。本文将详细介绍如何利用 Maven 将 Spring Boot 项目打包成可执行 JAR,并将 JAR 文件与依赖库分离,方便在 Docker 容器中高效部署。
Maven 依赖插件
spring-boot-maven-plugin 和 maven-dependency-plugin 是本文的主角。
spring-boot-maven-plugin 负责将 Spring Boot 应用打包为可执行的 JAR 或 WAR 存档;而 maven-dependency-plugin 用于将项目的依赖项复制到指定位置。
首先,配置 spring-boot-maven-plugin,将应用打包为可执行的 ZIP 存档文件,并不包含任何内部依赖(通过 includes 设置为 nothing):
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
<layout>ZIP</layout>
<!--解决windows命令行窗口中文乱码-->
<jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
<!--这里是填写需要包含进去的jar,
必须项目中的某些模块,会经常变动,那么就应该将其坐标写进来
如果没有则nothing ,表示不打包依赖 -->
<includes>
<include>
<groupId>nothing</groupId>
<artifactId>nothing</artifactId>
</include>
</includes>
</configuration>
</plugin>
接着,使用 maven-dependency-plugin 将项目的所有依赖(除了 scope 为 provided 的)拷贝到 target/lib 目录:
<!--拷贝依赖到jar外面的lib目录-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<!--指定的依赖路径-->
<outputDirectory>
${project.build.directory}/lib
</outputDirectory>
<excludeScope>provided</excludeScope>
</configuration>
</execution>
</executions>
</plugin>
最后,通过 maven-jar-plugin 配置 JAR 的 MANIFEST.MF,明确应用程序的主类,并指定类路径前缀 lib/,使得运行时能够自动加载外部的依赖库。请将 mainClass 替换为你的实际启动类。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>top.teainn.project.MyApplication</mainClass>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
打包完成后,查看 JAR 包内 META-INF/MANIFEST.MF 文件,可以看到依赖的路径前都加上了 lib/ 前缀,例如:

Package 打包
在 IDEA 或命令行中执行 Maven 的 package 生命周期:

构建成功后,进入 target 目录,可以发现 JAR 包和依赖库已经完美分离:Esurvey-backend-1.1.1.jar 是精简后的可执行 JAR,而 lib 文件夹中则存放了该应用运行所需的所有第三方依赖。

Dockerfile 编写
接下来编写 Dockerfile,核心指令就是 COPY ${OUT_DIRECTORY}/lib /lib,它将宿主机 target/lib 下的依赖库复制到容器内的 /lib 目录,随后通过 ADD 指令将精简 JAR 添加进去,最后通过 ENTRYPOINT 指定启动命令。
# 设置jdk版本
FROM java:8
# 维护者信息
MAINTAINER daqi <daqi_email@163.com>
# 设置容器内时间及JVM时区
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo "Asia/Shanghai" > /etc/timezone
# 复制依赖 jar
COPY ${OUT_DIRECTORY}/lib /lib
# 将本地的jar包添加到容器,并重命名
ADD Esurvey-backend-1.1.1.jar springboot.jar
# 容器对外暴露的端口
EXPOSE 9996
# 启动命令,设置JVM参数及激活profile
ENTRYPOINT ["java","-Xms256m","-Xmx256m","-jar","/springboot.jar","--spring.profiles.active=prod","-c"]
其他
后续如果还需结合 docker-compose 进行容器编排,可参考这篇博文:
https://blog.csdn.net/weixin_62726289/article/details/134140311
以上便是将 Spring Boot 项目 JAR 与依赖库分离并构建 Docker 镜像的完整流程。通过这种方式,我们可以将体积较大部分动辄数十兆的第三方依赖做成独立的镜像层,充分利用 Docker 的层缓存特性,显著加快构建和推送速度,同时让应用本身的 JAR 更加轻量。