背景概述
因为自己本身是做互联网金融业务,平时会对接比较多的银行,最近对接的一家给的加解密包,版本比较低导致在现有项目中不能使用,bcprov-jdk16-1.46.jar (12年的包),直接在现有项目中引入的话,直接报错。
Exception in thread "main" java.lang.IllegalAccessError: tried to access method
org.bouncycastle.math.ec.ECPoint$Fp.<init>(Lorg/bouncycastle/math/ec/ECCurve;Lorg/bouncycastle/math/ec/ECFieldElement;
Lorg/bouncycastle/math/ec/ECFieldElement;)V from class SM2Utils.SM2 at SM2Utils.
SM2.<init>(SM2.java:51) at SM2Utils.SM2.Instance(SM2.java:36) at
SM2Utils.SM2SignUtils.sign(SM2SignUtils.java:120) at EncryptUtils.EncryptUtils.encryptText(EncryptUtils.java:22) at
大概错误信息如下 非法的访问错误,尝试访问xxx.下的方法,失败了,仔细想下为什么,看了源码之后才发现原来项目中依赖传递直接使用的是高版本的bcprov包,所以导致低版本的jar不会被引入到其中。具体原因就是同一个jar中出现,包名+类名 在类加载的时候,因为双亲委派机制只会加载一次,而加载进来的正好是高版的的jar,并且高版本中不兼容低版本所以问题就出现。
画一个图如下,
解决方案1(尝试不同版本的jar)
所以可以看出来,解决办法,刚开始的时候是想办法通过bcprov包其他版本看是否可以兼容低版本的bcprov-jdk16-1.46版本。发现基本上都试了一下。都不可以使用。
解决方案2(手动升级jar)
https://qxlxi.blog.csdn.net/article/details/122419383
然后在同事的提示下说可以尝试将资方给的加解密包进行手动升级,新建一个项目,然后把依赖的bcprov-jdk16-1.46升级到bcprov-jdk15to18-1.68 版本,然后重新升级之后发现,加解密是没有问题的,验签的话出现问题,不能使用
解决方案3 (maven-shade-plugin)
既然重写资方的jar不能使用,那么有没有高低版本可以在项目中直接使用的相关配置呢,于是查到有这种方式。
https://segmentfault.com/a/1190000038382111 具体可以文章。
相关配置如下
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<!-- Maven 的生命周期 -->
<phase>package</phase>
<goals>
<!-- 插件目标 -->
<goal>shade</goal>
</goals>
<configuration>
<!-- <minimizeJar>true</minimizeJar>-->
<!-- 配置多版本 jar 包中类路径的重命名
-->
<relocations>
<relocation>
<pattern>org.bouncycastle</pattern>
<shadedPattern>org.new.bouncycastle</shadedPattern>
</relocation>
</relocations>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
配置如何设置为true的话,在maven私服不能打包。需要删除。
<dependency>-->
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.0.1</version>
</dependency>
jar中还包含其他的包,直接打入项目中,发现对一些类会有冲突,还是因为类加载机制的原因,只会加载一个类。所以删除无用的包。
重新打包,发现可以在测试环境和本地可以使用。
总结:
1.遇到问题不能慌张,需要慢慢分析出问题的来龙去脉,找到具体的原因。
2.jar冲突的问题,a.我们可以直接使用maven-helper进行直接jar冲突解决,但是对于高低版本不兼容的情况下,需要使用maven的插件进行解决。
具体的使用,https://maven.apache.org/plugins/maven-shade-plugin/shade-mojo.html
https://blog.csdn.net/yangguosb/article/details/80619481
参考文章
1.https://blog.csdn.net/yangguosb/article/details/80619481
2.https://www.playpi.org/2019120101.html
3.https://maven.apache.org/plugins/maven-shade-plugin/
4.https://xie.infoq.cn/article/5a18670154051e26591e2090f
原理
既然通过重命名jar包可以同一个项目中加载相同的jar不同版本,具体是什么原理呢,将打的包进行javap -c 看到后就恍然大雾。
原来,在生成的.class字节码文件中编译,构建包的时候替换成了新的包名,所以记载的时候相同jar不同版本就可以加载了。比较神奇,牛。
转载请注明:【复盘】bcprov-jdk16包冲突问题(不同版本jar兼容) 以及 maven-shade-plugin的使用 | 胖虎的工具箱-编程导航