用proguard混淆jar包之后,启动就报如下错误:
Exception in thread "main" java.lang.VerifyError: Bad return type
Exception Details:
Location:
aaa/bbb/ccc/ddd/eee/e/c.openConnection(Ljava/net/URL;)Ljava/net/URLConnection; @80: areturn
Reason:
Type 'java/lang/Object' (current frame, stack[0]) is not assignable to 'java/net/URLConnection' (from method signature)
Current Frame:
bci: @80
flags: { }
locals: { }
stack: { 'java/lang/Object' }
Bytecode:
0x0000000: b200 20bb 0014 59b7 0029 1203 b600 2a2b
0x0000010: b600 2eb6 002a b600 2cb6 0025 2a2b b700
0x0000020: 314d 2ab4 001f 2bb6 002e b900 3502 0099
0x0000030: 0020 2cc1 0016 9900 19bb 0008 592c c000
0x0000040: 162a b400 1d2a b400 1eb7 0021 a700 042c
0x0000050: b0
Stackmap Table:
full_frame(@79,{Top,Top,Object[#24]},{})
full_frame(@80,{},{Object[#18]})
at aaa.bbb.ccc.ddd.eee.e.a.<init>(XxxxClassLoader.java:41)
at aaa.bbb.ccc.ddd.eee.e.f.createClassLoader(XxxxxLauncher.java:32)
at org.springframework.boot.loader.Launcher.createClassLoader(Launcher.java:64)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:49)
at aaa.bbb.ccc.ddd.eee.e.f.a(XxxxLauncher.java:27)
at aaa.bbb.ccc.ddd.eee.e.f.main(XxxxLauncher.java:23)
这就很尴尬。。。在网上搜了下,java.lang.VerifyError: Bad return type这种错误引起的原因是:
JVM 在加载一个类时,会去校验类的正确性,只有类文件不合法才会报这个Error。
找了一圈,没找到相关答案,基本上都是说是版本,jar包重复什么的引起的,问题是我这根本就不存在这两个问题。。在官方issues里搜到了一堆相关的问题,和我的错误都差不多
搞了一天无果,在晚上的时候找到了解决方法。。
从错误日志中发现了问题,在如下行异常中:
at aaa.bbb.ccc.ddd.eee.e.a.<init>(XxxxClassLoader.java:41)
用Bytecode-Viewer打开混淆之后的jar,与没混淆的jar包,之间做了下对比,发现了其中的秘密:
aaa/bbb/ccc/ddd/eee/e/c.openConnection(Ljava/net/URL;)Ljava/net/URLConnection; @80:
Reason:
Type 'java/lang/Object' (current frame, stack[0]) is not assignable to 'java/net/URLConnection' (from method signature)
需要的是URLConnection,给的却是Object,所以导致了异常,这肯定是混淆引起的,调整proguard配置,以下是我这边调整后能用的:
<!-- proguard混淆插件-->
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<version>2.5.3</version>
<executions>
<execution>
<!-- 打包的时候开始混淆-->
<phase>package</phase>
<goals>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
<injar>${project.build.finalName}.jar</injar>
<outjar>${project.build.finalName}.jar</outjar>
<obfuscate>true</obfuscate>
<putLibraryJarsInTempDir>true</putLibraryJarsInTempDir>
<options>
<option>-target 1.8</option>
<option>-dontnote</option>
<option>-dontshrink</option>
<option>-dontoptimize</option>
<option>-adaptclassstrings</option>
<option>-ignorewarnings</option>
<option>-dontskipnonpubliclibraryclasses</option>
<option>-dontskipnonpubliclibraryclassmembers</option>
<option>-dontusemixedcaseclassnames</option>
<option>-keepdirectories</option>
<option>-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,LocalVariable*Table,*Annotation*,Synthetic,EnclosingMethod</option>
<option>-keepclassmembers enum * { *; }</option>
<option>-keepparameternames</option>
<option>-flattenpackagehierarchy aaa.fffff.xxxx.ddd.aaa</option>
<option>
-keepclassmembers class *{
public static void main(java.lang.String[]);
}
</option>
</options>
<libs>
<!-- 添加依赖 java8-->
<lib>${java.home}/lib/rt.jar</lib>
<lib>${java.home}/lib/jce.jar</lib>
</libs>
</configuration>
</plugin>
用上面的配置打包完成的jar包字节码如下: