SpringBoot瘦身
1.介绍
本教程中,我们将研究如何使用spring-boot-thin-launcher项目来将Spring Boot项目瘦身。
Spring Boot出了名的把所有依赖打包成单个可执行的Fat JAR,同时也被广泛应用于微服务。有时候和Fat JAR不一致的是,反复包括相同的依赖会成为一种资源浪费。
2.先决条件
首先,我们当然需要一个Spring Boot项目。在本文中,我们将研究Maven构建和Gradle构建的最常见配置。
这里是不可能覆盖所有构建系统和相应的配置,但是希望我们能够有常用的构建系统配置以便参考。
2.1 Maven 项目
用Maven 构建一个Spring Boot 项目,我们首先要在pom.xml或者它的parent等任何一个祖先添加Spring Boot的Maven插件:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
在这里,我们指的是插件的版本2.3.0.RELEASE
,这是编写本文时的最新版本。Spring Boot所用的依赖版本通常是用BOM或者从父的POM继承的了:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/>
</parent>
2.2 Gradle 项目
用Gradle构建Spring Boot项目,我们会有相应的Gradle插件
buildscript {
ext {
springBootPlugin = 'org.springframework.boot:spring-boot-gradle-plugin'
springBootVersion = '2.3.0.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("${springBootPlugin}:${springBootVersion}")
}
}
// elided
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
springBoot {
mainClassName = 'DemoApplication'
}
请注意,本文只考虑Spring Boot 2.x或者更高的版本,Thin Launcher也支持旧的版本,但是可能有稍微不同的版本,具体请查看项目的主页。
3.怎么创建一个Thin Jar
Spring Boot Thin Launcher是一个比较小的类库,它从打包的文件中读取项目工程的依赖关系,然后从maven仓库下载这些依赖,最后启动应用程序。所以在第一次启动下载相应依赖的时候会消耗一定的时间。
所以,当我们用库构建一个项目时,我们会得到一个包含代码的JAR文件,一个包含依赖关系的文件,以及执行入口的主类。
当然,事情会比我们简单的解析微妙得多,本文下面会继续探讨。
4.基本用法
现在让我们看下如何构建一个thin jar的Spring Boot 项目。
我们将使用通常的java -jar 启动应用程序,并使用可选的附加命令行参数来控制 Thin Launcher。
我们将在以下部分中看到其中使用参数的几个例子; 该项目的主页包含完整参数列表。
4.1 Maven 项目
在Maven项目中,我们必须修改SpringBoot的插件,添加相应的依赖:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot.experimental</groupId>
<artifactId>spring-boot-thin-layout</artifactId>
<version>1.0.23.RELEASE</version>
</dependency>
</dependencies>
</plugin>
Thin Launcher将会从Maven存储在JAR下的META-INF/maven目录中生成的pom.xml文件读取依赖关系。
我们像往常一样执行构建就行,例如使用 mvn install
如果我们需要同时打包fat jar和thin jar,我们可以在maven的profile中定义springboot插件。
4.2 Maven依赖:thin.properties
除了pom.xml之外,我们也可以让maven生产thin.properties。在这种情况下,该文件会包含完整的依赖列表,包括可传递的依赖列表,但是相对pom.xml来说,thin Launcher对thin.properties更加友好。
默认情况下,插件在src/main/resources/META-INF中输出thin.properties,但是我们可以用thin.output属性来指定它的位置:
mvn org.springframework.boot.experimental:spring-boot-thin-maven-plugin:properties -Dthin.output=.
4.3 Gradle项目
不同的是,在Gradle项目中,我们需要添加了一个专用的插件:
buildscript {
ext {
//...
thinPlugin = 'org.springframework.boot.experimental:spring-boot-thin-gradle-plugin'
thinVersion = '1.0.23.RELEASE'
}
//...
dependencies {
//...
classpath("${thinPlugin}:${thinVersion}")
}
}
//elided
apply plugin: 'maven'
apply plugin: 'org.springframework.boot.experimental.thin-launcher'
为了获取thin jar, 我们需要执行 thinJar 任务:
./gradlew thinJar
4.4 Graldle依赖:pom.xml
在前一小节的代码示例中,除了Thin Launcher之外,我们还声明了Maven插件(我们已经事先看到Spring Boot的依赖管理插件)
这是因为和我们之前的Maven案例一样,打包后的文件包含了一个pom.xml来列举应用程序所需要的依赖关系。pom.xml文件是由thinPom任务生成。 我们可以用专门的一个任务来定制生成pom.xml, 在这里,我们复制下插件已经做的东西:
task createPom {
def basePath = 'build/resources/main/META-INF/maven'
doLast {
pom {
withXml(dependencyManagement.pomConfigurer)
}.writeTo("${basePath}/${project.group}/${project.name}/pom.xml")
}
}
为了使用我们的自定义pom.xml文件,我们将上述任务添加到jar任务的依赖项中:
bootJar.dependsOn = [createPom]
4.5 Gralde依赖:thin.properties
和前面的maven项目一样,我们也可以让Gradle生成thin.properties而不是pom.xml, 生成thin.properties文件的任务叫做thinProperties,默认情况下是不使用它的。我们也可以把它添加到任务的依赖中:
bootJar.dependsOn = [thinProperties]
5.保存依赖
thin jar的目的是为了避免依赖项和应用程序绑在一起,然后依赖是不会消失的,这些依赖只是存储在其他地方而已。
特别地,Thin Launcher是使用maven的基础架构来解决依赖的,所以:
- 会检查本地的Maven仓库,默认是指
~/.m2/repository
,当然也可以移到其他地方。 - 会从maven中央仓库中下载缺失的依赖
- 最后会缓存所下载的依赖到本地maven仓库中,下次启动的时候就不会再继续下载了。
当然,下载依赖阶段是比较缓慢而且容易出错的部分,主要是因为是通过网络访问maven中央仓库来下载依赖,总之这些是不可靠的。
幸运的是,有很多种方式将依赖和应用程序一起部署,例如可以预打包在容器中。
5.1 运行预热的程序
缓存依赖的最简单方法就是在目标环境中对程序进行预热运行。正如前面所说的,预热运行会把所依赖的文件缓存到本地的maven仓库中去。如果我们运行了多个应用程序,maven仓库中已经饱和了所依赖的库的话,就没有必要重复下载了。
由于运行应用程序可能会导致不必要的副作用,我们还可以执行“试运行”,它只解析和下载依赖项,而不运行任何用户代码:
java -Dthin.dryrun=true -jar my-app-1.0.jar
5.2 在构建的时候打包依赖
另外一个选择就是在构建的时候打包依赖,当然,这不是把依赖打包到JAR中,然后我们可以复制这些依赖到目标的环境中。
通常这会更加简单,因为没必要在目标环境中运行应用程序。但是,如果我们部署多个环境,就必须手动或用脚本合并他们的依赖关系。
在构建过程中,Maven和Gradle的Thin 插件打包的依赖格式与maven的本地仓库是一样的:
root/
repository/
com/
net/
org/
...
实际上,我们还可以在运行的时候使用 thin.root参数来指定依赖的目录:
$ java -jar my-app-1.0.jar --thin.root=my-app/deps
5.3 用maven打包依赖
为了能让maven帮我们打包依赖,我们需要添加 spring-boot-thin-maven
插件
<plugin>
<groupId>org.springframework.boot.experimental</groupId>
<artifactId>spring-boot-thin-maven-plugin</artifactId>
<version>${thin.version}</version>
<executions>
<execution>
<id>resolve</id>
<goals>
<goal>resolve</goal>
</goals>
<inherited>false</inherited>
</execution>
</executions>
</plugin>
构建项目后,我们将找到一个目录target/thin/root/
会出现上一节讨论的结构。
5.4 用Gradle打包依赖
如我们用_thin-launcher_插件,我们会有_thinResolve_任务可以用。这个任务会保存应用和它的依赖在_build/thin/root/_ 目录中,跟maven的一样:
gradlew thinResolve
6.总结和进一步阅读
在这篇文章中,我们学习了如何制作Spring Boot的thin jar,同时也看到了如何使用maven的架构来下载和存储应用的依赖关系。
在项目主页 也有一些其他的使用指导,好比如一些命令参数等。
微信关注我,发现更多java领域知识
SpringBoot瘦身的更多相关文章
- SpringBoot瘦身部署(15.9 MB - 92.3 KB)
1. 简介 SpringBoot项目部署虽然简单,但是经常因为修改了少量代码而需要重新打包上传服务器重新部署,而公网服务器的网速受限,可能整个项目的代码文件仅仅只有1-2MB甚至更少,但是需要上传 ...
- SpringBoot-Maven打包压缩瘦身
SpringBoot-Maven打包压缩瘦身 一.Spring Boot 可执行 jar 分析 1.1 打包 1.2 两种 jar 的比较 1.3 一次打包两个 jar 二.SpringBoot迭代发 ...
- SpringBoot Jar包瘦身 - 跟大文件说再见!
前言 SpringBoot部署起来配置非常少,如果服务器部署在公司内网,上传速度还行,但是如果部署在公网(阿里云等云服务器上),部署起来实在头疼.就是 编译出来的 Jar 包很大,如果工程引入了许多开 ...
- springboot 打包插件去除jar包瘦身
1.pom文件配置 <plugin> <groupId>org.springframework.boot</groupId> <artifactId>s ...
- springboot项目打包瘦身
默认情况下,Spring Boot 项目发布时会将项目代码和项目的所有依赖文件一起打成一个可执行的 jar 包.但如果项目的依赖包很多,那么这个文件就会非常大.这样每次即使只改动一点东西,就需要将整个 ...
- maven war包打包去除jar包瘦身
1.pom文件配置 <!-- war包 --> <plugin> <groupId>org.apache.maven.plugins</groupId> ...
- Spring Boot打包瘦身 Docker 使用全过程 动态配置、日志记录配置
springBoot打包的时候代码和jar包打包在同一个jar包里面,会导致jar包非常庞大,在不能连接内网的时候调试代码,每次只改动了java代码就需要把所有的jar包一起上传,导致传输文件浪费了很 ...
- Spring Boot 项目瘦身指南,瘦到不可思议!129M->1.3M
之前在 从使用传统Web框架到切换到Spring Boot后的总结 中提到关于 Spring Boot 编译打包,Spring Boot 应用程序不用额外部署到外部容器中,可以直接通过 Maven 命 ...
- Drawable实战解析:Android XML shape 标签使用详解(apk瘦身,减少内存好帮手)
Android XML shape 标签使用详解 一个android开发者肯定懂得使用 xml 定义一个 Drawable,比如定义一个 rect 或者 circle 作为一个 View 的背景. ...
随机推荐
- JAVA 之 EL表达式
一.什么是EL表达式 1.Expression Language表达式语言 2.是一种在JSP页面获取数据的简单方式(只能获取数据,不能设置数据) 语法格式:${expression } 二.EL中的 ...
- java1-3总结 19201421-吴志越
关于最近几次作业,从C语言到Java的过渡,也就是从面向过程到面向对象的过渡.其中,一共有三次作业,前俩次可能更加偏向于过程的设计,利用C语言的想法就可以完成,但是,从需要使用类的开始,就逐渐向对象偏 ...
- Mybatis自动生成插件对数据库类型为text的处理
2019独角兽企业重金招聘Python工程师标准>>> 如果数据库中的字段为text或者blob这种大文本类型,在使用MybatisGenerator工具自动生成代码的时候会将其进行 ...
- zabbix3.x.x升级教程
1:停掉正在运行的zabbix服务,确保没有新数据写入数据库. /etc/init.d/zabbix_server stop 2:备份原zabbix的数据库数据,以及相关文件. mysqldump - ...
- FluxInterval实例及解析
为什么80%的码农都做不了架构师?>>> 序 本文主要研究下FluxInterval的机制 FluxInterval reactor-core-3.1.3.RELEASE-sou ...
- VS Code 全部快捷键一览表(巨TM全)
常用 General 按 Press 功能 Function Ctrl + Shift + P,F1 显示命令面板 Show Command Palette Ctrl + P 快速打开 Quick O ...
- 无向图双连通分量BCC(全网最好理解)
不是标题党,之前我也写过一篇比较全的,但是对于初学者不友好.传送门? 双连通分量(Biconnected component): 1.边双联通 E-BCC 2.点双连通 V-BCC 双 ...
- select函数的使用
select函数是 I/O 复用中非常重要的一个函数,属于并发编程的.它能够监视我们需要监视的文件描述符的变化情况–读.写或者异常 1. 函数原型 #include <sys/select.h& ...
- windows远程执行命令总结
1. 利用Impacket Impacket是一个Python类库,用于对SMB1-3或IPv4 / IPv6 上的TCP.UDP.ICMP.IGMP,ARP,IPv4,IPv6,SMB,MSRPC, ...
- 学习bootstarp第一天
一.下载bootstarp(https://v3.bootcss.com/),解压并将文件放入自己项目里去使用即可 二.安装bootstarp <!DOCTYPE html> <h ...