别再让你的SpringBoot包"虚胖"了!这份瘦身攻略请收好

作者:互联网

2026-03-22

Java教程

大家好,我是小悟。

一、什么是缩小打包体积

缩小打包体积是指通过各种优化手段,减少Spring Boot应用最终部署包(通常是JAR文件)的大小。这在微服务架构和云原生部署场景中尤为重要,主要体现在以下几个方面:

1.1 核心概念

  • 原始问题:Spring Boot默认采用"胖JAR"打包方式,将所有依赖(Spring框架、业务代码、嵌入式服务器、第三方库)全部打成一个可执行JAR,体积通常在50MB-200MB之间
  • 优化目标:通过分离依赖、精简内容、分层构建等方式,将部署包体积缩小30%-80%

1.2 为什么重要

  • 部署效率:更小的包意味着更快的上传、下载和部署速度
  • 存储成本:减少镜像仓库和服务器存储空间占用
  • 启动速度:精简后的包加载类文件更快,减少启动时间
  • CI/CD效率:缩短构建和发布流水线时间
  • 网络传输:特别是在带宽有限的环境下,小体积包优势明显
  • 容器化部署:更小的镜像体积意味着更快的拉取和扩展速度

二、缩小打包体积的详细步骤

2.1 依赖优化

步骤1:分析和精简依赖


<project>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-dependency-pluginartifactId>
                <version>3.5.0version>
                <executions>
                    <execution>
                        <id>analyzeid>
                        <goals>
                            <goal>analyzegoal>
                        goals>
                    execution>
                executions>
            plugin>
        plugins>
    build>
project>

步骤2:排除不必要的依赖


<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-webartifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-tomcatartifactId>
        exclusion>
    exclusions>
dependency>


<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-undertowartifactId>
dependency>

2.2 使用Spring Boot分层JAR

步骤3:配置分层JAR


<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-maven-pluginartifactId>
            <configuration>
                <layers>
                    <enabled>trueenabled>
                    <configuration>${project.basedir}/layers.xmlconfiguration>
                layers>
            configuration>
        plugin>
    plugins>
build>

创建自定义分层配置 layers.xml

<layers xmlns="http://www.springframework.org/schema/boot/layers"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/boot/layers
                          d">
    <application>
        <into layer="spring-boot-loader">
            <include>org/springframework/boot/loader/**include>
        into>
        <into layer="application" />
    application>
    <dependencies>
        <into layer="snapshot-dependencies">
            <include>*:*:*SNAPSHOTinclude>
        into>
        <into layer="internal-dependencies">
            <include>com.yourcompany:*include>
        into>
        <into layer="dependencies" />
    dependencies>
    <layerOrder>
        <layer>dependencieslayer>
        <layer>spring-boot-loaderlayer>
        <layer>snapshot-dependencieslayer>
        <layer>internal-dependencieslayer>
        <layer>applicationlayer>
    layerOrder>
layers>

2.3 构建Docker镜像优化

步骤4:创建优化的Dockerfile

# 使用多阶段构建
# 构建阶段
FROM maven:3.8.4-openjdk-11-slim AS builder
WORKDIR /app
COPY pom.xml .
# 下载依赖(利用Docker缓存)
RUN mvn dependency:go-offline
COPY src ./src
# 打包应用
RUN mvn clean package -DskipTests

# 运行阶段
FROM openjdk:11-jre-slim
WORKDIR /app

# 创建非root用户
RUN addgroup --system --gid 1001 appuser && 
    adduser --system --uid 1001 --gid 1001 appuser

# 从构建阶段复制JAR
COPY --from=builder --chown=appuser:appuser /app/target/*.jar app.jar

# 提取分层JAR
RUN java -Djarmode=layertools -jar app.jar extract

# 复制分层内容
COPY --from=builder --chown=appuser:appuser /app/dependencies/ ./
COPY --from=builder --chown=appuser:appuser /app/spring-boot-loader/ ./
COPY --from=builder --chown=appuser:appuser /app/snapshot-dependencies/ ./
COPY --from=builder --chown=appuser:appuser /app/application/ ./

USER appuser

# 优化JVM参数
ENTRYPOINT ["java", "-XX:+UseContainerSupport", "-XX:MaxRAMPercentage=75.0", "-XX:+UseG1GC", "-XX:+OptimizeStringConcat", "-XX:+UseStringDeduplication", "org.springframework.boot.loader.JarLauncher"]

2.4 资源文件优化

步骤5:优化静态资源和配置文件


<build>
    <resources>
        <resource>
            <directory>src/main/resourcesdirectory>
            <filtering>truefiltering>
            <excludes>
                <exclude>**/*.psdexclude>
                <exclude>**/*.aiexclude>
                <exclude>**/*.xcfexclude>
            excludes>
        resource>
    resources>
    <plugins>
        
        <plugin>
            <groupId>com.github.eirslettgroupId>
            <artifactId>frontend-maven-pluginartifactId>
            <version>1.12.1version>
            <executions>
                <execution>
                    <id>compress-resourcesid>
                    <goals>
                        <goal>yarngoal>
                    goals>
                    <configuration>
                        <arguments>buildarguments>
                    configuration>
                execution>
            executions>
        plugin>
    plugins>
