Spring Boot jar瘦身方案

Spring Boot 固然好用, 十八般武艺集于一身, 但是带来的后果是 jar 包太大, 普通加个 web 模块写个 HelloWorldController 打包出来都要 30+M, 如果要修改一行代码或配置都要重新上传。国外 VPS 还好, 带宽弥补了小延迟的不足, 国内小水管简直不能忍, 当然 CI/CD 就另当别论

在使用 Spring Cloud 过程中, 把项目分成了几个微服务, 加了几个 Spring Cloud 组件和项目公用模块后, 打包出来的 jar 有 200+M, 这不利于快速迭代。好在 Maven 和 Gradle 都提供了一些方法

Maven 篇

虽然可以通过mvn dependency:copy-dependencies把依赖拷出来, 但是如果项目中有相互依赖, 会报错, 所以还是手动把 jar 包分解

Spring Boot 打包出来的 jar 包结构是

1
2
3
- BOOT-INF
- classes
- lib

把 lib 拷到某个位置, 其他微服务 jar 处理方式一样, jar 包提示重复就跳过

分解完后修改parentpom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layout>ZIP</layout>
<includes>
<include>
<groupId>qw</groupId>
<artifactId>er</artifactId>
</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>

groupIdartifactId构造一个不存在的, 然后再打包, 此时打出来的 jar 包结构是

1
2
- BOOT-INF
- classes

这里注意 layout 要改成 ZIP, jar 包配置为Main-Class: org.springframework.boot.loader.PropertiesLauncher

如果不改, 配置为Main-Class: org.springframework.boot.loader.JarLauncher, 会无法启动

Gradle 篇 (基于 Kotlin DSL, 非 Groovy)

1
2
3
4
5
6
7
8
tasks {
withType<BootJar> {
manifest {
attributes("Main-Class" to "org.springframework.boot.loader.PropertiesLauncher")
}
exclude("**/*.jar")
}
}

查看一下大小, 只有 100+K, 未分解之前是 200+M, 此时基本可以实现秒传

最后修改 jar 包启动方式

1
java -jar -Dloader.path=jar包分解出来的路径 jar包

或者直接写进配置文件loader.properties(yml 文件不行)再打包, 就不需要额外再指定环境变量

1
loader.path=jar包分解出来的路径

此时 jar 可以正常启动提供服务

如果是容器部署, 只需挂载 lib 进去即可