从零搭建开发脚手架 Spring Boot应用瘦身打包便于部署

开发 架构
Spring Boot 默认打的Jar,包含应用程序代码及其所有依赖项(内置tomcat jar就不小了),所以打包出来的jar文件很大,动不动就几十,上百M,称之为Fat jar。
本文转载自微信公众号「Java大厂面试官」,作者laker。转载本文请联系Java大厂面试官公众号。
  • 背景
  • 使用
  • 工作原理
  • 额外补充
    • 运行应用程序进行预热
    • 使用Maven在编译期打包依赖项
    • 生产环境

背景

Spring Boot 默认打的Jar,包含应用程序代码及其所有依赖项(内置tomcat jar就不小了),所以打包出来的jar文件很大,动不动就几十,上百M,称之为Fat jar。

在网速不给力的情况下,上传服务器非常耗时。然而,其中我们引用到的Tomcat、Spring以及其他第三方组件,它们大部分时间是不会修改的而且占用了很大的空间,每次打包打进去。其实,我们经常改动的内容都是我们自己编写的代码,其大小大概也就几十KB,每次升级我们只需替换这些文件即可。

Spring社区大概也考虑到了开发者有这样的需求,所以提供了spring-boot-thin-launcher这个插件用来将项目的依赖和配置从jar包中分离出去。

使用

官网地址:https://github.com/spring-projects-experimental/spring-boot-thin-launcher

在Spring Boot pom文件中新增插件如下:

  1. <project ...> 
  2.     <build> 
  3.         <plugins> 
  4.             <plugin> 
  5.                 <groupId>org.springframework.boot</groupId> 
  6.                 <artifactId>spring-boot-maven-plugin</artifactId> 
  7.                 <dependencies> 
  8.                     <dependency> 
  9.                         <groupId>org.springframework.boot.experimental</groupId> 
  10.                         <artifactId>spring-boot-thin-layout</artifactId> 
  11.                         <version>1.0.27.RELEASE</version> 
  12.                     </dependency> 
  13.                 </dependencies> 
  14.             </plugin> 
  15.         </plugins> 
  16.     </build> 
  17. </project> 

 

 

 

 

 

 

然后还像以前一样执行mvn clean package,这时生成的jar包仅几十KB。

我这里因为项目有很多静态文件所以比较大有2MB。

执行java -jar xxx.jar即可直接运行程序。

除了jar文件减小了,其他效果看着与Fat jar是一样。

尝鲜之后,来看下其内部原理吧。

工作原理

我们来看下Jar包内部的构成。

  1. Manifest-Version: 1.0 
  2. Implementation-Title: map 
  3. Implementation-Version: 0.0.1-SNAPSHOT 
  4. Start-Class: com.laker.map.LakerMapApplication 
  5. Spring-Boot-Classes:  
  6. Build-Jdk-Spec: 1.8 
  7. Spring-Boot-Version: 2.3.7.RELEASE 
  8. Created-By: Maven Jar Plugin 3.2.0 
  9. Main-Class: org.springframework.boot.loader.wrapper.ThinJarWrapper 

即启动类实际为:ThinJarWrapper

ThinJarWrapper类

我们编写的代码

项目的Pom文件

当执行java -jar xxx.jar时,实际执行的是ThinJarWrapper,它会先在指定目录搜索看看依赖的jar包是否都存在,存在则直接使用,如果不存在,先从Maven中央仓库下载到本地,然后,再执行我们自己编写的main()入口方法。这种方式有点类似很多在线安装程序:用户下载后得到的是一个很小的exe安装程序,执行安装程序时,会首先在线下载所需的若干巨大的文件,再进行真正的安装。

这个spring-boot-thin-launcher在启动时搜索的默认目录是用户主目录的.m2,我们也可以指定下载目录,例如,将下载目录指定为当前目录:

  1. java -Dthin.root=. -jar xxx.jar 

执行后发现当前目录下自动生成了一个repository目录,这和Maven的默认下载目录~/.m2/repository的结构是完全一样的,只是它仅包含xxx.jar所需的运行期依赖项。

  1. repository/ 
  2.     com/ 
  3.     net/ 
  4.     org/ 
  5.     ... 

“注意:只有首次运行时会自动下载依赖项,再次运行时由于无需下载,所以启动速度会大大加快。如果删除了repository目录,再次运行时就会再次触发下载。

额外补充

运行应用程序进行预热

缓存依赖项的最简单方法是在目标环境中对应用程序进行预热运行。正如我们之前看到的,这将导致依赖项被下载并缓存在本地 Maven 存储库中。如果我们运行多个应用程序,存储库最终将包含所有依赖项而没有重复项。

由于运行应用程序可能会产生不必要的副作用,我们还可以执行“试运行”,只解析和下载依赖项,而无需运行任何用户代码:

  1. java -Dthin.dryrun=true -Dthin.root=. -jar xxx.jar 

使用Maven在编译期打包依赖项

添加以下依赖

  1. <plugin> 
  2.     <groupId>org.springframework.boot.experimental</groupId> 
  3.     <artifactId>spring-boot-thin-maven-plugin</artifactId> 
  4.     <version>${thin.version}</version> 
  5.     <executions> 
  6.         <execution> 
  7.         <!-- Download the dependencies at build time --> 
  8.         <id>resolve</id> 
  9.         <goals> 
  10.             <goal>resolve</goal> 
  11.         </goals> 
  12.         <inherited>false</inherited> 
  13.         </execution> 
  14.     </executions> 
  15. </plugin> 

 

 

 

构建项目后,目录为target/thin/root/。

生产环境

生产环境中,大部分都是内外网隔离的,建议先在本地“试运行”,然后把repository目录,瘦jar一起复制到服务器,设置thin.root指定目录,设置thin.offline切换到“离线”模式。所有依赖项都必须在本地可用.

  1. java -Dthin.root=. -Dthin.offline=true  -jar xxx.jar 

参考:

 

https://www.liaoxuefeng.com/wiki/1252599548343744/1304267002478625

 

责任编辑:武晓燕 来源: Java大厂面试官
相关推荐

2020-08-19 08:55:47

Redis缓存数据库

2021-09-01 10:07:43

开发零搭建Groovy

2021-03-09 17:11:09

数据库脚手架开发

2021-04-28 16:10:48

开发脚手架 Spring

2021-07-29 18:49:49

Spring开发脚手架

2021-03-11 14:16:47

Spring Boo开发脚手架

2021-05-13 17:02:38

MDC脚手架日志

2021-04-13 14:47:53

认证授权Java

2021-04-20 19:24:16

脚手架 Java微信

2021-06-02 17:58:49

脚手架 幂等性前端

2021-02-19 22:43:50

开发脚手架Controller

2020-06-29 11:35:02

Spring BootJava脚手架

2016-08-10 14:59:41

前端Javascript工具

2016-09-07 15:35:06

VueReact脚手架

2023-11-21 17:36:04

OpenFeignSentinel

2014-08-15 09:36:06

2021-01-07 05:34:07

脚手架JDK缓存

2018-06-11 14:39:57

前端脚手架工具node.js

2018-08-30 16:08:37

Node.js脚手架工具

2022-07-18 07:58:46

Spring工具工具类
点赞
收藏

51CTO技术栈公众号