Spring Boot中Proguard混淆类未加入Jar包问题求助
Spring Boot 3.2.5 + Java 21 混淆后Jar包丢失应用类问题
我正在为Spring Boot 3.2.5(Java 21)应用的Jar包做混淆处理,初始Jar和混淆后的Jar都已生成,但混淆Jar里没有包含应用包内的类。ProGuard映射文件proguard_map.txt中能看到应用类已被混淆,但最终Jar里找不到这些类,怀疑是打包流程或顺序问题,求解决。
环境信息
- Spring Boot 3.2.5
- Java 21
- ProGuard 7.3.2
- proguard-maven-plugin 2.6.1
我的ProGuard配置
# Obfuscation settings -useuniqueclassmembernames -classobfuscationdictionary obfuscation-dictionary.txt -packageobfuscationdictionary obfuscation-dictionary.txt # General options -verbose -dontoptimize -dontshrink -dontpreverify -allowaccessmodification -adaptclassstrings -keepdirectories -ignorewarnings # Keep annotations -keepattributes *Annotation* -keepattributes Signature -keepattributes Exceptions # Keep main classes -keep public class * extends org.springframework.boot.web.support.SpringBootServletInitializer -keep public class com.my.package.Application { public static void main(java.lang.String[]); } -keep,allowobfuscation class com.my.package.Application.** { *; } -keep interface com.my.package.** { *; } -keepclasseswithmembers public class * { public static void main(java.lang.String[]); } # If you use Lombok, you might need this -keep class lombok.** { *; } -dontwarn lombok.** -keepclassmembers class * { @lombok.Setter *; @lombok.Getter *; @lombok.Cleanup *; @lombok.ToString *; @lombok.EqualsAndHashCode *; @lombok.AllArgsConstructor *; @lombok.NoArgsConstructor *; @lombok.Builder *; } # Keep all classes in specific packages -keep class my.package.** { *; } -keep class org.springframework.boot.** { *; } -keep class org.springframework.boot.loader.** { *; } -dontwarn org.springframework.boot.loader.** # Keep Spring Boot specific classes -keep class org.springframework.boot.loader.jar.** { *; } -keep class org.springframework.boot.loader.zip.** { *; } -keep class java.util.jar.JarFile { *; } # Keep ZIP related classes -keep class java.util.zip.** { *; } -dontwarn java.util.zip.** # Keep all subclasses of InputStream -keep class * extends java.io.InputStream { *; } -keep class * extends java.util.zip.InflaterInputStream { *; } # Keep specific classes and their inner classes -keep class org.springframework.boot.loader.jar.NestedJarFile { *; } -keep class org.springframework.boot.loader.jar.NestedJarFile$* { *; } -keep class org.springframework.boot.loader.jar.ZipInflaterInputStream { *; } -keep class org.springframework.boot.loader.zip.ZipContent$Entry { *; } # Keep specific methods and fields -keepclassmembers class * { @org.springframework.beans.factory.annotation.Autowired *; @org.springframework.beans.factory.annotation.Qualifier *; @org.springframework.beans.factory.annotation.Value *; @org.springframework.beans.factory.annotation.Required *; @org.springframework.context.annotation.Bean *; @org.springframework.context.annotation.Primary *; @org.springframework.boot.context.properties.ConfigurationProperties *; @org.springframework.boot.context.properties.EnableConfigurationProperties *; @javax.inject.Inject *; @javax.annotation.PostConstruct *; @javax.annotation.PreDestroy *; @org.springframework.security.access.prepost.PreAuthorize *; } # Keep enums -keepclassmembers enum * { *; } # Keep Serializable classes -keepnames class * implements java.io.Serializable -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; private static final java.io.ObjectStreamField[] serialPersistentFields; !static !transient <fields>; !private <fields>; !private <methods>; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); } # Keep getters and setters -keepclassmembers class * { *** get*(); void set*(***); } # Keep specific annotations -keep @org.springframework.cache.annotation.EnableCaching class * -keep @org.springframework.context.annotation.Configuration class * -keep @org.springframework.boot.context.properties.ConfigurationProperties class * -keep @org.springframework.boot.autoconfigure.SpringBootApplication class * # Keep specific directories -keepdirectories org.springframework.boot.autoconfigure
Maven插件配置
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>3.2.5</version> <executions> <execution> <id>repackage</id> <phase>package</phase> <goals> <goal>repackage</goal> </goals> <configuration> <mainClass>com.my.package.Application</mainClass> </configuration> </execution> </executions> </plugin> <plugin> <groupId>com.github.wvengen</groupId> <artifactId>proguard-maven-plugin</artifactId> <version>2.6.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>proguard</goal> </goals> </execution> </executions> <configuration> <proguardVersion>7.3.2</proguardVersion> <injar>${project.build.finalName}.jar</injar> <outjar>${project.build.finalName}-obfuscated.jar</outjar> <obfuscate>true</obfuscate> <proguardInclude>${project.basedir}/proguard.cfg</proguardInclude> <libs> <lib>${java.home}/lib/jrt-fs.jar</lib> </libs> <options> <option>-verbose</option> </options> </configuration> <dependencies> <dependency> <groupId>com.guardsquare</groupId> <artifactId>proguard-base</artifactId> <version>7.3.2</version> </dependency> </dependencies> </plugin>
调试日志片段
[proguard] Number of obfuscated classes: 41 [proguard] Number of obfuscated fields: 196 [proguard] Number of obfuscated methods: 121
解决方案
1. 调整Maven插件执行顺序
Spring Boot的repackage目标会生成嵌套结构的可执行Jar,ProGuard直接处理该Jar无法正确识别应用类。需让ProGuard先处理原始非可执行Jar,再由Spring Boot插件重新打包混淆后的Jar:
- 修改ProGuard插件的执行阶段为
prepare-package(早于package阶段的repackage):<execution> <phase>prepare-package</phase> <goals> <goal>proguard</goal> </goals> </execution> - 调整Spring Boot插件,指定混淆后的Jar作为输入:
<configuration> <mainClass>com.my.package.Application</mainClass> <inputJar>${project.build.directory}/${project.build.finalName}-obfuscated.jar</inputJar> <outputJar>${project.build.directory}/${project.build.finalName}-obfuscated-exec.jar</outputJar> </configuration>
2. 修正ProGuard包名配置错误
配置中-keep class my.package.** { *; }缺少com前缀,与应用实际包名com.my.package不符,导致应用类未被正确保留,修改为:
-keep,allowobfuscation class com.my.package.** { *; }
3. 明确ProGuard输入源
确保ProGuard处理的是编译后的类文件而非可执行Jar,在ProGuard插件配置中指定输入为target/classes:
<injar>${project.build.directory}/classes</injar>
4. 保留应用类目录
在ProGuard配置中明确添加应用包目录的保留规则:
-keepdirectories com/my/package
验证步骤
- 执行
mvn clean package,查看ProGuard日志确认应用类被正常处理 - 解压混淆后的Jar,检查
BOOT-INF/classes目录下是否存在混淆后的应用类 - 运行最终的可执行混淆Jar,确认应用能正常启动
内容的提问来源于stack exchange,提问作者Marius D.
相关产品推荐
相关产品推荐

