Caused by : java.lang.NoSuchMethodError

问题

相信大家在开发过程中一定经常遇到此类报错 : Caused by: java.lang.NoSuchMethodError 。
因此今天总结特地做个总结,希望能够解决此类问题,而不是这一个问题。
下面以我遇到的一个报错为例,说一下我对此类问题的解决方法 。
今天在升级了 Spring 版本之后,启动 Tomcat 报错,报错见下 :


日志

[Loaded javax.servlet.ServletContextEvent from file:/D:/apache-tomcat-8.5.34/lib/servlet-api.jar] 
   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.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300)
   at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
   at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
   at com.sun.jmx.remote.security.MBeanServerAccessController.invoke(MBeanServerAccessController.java:468)
   at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1468)
   at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:76)
   at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1309)
   at java.security.AccessController.doPrivileged(Native Method)
   at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1408)
   at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:829)
   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 sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:357)
   at sun.rmi.transport.Transport$1.run(Transport.java:200)
   at sun.rmi.transport.Transport$1.run(Transport.java:197)
   at java.security.AccessController.doPrivileged(Native Method)
   at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
   at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:573)
   at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
   at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
   at java.security.AccessController.doPrivileged(Native Method)
   at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
  at java.lang.Thread.run(Thread.java:748)

Caused by: java.lang.NoSuchMethodError: org.springframework.util.ReflectionUtils.accessibleConstructor(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/reflect/Constructor;
   at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:154)
 ... 46 more

查找问题

首先我们需要确定项目使用的是哪个 jar 包 。以 IntelliJ IDEA 为例 :

tomcat 启动的时候添加 jvm 参数 “-XX:+TraceClassLoading” , 操作如下图 :

配置之后,重启 tomcat ,控制台除了打印输出错误日志以外,还可以看到使用的 jar 包 :

看到以上错误输出是使用了 spring-core-3.2.10 版本的 jar 包导致的 。
因此问题为转换为: 在spring-core-3.2.10 jar 中的 ReflectionUtils 类里没有找到 accessibleConstructor 方法。
在工程里搜索 ReflectionUtils,如下图:

我们看到工程里有两个 ReflectionUtils ,一个是 spring-core-3.2.10 ,另一个是 spring-core-5.1.5 版本,分别进入这两个类,发现在 spring-core-5.15 中有 accessibleConstructor 方法,而 spring-core-3.2.10 中没有 accessibleConstructor 方法。

通过以上步骤初步得出结论,项目同时依赖了 spring-core-3.2.10 和 spring-core-5.1.5 。 IDE 在编译时使用了低版本的 spring-core-3.2.10 jar 包,而 jar 中没有accessibleConstructor 方法,因此抛出了 NoSuchMethodError 异常。


分析依赖树

接下来继续分析是 哪些项目依赖了 spring-core-3.2.10 和 spring-core-5.1.5 ? 是自己的工程还是引用的第三方工程依赖的呢 ?因此问题转换为分析依赖关系。
如果项目依赖较简单,可以直接在 IDEA 右侧找到依赖树, 如果是使用 Gradle 构建项目就点击 Gradle, 如果是 Maven 构建项目就点击 Maven 。

下图中左侧有箭头的含义是这个库引用了其他 jar 包,可以点击箭头展开。

这样看的比较直观,但是有个缺点,一个大工程所依赖的 jar 包可能是几十或上百个的。因此,有时我们需要通过命令行分析依赖树,以下分析依赖树以 Gradle 为例 :
如果项目简单,仅仅有一个工程,没有依赖其他 moudle ,
进入工程 build.gradle 所在目录,执行以下命令。

gradlew dependencies 

在控制台可以到整个项目的依赖树,如下图:

如果工程比较庞大,依赖了很多 module ,仅仅想分析某一 module 的依赖 :

gradlew   :submoduleName:dependencies  >  dependencies.log

其中 > dependencies.log 是将日志导出到命令执行目录的 dependencies.log 中,原因是因为有时候 console 中日志太多,console 无法跳的太快,无法全部分析,因此导入到文件中。分析出的依赖树如下:

可以看到 org.springframework:spring-core:5.1.5.RELEASE 被 3.2.10.RELEASE 覆盖 ,因此会报 Caused by: java.lang.NoSuchMethodError 的错 。

问题找到了,那么解决就很简单了。


总结

整个问题的分析过程到此结束,解决问题的方案无非下面两种:

  1. 去除不必要的依赖
  2. 统一使用的版本号
    因为我使用的是 Gradle ,因此使用的命令就是 force 或 exclude 。 如果对这两个命令不熟悉, 可参考下我以前的一篇 文章
    如果你使用的 Maven , 分析问题的步骤大致相同,因为我对 Maven 不太熟悉,不在此赘述。
  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这是一个Java错误,通常是由于代码中调用了不存在的方法而导致的。可能是因为方法名称或参数不正确,或者是因为代码中使用了过时的方法。要解决此错误,需要检查代码中的方法调用,并确保方法名称和参数正确。如果方法已过时,则需要使用新的方法替换它。 ### 回答2: 在Java编程中,我们有时候可能会遇到一种异常错误:java.lang.nosuchmethoderror(找不到方法错误)。这个错误一般是因为我们的代码中调用了一个不存在的方法。 在Java中,所有的类和方法都会被编译成字节码文件,这些字节码文件中包含了类和方法的信息。当我们运行Java程序时,虚拟机会根据这些字节码文件加载类和方法,从而执行程序。 但是,如果我们在代码中调用了一个不存在的方法,虚拟机就无法找到这个方法对应的字节码文件,于是就会抛出java.lang.nosuchmethoderror错误。 例如,我们定义了一个类和一个方法: ``` public class Test { public void sayHello() { System.out.println("Hello!"); } } ``` 然后在另一个类中调用这个方法: ``` public class Main { public static void main(String[] args) { Test test = new Test(); test.sayHi(); } } ``` 这个时候,虚拟机就会抛出java.lang.nosuchmethoderror错误,因为我们在Test类中并没有定义sayHi()方法。 为了避免出现这种错误,我们应该仔细检查代码中调用的方法是否存在,并且检查导入的类是否正确。如果出现了这种错误,我们应该及时定位原因并修复代码。 ### 回答3: 造成java.lang.nosuchmethoderror的原因有很多,主要表现为方法未找到的异常。在Java程序运行时,如果没有找到匹配的方法,就会抛出NoSuchMethodError异常。 其中最常见的原因是在程序运行时使用了已经被移除或重构的方法。当升级应用程序并使用新的JAR包时,原本存在的某些方法可能已经被移除或重命名,此时程序可能会尝试调用这些无法找到的方法而抛出NoSuchMethodError异常。 此外,还有以下一些常见的原因: 1.版本不匹配:在Java中,客户端和服务器端都要有相同版本的类库才能顺利运行,如果版本不匹配会出现NoSuchMethodError异常。 2.类路径问题:在程序中,如果类路径中的两个不同版本的类库同时出现,可能会导致无法找到某些方法而报错。 3.不同编译器之间的问题:在使用不同的编译器进行开发时,可能会发生一些方法无法找到的问题。 4.项目构建问题:在进行项目构建时,如果没有正确地包含所有的类库,会导致NoSuchMethodError异常。 5.异常的捕获:如果子类没有合适地捕获父类方法抛出的异常,也会导致NoSuchMethodError异常。 在处理此类问题时,需要仔细核对代码并进行调试。可以尝试重新编译代码或升级应用程序所依赖的类库版本,也可以考虑修改代码以适应新版本的类库。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值