SpringBoot結(jié)合ProGuard實(shí)現(xiàn)代碼混淆(最新版)
前言
研究ProGuard也花了兩天時(shí)間,其實(shí)最主要的時(shí)間花在前面proguard讀取jar包的時(shí)候相關(guān)jar沖突的問(wèn)題,但是總的來(lái)說(shuō)不用拆分SpringBoot項(xiàng)目并且實(shí)現(xiàn)代碼混淆已經(jīng)很舒服了。
ProGuard集成
1.maven的配置
具體配置如下:
<build>
<finalName>${artifactId}</finalName>
<plugins>
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals><goal>proguard</goal></goals>
</execution>
</executions>
<configuration>
<proguardVersion>6.2.2</proguardVersion>
<injar>${project.build.finalName}.jar</injar>
<outjar>${project.build.finalName}.jar</outjar>
<!--<proguardInclude>${project.basedir}/proguard.cfg</proguardInclude>-->
<obfuscate>true</obfuscate>
<options>
<!-- 不做收縮(刪除注釋、未被引用代碼)-->
<option>-dontshrink</option>
<!-- 不做優(yōu)化(變更代碼實(shí)現(xiàn)邏輯)-->
<option>-dontoptimize</option>
<!--保持目錄結(jié)構(gòu),否則spring的自動(dòng)注入無(wú)法使用-->
<!--<option>-keepdirectories</option>-->
<option>-keepattributes Exceptions,InnerClasses,Signature,Deprecated,
SourceFile,LineNumberTable, *Annotation*,EnclosingMethod
</option>
<option>-adaptclassstrings</option>
<option>
<!-- 保護(hù)程序入口 -->
-keep class com.jingchen.ccny.CmepApplication { *; }
</option>
<option>-keepnames interface ** { *; }</option>
<!-- 固定幾個(gè)類(lèi)不能混淆-->
<option>-keepnames class com.jingchen.ccny.base.BaseService { *; }</option>
<option>-keep class com.jingchen.ccny.common.cache.ConvertorNewCache { *; }</option>
<option>-keep class com.jingchen.ccny.base.ControllerContext { *; }</option>
<option>-keep class * extends com.jingchen.ccny.base.BaseService</option>
<option>-keep class * implements com.jingchen.ccny.common.service.CallBackGuiService</option>
<option>-keep class * implements com.jingchen.ccny.common.service.CallBackUDService</option>
<option>-keep class com.jingchen.ccny.util.SpringUtil</option>
<!--<option>-keep interface * extends * { *; }</option>-->
<!-- 此選項(xiàng)將在所有包的所有類(lèi)中保存所有原始定義的注釋.-->
<option>
-keep class * {
@org.springframework.beans.factory.annotation.Autowired *;
@org.springframework.beans.factory.annotation.Value *;
@org.springframework.stereotype.Service *;
@org.springframework.stereotype.Component *;
@org.springframework.scheduling.annotation.Scheduled *;
}
</option>
</options>
<libs>
<!-- Include main JAVA library required.-->
<lib>${java.home}/lib/rt.jar</lib>
<lib>${java.home}/lib/jce.jar</lib>
</libs>
</configuration>
<dependencies>
<dependency>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard-base</artifactId>
<version>6.2.2</version>
</dependency>
</dependencies>
</plugin>
<!-- Maven assembly must be run after proguard obfuscation so it take already obfuscated files.-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<mainClass>com.jingchen.ccny.CcnyApplication</mainClass>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
這里里面級(jí)聯(lián)引用的jar很多,建議配置了私服的人先把鏡像地址配置成maven中央倉(cāng)庫(kù)地址,這樣先下下來(lái)相關(guān)依賴(lài)的包,然后再上傳到你們的私服上去。據(jù)我研究中知道的jar就有:

注意:不連外網(wǎng)配置maven中央倉(cāng)庫(kù)的話,少了jar你們會(huì)很頭疼的。而且不止net.sf.proguard相關(guān)包,還包括了com.guardsquare.proguard-base 和 com.guardsquare.proguard-core 相關(guān)的jar,所以真的連外網(wǎng)下包很重要?。。。?/p>
推薦一個(gè)IDEA解決maven引用沖突的插件:Maven Helper
2.相關(guān)異常解決
idea A required class was missing … org/apache/tools/ant/BuildListener
問(wèn)題原因:
這個(gè)問(wèn)題就是上面提到的因?yàn)閍pache的編譯用了一個(gè)ant-1.9.3的包,這個(gè)是級(jí)聯(lián)引用的,開(kāi)始我是內(nèi)網(wǎng)maven私服,單純的引入net.sf.proguard相關(guān)和com.github.wvengen相關(guān)的jar還是會(huì)缺少很多jar
解決方案:
連上外網(wǎng),配置你的maven的setting.xml 的mirror鏡像地址,配置成Maven中央倉(cāng)庫(kù)的地址,將相關(guān)的jar都下下來(lái),然后再通過(guò)命令把你本地maven倉(cāng)庫(kù)的jar上傳到私服去
Can't process class [META-INF/versions/9/org/apache/logging/log4j/util/Base64Util.class]
Can't process class [META-INF/versions/11/module-info.class]
問(wèn)題原因
這個(gè)問(wèn)題的原因有很多方面,最主要的就是我們的jdk版本是1.8,我最開(kāi)始用的ProGuard是5.3.3版本,然而我們SpringBoot的版本是2.3.3版本,SpringBoot2.3.3版本太新了,里面引用的相關(guān)包都是java9和java11的版本,這樣ProGuard在讀jar的時(shí)候會(huì)無(wú)法識(shí)別。這些問(wèn)題在提升Proguard版本到6.2.2之后都解決了
解決方案
開(kāi)始我的解決方案是忽略這些相關(guān)的jar, 例如在pom.xml的option配置:
<option>-libraryjars ${settings.localRepository}/com/zaxxer/HikariCP/3.4.5/HikariCP-3.4.5.jar(META-INF/versions/11/module-info.class)</option>
但是我這樣配置之后,重新打包會(huì)提示:
The same input jar [E:\maven\repo\com\zaxxer\HikariCP\3.4.5\HikariCP-3.4.5.jar] is specified twice.
解決方案:
而且我還嘗試了maven引用的時(shí)候排除這些高版本的級(jí)聯(lián)引用jar,單獨(dú)引用低版本,但最終還是因?yàn)樘爆嵍艞壛?。直接提升Proguard版本到6.2.2 這些讀jar的版本問(wèn)題就解決了。Annotation-specified bean name ‘a(chǎn)' for bean class
問(wèn)題原因:
出現(xiàn)這個(gè)問(wèn)題主要還是混淆之后,bean重名了,spring默認(rèn)是把類(lèi)名的首字母小寫(xiě)加載到容器里面,我們混淆類(lèi)名之后,就容易造成beanName重復(fù)。
解決方案:
慶幸的是,我們可以通過(guò)改變spring加載bean的命名策略來(lái)解決這個(gè)問(wèn)題,把包名帶上,同時(shí)在獲取Spring上下文getBean的時(shí)候,加上包名路徑即可
啟動(dòng)類(lèi)配置,具體如下:
@SpringBootApplication
public class CcnyApplication{
public static class CustomGenerator implements BeanNameGenerator {
@Override
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
return definition.getBeanClassName();
}
}
public static void main(String[] args) {
SpringApplicationBuilder sab=new SpringApplicationBuilder(CcnyApplication.class)
.beanNameGenerator(new CustomGenerator());
//這里如果想打印你加載的Spring的bean,可以這樣做:
ApplicationContext ac =sab.run(args);
Arrays.stream(ac.getBeanDefinitionNames()).forEach(System.out::println);
}
}
這樣配置,你啟動(dòng)的時(shí)候就能看到加載的所有的beanName(這里Service會(huì)帶上package路徑)
其他地方getBean的用法:
//這里的packagePath = com.jingchen.ccny.service
CallBackGuiService callBackGuiService = (CallBackGuiService) SpringUtil.getBean(packagePath+serviceName);
callBackResult = callBackGuiService.excute(convertMap);
這樣你就能正常的獲取到Spring容器加載的beanName了
注意事項(xiàng)
基本上影響打包和啟動(dòng)的就上面一些問(wèn)題了,其他的就是你們項(xiàng)目里面的細(xì)節(jié)了,
- 比如DAO要保留,要和mybatis里面的Mapper映射對(duì)應(yīng),DAO里面的方法傳參要改為map或者實(shí)體,另外序列化后的實(shí)體要保留
- Controller里面的方法入?yún)ⅲ绻昧藢?shí)體,這部分實(shí)體也要保留(保證其變量不會(huì)被混淆,不然傳值收不到)
- 另外就是你們spring相關(guān)的XML里面,如果單獨(dú)配置了Bean和Bean屬性的,這類(lèi)bean要保留,不能被混淆
- 我這里保留了所有的接口和接口里面的方法,已經(jīng)我們自定義的抽象類(lèi)BaseService里面的方法名不會(huì)被混淆,這些你們可以自己定義,而且我這里定義了有標(biāo)注@Component的類(lèi)也保留類(lèi)名,按照我上面的配置,基本上可以不用重新構(gòu)建beanName。正常的application啟動(dòng)就完事了
- 其他的沒(méi)了,就看你們還有沒(méi)有什么特定的類(lèi)不能被混淆,以及你們要混淆的力度(我們的要求是保留所有類(lèi)名、接口信息和抽象類(lèi)信息,除此之外的所有類(lèi)和方法都被混淆!)
總的來(lái)說(shuō)花了兩天時(shí)間,有這樣的成果也是值得高興的,前一天解決jar沖突的比較多,主要原因就是最開(kāi)始XX架構(gòu)師搭建這個(gè)項(xiàng)目采用最新的SpringBoot版本,jdk確是1.8 , 很多不兼容。
來(lái)個(gè)最終的效果圖吧:

參考案例
1、Springboot+proguard+maven 混淆.
2、proguard-spring-boot-example
3、官方解釋
4、Proguard的Keep使用方法
5、ProGuard 最全混淆規(guī)則說(shuō)明
6、ProGuard代碼混淆技術(shù)詳解
7、使用proguard混淆springboot代碼
到此這篇關(guān)于SpringBoot結(jié)合ProGuard實(shí)現(xiàn)代碼混淆(最新版)的文章就介紹到這了,更多相關(guān)SpringBoot ProGuard代碼混淆內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java實(shí)現(xiàn)將彩色PDF轉(zhuǎn)為灰度PDF的示例代碼
本文以Java代碼為例介紹如何實(shí)現(xiàn)將彩色PDF文件轉(zhuǎn)為灰度(黑白)的PDF文件,文中的示例代碼講解詳細(xì),感興趣的小伙伴快跟隨小編一起學(xué)習(xí)一下吧2022-03-03
mybatis教程之動(dòng)態(tài)sql語(yǔ)句_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了mybatis教程之動(dòng)態(tài)sql語(yǔ)句,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09
springboot集成druid,多數(shù)據(jù)源可視化,p6spy問(wèn)題
這篇文章主要介紹了springboot集成druid,多數(shù)據(jù)源可視化,p6spy問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
使用@ConditionalOnProperty控制是否加載的操作
這篇文章主要介紹了使用@ConditionalOnProperty控制是否加載的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
Java8時(shí)間接口LocalDateTime詳細(xì)用法
最近看別人項(xiàng)目源碼,發(fā)現(xiàn)Java8新的日期時(shí)間API很方便強(qiáng)大,所以整理了這篇文章,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有很好的幫助,需要的朋友可以參考下2021-05-05
mybatis中的動(dòng)態(tài)sql問(wèn)題
這篇文章主要介紹了mybatis中的動(dòng)態(tài)sql問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02
SWT(JFace) FTP客戶端實(shí)現(xiàn)
SWT(JFace)小制作:FTP客戶端實(shí)現(xiàn)2009-06-06