build>

2.5 自定义ClassLoader和数据压缩

步骤6:实现自定义类加载器

// 自定义类加载器实现懒加载
public class LazyLoadingClassLoader extends ClassLoader {
    
    private Map<String, byte[]> classBytesMap = new ConcurrentHashMap<>();
    
    public void registerClassBytes(String className, byte[] bytes) {
        classBytesMap.put(className, bytes);
    }
    
    @Override
    protected Class findClass(String name) throws ClassNotFoundException {
        byte[] bytes = classBytesMap.remove(name);
        if (bytes == null) {
            return super.findClass(name);
        }
        return defineClass(name, bytes, 0, bytes.length);
    }
}

步骤7:配置文件压缩

@Configuration
@PropertySource(value = "classpath:application.properties", 
                encoding = "UTF-8")
public class CompressedConfig {
    
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        PropertySourcesPlaceholderConfigurer configurer = 
            new PropertySourcesPlaceholderConfigurer();
        
        // 启用压缩属性文件
        configurer.setIgnoreUnresolvablePlaceholders(true);
        configurer.setFileEncoding("UTF-8");
        
        return configurer;
    }
}

2.6 使用GraalVM Native Image

步骤8:配置GraalVM原生编译


<plugin>
    <groupId>org.graalvm.buildtoolsgroupId>
    <artifactId>native-maven-pluginartifactId>
    <version>0.9.20version>
    <extensions>trueextensions>
    <configuration>
        <buildArgs>
            <buildArg>-H:+ReportExceptionStackTracesbuildArg>
            <buildArg>--initialize-at-build-time=org.springframework.util.unit.DataSizebuildArg>
            <buildArg>--initialize-at-build-time=org.slf4jbuildArg>
        buildArgs>
    configuration>
    <executions>
        <execution>
            <id>build-nativeid>
            <goals>
                <goal>compile-no-forkgoal>
            goals>
            <phase>packagephase>
        execution>
    executions>
plugin>

2.7 自动化瘦身脚本

步骤9:创建自动化瘦身脚本

#!/bin/bash
# slim-down.sh - 自动化瘦身脚本

echo "开始Spring Boot应用瘦身..."

