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文件复制进去即可。