解决NoSuchMethodError,maven的依赖冲突,jar包冲突,SecurityException,ExceptionInInitializerError问题。

遇到maven的依赖冲突三种主要解决方法:

1、当冲突两者其中一方兼容另外一方时,通过exclusions和exclusion标签解决。

2、当冲突两者互不兼容时,使用maven-shade-plugin管理插件解决。

3、覆盖jar包中的代码并结合反编译软件解决。

问题:第三方给的SDK加密包与我们工程中的这两个包的 org.bouncycastle.asn1.x9.X9IntegerConverter类冲突。

A.jar == national.secrets-2.0.0.jar

B.jar == bcprov-jdk15on-1.68.jar、bcpkix-jdk15on-1.68.jar

下文统一用A、B.jar代替。

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.68</version>
</dependency>
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpkix-jdk15on</artifactId>
    <version>1.68</version>
</dependency>

代码报错:

Caused by: java.lang.NoSuchMethodError: org.bouncycastle.asn1.x9.X9IntegerConverter.getByteLength(Lcom/xmsme/national/secrets/math/ec/ECFieldElement;)I
	at com.xmsme.national.secrets.math.ec.ECPoint$Fp.getEncoded(ECPoint.java:203)
	at com.xmsme.national.secrets.SM2Utils.encrypt(SM2Utils.java:73)
	at com.a.sunis.b.util.RequestUtil.getResData(RequestUtil.java:50)
	at com.a.sunis.b.controller.QueryInfoController.judgementDocuments(QueryInfoController.java:29)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

在这里插入图片描述

初步判断:

1.对方给的A.jar包有问题。

2.我们项目中的B.jar包和A.jar包冲突了。

首先新建一个项目,导入A.jar,把在我们项目中报错的那行代码放到新项目中,发现运行正常。

所以排除第一种情况对方给的A.jar包有问题。

既然是jar包冲突,我就用Maven Helper插件,进行依赖分析。

在这里插入图片描述
在这里插入图片描述

结果如图,并没有发现A.jar和其他jar存在冲突的问题。

然后,我就自己胡搞,把报错的那几个类从A.jar包class文件中反编译成java类,放到自己项目中,包名类名都保持一致,

看看能否发现问题。(还是经验不足,不然应该能直接知道是ECPoint类调用X9IntegerConverter类getByteLength方法这块有问题。)

然后就打断点,在这几个源码类中一行一行往下运行。

在这里插入图片描述

最终发现在ECPoint类里发现,这个方法的参数类型有问题。
在这里插入图片描述
在这里插入图片描述

那么为什么它这个参数类型不对呢,是调用的时候填的这个this.x参数类型不对,还是X9IntegerConverter.getByteLength的形参类型有问题。

答案是X9IntegerConverter.getByteLength的形参类型有问题,但并不是A.jar包中的X9IntegerConverter.getByteLength的形参类型有问题,而是B.jar包中的X9IntegerConverter.getByteLength的形参类型有问题。也不能说有问题,只是说A.jar包的ECPoint类应该要去调用A.jar包里的org.bouncycastle.asn1.x9.X9IntegerConverter类的getByteLength方法,但是因为 某些原因 去调用了B.jar包里的org.bouncycastle.asn1.x9.X9IntegerConverter类的getByteLength方法,但是这两个方法的形参类型不同,如下图,所以才发生了错误。

这个某些原因我暂时认为是在pom.xml中,B.jar包的依赖引入在A.jar包上面,maven的仲裁机制会按照路径最短原则,或者是最先声明原则,所以在A.jar包想调用同包名同类名的X9IntegerConverter类的getByteLength方法时会选择B.jar包中的X9IntegerConverter类的getByteLength方法。(这个某些原因的解释有待商榷,仅供参考。只是我暂时这么理解的。)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在我中间胡搞覆盖源码的时候把ECPoint,X9IntegerConverter 类从源码中提取出来,就报这么一个错。

org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.ExceptionInInitializerError
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1055)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:497)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:584)
	at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
	at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:92)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
	at com.a.sunis.support.XssSqlFilter.doFilter(XssSqlFilter.java:28)
	at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
	at com.a.sunis.support.RepeatFlowFilter.doFilter(RepeatFlowFilter.java:28)
	at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
	at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:97)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
	at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
	at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
	at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
	at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
	at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
	at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:111)
	at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
	at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
	at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
	at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
	at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:269)
	at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:78)
	at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:133)
	at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130)
	at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
	at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
	at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:249)
	at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:78)
	at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99)
	at io.undertow.server.Connectors.executeRootHandler(Connectors.java:390)
	at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:836)
	at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
	at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2019)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1558)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1423)
	at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.ExceptionInInitializerError
	at com.xmsme.national.secrets.math.ec.ECCurve$Fp.<init>(ECCurve.java:46)
	at com.xmsme.national.secrets.SM2.<init>(SM2.java:62)
	at com.xmsme.national.secrets.SM2.Instance(SM2.java:35)
	at com.xmsme.national.secrets.SM2Utils.encrypt(SM2Utils.java:64)
	at com.a.sunis.b.util.RequestUtil.getResData(RequestUtil.java:50)
	at com.a.sunis.b.controller.QueryInfoController.judgementDocuments(QueryInfoController.java:29)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
	... 61 more
Caused by: java.lang.SecurityException: class "org.bouncycastle.asn1.x9.X9IntegerConverter"'s signer information does not match signer information of other classes in the same package
	at java.lang.ClassLoader.checkCerts(ClassLoader.java:898)
	at java.lang.ClassLoader.preDefineClass(ClassLoader.java:668)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:761)
	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
	at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
	at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	at com.xmsme.national.secrets.math.ec.ECPoint.<clinit>(ECPoint.java:18)
	... 78 more

主要就是这句话给了我改包名的灵感。

Caused by: java.lang.SecurityException: class “org.bouncycastle.asn1.x9.X9IntegerConverter”'s signer information does not match signer information of other classes in the same package

我就把X9IntegerConverter类改了包名,并且把A.jar用到X9IntegerConverter类的ECPoint类也改了导入的X9IntegerConverter类的包名。这样我就覆盖了A.jar包中X9IntegerConverter和ECPoint类,让ECPoint类能调用到正确的X9IntegerConverter类的getByteLength方法。然后我重新启动项目,发现不报错了。

在这里插入图片描述
在这里插入图片描述

这就是我乱搞之后想到的第一种解决办法。(这种可以用,但是不太保险不太友好,因为你不知道A.jar包内部的类还有没有其他地方用到了这个X9IntegerConverter类。但是可以通过一些方式来保证这种方式的可靠性。比如,1、用class反编译软件,像jd-gui这种,打开A.jar,搜索X9IntegerConverter,这样就可以看到所有引用X9IntegerConverter类的地方,这种方式来保证我们自己手动覆盖代码的可靠性。2、在自己项目中把用到A.jar包的地方的代码都过一遍,看看是否有问题,多测测。3、如果A.jar包中类较少的话可以从IDEA中翻翻,还有C类用到X9IntegerConverter类,就把C类也拿到自己项目中改导入X9IntegerConverter类的包名进行覆盖。)

在这里插入图片描述

然后我又去查资料看看有没有其他解决办法,我的问题主要是jar隔离这个方向的。

期间试了exclusions和exclusion标签来解决,但是不管用。

jar包隔离的几种方式,参考了这位大佬的博客。https://blog.csdn.net/qq_37527921/article/details/102839369

1、spring boot方式,统一管理各个组件版本,简洁高效,但遇到必须使用不同版本jar包时,就不行了
2、OSGI技术,用容器对jar包进行暴露和隔离,实际上是通过不同classload加载类来达到目的,真正的jar包隔离,还能做模块化,服务热部署,热更新等,缺点就是太重了。
3、sofa-ark 用FatJar技术去实现OSGI的功能,jar包隔离原理上跟osgi一致,不过基于fat jar技术,通过maven 插件来简化复杂度,比较轻量,也支持服务热部署热更新等功能。
4、shade 也有maven插件,通过更改jar包的字节码来避免jai包冲突,jar包冲突的本质是类的全限定名(包名+类名)冲突了,通过全限定名不能定位到你想用的那个类,maven-shade插件可以更改jar包里的包名,来达到解决冲突的目的。
5、自己定义classload,反射调用冲突方法,代码量太大,不通用,但是会帮助理解上面组件的原理。

