打包部署优化之构建 Spring Boot 瘦包 Thin JAR

1,780 阅读3分钟

Spring Boot 项目常规打 JAR 包时,是将应用本身及所有依赖打到同一个 *.jar 文件中。在部署时,只要将这个文件拷贝到生产环境,就可以使用 java -jar *.jar 这样的简单命令运行应用,非常方便。

这个 jar 文件包含了所有依赖,因此体积较大,常在 50MB 以上,在有些传输受限的部署环境中(比如政务外网),上传大文件会比较耗时。

通过一些技巧,将应用自身的编译结果单独打包,形成体积较小的 jar 文件,与较大的依赖包分开传输、增量更新部署,是解决上述问题的一个思路。 这种打包方式被形象的称之为 “瘦包” -Thin JAR,相对的常规打包方式称为 “肥包” - Fat JAR

Spring Boot 官方开发了一个子项目来帮助解决这个问题:spring-boot-thin-launcher

这个项目尚处于试验阶段,当前已发布了 v1.0.28.RELEASE 版本。

用一个 gradle 示例简单展示一下。

利用 Spring 官网在线工具 start.spring.io/ 创建一个 demo 工程,添加 "Spring Web" 作为依赖。

thin-jar-initializr.png

build.gradle 中添加插件 org.springframework.boot.experimental.thin-launcher

plugins {
	id 'org.springframework.boot' version '2.7.3'
	id 'io.spring.dependency-management' version '1.0.13.RELEASE'
	id 'java'

	id 'org.springframework.boot.experimental.thin-launcher' version '1.0.28.RELEASE'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
}

这个插件会给工程的 Gradle 构建添加了几个 thin* 开头的任务,并将默认 build 任务打 Fat JAR 的行为调整为打 Thin JAR

此时运行命令 gradlew build 就会在工程 build/libs/ 目录中输出瘦包。

这个瘦包不是简单的对应用编译成果的组装,插件对瘦包中的启动类做了调整,加入了在启动时准备所需依赖包的逻辑,使用起来会很方便。

执行

java -jar demo-0.0.1-SNAPSHOT.jar

插件加入的启动类会自行下载所需的依赖包,存放到 Maven 默认本地仓库目录 ~/.m2/repository/ 中,并以这个目录为基础配置好 CLASSPATH,以便正常运行 demo-0.0.1-SNAPSHOT.jar 应用。

第一次启动需要下载依赖包,需耐心等待依赖包下载完成,后续启动就很快了。如果第一次下载包中途因为网络或其它原因异常中断了,需要清理 ~/.m2/repository/ 目录后重新执行。

如果能在部署环境中正常访问 Maven 包仓库(包括互联网仓库或私有仓库),这种方法很方便就能让瘦包在部署环境中跑起来,而且后续应用升级也只需要更新瘦包就可以。

如果不能访问 Maven 包仓库,还可以利用插件提供的 thinResolve 任务来将依赖包预先准备好。

在 IDE 中执行任务

gradlew thinResolve

或使用命令行,

cp build/libs/demo-0.0.1-SNAPSHOT.jar build/thin/root/
cd build/thin/root
java -jar demo-0.0.1-SNAPSHOT.jar --thin.root=.

耐心等待一段时间,会在工程 build/thin/root/ 目录下生成瘦包并下载依赖包。

将此目录传输到生产环境,同样通过指定参数 thin.root=. 告诉插件的启动类在哪里找依赖包,就能把应用跑起来。

java -jar demo-0.0.1-SNAPSHOT.jar --thin.root=.

为了加速依赖包下载,可以在 Maven ~/.m2/settings.xml 中加入阿里云镜像。(但实测依然不是很快)

上面 demo 已在 Gradle 7.3.1/7.5 版本,以及 Spring Boot 2.6.6/2.7.3 中实测通过。

推荐阅读: