之前在 从使用传统Web框架到切换到Spring Boot后的总结 中提到关于 Spring Boot 编译打包,Spring Boot 应用程序不用额外部署到外部容器中,可以直接通过 Maven 命令将项目编译成可执行的 jar 包,然后通过 java -jar 命令启动即可,非常方便。

最近有小伙伴私信我说,打 jar 包方便是方便,就是每次打包出来的 jar 太大了,先不说上传时间的问题,如果只修改了 1 个类就需要重新打包项目,然后重新上传项目到服务器,怎么觉得还不如我之前使用 war 包方便呢,使用 war 包时,虽然要部署到 Tomcat 中,但只需要将修改的 class 替换一下,重启一下 Tomcat 就可以了。。。

其实到底选择哪种打包方式,主要还是看个人习惯和业务场景需求,毕竟 Spring Boot 也支持打包 war 包的。

今天的重点不是打包方式,而是解决困惑了小伙伴打包的 jar 太大的问题。

正常打包项目

给 Spring Boot 打包大家应该很熟了吧,只需要在 pom.xml 文件中配置 spring-boot-maven-plugin 打包插件:

<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins>
</build>

然后在项目根目录执行 mvn clean pavkage 就可以完成打包了,如下是我本地的一个项目打包情况:

可以看到打包出的 jar 应用是相当的大了,如小伙伴说的一样,如果每次修改一个 class 文件或者配置文件,就需要重新打包然后上传服务器的话,那确实是太麻烦了,可能上传就浪费大部分时间。。。

应用瘦身(分离lib和配置文件)

其实 jar 包大的原因在于所有的依赖包全部集成在 jar 包里面,如下是瘦身前的 jar 包内部结构:

其中 classes 就是我们项目的代码,仅仅1.3M,而 129MB 的 lib 目录是项目中所有的依赖(比如spinrg、Hibernate等依赖),如果我们能把这个 lib 目录提取出来,整个项目就会变得特别小了。说干就干。

我们知道 Spring Boot 的打包终究是依赖于 Maven ,所以想到更改打包信息,无非就是指定 Maven 的配置。

在 pom.xml 添加如下信息(后文解释):

<build><finalName>你想要的jar包名称</finalName><plugins><!-- 1、编译出不带 lib 文件夹的Jar包 --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><!--表示编译版本配置有效--><fork>true</fork><!--引入第三方jar包时,不添加则引入的第三方jar不会被打入jar包中--><includeSystemScope>true</includeSystemScope><!--排除第三方jar文件--><includes><include><groupId>nothing</groupId><artifactId>nothing</artifactId></include></includes></configuration><executions><execution><goals><goal>repackage</goal></goals></execution></executions></plugin><!-- 2、完成对Java代码的编译,可以指定项目源码的jdk版本,编译后的jdk版本,以及编码 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><!-- 源代码使用的JDK版本 --> <source>${java.version}</source><!-- 需要生成的目标class文件的编译版本 --><target>${java.version}</target><!-- 字符集编码 --><encoding>UTF-8</encoding><!-- 用来传递编译器自身不包含但是却支持的参数选项 -->  <compilerArguments><verbose/><!-- windwos环境(二选一) --><bootclasspath>${java.home}/lib/rt.jar:${java.home}/lib/jce.jar</bootclasspath><!-- Linux环境(二选一) --><bootclasspath>${java.home}/lib/rt.jar:${java.home}/lib/jce.jar</bootclasspath></compilerArguments></configuration></plugin><!-- 3、将所有依赖的jar文件复制到target/lib目录 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-dependency-plugin</artifactId><executions><execution><id>copy-dependencies</id><phase>prepare-package</phase><goals><goal>copy-dependencies</goal></goals><configuration><!--复制到哪个路径,${project.build.directory} 缺醒为 target,其他内置参数见下面解释--><outputDirectory>${project.build.directory}/lib</outputDirectory><overWriteReleases>false</overWriteReleases><overWriteSnapshots>false</overWriteSnapshots><overWriteIfNewer>true</overWriteIfNewer></configuration></execution></executions></plugin><!-- 4、指定启动类,指定配置文件,将依赖打成外部jar包 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><configuration><archive><manifest><!-- 是否要把第三方jar加入到类构建路径 --><addClasspath>true</addClasspath><!-- 外部依赖jar包的最终位置 --><classpathPrefix>lib/</classpathPrefix><!-- 项目启动类 --><mainClass>com.javam4.MyApplication</mainClass></manifest></archive><!--资源文件不打进jar包中,做到配置跟项目分离的效果--><excludes><!-- 业务jar中过滤application.properties/yml文件,在jar包外控制 --><exclude>*.properties</exclude><exclude>*.xml</exclude><exclude>*.yml</exclude></excludes></configuration></plugin></plugins>
</build>