然后我排除了第一个,用了第五种的方式,但我发现对我这种情况不好用。它编译的时候会报错。

在这里插入图片描述
在这里插入图片描述

然后就去用了第四种方式maven插件maven-shade-plugin.

这种方式和我第一种解决方式一样,本质就是改包名。

只不过这种方式相当于我第一种方式覆盖代码改包名+反编译软件查找X9IntegerConverter类改它用到的地方的结合体。

而且更可靠友好,简单快捷。

1、新建一个工程,在pom.xml导入A.jar

<dependencies>
<!-- 只留一个依赖,其他依赖一定删掉,不然后面会有很多坑>
<!--        <dependency>-->
<!--            <groupId>org.springframework.boot</groupId>-->
<!--            <artifactId>spring-boot-starter</artifactId>-->
<!--        </dependency>-->

<!--        <dependency>-->
<!--            <groupId>org.springframework.boot</groupId>-->
<!--            <artifactId>spring-boot-starter-test</artifactId>-->
<!--            <scope>test</scope>-->
<!--        </dependency>-->
		<dependency>
            <groupId>com.xmsme</groupId>
            <artifactId>national.secrets</artifactId>
            <version>2.0.0</version>
        </dependency>
</dependencies>

这个版本之前用的2.4.3成功踩坑。把版本换成3.2.1就好了。

<groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>2.4.3</version>
    
Failed to execute goal org.apache.maven.plugins:maven-shade-plugin:2.4.3:shade (default) on project test_receive_request_param_format: Error creating shaded jar: null

2、添加maven-shade-plugin插件。

<build>
  <plugins>
      <!--       省略maven-compiler-plugin、spring-boot-maven-plugin     -->
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.2.1</version>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>shade</goal>
                </goals>
                <configuration>
                    <createDependencyReducedPom>true</createDependencyReducedPom>
                    <relocations>                
                        <!-- 多个包需要替换使用多个relocation,和exclude的用法类似。-->
                        <relocation>
                            <!-- pattern 为包名匹配的前缀 -->
                            <pattern>org.bouncycastle</pattern>
                            <!-- shadedPattern 为想要把包名替换成什么的前缀 -->
                            <shadedPattern>shaded.org.bouncycastle</shadedPattern>
                        </relocation>
                    </relocations>
                </configuration>
            </execution>
        </executions>
    </plugin>
  </plugins>
</build>

3、刷新maven工程,打包。
在这里插入图片描述

发现X9IntegerConverter类的包路径已经更改。

在这里插入图片描述

ECPoint类的导入X9IntegerConverter类的包路径也已经修改。

在这里插入图片描述

4、安装jar包到maven仓库中。

mvn install:install-file "-Dfile=package-demo-0.0.1-SNAPSHOT.jar" "-DgroupId=com.xmsme" "-DartifactId=shaded.national.secrets" "-Dversion=2.0.0" "-Dpackaging=jar"

5、在我们原来的项目中去掉
在这里插入图片描述

改为

<dependency>
    <groupId>com.xmsme</groupId>
    <artifactId>shaded.national.secrets</artifactId>
    <version>2.0.0</version>
</dependency>

6、刷新maven,maven clean,重新启动项目调用接口。

7、如果打完的jar包安装到本地,依赖到项目中,项目运行的时候报这个错。(踩坑)

java.lang.SecurityException: Invalid signature file digest for Manifest main attributes

就用压缩软件在maven仓库中打开刚才安装到本地的jar包,打开META-INF目录,将*.SF,*.DSA,*.RSA文件都删除。

看别的大佬说的是因为某些包的重复引用,导致打包之后的META-INF的目录下多出了一些*.SF,*.DSA,*.RSA文件。


遇到maven的依赖冲突三种主要解决方法:

1、当冲突两者其中一方兼容另外一方时,通过exclusions和exclusion标签解决。

2、当冲突两者互不兼容时,使用maven-shade-plugin管理插件解决。

3、覆盖jar包中的代码并结合反编译软件解决。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值