烟台网站建设方案咨询企业 备案 网站服务内容
在maven项目中使用插件直接混淆之后再打包
修改 pom 文件
定义 proguard-maven-plugin 插件且插件位于 spring-boot-maven-plugin 插件的前面。
-
proguardInclude
表示使用外部扩展的配置文件 proguard.cfg,和 pom.xml 同目录
-
keepparameternames
此选项将保留所有原始方法参数,controller 如果函数的参数也混淆(如混淆为a、b、c等)会导致传参映射不上
详细配置如下(由于有详细注释,不再一一说明):
<build><plugins><!--proguard混淆插件--><plugin><groupId>com.github.wvengen</groupId><artifactId>proguard-maven-plugin</artifactId><version>2.6.0</version><executions><execution><!--打包的时候开始混淆--><phase>package</phase><goals><goal>proguard</goal></goals></execution></executions><configuration><proguardVersion>7.2.2</proguardVersion><injar>${project.build.finalName}.jar</injar><!--输出的jar--><outjar>${project.build.finalName}.jar</outjar><!--是否混淆--><obfuscate>true</obfuscate><proguardInclude>${basedir}/proguard.cfg</proguardInclude><options><!--默认开启,不做收缩(删除注释、未被引用代码)--><option>-dontshrink</option><!--默认是开启的,这里关闭字节码级别的优化--><option>-dontoptimize</option><!--对于类成员的命名的混淆采取唯一策略--><option>-useuniqueclassmembernames</option><!--混淆时不生成大小写混合的类名,默认是可以大小写混合--><option>-dontusemixedcaseclassnames </option><!--混淆类名之后,对使用Class.forName('className')之类的地方进行相应替代--><option>-adaptclassstrings</option><!--对异常、注解信息在runtime予以保留,不然影响springboot启动--><option>-keepattributesExceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod</option><!--此选项将保存接口中的所有原始名称(不混淆)--><option>-keepnames interface ** { *; }</option><!--此选项将保存所有软件包中的所有原始接口文件(不进行混淆)--><!--<option>-keep interface * extends * { *; }</option>--><!--此选项将保留所有原始方法参数,controller如果参数也混淆会导致传参映射不上 --><option>-keepparameternames</option><!--保留枚举成员及方法--><option>-keepclassmembers enum * { *; }</option><!--防止mybatis resultType 找不到bean--><option>-keep class cn.fuzhi.model.** { *; }</option><option>-keep class cn.fuzhi.config.** { *; }</option><option>-keep class cn.fuzhi.task.** { *; }</option><!--不混淆所有类,保存原始定义的注释--><!--<option>-keepclassmembers class * {@org.springframework.context.annotation.Bean *;@org.springframework.beans.factory.annotation.Autowired *;@org.springframework.beans.factory.annotation.Value *;@org.springframework.stereotype.Service *;@org.springframework.stereotype.Component *;}</option>--><!--忽略warn消息--><option>-ignorewarnings</option><!--忽略note消息--><option>-dontnote</option></options><!--java 11-->
<!-- <libs>-->
<!-- <lib>${java.home}/jmods/</lib>-->
<!-- </libs>--><!--java 8--><libs><lib>${java.home}/lib/rt.jar</lib><lib>${java.home}/lib/jsse.jar</lib></libs></configuration><dependencies><dependency><groupId>com.guardsquare</groupId><artifactId>proguard-base</artifactId><version>7.2.2</version></dependency></dependencies></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><!--jar可直接运行--><executable>true</executable></configuration></plugin></plugins></build>
proguard.cfg
作为 pom.xml 中的扩展配置,详细配置如下:
#所有类(包括接口)的方法参数不混淆(包括没被keep的),如果参数混淆了,mybatis的mapper参数绑定会出错(如#{id})
-keepattributes MethodParameters#入口程序类不能混淆,混淆会导致springboot启动不了
-keep class cn.fuzhi.Application {public static void main(java.lang.String[]);}#mybatis的mapper/实体类不混淆,否则会导致xml配置的mapper找不到
-keep class cn.fuzhi.mapper.*
-keeppackagenames cn.fuzhi.mapper#考虑到scanBasePackages,需要包名不被修改
-keeppackagenames cn.fuzhi#一些配置类比如datasource,aopconfig如果混淆会导致各种启动报错
# 比如用@Pointcut("execution(public * com.langyastudio.edu.*.controller..*.*(..))")
# 指定webLog方法对应的@Pointcut作为切入点,所以包的名字不能修改
-keeppackagenames cn.fuzhi.controller.**
-keep class cn.fuzhi.task.*#保留Serializable序列化的类不被混淆
#例如传入/输出的Bean属性
-keepclassmembers class * implements java.io.Serializable {*;}#保留空的构造函数
-keepclassmembers class com.fuzhi.* {public <init>(...);
}
混淆配置要点
-
建议逐个 java 包定义混淆规则,这样思路更清晰
-
repository(dao)层需要保存包名和类名,因为 Mybatis 的 xml 文件中引用了dao 层的接口
-
controller 层注意在使用 @PathVariable、@RequestParam 时需要显式声明参数名
-
dao 层用于映射数据库表的类和 controller 层映射前台参数的类,都需要保留类成员
-
修改 spring 的 bean 命名策略,改成按类的全限定名来命名
-
等等
入口程序类
入口程序类不能混淆,混淆会导致 springboot 启动不了,增加如下配置:
-keep class cn.fuzhi.Application {public static void main(java.lang.String[]);}
bean 名称冲突
默认混淆后的类名为 xx.a.b、xx.c.a,直接使用混淆后的类名作为 bean 会引发重名异常,所以需要修改 BeanName 生成策略。
不能重写 generateBeanName 方法,因为有些 Bean 会自定义 BeanName,所以这些情况还需要走原来的逻辑。
public static void main(String[] args) {new SpringApplicationBuilder(Application.class).beanNameGenerator(new UniqueNameGenerator()).run(args);
// SpringApplication.run(Application.class, args);log.error("============Web application Start Success====port:" + Global.System.SERVER_PORT + "===" + Global.System.EV + "=============");}@Component("UniqueNameGenerator")public @NotNullstatic class UniqueNameGenerator extends AnnotationBeanNameGenerator {@Overridepublic String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {return Objects.requireNonNull(definition.getBeanClassName());}}
包名保留
-
考虑到
scanBasePackages
等特殊的注解配置,需要包名不被修改,配置如下: -
<!--此选项将保留所有原始方法参数,controller如果参数也混淆会导致传参映射不上 --> <option>-keepparameternames</option>
-
scanBasePackages
样例:
如果 cn
fuzhi 名称被混淆,将导致 scanBasePackages
失效
@SpringBootApplication(scanBasePackages = {"cn.fuzhi.*"})
public class Application
{public static void main(String[] args){xxxxx}
}
配置类
一些配置类比如 datasource、aop、config 等如果混淆会导致各种启动报错
比如用 @Pointcut("execution(public * cn.fuzhi.controller.*.*(..))") 指定 ControllerAspect 方法对应的 @Pointcut 作为切入点。所以包的名字与函数名称不能修改
@Pointcut("execution(public * cn.fuzhi.controller.*.*(..)))")
public void ControllerAspect(){}
dao 层
mybatis 的 mapper/实体类 不能混淆,否则会导致 xml 配置的 mapper 找不到
-keep class cn.fuzhi.mapper.*
-keeppackagenames cn.fuzhi.mapper
#接口类保留
xxxx
bean 属性保留
controller 层映射前台参数的类、后端返回的 bean 属性类等,不能混淆类的成员属性(如变成 string a;)
修改方案为保留 Serializable 序列化的类成员不被混淆
-keepclassmembers class * implements java.io.Serializable {*;}
bean 样例:
需要将原有的属性类增加 Serializable 的继承
@Data
@NoArgsConstructor
public class TokenVO implements Serializable
{/*** token*/private String token;/*** token 前缀*/private String tokenHead;
}
编译打包
mvnw clean package -Dmaven.test.skip=true
混淆效果
用于进一步查看打包后的 jar 文件是否符合要求,同时还可以辅助查找 jar 文件运行失败的原因
常见的反编译工具使用 jd-gui
。下载地址:http://java-decompiler.github.io/。
直接通过 jd-gui
窗口打开编译打包后的 jar 文件即可。
混淆常见问题
混淆后自己全部代码没有被放入混淆后的jar包里(jar\BOOT-INF\classes 里面不包含com)
原因: proguard-maven-plugin插件放到了spring-boot-maven-plugin插件后面,应该是因为spring-boot-maven-plugin放在前面会先执行spring-boot-maven-plugin的repackage再执行proguard-maven-plugin的混淆,混淆后没有重新repackage
解决:把proguard-maven-plugin插件放到spring-boot-maven-plugin前面
DataSource,Aop,swagger等相关配置类混淆后导致的运行报错
原因:比如Aop是因为用@Around(value = "apiLog()")指定apiLog方法对应的@Pointcut作为切入点,但是因为apiLog方法被混淆成a导致找不到对应apiLog方法。就不一一列举了
解决:我是直接把所有配置类放到framework下面,然后proguard-maven-plugin配置让framework 下面的类和方法全部不混淆,这样省事点
-keep class cn.fuzhi.task.** {*;
}
aop事务控制,事务失效问题
原因:因为aop pointcut 是根据包路径和方法名(update,find)拦截,service 混淆后 包路径和方法名都变成 a,b导致拦截不到
解决:不混淆包路径和方法public方法名,如下
#不混淆service下的public方法名
-keepclassmembers class cn.fuzhi.service.** {public *** *(...);}
#不混淆service包名
-keeppackagenames cn.fuzhi.service.**
swagger 文档看不到api,以及接口请求参数controller 参数绑定报错
1)swagger 文档看不到api:因为我swagger配置的api 是通过.apis(RequestHandlerSelectors.basePackage(packageName))指定了具体包名,controller混淆后包名变成a,b,c所以扫描不到接口自然就生成不了文档
2)api接口请求出错:spring接口参数绑定是根据参数名称,混淆后参数名称会变成var1等,绑定的时候找不到原来定义的参数名就报错了.
解决:proguard-maven-plugin配置所有controller public 方法不参与混淆以及参数也不参与混淆,如下
#所有controller类的public方法你参与混淆
<option>-keepclassmembers class cn.fuzhi.controller.* {public *** *(...);}</option>
#不混淆controller的包路径
<option>-keeppackagenames cn.fuzhi.controller</option>#参数不参与混淆
<option>-keepparameternames</option>
spring controller 参数绑定问题
原因:spring参数绑定有些是根据controller的方法参数名称绑定的,参数名称混淆后就会绑定不上
解决:
方法1:Controller用如@RequestParam的方式绑定
方法2:
①.配置-keepparameternames,这个参数可以让不被混淆的方法也不会混淆其参数,对interface无效.
<option>-keepparameternames</option>
②. 因为第①步的配置,那只要配置controller里的方法不混淆,那么方法参数也就不会混淆了,如下
-keepclassmembers class cn.fuzhi.controller.* {public *** *(...);}
mybatis 参数绑定报错org.apache.ibatis.binding.BindingException
原因:和第6点类似,因为方法参数被混淆,所以导致mybatis的mapper(是interface)定义的接口参数Id被混淆成 var1,mybatis xml #{id}绑定的时候只能找到var1于是BindingException.但是不能用第6点的方法2,因为keepparameternames 能让keep的class参数不混淆,却不能让interface的参数不参与混淆,而mybatis的mapper就是interface
解决:
方法1:mapper的参数 用 @Param("id") 强行绑定
方法2:此方法也可以解决第6点的问题
①. 配置 -keepattributes MethodParameters ,这个参数可以让不管有没有参与混淆的类的方法参数都不参与混淆,对类和接口都生效,但是这样会导致即使参与混淆的类也无法混淆参数
-keepattributes MethodParameters
②. 上面的配置是可以让所有方法参数不被proguard混淆,但是有些项目在java编译的时候却可能会对方法参数混淆(好像是针对interface方法参数的混淆,不针对class).所以可以配置编译时不混淆方法参数(-parameters),如下所示(这个根据自己项目实际情况配置,好像是和idea版本有关系)
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><compilerArgument>-parameters</compilerArgument></configuration></plugin>
CreateProcess error=206, 文件名或扩展名太长。
原因:因为window的cmd有长度限制,而proguard混淆时依赖太多的jar包导致命令行过长
解决:在proguard-maven-plugin的configuration中加入下面配置,这个配置会把jar包放到临时目录以便缩短命令行
<putLibraryJarsInTempDir>true</putLibraryJarsInTempDir>