# 1. 分析当前JAR大小
JAR_FILE=$(ls target/*.jar | head -1)
ORIGINAL_SIZE=$(du -h $JAR_FILE | cut -f1)
echo "原始JAR大小: $ORIGINAL_SIZE"

# 2. 提取并分析依赖
mkdir -p tmp/unpacked
cd tmp/unpacked
jar -xf ../../$JAR_FILE
cd BOOT-INF/lib

# 3. 找出大文件依赖
echo "前10大依赖:"
ls -lhS | head -10

# 4. 分析可移除的依赖
cd ../../..
rm -rf tmp

# 5. 重新打包(使用分层JAR)
echo "执行分层JAR打包..."
mvn clean package -Dspring-boot.thin.jar=true

# 6. 构建优化后的Docker镜像
echo "构建优化镜像..."
docker build -t optimized-app:latest -f Dockerfile.multistage .

NEW_JAR=$(ls target/*.jar | head -1)
NEW_SIZE=$(du -h $NEW_JAR | cut -f1)
REDUCTION=$(echo "scale=2; ($(du -b $JAR_FILE | cut -f1) - $(du -b $NEW_JAR | cut -f1)) / $(du -b $JAR_FILE | cut -f1) * 100" | bc)

echo "优化完成!"
echo "原始大小: $ORIGINAL_SIZE"
echo "优化后大小: $NEW_SIZE"
echo "体积减少: $REDUCTION%"

2.8 使用Thin Launcher

步骤10:配置Thin Launcher


<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot.experimentalgroupId>
            <artifactId>spring-boot-thin-maven-pluginartifactId>
            <version>1.0.29.RELEASEversion>
            <executions>
                <execution>
                    <id>resolveid>
                    <goals>
                        <goal>resolvegoal>
                    goals>
                    <inherited>falseinherited>
                execution>
            executions>
        plugin>
        
        
        <plugin>
            <groupId>org.apache.maven.pluginsgroupId>
            <artifactId>maven-jar-pluginartifactId>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>${start-class}mainClass>
                    manifest>
                    <manifestEntries>
                        <Spring-Boot-Version>${spring-boot.version}Spring-Boot-Version>
                        <Spring-Boot-Lib>lib/Spring-Boot-Lib>
                    manifestEntries>
                archive>
            configuration>
        plugin>
    plugins>
build>

2.9 配置排除和瘦身优化

步骤11:完整的pom.xml优化配置

"1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         d">
    <modelVersion>4.0.0modelVersion>
    
    <groupId>com.examplegroupId>
    <artifactId>slim-appartifactId>
    <version>1.0.0version>
    <packaging>jarpackaging>
    
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.7.0version>
    parent>
    
    <properties>
        <java.version>11java.version>
        
        <spring-boot.thin.jar>truespring-boot.thin.jar>
        
        <spring-boot.devtools.exclude>truespring-boot.devtools.exclude>
    properties>
    
    <dependencies>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-starter-tomcatartifactId>
                exclusion>
                <exclusion>
                    <groupId>org.hibernate.validatorgroupId>
                    <artifactId>hibernate-validatorartifactId>
                exclusion>
                <exclusion>
                    <groupId>org.springframeworkgroupId>
                    <artifactId>spring-webmvcartifactId>
                exclusion>
            exclusions>
        dependency>
        
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-jettyartifactId>
        dependency>
        
        
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <optional>trueoptional>
            <scope>providedscope>
        dependency>
    dependencies>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
                <configuration>
                    
                    <layers>
                        <enabled>trueenabled>
                    layers>
                    
                    <excludeDevtools>trueexcludeDevtools>
                    
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombokgroupId>
                            <artifactId>lombokartifactId>
                        exclude>
                    excludes>
                configuration>
            plugin>
            
            
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-dependency-pluginartifactId>
                <version>3.5.0version>
                <executions>
                    <execution>
                        <id>analyze-dependenciesid>
                        <goals>
                            <goal>analyze-onlygoal>
                        goals>
                        <configuration>
                            <failOnWarning>falsefailOnWarning>
                        configuration>
                    execution>
                executions>
            plugin>
            
            
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-resources-pluginartifactId>
                <version>3.3.1version>
                <configuration>
                    <encoding>UTF-8encoding>
                    <nonFilteredFileExtensions>
                        <nonFilteredFileExtension>pdfnonFilteredFileExtension>
                        <nonFilteredFileExtension>pngnonFilteredFileExtension>
                        <nonFilteredFileExtension>jpgnonFilteredFileExtension>
                    nonFilteredFileExtensions>
                configuration>
            plugin>
        plugins>
    build>
project>

三、详细总结

3.1 优化效果对比

优化策略原始体积优化后体积缩减比例适用场景
基础依赖精简80MB60MB25%所有项目
分层JAR + 多阶段构建80MB45MB44%容器部署
Thin Launcher80MB15MB81%微服务
GraalVM Native80MB25MB69%高性能场景
综合优化80MB18MB78%云原生部署

3.2 最佳实践总结

优先级策略:

  1. 第一优先级(立即实施)
    • 使用spring-boot-maven-plugin的分层JAR功能
    • 排除不必要的传递依赖
    • 使用多阶段Docker构建
  2. 第二优先级(推荐实施)
    • 替换为轻量级嵌入式服务器(Undertow/Jetty)
    • 配置资源过滤和排除
    • 使用maven-dependency-plugin分析并移除无用依赖
  3. 第三优先级(可选实施)
    • 采用Thin Launcher方案
    • 使用GraalVM Native Image
    • 实现自定义类加载器

3.3 关键注意事项

1. 兼容性考量

  • Native Image对反射、动态代理支持有限
  • Thin Launcher可能需要调整类加载逻辑
  • 分层JAR需要Spring Boot 2.3+

2. 性能权衡

  • Native Image启动快但构建慢
  • Thin Launcher首次启动需要下载依赖
  • 过度精简可能影响功能完整性

3. 监控与维护

  • 建立体积监控基准
  • 在CI/CD流程中自动检查JAR大小
  • 定期review依赖使用情况

3.4 实施建议路线图

3.5 最后

缩小Spring Boot打包体积是一个持续优化的过程,建议:

  1. 从简单开始:先实施基础依赖优化和分层JAR
  2. 测量驱动:每次优化前后都要测量体积变化
  3. 平衡取舍:在体积、性能、开发效率之间找到平衡点
  4. 自动化集成:将体积检查集成到CI/CD流程中
  5. 文档记录:记录优化决策和效果,便于团队协作

通过系统性地实施上述优化策略,大多数Spring Boot应用可以将部署体积缩减50%以上,显著提升部署效率和运行时性能。

谢谢你看我的文章,既然看到这里了,如果觉得不错,随手点个赞、转发、在看三连吧,感谢感谢。那我们,下次再见。

您的一键三连,是我更新的最大动力,谢谢

山水有相逢,来日皆可期,谢谢阅读,我们再会

我手中的金箍棒,上能通天,下能探海