如下一一细拆如上配置:

1、spring-boot-maven-plugin

Springboot 默认使用 spring-boot-maven-plugin 来打包,这个插件会将项目所有的依赖打入项目 jar 包里面,正常打包时 spring-boot-maven-plugin 结构如下:

<plugin>  <groupId>org.springframework.boot</groupId>   <artifactId>spring-boot-maven-plugin</artifactId>  <configuration>  <mainClass>com.javam4.MyApplication</mainClass>  <layout>ZIP</layout>  </configuration>  <executions>  <execution>  <goals>  <goal>repackage</goal>  </goals>  </execution>  </executions>
</plugin>

如下是提取的修改项:

<configuration><!--表示编译版本配置有效--><fork>true</fork><!--引入第三方jar包时,不添加则引入的第三方jar不会被打入jar包中--><includeSystemScope>true</includeSystemScope><!--排除第三方jar文件--><includes><include><groupId>nothing</groupId><artifactId>nothing</artifactId></include></includes>
</configuration>

修改的作用:

  • includeSystemScope:jar包分两种,一种是spring、mybatis等这种项目依赖的,再就是我们外部手动引入的第三方 jar 依赖,如果该参数不设置为 true 的话是不能被打包进来的~
  • includes:这个节点就是排除项目中所有的 jar,那还怎么打包?

其实我们需要将打包插件替换为 maven-jar-plugin,然后使用该插件拷贝依赖到 jar 到外面的 lib 目录。

2、maven-xxx-plugin

从 2、3、4 你会发现用到了 maven-xxx-plugin 格式的三种插件,简单说一下这三者的作用:

  • maven-compiler-plugin:

    完成对Java代码的编译,可以指定项目源码的jdk版本、编译后的jdk版本,以及编码,如果不写这个插件也是没问题的,不写会使用默认的 jdk 版本来处理,只是这样容易出现版本不匹配的问题,比如本地maven环境用的3.3.9版本,默认会使用jdk1.5进行编译,而项目中用的jdk1.8的编译环境,那就会导致打包时编译不通过。

  • maven-dependency-plugin:

    作用就是将所有依赖的jar文件复制到指定目录下,其中涉及到的 ${project.xx} 见下文补充。

  • maven-jar-plugin:

    主要作用就是将maven工程打包成jar包。

主要说一下 maven-jar-plugin 插件的如下配置:

<configuration><!--资源文件不打进jar包中,做到配置跟项目分离的效果--><excludes><!-- 业务jar中过滤application.properties/yml文件,在jar包外控制 --><exclude>*.properties</exclude><exclude>*.xml</exclude><exclude>*.yml</exclude></excludes>
</configuration>

打包时排除资源配置文件,如果排除了配置文件那么项目启动是怎么读取呢?

配置文件有这么一个默认的优先级:

当前项目config目录下 > 当前项目根目录下 > 类路径config目录下 > 类路径根目录下

因此只需要将配置文件复制一份到与 jar 包平级目录下,或者与jar包平行config目录下,就能优先使用此配置文件,达到了伪分离目的。

最终的目录结构如下:

Maven 中的内置变量说明:

  • ${basedir} 项目根目录
  • ${project.build.directory} 构建目录,缺省为target
  • ${project.build.outputDirectory} 构建过程输出目录,缺省为target/classes
  • ${project.build.finalName} 产出物名称,缺省为{project.artifactId}-${project.version}
  • ${project.packaging} 打包类型,缺省为jar
  • ${project.packaging} 打包类型,缺省为jar
  • ${project.xxx} 当前pom文件的任意节点的内容

瘦身总结

Spring Boot 框架提供了一套自己的打包机制 — spring-boot-maven-plugin,Springboot 默认使用该插件来打包,打包时会将项目所有的依赖打入项目 jar 包里面,如果我们想要抽离依赖的 jar 仅仅使用该插件是不行的,就需要将打包插件替换为 maven-jar-plugin,并拷贝所有的依赖到 jar 外面的 lib 目录。

项目打包时,在分离依赖 jar 包基础上,我们又排除了配置文件,因为配置文件有一个默认的读取路径:

当前项目config目录下 > 当前项目根目录下 > 类路径config目录下 > 类路径根目录下

我们只需要在当前项目 jar 包同级目录创建一个 config 文件夹,然后将配置文件复制一份,这样就达到了伪分离目的。

之后再修改配置文件,比如端口号、数据库连接信息等,就不需要重新打包项目了,直接修改完配置文件重启项目就可以了。

而经过分离依赖后的 jar 包从原来的100多兆到现在的1兆,如果后面需要变更业务逻辑,只需要轻量的编译项目,快速的实现项目的上传替换,有效的减少了网络开销,提高项目部署的效率。

