【问题标题】:How to handle the runtime error: java.lang.NoSuchMethodError如何处理运行时错误:java.lang.NoSuchMethodError
【发布时间】:2020-01-22 06:13:30
【问题描述】:

我有一个有很多依赖项的应用程序。一种依赖是 ActiveMQ Artemis。在 Maven 模块的 pom.xml 中,我将版本从 2.4.0 更新到 2.10.0

<dependency>
   <groupId>org.apache.activemq</groupId>
   <artifactId>artemis-server</artifactId>
   <version>2.10.0</version>
</dependency>
<dependency>
   <groupId>org.apache.activemq</groupId>
   <artifactId>artemis-commons</artifactId>
   <version>2.10.0</version>
</dependency>
<dependency>
   <groupId>org.apache.activemq</groupId>
   <artifactId>artemis-jms-client-all</artifactId>
   <version>2.10.0</version>
</dependency>

我用来启动 Artemis 代理的代码如下:

EmbeddedActiveMQ broker = new EmbeddedActiveMQ();
String fileConfig = "file:///" + brokerFile.getAbsolutePath();
broker.setConfigResourcePath(fileConfig);

通过 Camel 的 sjms 组件连接代理客户端:

org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory cf = new ActiveMQJMSConnectionFactory(url);
SjmsComponent component = new SjmsComponent();
component.setConnectionFactory(cf);
context.addComponent("sjms", component);

我在另一个使用 Gradle 5.6.2 构建/编译的应用程序中使用这个 Maven 模块。此应用程序还包含 Apache Camel 2.24.2 和 Apache ActiveMQ 5.5.10 的库。

应用程序编译正常,但在运行时出现“NoSuchMethodError”:

Handler dispatch failed; nested exception is java.lang.NoSuchMethodError: org.apache.activemq.artemis.utils.ClassloadingUtil.loadProperty(Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;

来自日志记录:

2019-09-21 03:03:00.883 WARN 4984 --- [ XNIO-2 task-14] .m.m.a.ExceptionHandlerExceptionResolver : Resolved exception caused by handler execution: org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.NoSuchMethodError: org.apache.activemq.artemis.utils.ClassloadingUtil.loadProperty(Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
java.lang.NullPointerException
   at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.finalize(ActiveMQConnectionFactory.java:961)
   at java.lang.System$2.invokeFinalize(System.java:1270)
   at java.lang.ref.Finalizer.runFinalizer(Finalizer.java:102)
   at java.lang.ref.Finalizer.access$100(Finalizer.java:34)
   at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:217)

根据文章3 Steps to Fix NoSuchMethodErrors and NoSuchMethodExceptions我跑了“gradlew dependencies”。

|    +--- org.apache.activemq:artemis-server:2.10.0 -> 2.4.0
|    |    +--- org.jboss.logging:jboss-logging:3.3.0.Final -> 3.3.2.Final
|    |    +--- org.apache.activemq:artemis-commons:2.4.0
|    |    |    +--- org.jboss.logging:jboss-logging:3.3.0.Final -> 3.3.2.Final
|    |    |    +--- io.netty:netty-buffer:4.1.16.Final -> 4.1.31.Final (*)
|    |    |    +--- io.netty:netty-transport:4.1.16.Final -> 4.1.31.Final (*)
|    |    |    +--- io.netty:netty-handler:4.1.16.Final -> 4.1.31.Final (*)
|    |    |    +--- commons-beanutils:commons-beanutils:1.9.3
|    |    |    |    +--- commons-logging:commons-logging:1.2
|    |    |    |    \--- commons-collections:commons-collections:3.2.2
|    |    |    \--- com.google.guava:guava:19.0 -> 25.1-jre (*)
|    |    +--- org.apache.activemq:artemis-selector:2.4.0
|    |    +--- org.apache.activemq:artemis-journal:2.4.0
|    |    |    +--- org.jboss.logging:jboss-logging:3.3.0.Final -> 3.3.2.Final
|    |    |    +--- org.apache.activemq:artemis-commons:2.4.0 (*)
|    |    |    \--- org.apache.activemq:artemis-native:2.4.0
|    |    |         \--- org.jboss.logging:jboss-logging:3.3.0.Final -> 3.3.2.Final
|    |    +--- org.apache.activemq:artemis-jdbc-store:2.4.0
|    |    |    +--- org.jboss.logging:jboss-logging:3.3.0.Final -> 3.3.2.Final
|    |    |    +--- org.apache.activemq:artemis-journal:2.4.0 (*)
|    |    |    \--- org.apache.activemq:artemis-core-client:2.4.0
|    |    |         +--- org.jgroups:jgroups:3.6.13.Final -> 3.6.7.Final
|    |    |         +--- org.apache.activemq:artemis-commons:2.4.0 (*)
|    |    |         +--- org.apache.johnzon:johnzon-core:0.9.5 -> 1.1.10
|    |    |         +--- io.netty:netty-transport-native-epoll:4.1.16.Final -> 4.1.31.Final (*)
|    |    |         +--- io.netty:netty-transport-native-kqueue:4.1.16.Final -> 4.1.31.Final (*)
|    |    |         \--- io.netty:netty-codec-http:4.1.16.Final -> 4.1.31.Final (*)
|    |    +--- org.apache.activemq:artemis-core-client:2.4.0 (*)
|    |    \--- io.netty:netty-all:4.1.16.Final -> 4.1.9.Final
|    +--- org.apache.activemq:artemis-commons:2.10.0 -> 2.4.0 (*)
|    +--- org.apache.activemq:artemis-jms-client-all:2.10.0

所以 Artemis 代理实际上是在 2.4.0 版本下运行,而客户端在 2.10.0 下运行(使它们不兼容)。

我在文章中说:

“最后,我们需要确定我们实际上需要满足两个依赖项的两个版本中的哪个版本。通常,这是较新的版本,因为大多数框架在某种程度上向后兼容。但是,它可以是相反的方式或我们甚至可能根本无法解决冲突。”

为了强制两者都在 2.10.0 上运行,我在 build.gradle 文件中明确声明:

configurations.all {
  resolutionStrategy {  
    force 'org.apache.activemq:artemis-core-client:2.10.0', 'org.apache.activemq:artemis-broker:2.10.0','org.apache.activemq:artemis-commons:2.10.0','org.apache.activemq:artemis-selector:2.10.0','org.apache.activemq:artemis-journal:2.10.0'
  }
}

compile group: 'org.apache.activemq', name: 'artemis-core-client', version: '2.10.0'
compile group: 'org.apache.activemq', name: 'artemis-commons', version: '2.10.0'
compile group: 'org.apache.activemq', name: 'artemis-server', version: '2.10.0'
compile group: 'org.apache.activemq', name: 'artemis-selector', version: '2.10.0'
compile group: 'org.apache.activemq', name: 'artemis-journal', version: '2.10.0'

在这个“gradlew依赖”之后:

|    +--- org.apache.activemq:artemis-server:2.10.0
|    |    +--- org.jboss.logging:jboss-logging:3.4.0.Final -> 3.3.2.Final
|    |    +--- org.jboss.logmanager:jboss-logmanager:2.1.10.Final
|    |    |    \--- org.wildfly.common:wildfly-common:1.5.1.Final
|    |    +--- org.apache.activemq:artemis-commons:2.10.0
|    |    |    +--- org.jboss.logging:jboss-logging:3.4.0.Final -> 3.3.2.Final
|    |    |    +--- io.netty:netty-buffer:4.1.34.Final -> 4.1.31.Final (*)
|    |    |    +--- io.netty:netty-transport:4.1.34.Final -> 4.1.31.Final (*)
|    |    |    +--- io.netty:netty-handler:4.1.34.Final -> 4.1.31.Final (*)
|    |    |    \--- commons-beanutils:commons-beanutils:1.9.3
|    |    |         +--- commons-logging:commons-logging:1.2
|    |    |         \--- commons-collections:commons-collections:3.2.2
|    |    +--- org.apache.activemq:artemis-selector:2.10.0
|    |    |    \--- org.apache.activemq:artemis-commons:2.10.0 (*)
|    |    +--- org.apache.activemq:artemis-journal:2.10.0
|    |    |    +--- org.jboss.logging:jboss-logging:3.4.0.Final -> 3.3.2.Final
|    |    |    +--- org.apache.activemq:artemis-commons:2.10.0 (*)
|    |    |    +--- org.apache.activemq:activemq-artemis-native:1.0.0
|    |    |    |    +--- org.jboss.logging:jboss-logging:3.3.1.Final -> 3.3.2.Final
|    |    |    |    \--- org.jboss.logmanager:jboss-logmanager:2.0.3.Final -> 2.1.10.Final (*)
|    |    |    +--- io.netty:netty-buffer:4.1.34.Final -> 4.1.31.Final (*)
|    |    |    \--- io.netty:netty-common:4.1.34.Final -> 4.1.31.Final
|    |    +--- org.apache.activemq:artemis-jdbc-store:2.10.0
|    |    |    +--- org.jboss.logging:jboss-logging:3.4.0.Final -> 3.3.2.Final
|    |    |    +--- org.apache.activemq:artemis-commons:2.10.0 (*)
|    |    |    +--- org.apache.activemq:artemis-journal:2.10.0 (*)
|    |    |    \--- org.apache.activemq:artemis-core-client:2.10.0
|    |    |         +--- org.jgroups:jgroups:3.6.13.Final -> 3.6.7.Final
|    |    |         +--- org.apache.activemq:artemis-commons:2.10.0 (*)
|    |    |         +--- org.apache.johnzon:johnzon-core:0.9.5 -> 1.1.10
|    |    |         +--- io.netty:netty-transport-native-epoll:4.1.34.Final -> 4.1.31.Final (*)
|    |    |         +--- io.netty:netty-transport-native-kqueue:4.1.34.Final -> 4.1.31.Final (*)
|    |    |         +--- io.netty:netty-codec-http:4.1.34.Final -> 4.1.31.Final (*)
|    |    |         +--- io.netty:netty-buffer:4.1.34.Final -> 4.1.31.Final (*)
|    |    |         +--- io.netty:netty-transport:4.1.34.Final -> 4.1.31.Final (*)
|    |    |         +--- io.netty:netty-handler:4.1.34.Final -> 4.1.31.Final (*)
|    |    |         +--- io.netty:netty-codec:4.1.34.Final -> 4.1.31.Final (*)
|    |    |         \--- io.netty:netty-common:4.1.34.Final -> 4.1.31.Final
|    |    +--- org.apache.activemq:artemis-core-client:2.10.0 (*)
|    |    +--- org.apache.activemq:activemq-artemis-native:1.0.0 (*)

问题

代理和客户端库都在同一版本上,应用程序似乎工作正常。然而,这让我感到不安:

  1. 如何通过自动依赖解析在应用程序的发行说明中写入库已更新而实际上使用的是两年前的版本?作为开发人员,我怎么知道事实并非如此?
  2. 如何读取 gradlew 依赖输出?强制使用旧的“2.4.0”版本的真正根本原因库是什么。
  3. 强制使用新版本真的是一个很好的解决方案,还是在覆盖自动依赖解析时会出现预期问题?

【问题讨论】:

  • 值得注意的是,新版本的 ActiveMQ Artemis 客户端不一定与旧版本的代理不兼容。 假设它们通过网络连接,它们应该是兼容的。但是,在我看来,您实际上有一个较新的客户端和一个较旧的代理在同一个 JVM 中运行,而没有任何类型的类加载器隔离,正如您所见,这通常不会很好地工作。
  • 我无法真正解决 Gradle 的问题,因为我不太熟悉它,但无论如何,您的问题中存在太多不同的问题。你应该把你的问题集中在一个问题上,这样正确的答案就很容易识别。如果您有多个不同的问题,那么您实际上应该创建多个问题,而不是将它们捆绑到一个帖子中。
  • 对于第2点,您可以使用gradle -q dependencyInsight --dependency artemis-server --configuration compile
  • 对于第 2 点,通常 Gradle 会在发生冲突时解析为更高版本 (2.10)。这里它使用 2.4,应该有一个明显的原因(但你应该共享整个 build.gradle 文件)
  • gradle 语句似乎很有帮助,但这只是将 maven 模块(包含其他依赖项)作为使用而不是根本原因。

标签: java maven gradle dependencies


【解决方案1】:
  1. Gradle 6.0 之前的版本降级只能通过force、配置级别force 或替换规则进行。您的构建中有一些东西使用这些技术之一来强制降低版本。
  2. 要调查特定库的版本,请使用dependencyInsight 任务获取有关选择模块特定版本的原因的更详细报告。 ./gradlew dependencyInsight --configuration &lt;relevantConfiguration&gt; --dependency artemis-server 之类的东西,其中 &lt;relevantConfiguration&gt; 可以是 compileClasspathruntimeClasspath 或更特定于您的项目的东西。
  3. 一旦您弄清楚为什么2.10.0 被降级为2.4.0,您就可以使用与force 不同的解决方案来获得您期望的版本。

【讨论】:

    猜你喜欢
    • 2011-09-05
    • 2015-06-05
    • 1970-01-01
    • 1970-01-01
    • 2015-12-06
    • 2016-03-31
    • 2021-02-04
    • 2019-06-23
    • 1970-01-01
    相关资源
    最近更新 更多