ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SpringBoot应用瘦身优化实战:从依赖管理到镜像构建

SpringBoot应用瘦身优化实战:从依赖管理到镜像构建 1. 为什么SpringBoot应用会虚胖SpringBoot应用体积膨胀的问题困扰着不少开发者。一个简单的Web应用动辄100MB的jar包部署时传输慢、启动耗时长甚至可能触发云平台的资源限制。这种虚胖现象主要来自几个方面首先SpringBoot的starter机制虽然方便但容易引入大量实际用不到的依赖。比如你只想用Redis做缓存但spring-boot-starter-data-redis可能连带引入了Lettuce、Jackson、Commons Pool等一堆库。其次默认打包方式会把所有依赖打进一个fat jar包括那些运行时根本不会调用的代码。我见过一个报表导出功能引入了POI全家桶结果光这部分就增加了20MB而实际只用到了基础的Excel导出。另外资源文件也是重灾区。前端同学把node_modules里的东西全扔进了static目录或者配置文件里保留了大量注释和示例的情况比比皆是。提示用mvn dependency:tree命令可以清晰看到依赖树这是瘦身工作的第一步。2. 依赖优化实战技巧2.1 精确控制starter依赖不要无脑引入完整的starter。比如!-- 不推荐 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-jpa/artifactId /dependency !-- 推荐 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-jdbc/artifactId /dependency dependency groupIdorg.hibernate/groupId artifactIdhibernate-core/artifactId /dependency2.2 使用dependency:analyze找出无用依赖Maven的analyze工具能检测出声明了但未使用的依赖使用了但未声明的依赖执行命令mvn dependency:analyze注意要把报错项分为两类处理Unused declared dependencies可以安全移除Used undeclared dependencies需要显式声明2.3 排除传递依赖比如你用了Spring Cloud Stream但不需要RabbitMQdependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-stream/artifactId exclusions exclusion groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-stream-binder-rabbit/artifactId /exclusion /exclusions /dependency3. 打包优化方案3.1 分层构建Docker镜像这是目前最有效的方案之一。通过分层打包可以充分利用Docker的缓存机制FROM eclipse-temurin:17-jdk-jammy as builder WORKDIR application ARG JAR_FILEtarget/*.jar COPY ${JAR_FILE} application.jar RUN java -Djarmodelayertools -jar application.jar extract FROM eclipse-temurin:17-jre-jammy WORKDIR application COPY --frombuilder application/dependencies/ ./ COPY --frombuilder application/spring-boot-loader/ ./ COPY --frombuilder application/application/ ./ ENTRYPOINT [java, org.springframework.boot.loader.JarLauncher]关键点使用jre基础镜像而非jdk按依赖层级分开COPY最常变更的层放最后实测可将镜像体积减少40%以上3.2 瘦身插件配置在pom.xml中添加build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId configuration excludes exclude groupIdorg.projectlombok/groupId artifactIdlombok/artifactId /exclude /excludes /configuration /plugin /plugins /build4. 资源文件优化4.1 静态资源处理前端资源建议启用Gzip压缩Nginx配置示例gzip on; gzip_types text/plain text/css application/json application/javascript;使用CDN托管第三方库!-- 替换本地jquery -- script srchttps://cdn.jsdelivr.net/npm/jquery3.6.0/dist/jquery.min.js/script4.2 配置文件精简删除application.yml中未使用的配置项示例配置特别是Spring Security的示例规则重复定义的配置推荐使用ConfigurationProperties进行分组管理避免散落各处的Value注解。5. 高级技巧类级别优化5.1 使用ProGuard混淆配置示例proguard.cfg-dontwarn org.springframework.** -keep class com.example.myapp.** { *; }Maven集成plugin groupIdcom.github.wvengen/groupId artifactIdproguard-maven-plugin/artifactId executions execution phasepackage/phase goalsgoalproguard/goal/goals /execution /executions configuration obfuscatetrue/obfuscate injar${project.build.finalName}.jar/injar /configuration /plugin5.2 模块化打包对于大型项目可以考虑按功能拆分子模块使用Spring Boot的瘦jar打包方式mvn package -Dspring-boot.repackage.skiptrue6. 效果验证与对比优化前后典型对比指标优化前优化后降幅打包文件大小156MB48MB69%启动时间12.3s6.8s45%内存占用1.2GB780MB35%验证工具推荐JDK自带jcmd pid VM.native_memoryjvisualvm查看类加载情况wrk进行压测对比7. 常见问题解决Q排除依赖后出现ClassNotFoundExceptionA按这个顺序排查检查是否误排除了必要依赖使用mvn dependency:tree查看完整依赖关系在测试环境用-verbose:class参数启动观察类加载QProGuard导致Spring注解失效A需要添加keep规则-keep org.springframework.stereotype.Component class * { *; } -keep org.springframework.context.annotation.Configuration class * { *; }Q分层构建后镜像反而变大A检查是否使用了alpine等更小的基础镜像清理了构建中间件合并了同类依赖项最后分享一个实用命令可以快速分析jar包内容大小# Linux/Mac unzip -l your.jar | awk {print $4,$1/1024KB} | sort -nr # Windows jar tvf your.jar | find 文件大小
返回列表