使用idfc-proguard-maven-plugin混淆優化Jave Web工程二
上篇文章說了下大致流程和我們要達到的效果。本文主要講一下詳細配置。
其實只要弄過一次,就覺得很簡單了。只需要配置兩個檔案。
pom.xml和${project.artifactId}-maven.pro 這兩個檔案即可。 其中pom.xml配置外掛的使用,真正的優化選項 在${project.artifactId}-maven.pro 檔案裡配置。
先來看一下完整的pom.xml。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>Struts2Spring4Hibernate4XML</groupId> <artifactId>Struts2Spring4Hibernate4XML</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>Struts2Spring4Hibernate4</name> <description>Integration of Struts 2, Spring 4 and Hibernate 4 frameworks</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java-version>1.8</java-version> <org.springframework-version>4.1.4.RELEASE</org.springframework-version> <org.strutsframework-version>2.3.20</org.strutsframework-version> <org.hibernateframework-version>4.3.8.Final</org.hibernateframework-version> <org.mysqlconnector-version>5.1.34</org.mysqlconnector-version> </properties> <dependencies> <!-- Spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${org.springframework-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${org.springframework-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${org.springframework-version}</version> <type>jar</type> <scope>compile</scope> </dependency> <!-- Struts --> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-core</artifactId> <version>${org.strutsframework-version}</version> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-spring-plugin</artifactId> <version>${org.strutsframework-version}</version> </dependency> <!-- Hibernate --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${org.hibernateframework-version}</version> </dependency> <!-- Apache Commons DBCP --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-dbcp2</artifactId> <version>2.0</version> </dependency> <!-- MySQL Connector-Java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${org.mysqlconnector-version}</version> </dependency> <!-- jstl --> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency> </dependencies> <build> <sourceDirectory>src</sourceDirectory> <finalName>abc</finalName> <resources> <resource> <!--打包時排除資原始檔--> <directory>resources</directory> <excludes> <exclude>*.*</exclude> </excludes> </resource> </resources> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>2.4</version> <configuration> <warSourceDirectory>WebContent</warSourceDirectory> <failOnMissingWebXml>false</failOnMissingWebXml> <packagingExcludes>WEB-INF/lib/${project.artifactId}-${version}.jar</packagingExcludes> <!--將類檔案打成jar包--> <archiveClasses>true</archiveClasses> <!--將資原始檔打到classes目錄下--> <webResources> <resource> <directory>resources</directory> <targetPath>WEB-INF/classes</targetPath> <filtering>true</filtering> </resource> </webResources> </configuration> </plugin> <!-- BEGIN OBFUSCATE --> <plugin> <groupId>com.idfconnect.devtools</groupId> <artifactId>idfc-proguard-maven-plugin</artifactId> <version>1.0.1</version> <executions> <execution> <phase>prepare-package</phase> <goals> <goal>obfuscate</goal> </goals> </execution> </executions> <configuration> <options> <repackageclasses>com.idfconnect.sample.obfuscated</repackageclasses> </options> <inputFile>${project.build.outputDirectory}</inputFile> <inputFileFilter>**.class</inputFileFilter> <outputArtifacts> <outputArtifact> <file>${project.build.finalName}/WEB-INF/lib/${project.build.finalName}.jar</file> <type>jar</type> </outputArtifact> </outputArtifacts> <libraryArtifacts> <libraryArtifact>junit:junit:4.11</libraryArtifact> </libraryArtifacts> <libraryJarPaths> <libraryJarPath>${java.home}/lib/jsse.jar</libraryJarPath> </libraryJarPaths> <proguardIncludeFile>${basedir}/resources/${project.artifactId}-maven.pro</proguardIncludeFile> </configuration> <dependencies> <dependency> <groupId>net.sf.proguard</groupId> <artifactId>proguard-base</artifactId> <version>5.0</version> </dependency> </dependencies> </plugin> <!-- END OBFUSCATE --> </plugins> </build> </project>
pom.xml裡配置三個外掛如上所示:
1.maven-compiler-plugin: 就是配置一下專案用到的編譯器版本,沒什麼好說的。
2.idfc-proguard-maven-plugin: 就是proguard在maven下的一個外掛。注意,這個外掛只能混淆.class檔案。只能生成jar包不能生成war包。就是說我們只能先把.class檔案混淆優化後打成一個jar包,然後利用maven-war-plugin外掛將專案打成一個war包。 所以execution裡的<phase>要配置成prepare-package而不是package。<outputArtifact>裡要配置輸出的檔案型別是jar包。prepare-package
注意我們要用<proguardIncludeFile>${basedir}/resources/${project.artifactId}-maven.pro</proguardIncludeFile>指出優化選項檔案所在的位置。 它有預設的位置,但是我們的maven檔案結構是精簡後的,所以需要明確指出。
我們這個專案的artifactId 是
<artifactId>Struts2Spring4Hibernate4XML</artifactId>
所以${project.artifactId}-maven.pro 就是Struts2Spring4Hibernate4XML-maven.pro。 當然也可以改成其他名字,這裡這樣寫是防止專案的artifactId改名字了。
<inputFile> :輸入檔案,表示哪個路徑下的.class檔案要被混淆優化,就是maven編譯後的輸出路徑。<libraryArtifact>: generate additional injars input entries to ProGuard from the project artifacts.(我的理解是通過artifactId的方式指出需要加入混淆的jar包)
<InputJarPaths>: Additional external (e.g. non-artifact) input to include to Proguard as injars parameters (我的理解是通過指定路徑的方式指出需要加入混淆的jar包)
3.maven-war-plugin: 下面的這幾個配置至關重要。
<packagingExcludes>WEB-INF/lib/${project.artifactId}-${version}.jar</packagingExcludes>
指定打war包時排除的某些jar包。
將我們的.class檔案打成一個jar包。
<archiveClasses>true</archiveClasses>
將資原始檔放在WEB-INF/classes目錄下。
<webResources>
</span><resource>
</span><directory>resources</directory>
</span><targetPath>WEB-INF/classes</targetPath>
</span><filtering>true</filtering>
</span></resource>
</webResources>
打jar包時,忽略掉resources資料夾下的所有檔案。 這個是為了實現jar包裡只有.class檔案。配置檔案都在WEB-INF/class下的同級目錄裡。
<sourceDirectory>src</sourceDirectory>
<finalName>abc</finalName>
<resources>
<resource>
</span><!--打包時排除資原始檔-->
</span><directory>resources</directory>
</span><excludes>
</span><exclude>*.*</exclude>
</span></excludes>
</resource>
</resources>
但是為什麼要排除掉WEB-INF/lib/${project.artifactId}-${version}.jar 這個jar包呢? idfc-proguard-maven-plugin已經為我們生成了一個abc.jar了,為什麼還要在maven-war-plugin裡設定archiveClasses為true呢?
如果不設定這些,我們看看是什麼效果:
看到沒有,如果不設定archiveClasses為true. maven只會把混淆前的檔案直接部署到WEB-INF/classes目錄下。但是lib裡已經有一個abc.jar了。abc.jar就是混淆後的.class檔案。這跟WEB-INF/classes下的.class檔案重複了。
注意,注意,如果沒有配置archiveClasses為true。maven只會把編譯後的檔案部署到WEB-INF/classes目錄下,不會生成Struts2Spring4Hibernate4XML-0.0.1-SNAPSHOT.jar 這個jar包。 上圖中之所以會出現,應該是我沒有maven update,clean的原因。 我在這裡卡了很長時間。 所以強烈建議大家。每改一次 pom.xml就maven >> update project一下,然後 project >> clean. 每次mvn clean, mvn package要 重新整理下專案。 切記,這些操作看似煩人,但是不能省。我就是因為這個原因,結果第二天重啟機器再次嘗試時才發現的。我以為自己固態硬碟,速度快,反覆讀寫也不會有事,事實上並不是這樣。反編譯工具jd-gui最好每次用完就關閉,然後重新開啟。 不要嫌麻煩,嫌慢。 慢是機器的原因,我就是受不了自己的筆記本速度慢,才買了個桌上型電腦的。
所以我們要設定archiveClasses為true。這樣就會把混淆優化前的.class檔案打成一個jar包(Struts2Spring4Hibernate4XML-0.0.1-SNAPSHOT.jar), 而不是把這些.class檔案部署到WEB-INF/classes目錄下。
但是lib裡已經有一個abc.jar了。所以我們要配置packagingExcludes把Struts2Spring4Hibernate4XML-0.0.1-SNAPSHOT.jar這個Jar包排除掉,因為我們只需要一個混淆後的abc.jar就行了。
可能說的比較囉嗦,小結上面的一小段話: 配置<archiveClasses>true</archiveClasses>就是不讓WEB-INF/classes下出現未經過混淆優化的.class檔案。配置 packagingExcludes是為了把Struts2Spring4Hibernate4XML-0.0.1-SNAPSHOT.jar這個jar包排除掉。因為我們只需要經過混淆優化後的檔案abc.jar 就行了。
最終的效果就是這樣的:
pom.xml裡說的差不多了,下面就說說我們的優化配置檔案 .pro檔案
#保留除錯資訊(異常資訊原始碼行數)
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
#混淆時不要形成混合大小寫類名
-dontusemixedcaseclassnames
#保留除錯級別的屬性
#-keepparameternames
# 保留註解資訊,簽名信息,異常資訊,內部類資訊
-keepattributes *Annotation*,Signature,Exceptions,InnerClasses
#指定混淆時方法和屬性名替換字典檔案
#-obfuscationdictionary shakespeare.txt
#-keep class net.codejava.framework.action.**{*;}
#-keep class net.codejava.framework.dao.**{*;}
#-keep class net.codejava.framework.model.**{*;}
-keep public class * {
public protected *;
}
-keepnames class net.codejava.framework.action.**{
<fields>;
<methods>;
}
-keepnames class net.codejava.framework.dao.**{
<fields>;
<methods>;
}
-keepnames class net.codejava.framework.model.**{
<fields>;
<methods>;
}
#保留列舉類方法
-keepclassmembers,allowoptimization enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
#保留所有實現序列化的類的素有屬性
-keepclassmembers class * implements java.io.Serializable {
private <fields>;
}
-printusage aaa.txt
#優化時允許訪問並修改有修飾符的類和類的成員
-allowaccessmodification
#混淆時應用侵入式過載
-overloadaggressively
#確定統一的混淆類的成員名稱來增加混淆
-useuniqueclassmembernames
這裡每一句上都有註釋,比較簡單。 我就說下注意點: keepnames和keepattributes
names:就是我們熟知的方法名,field名等。
keepattributes,官網裡有說明,一般都加上的。 如何配置.pro檔案,請參考官網文件: http://proguard.sourceforge.net/
keepnames表示哪些name不需要改名字。 這個根據你的需求決定要不要保留原有的名稱。
有些欄位,比如action裡的userService屬性。JSP裡EL表示式引用的一些欄位。 它們的名字被改掉時, 只要getter和setter沒有變。就可以保證程式碼的正確執行。
一定要注意,這些名稱跟xml檔案或者jsp頁面有互動。所以優化它們時要特別小心。
下面舉個例子,看看優化效果到底如何。這是我故意加的垃圾程式碼:
私有變數和方法都被優化掉了。
<fields>;
<methods>;
}
所以action裡的變數名沒有被混淆成a,b,c...。
總結:
現在混淆和優化的程度取決於你對.pro檔案配置的理解程度。 多動手寫一些垃圾程式碼試一試,看看到底能優化到什麼程度,別忘了經常update,clean,refresh。
這個配置理解起來比較簡單,主要是多嘗試。 個人覺得難點就是 打war包的時候會有些小麻煩。網上關於這個的文章比較少,說的也不清楚。總結了一下個人經驗,希望對你有幫助。希望你能成為一個會精簡maven專案檔案結構,會做混淆優化的猿兒而不只是編碼。