【问题标题】:Spring Amqp internal NullPointerException on RabbitTemplate convertAndSendRabbitTemplate convertAndSend 上的 Spring Amqp 内部 NullPointerException
【发布时间】:2018-12-19 17:09:49
【问题描述】:

我在尝试使用 RabbitTemplate.convertAndSend 发布消息时随机遇到 NullPointerException

我尝试了 spring-amqp:1.7.6 和 spring-amqp:1.7.8 这应该是我的依赖树的相关部分:

[INFO] | +- org.springframework.amqp:spring-rabbit:jar:1.7.4.RELEASE:compile
[INFO] | | +- com.rabbitmq:http-client:jar:1.1.1.RELEASE:compile
[INFO] | | \- com.rabbitmq:amqp-client:jar:4.0.3:compile

这是异常的堆栈跟踪

org.springframework.amqp.UncategorizedAmqpException: java.lang.NullPointerException
        at org.springframework.amqp.rabbit.support.RabbitExceptionTranslator.convertRabbitAccessException(RabbitExceptionTranslator.java:83)
        at org.springframework.amqp.rabbit.connection.RabbitAccessor.convertRabbitAccessException(RabbitAccessor.java:113)
        at org.springframework.amqp.rabbit.core.RabbitTemplate.doExecute(RabbitTemplate.java:1461)
        at org.springframework.amqp.rabbit.core.RabbitTemplate.execute(RabbitTemplate.java:1411)
        at org.springframework.amqp.rabbit.core.RabbitTemplate.send(RabbitTemplate.java:712)
        at org.springframework.amqp.rabbit.core.RabbitTemplate.convertAndSend(RabbitTemplate.java:813)
        at org.springframework.amqp.rabbit.core.RabbitTemplate.convertAndSend(RabbitTemplate.java:791)

        at io.reactivex.internal.operators.completable.CompletableFromAction.subscribeActual(CompletableFromAction.java:34)
        at io.reactivex.Completable.subscribe(Completable.java:1635)
        at io.reactivex.internal.operators.completable.CompletableCache.subscribeActual(CompletableCache.java:59)
        at io.reactivex.Completable.subscribe(Completable.java:1635)
        at io.reactivex.internal.operators.completable.CompletableSubscribeOn$SubscribeOnObserver.run(CompletableSubscribeOn.java:64)
        at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:452)
        at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:61)
        at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:52)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
        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.NullPointerException: null
        at sun.reflect.GeneratedMethodAccessor487.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.amqp.rabbit.connection.CachingConnectionFactory$CachedChannelInvocationHandler.invoke(CachingConnectionFactory.java:980)
        at com.sun.proxy.$Proxy174.basicPublish(Unknown Source)
        at org.springframework.amqp.rabbit.core.RabbitTemplate.doSend(RabbitTemplate.java:1532)
        at org.springframework.amqp.rabbit.core.RabbitTemplate$3.doInRabbit(RabbitTemplate.java:716)
        at org.springframework.amqp.rabbit.core.RabbitTemplate.doExecute(RabbitTemplate.java:1455)
        ... 19 common frames omitted 

有什么可能导致这种情况的线索吗?

编辑:附加信息

一开始我没有注意到 spring-rabbit 和 spring-amqp 之间的区别,但是在 jar 里面我有这些依赖关系:

128356 Tue May 29 17:50:46 CEST 2018 lib/spring-amqp-1.7.8.RELEASE.jar
469867 Mon Sep 11 15:28:04 CEST 2017 lib/spring-rabbit-1.7.4.RELEASE.jar
481919 Wed Jun 07 15:25:06 CEST 2017 lib/amqp-client-4.0.3.jar

【问题讨论】:

    标签: java nullpointerexception rabbitmq spring-amqp spring-rabbit


    【解决方案1】:

    我在实时环境中随机发布时遇到了同样的错误,这是由于创建了频道而不是关闭它们。 Rabbitmq 有 5000 个通道的限制。 这在测试环境中不容易重现,因为它需要打开 5k 个通道。

    【讨论】:

      【解决方案2】:

      我会说问题出在这样的块中:

      synchronized (this.targetMonitor) {
                      if (this.target == null) {
                          this.target = createBareChannel(this.theConnection, this.transactional);
                      }
                      Object result = method.invoke(this.target, args);
                      if (this.transactional) {
                          if (txStarts.contains(methodName)) {
                              this.txStarted = true;
                          }
                          else if (txEnds.contains(methodName)) {
                              this.txStarted = false;
                          }
                      }
                      return result;
                  }
      

      关注if (this.target == null) {,进入method.invoke(this.target, args);。在这些操作之间,this.target 可能变为null。这就是下面catch (InvocationTargetException ex) { 块的事实:我们在synchronized (this.targetMonitor) { 之外执行this.target = null;。因此,其他一些线程可能会导致此 target 属性出现竞争条件。

      这就是我对NPE 问题的意思,这是一个关于如何解决的建议。

      现在我们需要了解不同的线程如何访问相同的ChannelProxy 从而导致这种竞争条件......也许在缓存通道方面仍然存在一些缺陷。

      当然,如果您使用最新的 spring-rabbit-1.7.8 尝试您的解决方案,那就太好了,因为您的依赖项仍将其显示为 1.7.4

      【讨论】:

      • 我编辑了我的帖子以添加我在 jar 中的版本,我将更新 spring-rabbit 版本并在接下来的几天内回复您。
      • 你只需要spring-rabbit-1.7.8.RELEASE:所有其他都是传递的,会被自动轮询。
      • 我尝试升级到 spring-rabbit 1.7.8 并且我仍然得到空指针,也许如果我尝试另一个连接工厂我至少可以绕过这个问题?
      • 好的。我知道了。太可惜了……能不能和我们分享一下GitHub上一个简单的项目来复现和玩?不过,您可能会从其他线程执行一些 physicalClose()...
      • 我打算尝试在一个简单的项目中重现,但是 atm 我什至无法在实际项目中的测试中重现,它只出现在实时环境中...查看我的代码我只直接处理一个连接来创建一个队列,然后我不关闭那个连接,我不确定这是否会在某个时候导致我看到的 npe。
      猜你喜欢
      • 2017-08-15
      • 1970-01-01
      • 2022-08-15
      • 1970-01-01
      • 2016-04-01
      • 2022-08-18
      • 1970-01-01
      • 1970-01-01
      • 2010-11-25
      相关资源
      最近更新 更多