博客地址:https://niceyoo.cnblogs.com

更多原创内容可以移步我的公众号,回复「面试」获取我整理的2020面经。

Spring Boot 项目瘦身指南,瘦到不可思议!129M->1.3M相关推荐

  1. 使用Spring Boot Thin Launcher 打包Spring Boot项目,jar包瘦身

    原文地址:https://www.jianshu.com/p/3fa4039d90d7 -------------------------------------------------------- ...

  2. Spring Boot项目瘦身

    目录 1,什么是瘦身? 2,为什么要瘦身? 3,如何瘦身? 3.1,瘦身思路: 3.2,瘦身方法 4,瘦身后运行 1,什么是瘦身? 瘦身:thinBody,又称"减肥"." ...

  3. 我的Android进阶之旅------gt;Android APP终极瘦身指南

    首先声明,下面文字转载于: APK瘦身实践 http://www.jayfeng.com/2015/12/29/APK%E7%98%A6%E8%BA%AB%E5%AE%9E%E8%B7%B5/ APP ...

  4. Android Apk瘦身指南大全

    Android Apk瘦身指南大全 前言 为什么Android应用Apk要瘦身?虽然安装包大小对应用使用没有影响,但应用的安装包越大,用户下载的门槛越高,安装等待时间也会越长,特别是在移动网络情况下, ...

  5. win10防火墙删除的文件在哪里_Win10系统瘦身指南:删除C盘这些文件,让你的电脑秒变新机!...

    前言 目前市面上存在较多山寨的电脑店,为了大家的电脑安全,请一定前往电脑店官方地址进行下载,官方地址为 u.diannaodian.com 当你打开计算机,一道红光突然从你眼前闪过,这时你才恍惚想起: ...

  6. 后端开发实践:Spring Boot项目模板

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达今日推荐:2020年7月程序员工资统计,平均14357元,又跌了,扎心个人原创100W+访问量博客:点击前往,查看更多 作者 ...

  7. 后端开发实践:Spring Boot项目模板,拿去用吧!

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:干掉 Navicat:这个 IDEA 的兄弟真香!个人原创100W+访问量博客:点击前往,查看更多 作者:无知者 ...

  8. boot spring test 文档_Spring、Spring Boot 和 TestNG 测试指南 ( 3 )

    原标题:Spring.Spring Boot 和 TestNG 测试指南 ( 3 ) 来源:chanjarster, github.com/chanjarster/spring-test-exampl ...

  9. Spring Boot登录选项快速指南

    "我喜欢编写身份验证和授权代码." 〜从来没有Java开发人员. 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证. 在本文中 ...

  10. IDEA创建第一个Spring Boot项目

    Spring Boot官方参考指南 Spring Boot慨念请自行百度查找,这里就不多说了 一. 创建项目 File -> New -> Project 选择 Spring Initia ...

最新文章

  1. Mybatis Plus 是如何实现动态 SQL 语句的?原理你懂吗?
  2. oracle dba_seg,Oracle DBA 应知应会 -- PGA自动管理
  3. python 什么是上下文管理器(ContextManager)?
  4. 说说PendingIntent的内部机制
  5. response设置响应头
  6. 深圳软件开发向前跳转会略过一些节点
  7. win10系统windows hello无法设置 windows hello设置开启教程
  8. 使用grunt运行hintjs任务
  9. 装双系统?不需要!教你在iMac上流畅使用Windows!
  10. php api json查错,PHP使Laravel为JSON REST API返回自定义错误的问题
  11. 视屏教程、电子书、技术文档
  12. android:scaleType属性 centerCrop,fitXY,fitCenter
  13. python整形_Python中的最大整型数值
  14. cogs908. 校园网
  15. 计算机用word做贺卡,利用word制作贺卡
  16. java健身房管理系统业务_基于SSM的健身房管理系统
  17. Java性能优化从20s优化到500ms,我用了这三招,内容知识满满
  18. ZCMU 1919: kirito's 星爆气流斩【01背包的二进制优化】
  19. TCP的状态 (SYN, FIN, ACK, PSH, RST, URG)
  20. Spring Boot 中使用 Hikari连接各类数据源

热门文章

  1. 前端学习(2902):javascript浏览器的历史
  2. [vue] 使用vue渲染大量数据时应该怎么优化?说下你的思路!
  3. [css] 使用css实现蒙版的效果
  4. [vue-cli]vue-cli默认是单页面的,那要弄成多页面该怎么办呢
  5. 前端学习(2053)vue之电商管理系统电商系统之使用pm2管理
  6. 前端学习(1799):前端调试之清除浮动
  7. 前端学习(1324):anysc关键字
  8. java学习(120):set的iterator
  9. matlab LSTM序列分类的官方示例
  10. 嵌入式开发中模拟SPI的驱动