这篇文章运用简单易懂的例子给大家介绍使用SpringBoot实现结合ProGuard,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。
1.maven的配置
具体配置如下:
<build> <finalName>${artifactId}</finalName> <plugins> <plugin> <groupId>com.github.wvengen</groupId> <artifactId>proguard-maven-plugin</artifactId> <executions> <execution> <phase>package</phase> <goals><goal>proguard</goal></goals> </execution> </executions> <configuration> <proguardVersion>6.2.2</proguardVersion> <injar>${project.build.finalName}.jar</injar> <outjar>${project.build.finalName}.jar</outjar> <!--<proguardInclude>${project.basedir}/proguard.cfg</proguardInclude>--> <obfuscate>true</obfuscate> <options> <!-- 不做收缩(删除注释、未被引用代码)--> <option>-dontshrink</option> <!-- 不做优化(变更代码实现逻辑)--> <option>-dontoptimize</option> <!--保持目录结构,否则spring的自动注入无法使用--> <!--<option>-keepdirectories</option>--> <option>-keepattributes Exceptions,InnerClasses,Signature,Deprecated, SourceFile,LineNumberTable, *Annotation*,EnclosingMethod </option> <option>-adaptclassstrings</option> <option> <!-- 保护程序入口 --> -keep class com.jingchen.ccny.CmepApplication { *; } </option> <option>-keepnames interface ** { *; }</option> <!-- 固定几个类不能混淆--> <option>-keepnames class com.jingchen.ccny.base.BaseService { *; }</option> <option>-keep class com.jingchen.ccny.common.cache.ConvertorNewCache { *; }</option> <option>-keep class com.jingchen.ccny.base.ControllerContext { *; }</option> <option>-keep class * extends com.jingchen.ccny.base.BaseService</option> <option>-keep class * implements com.jingchen.ccny.common.service.CallBackGuiService</option> <option>-keep class * implements com.jingchen.ccny.common.service.CallBackUDService</option> <option>-keep class com.jingchen.ccny.util.SpringUtil</option> <!--<option>-keep interface * extends * { *; }</option>--> <!-- 此选项将在所有包的所有类中保存所有原始定义的注释.--> <option> -keep class * { @org.springframework.beans.factory.annotation.Autowired *; @org.springframework.beans.factory.annotation.Value *; @org.springframework.stereotype.Service *; @org.springframework.stereotype.Component *; @org.springframework.scheduling.annotation.Scheduled *; } </option> </options> <libs> <!-- Include main JAVA library required.--> <lib>${java.home}/lib/rt.jar</lib> <lib>${java.home}/lib/jce.jar</lib> </libs> </configuration> <dependencies> <dependency> <groupId>net.sf.proguard</groupId> <artifactId>proguard-base</artifactId> <version>6.2.2</version> </dependency> </dependencies> </plugin> <!-- Maven assembly must be run after proguard obfuscation so it take already obfuscated files.--> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <goals> <goal>repackage</goal> </goals> <configuration> <mainClass>com.jingchen.ccny.CcnyApplication</mainClass> </configuration> </execution> </executions> </plugin> </plugins> </build>
这里里面级联引用的jar很多,建议配置了私服的人先把镜像地址配置成maven中央仓库地址,这样先下下来相关依赖的包,然后再上传到你们的私服上去。据我研究中知道的jar就有:
注意:不连外网配置maven中央仓库的话,少了jar你们会很头疼的。而且不止net.sf.proguard相关包,还包括了com.guardsquare.proguard-base 和 com.guardsquare.proguard-core 相关的jar,所以真的连外网下包很重要!!!!
推荐一个IDEA解决maven引用冲突的插件:Maven Helper
2.相关异常解决
idea A required class was missing … org/apache/tools/ant/BuildListener
问题原因:
这个问题就是上面提到的因为apache的编译用了一个ant-1.9.3的包,这个是级联引用的,开始我是内网maven私服,单纯的引入net.sf.proguard相关和com.github.wvengen相关的jar还是会缺少很多jar
解决方案:
连上外网,配置你的maven的setting.xml 的mirror镜像地址,配置成Maven中央仓库的地址,将相关的jar都下下来,然后再通过命令把你本地maven仓库的jar上传到私服去
Can't process class [META-INF/versions/9/org/apache/logging/log4j/util/Base64Util.class]
Can't process class [META-INF/versions/11/module-info.class]
问题原因
这个问题的原因有很多方面,最主要的就是我们的jdk版本是1.8,我最开始用的ProGuard是5.3.3版本,然而我们SpringBoot的版本是2.3.3版本,SpringBoot2.3.3版本太新了,里面引用的相关包都是java9和java11的版本,这样ProGuard在读jar的时候会无法识别。这些问题在提升Proguard版本到6.2.2之后都解决了
解决方案
开始我的解决方案是忽略这些相关的jar, 例如在pom.xml的option配置:
<option>-libraryjars ${settings.localRepository}/com/zaxxer/HikariCP/3.4.5/HikariCP-3.4.5.jar(META-INF/versions/11/module-info.class)</option>
但是我这样配置之后,重新打包会提示:
The same input jar [E:\maven\repo\com\zaxxer\HikariCP\3.4.5\HikariCP-3.4.5.jar] is specified twice.
解决方案:
而且我还尝试了maven引用的时候排除这些高版本的级联引用jar,单独引用低版本,但最终还是因为太繁琐而放弃了。直接提升Proguard版本到6.2.2 这些读jar的版本问题就解决了。Annotation-specified bean name ‘a' for bean class
问题原因:
出现这个问题主要还是混淆之后,bean重名了,spring默认是把类名的首字母小写加载到容器里面,我们混淆类名之后,就容易造成beanName重复。
解决方案:
庆幸的是,我们可以通过改变spring加载bean的命名策略来解决这个问题,把包名带上,同时在获取Spring上下文getBean的时候,加上包名路径即可
启动类配置,具体如下:
@SpringBootApplication public class CcnyApplication{ public static class CustomGenerator implements BeanNameGenerator { @Override public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { return definition.getBeanClassName(); } } public static void main(String[] args) { SpringApplicationBuilder sab=new SpringApplicationBuilder(CcnyApplication.class) .beanNameGenerator(new CustomGenerator()); //这里如果想打印你加载的Spring的bean,可以这样做: ApplicationContext ac =sab.run(args); Arrays.stream(ac.getBeanDefinitionNames()).forEach(System.out::println); } }
这样配置,你启动的时候就能看到加载的所有的beanName(这里Service会带上package路径)
其他地方getBean的用法:
//这里的packagePath = com.jingchen.ccny.service CallBackGuiService callBackGuiService = (CallBackGuiService) SpringUtil.getBean(packagePath+serviceName); callBackResult = callBackGuiService.excute(convertMap);
这样你就能正常的获取到Spring容器加载的beanName了
注意事项
基本上影响打包和启动的就上面一些问题了,其他的就是你们项目里面的细节了,
总的来说花了两天时间,有这样的成果也是值得高兴的,前一天解决jar冲突的比较多,主要原因就是最开始XX架构师搭建这个项目采用最新的SpringBoot版本,jdk确是1.8 , 很多不兼容。
来个最终的效果图吧:
关于使用SpringBoot实现结合ProGuard就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。