1. 程式人生 > >使用idfc-proguard-maven-plugin混淆優化Jave Web工程二

使用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

 在真正的打包之前,執行一些準備打包必要的操作,這裡就是做混淆優化處理。注意<inputFileFilter>是過濾出哪些檔案打包到jar包裡。此時我們的專案裡.hbm.xml是放在resources資料夾下的。我們希望生成的 jar包裡只有.class檔案裡。資原始檔都在WEB-INF/classes下同級目錄裡。 所以這裡配置成**.class。表示任意包下的所有.class檔案都打包進jar包裡。 如果.hbm.xml檔案和Java檔案在一個地方。這裡就不能配置inputFileFilter為**.class了。

注意我們要用<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頁面有互動。所以優化它們時要特別小心。

下面舉個例子,看看優化效果到底如何。這是我故意加的垃圾程式碼:


私有變數和方法都被優化掉了。



看方法cde裡。變數j直接用立即數來替換了,方法裡的引數名也被換掉了。 注意因為配置了-keepnames class net.codejava.framework.action.**{
<fields>;
<methods>;
}

所以action裡的變數名沒有被混淆成a,b,c...。



總結:

現在混淆和優化的程度取決於你對.pro檔案配置的理解程度。 多動手寫一些垃圾程式碼試一試,看看到底能優化到什麼程度,別忘了經常update,clean,refresh。

這個配置理解起來比較簡單,主要是多嘗試。 個人覺得難點就是 打war包的時候會有些小麻煩。網上關於這個的文章比較少,說的也不清楚。總結了一下個人經驗,希望對你有幫助。希望你能成為一個會精簡maven專案檔案結構,會做混淆優化的猿兒而不只是編碼。