SpringBoot打包瘦身
起因:使用SpringBoot开发项目,引用了很多依赖,最终打包成可运行的jar文件时,往往有几十M,或者更大,上传服务器要浪费很长时间。
优化方式一
1. 依赖分离
SpringBoot可运行的jar文件很大是因为,jar文件里包含了很多依赖jar,所以才会生成几十M的文件。
解决办法是在maven配置中,使用插件:
<build> <finalName>${project.artifactId}</finalName> <plugins> <!-- 运行时,读取的lib目录,启动类路径 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <useUniqueVersions>false</useUniqueVersions> <addClasspath>true</addClasspath> <classpathPrefix>/data/server/system-demo/libs/</classpathPrefix> <mainClass>com.zh.system.SystemApplication</mainClass> </manifest> <manifestEntries> </manifestEntries> </archive> <!-- 打包时,排除配置文件,配置文件放到jar包同目录的config下 --> <excludes> <!-- 注意,文件路径是按照编译打包后结果目录 --> <exclude>application.yml</exclude> </excludes> </configuration> </plugin> <!-- 打包时,把jar拷贝到指定目录 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>copy</id> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>/data/server/system-demo/libs/</outputDirectory> </configuration> </execution> </executions> </plugin> <!-- 跳过单元测试 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <skipTests>true</skipTests> </configuration> </plugin> </plugins> </build>
maven-jar-plugin 插件的作用是jar运行时使用的配置,属性包括:classpathPrefix 指定外部jar的路径,mainClass 指定jar包的启动类
maven-dependency-plugin 插件的作用是打包时,指定依赖jar拷贝的目录。
/data/server/system-demo 是我准备的项目运行jar包的目录。
我这里使用的路径都是 /data/server/system-demo/libs/,如果你是在windows系统下编译打包项目,你可以到项目所在的workspace的磁盘根目录下查找,会发现也生成了这样的目录,项目相关的jar包都拷贝到这里了。在服务器上创建目录/data/server/system-demo/libs/,并且把项目需要的jar包都上传到此目录。
2. 配置文件管理
我的项目中的配置文件按服务器环境配置了几套,如下图:
在application.yml的代码,使用这条命令指定加载的子配置文件:spring.profiles.active: test
这样管理配置很方便,避免多个服务器环境之间的参数切换,带来混淆的问题。但如果你修改代码之后,每个环境都要发布一遍,就会需要修改spring.profiles.active的值后,重复打包的问题。
所以,按照SpringBoot的运行加载规则,如果在运行jar同一目录有 config 文件夹,会被提前加载的。我们只需要在服务器 /data/server/system-demo/ 下创建一个config文件夹。并只上传此环境的配置文件就好了。
3. 总结
当项目运行时,最终在system-demo目录下,会有2个文件夹,2个文件。
system-demo-1.0-SNAPSHOT.jar -------SpringBoot启动jar包
config ---------项目的配置文件
libs -----------项目的依赖jar
nohup.out ------nohup命令运行jar文件之后,生成的临时日志文件
优化方式二
1. 正常编译JAR包,解压出lib文件夹
POM文件如下:
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <mainClass>com.johnnian.App</mainClass> <layout>ZIP</layout> </configuration> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> <plugins> <build>
进入项目根目录,执行命令:mvn clean install
将编译后的Jar包解压,拷贝 BOOT-INF 目录下的lib文件夹 到目标路径;
2. 修改pom.xml配置,编译出不带 lib 文件夹的Jar包
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <mainClass>com.johnnian.App</mainClass> <layout>ZIP</layout> <includes> <include> <groupId>nothing</groupId> <artifactId>nothing</artifactId> </include> </includes> </configuration> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> <plugins> <build>
配置完成后,再次执行编译:mvn clean install
生成的 Jar 包体积明显变小,外部的 jar 包已经不会被引入了。
3. 运行编译后的Jar包
将 步骤1 解压出来的lib文件夹、步骤2编译的jar包放在同一个目录, 运行下面命令:
java -Dloader.path=/path/to/lib -jar /path/to/springboot-jsp-0.0.1-SNAPSHOT.jar
或者在maven中输入一下命令导出需要用到的jar包
mvn dependency:copy-dependencies -DoutputDirectory=F:\ideaWorkPlace\AnalysisEngine\lib -DincludeScope=runtime
备注:将/path/to/改成实际的路径。-Dloader.path=lib文件夹路径
最终目录文件结构是:
├── lib #lib文件夹
└── springboot-jsp-0.0.1-SNAPSHOT.jar
说明:
1、通常,一个工程项目架构确定后,引入的jar包基本上不会变,改变的大部分是业务逻辑;
2、后面如果需要变更业务逻辑,只需要轻量地编译工程,大大提高项目部署的效率。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通