Maven项目混淆、瘦身、打包exe
项目混淆
ProGuard 是一个混淆代码的开源项目,它的主要作用是混淆代码,ProGuard 包括以下 4 个功能:
-
压缩(Shrink):检测并移除代码中无用的类、字段、方法和特性(Attribute)
-
优化(Optimize):对字节码进行优化,移除无用的指令
-
混淆(Obfuscate):使用 a,b,c,d 这样简短而无意义的名称,对类、字段和方法进行重命名
-
预检(Preveirfy):在 Java 平台上对处理后的代码进行预检,确保加载的 class 文件是可执行的
使用 proguard 混淆代码只能增加阅读和理解的难度, 并不能百分百保证代码安全。常用的应用场景是项目需要部署到客户机器上,一定程度上防止代码泄露
具体实现
1.在原本的SpringBoot项目的pom.xml文件里面加上以下配置
<!--经过修改后,能够混淆的build段-->
<build>
<plugins>
<!--maven打包插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.mmg.Main</mainClass> <!-- 此处为主入口-->
</manifest>
</archive>
</configuration>
</plugin>
<!--proguard混淆插件-->
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<version>2.5.3</version>
<executions>
<execution>
<!--打包的时候开始混淆-->
<phase>package</phase>
</execution>
</executions>
<configuration>
<proguardVersion>${proguard.version}</proguardVersion>
<injar>${project.build.finalName}.jar</injar>
<!--输出的jar-->
<outjar>${project.build.finalName}.jar</outjar>
<!--是否混淆-->
<obfuscate>true</obfuscate>
<proguardInclude>${basedir}/proguard.cfg</proguardInclude>
<options>
<!--默认开启,不做收缩(删除注释、未被引用代码)-->
<option>-dontshrink</option>
<!--默认是开启的,这里关闭字节码级别的优化-->
<option>-dontoptimize</option>
<!--对于类成员的命名的混淆采取唯一策略-->
<option>-useuniqueclassmembernames</option>
<!--混淆时不生成大小写混合的类名,默认是可以大小写混合-->
<option>-dontusemixedcaseclassnames</option>
<!--混淆类名之后,对使用Class.forName('className')之类的地方进行相应替代-->
<option>-adaptclassstrings</option>
<!--对异常、注解信息在runtime予以保留,不然影响springboot启动-->
<option>-keepattributes
Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
</option>
<!--此选项将保存接口中的所有原始名称(不混淆)-->
<option>-keepnames interface ** { *; }</option>
<!--此选项将保存所有软件包中的所有原始接口文件(不进行混淆)-->
<!--<option>-keep interface * extends * { *; }</option>-->
<!--此选项将保留所有原始方法参数,controller如果参数也混淆会导致传参映射不上 -->
<option>-keepparameternames</option>
<!--保留枚举成员及方法-->
<option>-keepclassmembers enum * { *; }</option>
<!--不混淆所有类,保存原始定义的注释-->
<!--<option>-keepclassmembers class * {
@org.springframework.context.annotation.Bean *;
@org.springframework.beans.factory.annotation.Autowired *;
@org.springframework.beans.factory.annotation.Value *;
@org.springframework.stereotype.Service *;
@org.springframework.stereotype.Component *;
}
</option>-->
<!--忽略warn消息-->
<option>-ignorewarnings</option>
<!--忽略note消息-->
<option>-dontnote</option>
</options>
<!--java 11-->
<libs>
<lib>${java.home}/jmods/</lib>
</libs>
<!--java 8-->
<!-- <libs>
<lib>${java.home}/lib/rt.jar</lib>
<lib>${java.home}/lib/jsse.jar</lib>
</libs>-->
</configuration>
<dependencies>
<dependency>
<groupId>com.guardsquare</groupId>
<artifactId>proguard-base</artifactId>
<version>7.2.1</version>
</dependency>
</dependencies>
</plugin>
<!--将自己加入的jar也打包插件 可加可不加-->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.mmg.Main</mainClass>
</manifest>
<manifestEntries>
<Class-Path>.</Class-Path>
</manifestEntries>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
2.在与pom.xml文件同级目录下新建一个proguard.cfg文件,这个文件是混淆的核心配置文件,根据需求进行配置
#所有类(包括接口)的方法参数不混淆(包括没被keep的),如果参数混淆了,mybatis的mapper参数绑定会出错(如#{id})
-keepattributes MethodParameters
#入口程序类不能混淆,混淆会导致springboot启动不了
-keep class com.langyastudio.edu.admin.Application {
public static void main(java.lang.String[]);
}
#mybatis的mapper/实体类不混淆,否则会导致xml配置的mapper找不到
-keep class com.langyastudio.edu.admin.dao.*
-keeppackagenames com.langyastudio.edu.admin.dao
#考虑到scanBasePackages,需要包名不被修改
-keeppackagenames com.langyastudio.edu
-keeppackagenames com.langyastudio.edu.admin.common
#一些配置类比如datasource,aopconfig如果混淆会导致各种启动报错
# 比如用@Pointcut("execution(public * com.langyastudio.edu.*.controller..*.*(..))")
# 指定webLog方法对应的@Pointcut作为切入点,所以包的名字不能修改
-keeppackagenames com.langyastudio.edu.*.controller.**
-keep class com.langyastudio.edu.admin.config.*
#保留Serializable序列化的类不被混淆
#例如传入/输出的Bean属性
-keepclassmembers class * implements java.io.Serializable {*;}
#保留空的构造函数
#-keepclassmembers class com.hacfin.* {
# public <init>(...);
#}
3.点击maven生命周期中的package将项目进行打包,然后点击maven插件中的proguard插件对打出来的jar进行混淆。值得注意的是,如果你使用将自己加入的jar也打包插件,他会把加入自己jar包的命名为xxxxx-jar-with-dependencies.jar,而混淆只能混淆原jar包,这时候需要你把xxxxx-jar-with-dependencies.jar修改为正常打包出来的jar名字(xxx-1.0-SNAPSHOT),不然会混淆不了
项目瘦身
什么是瘦身?
瘦身: thin Body 又称 "减肥"、"减重"。 就是合理、科学的减轻自身重量的。SpringBoot 应用瘦身顾名思议:就是将 SpringBoot 应用打包的 jar 利用合理的方式、方法减小体积。
为什么要瘦身?
场景: 现有的应用开发中,不论是单体架构、微服务架构,如果项目采用的是 springboot、springcloud 来作为底层框架,打包时最终都会以jar包的方式打包、部署。这是就会面临一个问题,就是 jar 包非常大,单体应用还好,但是如果是微服务就非常痛苦,几十个微服务就要拆分打包几十个 jar 包,每个 jar 包都很大(几百M),合起来就好几个 GB,非常占用空间。如果是内网部署,遇到动辄GB的升级包还能勉强接受,最多就是运维心里默默地吐槽一下,但是如果在外网云环境、或者客户现场,那令人痛不欲生的带宽加上各种网络转换限制,运维心里各种🐴。因为这个你的领导又给你各种批头盖脸一顿。
如何瘦身?
瘦身思路:
其实就是将你自己写的代码和引入依赖包进行分离操作,它并不能改变项目总体的大小,但是它方便你日后对项目进行升级操作,日后只需要换jar就可以了,不需要动固定引入依赖jar包文件夹。
具体实现
1.在原本的SpringBoot项目的pom.xml文件里面加上以下配置
<!--经过修改后,能够瘦身的build段-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
<finalName>${project.build.finalName}</finalName>
<!--解决windows命令行窗口中文乱码-->
<jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
<layout>ZIP</layout>
<includes>
<!--这里是填写需要包含进去的jar,
必须项目中的某些模块,会经常变动,那么就应该将其坐标写进来
如果没有则non-exists ,表示不打包依赖
-->
<include>
<groupId>non-exists</groupId>
<artifactId>non-exists</artifactId>
</include>
</includes>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 此插件用于将依赖包抽出-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<!--抽出到哪个目录,${project.build.directory}表示当前项目构建的目录-->
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<!--是否排除传递性-->
<excludeTransitive>false</excludeTransitive>
<!--是否去掉 jar 包版本信息-->
<stripVersion>false</stripVersion>
<!--包含范围-->
<includeScope>runtime</includeScope>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
2.经过以上操作你再进行项目打包后,你的项目将会分为自己写的代码jar包和分离出来的jar包目录,到这还没结束,需要配合以下参数启动项目才行。
java -Dloader.path=./lib -jar xxx.jar
项目打包exe
可以使我们的项目直接由jar包打包成exe可执行程序
具体实现
第一种实现方式
正常将我们的项目打成jar包,打包好以后先打开看一下确保可以正确执行
2.在当前目录加入以下脚本对jar包进行打包,根据自己的jar包名称对以下脚本进行修改即可!全部修改完成,双击此bat脚本即可
@echo off
echo package current jar to exe
set USE_JAR=PackageExe-1.0-SNAPSHOT.jar
set USE_CONFIG=config
set APP_CLASS=
set APP_NAME="SpringBootTest"
set OUT_FILE="SpringBootTest"
set TITLE="SpringBootTestDemo"
javapackager -deploy -native -outdir packages -outfile %OUT_FILE% -srcfiles %USE_JAR% -appclass org.springframework.boot.loader.JarLauncher -name %APP_NAME% -title %TITLE%
pause
第二种实现方式
1.在原本的SpringBoot项目的pom.xml文件里面加上以下配置,一样的道理根据自己的情况进行修改!
<!--经过修改后,能够打包exe的build段-->
<build>
<plugins>
<plugin>
<groupId>io.github.fvarrui</groupId>
<artifactId>javapackager</artifactId>
<version>1.7.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>package</goal>
</goals>
<configuration>
<!-- 修改点1:自己的main方法主类 -->
<mainClass>com.mmg.mainClass</mainClass>
<!-- optional -->
<bundleJre>true</bundleJre>
<!-- 修改点2:本机的jdk所在目录路径 -->
<jrePath>E:\Java\jdk1.8.0_351</jrePath>
<generateInstaller>true</generateInstaller>
<administratorRequired>true</administratorRequired>
<!-- <platform>auto|linux|mac|windows</platform> -->
<platform>windows</platform>
<additionalResources>
<!-- <additionalResource>file path</additionalResource>
<additionalResource>folder path</additionalResource>
<additionalResource>...</additionalResource> -->
</additionalResources>
<!-- <linuxConfig>...</linuxConfig>
<macConfig>...</macConfig> -->
<winConfig>
<!-- 修改点3:生成后的exe文件的图标文件所在路径 -->
<icoFile>E:\Desktop\PackageExe\bizui.ico</icoFile>
<generateSetup>true</generateSetup>
<generateMsi>true</generateMsi>
<generateMsm>true</generateMsm>
<!-- 以下的想修改就修改,不影响 -->
<headerType>gui</headerType>
<companyName>木芒果</companyName>
<fileVersion>1.0.0.0</fileVersion>
<txtFileVersion>${version}</txtFileVersion>
<productVersion>1.0.0.0</productVersion>
<txtProductVersion>${version}</txtProductVersion>
<fileDescription>${description}</fileDescription>
<copyright>木芒果</copyright>
<productName>${name}</productName>
<internalName>${name}</internalName>
<!-- <originalFilename>${name}.exe</originalFilename> -->
<originalFilename>${name}.exe</originalFilename>
<!-- installer generation properties -->
<disableDirPage>true</disableDirPage>
<disableProgramGroupPage>true</disableProgramGroupPage>
<disableFinishedPage>true</disableFinishedPage>
<createDesktopIconTask>true</createDesktopIconTask>
<!-- enables/disables installers generation -->
<generateSetup>true</generateSetup>
<generateMsi>true</generateMsi>
</winConfig>
<!-- [...] -->
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
2.双击package打包按钮,他就会根据你的配置生成对应的目录,目录内含有exe文件和jdk运行环境
总结
1.代码混淆使用的是ProGuard开源项目的插件
2.项目瘦身采用的是将jar包和依赖项分离
3.打成exe可执行文件使用的是javapackager