SpringBoot-Maven打包压缩瘦身
SpringBoot-Maven打包压缩瘦身
相关内容原文地址:
腾讯云:江南一点雨:Spring Boot2 系列教程(四十)Spring Boot 可执行 jar 分析
脚本之家:田心双木:详解SpringBoot迭代发布JAR瘦身配置
CSDN:希尔伯特:SpringBoot瘦身打包部署
简书:思_路:Springboot 打包瘦身
张扎瓦的博客:springboot将项目与依赖分开打包
柒’s Blog:SpringBoot 2.0 开发案例之百倍级减肥瘦身之旅
周钦雄:Spring cloud的Maven插件(一):repackage目标
一、Spring Boot 可执行 jar 分析
Spring Boot 中默认打包成的 jar 叫做 可执行 jar,这种 jar 不同于普通的 jar,普通的 jar 不可以通过 java -jar xxx.jar 命令执行,普通的 jar 主要是被其他应用依赖,Spring Boot 打成的 jar 可以执行,但是不可以被其他的应用所依赖,即使强制依赖,也无法获取里边的类。但是可执行 jar 并不是 Spring Boot 独有的,Java 工程本身就可以打包成可执行 jar 。
Spring Boot 项目中一个默认的插件配置 spring-boot-maven-plugin ,这个打包插件存在 5 个方面的功能,从插件命令就可以看出:
五个功能分别是:
- build-info:生成项目的构建信息文件 build-info.properties
- repackage:这个是默认 goal,在 mvn package 执行之后,这个命令再次打包生成可执行的 jar,同时将 mvn package 生成的 jar 重命名为 *.origin
- run:这个可以用来运行 Spring Boot 应用
- start:这个在 mvn integration-test 阶段,进行 Spring Boot 应用生命周期的管理
- stop:这个在 mvn integration-test 阶段,进行 Spring Boot 应用生命周期的管理
这里功能,默认情况下使用就是 repackage 功能,其他功能要使用,则需要开发者显式配置。
1.1 打包
repackage 功能的 作用,就是在打包的时候,多做一点额外的事情:
- 首先 mvn package 命令 对项目进行打包,打成一个 jar,这个 jar 就是一个普通的 jar,可以被其他项目依赖,但是不可以被执行。
- repackage 命令,对第一步 打包成的 jar 进行再次打包,将之打成一个 可执行 jar ,通过将第一步打成的 jar 重命名为 *.original 文件
举个例子:
对任意一个 Spring Boot 项目进行打包,可以执行 mvn package 命令,也可以直接在 IDEA 中点击 package ,如下 :
打包成功之后, target 中的文件如下:
这里有两个文件,第一个 restful-0.0.1-SNAPSHOT.jar 表示打包成的可执行 jar ,第二个 restful-0.0.1-SNAPSHOT.jar.original 则是在打包过程中 ,被重命名的 jar,这是一个不可执行 jar,但是可以被其他项目依赖的 jar。
1.2 两种 jar 的比较
可执行 jar 解压之后,目录如下:
可执行 jar 中,我们自己的代码是存在 于 BOOT-INF/classes/ 目录下,另外,还有一个 META-INF 的目录,该目录下有一个 MANIFEST.MF 文件,打开该文件,内容如下:
Manifest-Version: 1.0
Implementation-Title: restful
Implementation-Version: 0.0.1-SNAPSHOT
Start-Class: org.javaboy.restful.RestfulApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Build-Jdk-Spec: 1.8
Spring-Boot-Version: 2.1.6.RELEASE
Created-By: Maven Archiver 3.4.0
Main-Class: org.springframework.boot.loader.JarLauncher
可以看到,这里定义了一个 Start-Class,这就是可执行 jar 的入口类,Spring-Boot-Classes 表示我们自己代码编译后的位置,Spring-Boot-Lib 则表示项目依赖的 jar 的位置。
换句话说,如果自己要打一个可执行 jar 包的话,除了添加相关依赖之外,还需要配置 META-INF/MANIFEST.MF 文件。
这是可执行 jar 的结构,那么不可执行 jar 的结构呢?
首先将默认的后缀 .original 除去,然后给文件重命名,重命名完成,进行解压:
解压后可以看到,不可执行 jar 根目录就相当于我们的 classpath,解压之后,直接就能看到我们的代码,它也有 META-INF/MANIFEST.MF 文件,但是文件中没有定义启动类等。
Manifest-Version: 1.0
Implementation-Title: restful
Implementation-Version: 0.0.1-SNAPSHOT
Build-Jdk-Spec: 1.8
Created-By: Maven Archiver 3.4.0
注意
不可以执行 jar 也没有将项目的依赖打包进来。
从这里我们就可以看出,两个 jar ,虽然都是 jar 包,但是内部结构是完全不同的,因此一个可以直接执行,另一个则可以被其他项目依赖。
1.3 一次打包两个 jar
一般来说,Spring Boot 直接打包成可执行 jar 就可以了,不建议将 Spring Boot 作为普通的 jar 被其他的项目所依赖。如果有这种需求,建议将被依赖的部分,单独抽出来做一个普通的 Maven 项目,然后在 Spring Boot 中引用这个 Maven 项目。
如果非要将 Spring Boot 打包成一个普通 jar 被其他项目依赖,技术上来说,也是可以的,给 spring-boot-maven-plugin 插件添加如下配置:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
</plugins>
</build>
配置的 classifier 表示可执行 jar 的名字,配置了这个之后,在插件执行 repackage 命令时,就不会给 mvn package 所打成的 jar 重命名了,所以,打包后的 jar 如下:
第一个 jar 表示可以被其他项目依赖的 jar ,第二个 jar 则表示一个可执行 jar。
二、SpringBoot迭代发布JAR瘦身配置
默认情况下,插件 spring-boot-maven-plugin 会把整个项目打包成一个可运行的Jar包(即所谓的Flat Jar),导致了这个Jar包很大(通常有几十M+)。
把第三方的JAR与项目代码分离,第三方的JAR把移除到lib文件夹中,即可实现为我们的可执行JAR瘦身,配置如下:
<plugins>
<!-- spring boot thin jar configuration -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- main 入口 -->
<mainClass>com.bdfint.logistics.app.driver.LogisticsAppDriverApplication</mainClass>
<!-- 设置为ZIP,此模式下spring-boot-maven-plugin会将Manifest.MF文件中的Main-Class设置为org.springframework.boot.loader.PropertiesLauncher -->
<layout>ZIP</layout>
<!-- 需要包含的jar包 -->
<includes>
<!-- 不包含任何jar包 -->
<!--<include>-->
<!--<groupId>nothing</groupId>-->
<!--<artifactId>nothing</artifactId>-->
<!--</include>-->
<include>
<groupId>com.bdfint.logistics</groupId>
<artifactId>logistics-api</artifactId>
</include>
<include>
<groupId>com.bdfint.logistics</groupId>
<artifactId>logistics-common</artifactId>
</include>
</includes>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- third-party jar into lib directory -->
<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>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<!-- 需要排除的jar的 groupId -->
<excludeGroupIds>
com.bdfint.logistics
</excludeGroupIds>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
接下来,执行打包命令:mvn clean package -Dmaven.test.skip=true,打包后在target目录下就包含我们的JAR和lib目录,如下图:

CMD定位到target目录下,执行命令:java -Dloader.path=./lib -jar logistics-app-driver-2.9.1.1.jar,即可把项目JAR跑起来!
三、引入内部编译的依赖
如果想引入内部编译的依赖包可以通过includes属性进行添加,利用引用了内部的dubbo可以通过如下配置:

配置完成后,再次执行编译:mvn clean package。
如果引入内部包过多,也可以通过excludeGroupIds属性去掉不变的依赖包。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layout>ZIP</layout>
<!--去除在生产环境中不变的依赖-->
<excludeGroupIds>
org.springframework.boot,
org.springframework,
org.springframework.data,
org.apache.tomcat.embed
</excludeGroupIds>
</configuration>
</plugin>
</plugins>
</build>
注:layout 必须是 ZIP 、 excludeGroupIds 中时忽略也是就需要打在外部的 jar。
3.1 剔除不需要的依赖
3.1.1 方式一:排除一个具体的maven 模块,通过唯一的groupId和artifactId组合来实现。(如果有必要,可以加入classifier来唯一确认。)
1 <project>
2 ...
3 <build>
4 ...
5 <plugins>
6 ...
7 <plugin>
8 <groupId>org.springframework.boot</groupId>
9 <artifactId>spring-boot-maven-plugin</artifactId>
10 <version>1.5.6.RELEASE</version>
11 <configuration>
12 <excludes>
13 <exclude>
14 <groupId>com.foo</groupId>
15 <artifactId>bar</artifactId>
16 </exclude>
17 </excludes>
18 </configuration>
19 ...
20 </plugin>
21 ...
22 </plugins>
23 ...
24 </build>
25 ...
26 </project>
3.1.2 方式二:排除和“指定的artifactId”相符的所有maven模块
1 <project>
2 ...
3 <build>
4 ...
5 <plugins>
6 ...
7 <plugin>
8 <groupId>org.springframework.boot</groupId>
9 <artifactId>spring-boot-maven-plugin</artifactId>
10 <version>1.5.6.RELEASE</version>
11 <configuration>
12 <excludeArtifactIds>my-lib,another-lib</excludeArtifactIds>
13 </configuration>
14 ...
15 </plugin>
16 ...
17 </plugins>
18 ...
19 </build>
20 ...
21 </project>
3.1.3 方式三:排除属于“指定的groupId”的所有maven模块
1 <project>
2 ...
3 <build>
4 ...
5 <plugins>
6 ...
7 <plugin>
8 <groupId>org.springframework.boot</groupId>
9 <artifactId>spring-boot-maven-plugin</artifactId>
10 <version>1.5.6.RELEASE</version>
11 <configuration>
12 <excludeGroupIds>com.foo</excludeGroupIds>
13 </configuration>
14 ...
15 </plugin>
16 ...
17 </plugins>
18 ...
19 </build>
20 ...
21 </project>
四、Spring Boot Thin Launcher
使用插件以后,原来打包45M的jar包,现在体积只有 40K,瘦身效果非常明显,并且也不改变原有的打包方式和部署方法。打包以后的jar也是可执行的。
第一次执行时,会自动下载所有的依赖包,并且缓存到本地,默认的缓存路径是${user.home}/.m2/,你也可以使用如下命令在启动时修改依赖的路径
java -Dthin.root=. -jar app-0.0.1-SNAPSHOT.jar
在pom.xml添加以下插件代码,然后正常地打包即可:
<build>
<plugins>
<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.3.RELEASE</version>
</dependency>
</dependencies>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
</plugins>
</build>
五、 maven的assembly打包插件
assembly配置:
在项目中创建一个文件,放在src/main/assembly/assembly.xml中。
assembly中的具体配置:
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<!--
必须写,否则打包时会有 assembly ID must be present and non-empty 错误
这个名字最终会追加到打包的名字的末尾,如项目的名字为 speed-api-0.0.1-SNAPSHOT,
则最终生成的包名为 speed-api-0.0.1-SNAPSHOT-bin.zip
-->
<id>bin</id>
<!-- 打包后的文件格式,可以是zip,tar,tar.gz,tar.bz2,jar,war,dir -->
<formats>
<format>zip</format>
</formats>
<!-- 压缩包下是否生成和项目名相同的根目录 -->
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<!-- 不使用项目的artifact,第三方jar不要解压,打包进zip文件的lib目录 -->
<useProjectArtifact>false</useProjectArtifact>
<outputDirectory>lib</outputDirectory>
<unpack>false</unpack>
</dependencySet>
</dependencySets>
<fileSets>
<!-- 把项目相关的说明文件,打包进zip文件的根目录 -->
<fileSet>
<directory>${project.basedir}</directory>
<outputDirectory></outputDirectory>
<includes>
<include>README*</include>
<include>LICENSE*</include>
<include>NOTICE*</include>
</includes>
</fileSet>
<!-- 把项目的配置文件,打包进zip文件的config目录 -->
<fileSet>
<directory>${project.basedir}/src/main/resources</directory>
<outputDirectory>config</outputDirectory>
</fileSet>
<!-- 把项目的脚本文件,打包进zip文件的bin目录 -->
<fileSet>
<directory>${project.basedir}/src/main/bin</directory>
<outputDirectory>bin</outputDirectory>
</fileSet>
<!-- 把项目自己编译出来的jar文件,打包进zip文件的根目录 -->
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory></outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
</fileSets>
</assembly>
maven中的配置:
<build>
<plugins>
<!-- 指定启动类,将依赖打成外部jar包 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<!-- 生成的jar中,不要包含pom.xml和pom.properties这两个文件 -->
<addMavenDescriptor>false</addMavenDescriptor>
<manifest>
<!-- 是否要把第三方jar放到manifest的classpath中 -->
<addClasspath>true</addClasspath>
<!-- 外部依赖jar包的最终位置 -->
<classpathPrefix>lib/</classpathPrefix>
<!-- 项目启动类 -->
<mainClass>com.zbrx.speed.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<!-- 使用assembly打包 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<!-- assembly配置文件位置 -->
<descriptor>src/main/assembly/assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 打包发布时,跳过单元测试 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>
最终打包后的效果:
压缩包里的文件内容:
config配置文件:
六、SpringBoot剔除静态文件
静态文件排除到项目外面,pom.xml 继续引入:
<resources>
<resource>
<filtering>true</filtering>
<directory>src/main/resources</directory>
<excludes>
<exclude>static/**</exclude>
</excludes>
</resource>
</resources>
配置nginx,访问静态资源文件:
server {
listen 80;
server_name www.cloudbed.vip;
location / {
proxy_pass http://127.0.0.1:8080;
}
#静态文件交给nginx处理
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|ioc|rar|
zip|txt|flv|mid|doc|ppt|pdf|xls|mp3|wma)$
{
root /cloudbed/static;
expires 30d;
}
location ~ .*\.(js|css)?$
{
root /cloudbed/static;
expires 1h;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
6.1 打包时排除resources下的资源文件
1 <build>
2 ...
3 <resources>
4 <resource>
5 <directory>src/main/resources</directory>
6 <excludes>
7 <exclude>**/*.properties</exclude>
8 <exclude>**/*.xml</exclude>
9 <exclude>**/*.yml</exclude>
10 </excludes>
11 </resource>
12 </resources>
13 <plugins>
14 ...
15 <plugin>
16 <groupId>org.springframework.boot</groupId>
17 <artifactId>spring-boot-maven-plugin</artifactId>
18 <executions>
19 <execution>
20 <goals>
21 <goal>repackage</goal>
22 </goals>
23 </execution>
24 </executions>
25 </plugin>
26 ...
27 </plugins>
28 ...
29 </build>
SpringBoot-Maven打包压缩瘦身的更多相关文章
- 虚拟机硬盘vmdk压缩瘦身并挂载到VirtualBox
这个问题其实困扰了挺久的,一直没闲情去解决,网上搜索过很多压缩方法感觉都太麻烦太复杂,因最近在windows上搞docker就一并解决了. 压缩vmdk 首先下载DiskGenius,这工具很牛X,相 ...
- springboot maven打包插件
<build> <plugins> <!-- springboot maven打包--> <plugin> <groupId>org.spr ...
- SpringBoot Maven打包项目JAR/WAR
安装Maven 1. 登录 http://maven.apache.org/download.cgi 2. 下载 maven 压缩包 3. 解压apache-maven-3.6.0-bin.tar.g ...
- webpack分开打包和合并打包的瘦身
webpack.config.js 记录一下优化webpack的几个点: 1. devtool: false, //产品阶段不应该有devtool entry: { bundle : pa ...
- springboot 使用maven 打包 报 (请使用 -source 7 或更高版本以启用 diamond 运算符) 错误解决办法
在使用springboot maven 打包时 报如下错误 (请使用 -source 7 或更高版本以启用 diamond 运算符) pom.xml编译插件 配置如下: <plugin> ...
- Maven使用yuicompressor-maven-plugin打包压缩css、js文件
最近项目想使用在maven打包的时间压缩js,css文件,采用yuicompressor-maven-plugin插件进行压缩,但只是压缩减小大小,提高请求速度,并没有对js进行混淆.下面就写一下这个 ...
- springboot(六) Maven打包引入本地jar包
springboot Maven打包引入本地jar包 最近在做项目的时候,有一些jar包不存在maven的依赖库中,所以需要自己引入本地jar包来达到需求,那么我们该如何去将本地的jar包引入s ...
- spring-boot子模块打包去掉BOOT-INF文件夹
1.spring-boot maven打包,一般pom.xml文件里会加 <plugin> <groupId>org.springframework.boot</grou ...
- ******可用 SpringBoot 项目打包分开lib,配置和资源文件
spring-boot多模块打包后,无法找到其他模块中的类https://blog.csdn.net/Can96/article/details/96172172 关于SpringBoot项目打包没有 ...
随机推荐
- FPT: Feature Pyramid Transfomer
导言: 本文介绍了一个在空间和尺度上全活跃特征交互(fully active feature interaction across both space and scales)的特征金字塔transf ...
- 用漫画的形式展现——什么是web
Web主要经历了web1.0和web2.0的阶段.万维网的初期都是web1.0的时代:静态页面. 在不同的时代,流行的web安全问题也不太相同.在web1.0时代,web安全主要是 Web1.0:sq ...
- mysql锁类型
mysql锁类型 问题 都有哪些锁 锁与隔离级别的关系 sql语句中涉及都涉及哪些锁 事务中,锁何时释放 死锁检测机制 概要
- java:原子类的CAS
当一个处理器想要更新某个变量的值时,向总线发出LOCK#信号,此时其他处理器的对该变量的操作请求将被阻塞,发出锁定信号的处理器将独占共享内存,于是更新就是原子性的了. 1.compareAndSet- ...
- Redis核心原理-简单动态字符串SDS
SDS简介 Redis是C语言编写的,但没有使用c语言的字符串结构,而是自己实现了一套简单动态字符串 simple dynamic string 简称SDS,SDS兼容C语言的字符串类型,原理类似Ja ...
- PostgreSQL WAL日志详解
wal日志即write ahead log预写式日志,简称wal日志.wal日志可以说是PostgreSQL中十分重要的部分,相当于oracle中的redo日志. 当数据库中数据发生变更时:chang ...
- Spring Boot GraphQL 实战 03_分页、全局异常处理和异步加载
hello,大家好,我是小黑,又和大家见面啦~ 今天我们来继续学习 Spring Boot GraphQL 实战,我们使用的框架是 https://github.com/graphql-java-ki ...
- 【Java基础】基本语法-程序流程控制
基本语法-程序流程控制 程序流程控制 流程控制语句是用来控制程序中各语句执行顺序的语句,可以把语句组合成能完成一定功能的小逻辑模块. 其流程控制方式采用结构化程序设计中规定的三种基本流程结构,即: 顺 ...
- LeetCode739 每日温度
根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高的天数.如果之后都不会升高,请输入 0 来代替. 例如,给定一个列表 temperatures = [73, 74 ...
- selenium爬虫 | 爬取疫情实时动态
import csvimport selenium.webdriverfrom selenium.webdriver.chrome.options import Optionsclass spider ...