1.情景展示
我的需求是:為了將項目部署到機器上時,既不影響項目的正常運行,又可以做到降低項目源碼(class文件)的可讀性,其主要目的是為了防盜。
一般情況下是用不到混淆器的,但是實際生活中往往存在這樣的問題或需求,比方說:由於時間緊迫,兩家企業被迫聯合共同上線一個產品,現在是雖是合作關系,他們又可以相互取締,同樣的市場,蛋糕就這么大,時間長了難免互生嫌隙,所以為了保護各自產品被竊取,就需要防盜神器proguard了。
2.proguard簡介
ProGuard 是一個免費的 Java類文件的壓縮,優化,混餚器。它刪除沒有用的類,字段,方法與屬性。使字節碼最大程度地優化,使用簡短且無意義的名字來重命名類、字段和方法 。eclipse已經把Proguard集成在一起了。
吐槽:但說句實在話,proguard雖然降低了代碼的可讀性,但是,仍是能夠讀懂的,只是費點勁罷了。正所謂:防君子不防小人。
3.proguard教程
第一步:maven配置(pom.xml)
<!--構建工具--> <build> <!--自定義打包后的項目名稱 可以無視默認的打包名稱規則:${artifactId}-${version}--> <finalName>bill</finalName> <plugins> <!--maven編譯插件--> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <!--二選一--> <version>${spring.version}</version> <!--<version>2.3.1.RELEASE</version>--> </plugin> <!--java混淆器插件--> <plugin> <groupId>com.github.wvengen</groupId> <artifactId>proguard-maven-plugin</artifactId> <version>2.3.1</version> <executions> <execution> <!-- 混淆時刻:這里是打包的時候混淆 --> <phase>package</phase> <goals> <!-- 使用插件的什么功能: 混淆--> <goal>proguard</goal> </goals> </execution> </executions> <configuration> <proguardVersion>${proguard.version}</proguardVersion> <!--<proguardVersion>6.2.2</proguardVersion>--> <!-- 是否混淆--> <obfuscate>true</obfuscate> <!--關鍵:引入配置文件,這里換成你的配置文件所在路徑,一般情況下就是把proguard.cfg放到這個目錄--> <proguardInclude>${project.basedir}/src/main/resources/proguard.cfg</proguardInclude> <!-- 混淆時需要引用的java庫,這些庫的類不會做混淆 --> <libs> <lib>${java.home}/lib/rt.jar</lib> <lib>${java.home}/lib/jce.jar</lib> </libs> <!--當<injar></injar>的值為:classes時,可以結合該標簽使用,作用:相關混淆配置只為指定目錄下的class文件起效--> <!--<inFilter>com/marydon/**</inFilter>--> <!-- 需要做混淆的jar或class目錄,也就是:選擇對什么東西進行加載--> <injar>classes</injar> <!--<injar>${project.build.finalName}.jar</injar>--> <!--class 混淆后輸出的jar包,說明:這個輸出格式可有可無,下面會講 --> <outjar>${project.build.finalName}-pd.jar</outjar> <!-- 輸出目錄 --> <outputDirectory>${project.build.directory}</outputDirectory> </configuration> <dependencies> <dependency> <groupId>net.sf.proguard</groupId> <artifactId>proguard-base</artifactId> <version>${proguard.version}</version> <!--<version>6.2.2</version>--> <scope>runtime</scope> </dependency> </dependencies> </plugin> </plugins> </build>
這里需要注意的一點是:build標簽需要在dependencies下方
第二步:插件下載
先不要管proguard.cfg文件怎么寫,搞定這個插件才能繼續往下走,不然就是浪費時間,即使你將配置文件寫好,離開了這個插件,要配置文件有啥用?
為了搞定最新版的插件,浪費了我不少時間,下面科普一下,如果你引入以上配置文件后,proguard插件下載成功,就可以跳過這一步了。
上面這個插件,明確的告訴你:阿里雲maven中央倉庫有!!!
如果下載失敗,說明:該項目使用的maven中央倉庫不是阿里雲的,怎么辦?
很簡單,不用去該maven下面的settings.xml,直接在項目中引入即可。
<!--配置項目的jar包倉庫--> <repositories> <!--阿里雲倉庫,id=central,會覆蓋掉setting.xml中配置的中央倉庫--> <repository> <id>central</id> <name>central maven</name> <url>https://maven.aliyun.com/repository/central</url> <!--<url>http://maven.aliyun.com/nexus/content/groups/public/</url>--> </repository> <!--maven官網--> <repository> <id>public</id> <name>public maven</name> <url>https://mvnrepository.com</url> </repository> </repositories>
這樣,倉庫配置僅對本項目生效,也不會影響到其它項目對於settings.xml的依賴。
這里需要注意的一點是:repositories標簽需要在dependencies上方
點擊右側maven視圖里的這個按鈕,網絡較好的情況下,很快就下載完成了。
如果插件不再報錯,基本上就成了
如果該插件下載不成功,就沒有繼續進行下去的必要了,等搞定再往下看。
第三步:proguard.cfg配置文件
新建proguard.cfg文件,並將其放到src/main/resources目錄下
第四步:打包
使用maven插件打包,打開maven視圖,找到package,進行打包即可。
打包成功日志
成功后,target目錄下會多出三個文件
bill-pd.jar,就是項目混淆后的jar包(
也就是說:混淆后的代碼會被proguard插件單獨打成一個jar包,與bill.jar的主要區別就是:前者是帶有混淆的class文件,后者是正常的class文件
這里,講一下前面在pom.xml中配置的<outjar>${project.build.finalName}-pd.jar</outjar>標簽,這個標簽可有可無。
如果去掉指定混淆文件的輸出格式,打包后會是什么樣的呢?
區別在於:原來的bill-pd.jar變成了classes_proguard_base目錄
里面的內容沒有區別。
第五步:injar與outjar
這兩個標簽如果不配合好,效率將會大打折扣,而且還容易出錯。由上面我們知道,
injar:是在插件混淆的源目錄,也就是,混淆前的代碼來源,它有兩種表現形式:第一種是class目錄,第二種是${project.build.finalName}.jar;
outjar:插件執行混淆完畢后,將要輸出的文件打包成什么樣的格式,這里僅支持jar包,不支持war包,injar標簽也一樣;如果不聲明該標簽的話,將會默認生成classes_proguard_base目錄。
第六步:部署項目
方式一:部署jar包
編譯源目錄格式使用:<injar>${project.build.finalName}.jar</injar>
輸出目錄格式使用:<outjar>${project.build.finalName}-pd.jar</outjar>
這樣,即使沒有前后端分離,我們也可以確保bill-pd.jar包含的是項目的完整代碼,可以拿出直接使用
測試結果如下:
可能會報這個錯:Unable to open nested entry ********.jar
分析:因為javaUtils.jar是我自己封裝的一個jar包,混淆插件會將它單獨抽出來再次壓縮,導致java解析失敗,所以我就想將輸入輸出名字保持一致。
測試結果如下:
使用將輸出的jar包名稱和輸入jar包名稱保持一致
即:<outjar>${project.build.finalName}.jar</outjar>,其執行結果是:生成的默認值(項目名稱_proguard_base.jar)
項目啟動成功,但仍無法訪問項目,這個問題是idea maven插件自身package命令的bug
解決方案,就是使用原始的maven命令,手動將其打成jar包,不懂的可以見文末推薦
項目訪問成功(<outjar>${project.build.finalName}.jar</outjar>,必須是這個)
方式二:部署war包
編譯源目錄格式使用:<injar>classes</injar>
輸出目錄格式使用:刪除<outjar></outjar>標簽
打包標簽設置成war:<packaging>war</packaging>
將項目打成war包后,用壓縮軟件打開,依次打開WEB-INF/classes目錄,刪掉,再將生成的混淆文件里的class文件復制進去即可。