java - Spring注解@Retryable——如何设置一个拦截器

标签 java spring spring-rabbit spring-retry

我在 @Service 类中的方法上使用了 @Retryable 注释

@Service
@EnableRetry 
public class PushService {

    @Retryable(maxAttempts=5)
    public Result pushIt(myMessage messageIn) {
        ...
    }
}

它的工作原理非常棒:我直接从 RabbitMQ 收到消息,直到没有错误或尝试次数达到 5 时才会确认消息,此时消息直接进入 DLQ,正如我所愿。

我唯一的问题是我需要从属性文件中动态设置 maxAttempts。解决方案应该是设置一个拦截器,但唯一会导致错误的事实是,例如当我有:

@Service
@EnableRetry 
public class PushService {

    @Retryable(interceptor="myInterceptor") 
    public Result pushIt(myMessage messageIn) {
        ...
    }
}

其中 myInterceptor 定义为:

@Bean
public StatefulRetryOperationsInterceptor myInterceptor() {
    return RetryInterceptorBuilder.stateful().maxAttempts(5).build();
}

我得到一个无限循环,但有以下异常:

2015-04-08 07:12:10,970 GMT [SimpleAsyncTaskExecutor-1] (ConditionalRejectingErrorHandler.java:67) WARN  listener.ConditionalRejectingErrorHandler: Execution of Rabbit message listener failed.
org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException: Listener threw exception
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.wrapToListenerExecutionFailedExceptionIfNeeded(AbstractMessageListenerContainer.java:864)
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:802)
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:690)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$001(SimpleMessageListenerContainer.java:82)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$1.invokeListener(SimpleMessageListenerContainer.java:167)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.invokeListener(SimpleMessageListenerContainer.java:1241)
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:660)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:1005)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:989)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$700(SimpleMessageListenerContainer.java:82)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1103)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.ArrayIndexOutOfBoundsException: 1
    at org.springframework.amqp.rabbit.config.StatefulRetryOperationsInterceptorFactoryBean$3.getKey(StatefulRetryOperationsInterceptorFactoryBean.java:103)
    at org.springframework.retry.interceptor.StatefulRetryOperationsInterceptor.invoke(StatefulRetryOperationsInterceptor.java:132)
    at org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor.invoke(AnnotationAwareRetryOperationsInterceptor.java:118)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
    at com.acme.push.service.PushService$$EnhancerBySpringCGLIB$$9d503bc1.pushMessage(<generated>)
    at com.acme.push.receiver.PushListener.onMessage(PushListener.java:42)
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:799)
    ... 10 more

我很确定我把它保持得太简单了,但我不知道什么可能导致这个错误以及如何解决它,有人知道发生了什么吗?

最佳答案

org.springframework.amqp.rabbit.config.RetryInterceptorBuilder 的目的不是使用注解@Retryable

它的目的是与 SimpleRabbitListenerContainerFactory 类的通知链一起使用。 请参阅引用文档 receiving-messagesSimpleMessageListenerContainer#invokeListener 签名:

@Override
protected void invokeListener(Channel channel, Message message) throws Exception {
    proxy.invokeListener(channel, message);
}

一旦您使用适当的RetryInterceptor 配置通知链,您的注解就会失效。

关于java - Spring注解@Retryable——如何设置一个拦截器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29508311/

相关文章:

java - 自定义 Zuul 异常

java - GWT、GWT Designer 和 Eclipse 插件问题

spring - 在测试之间重置作为 Spring bean 提供的 Mockito 模拟?

java - RabbitMQ 生产者不会终止

java - 如何处理网络故障代码并恢复?

java - 为什么这里是 "Duplicate local variable messages"?

spring - 查询 @DBRef 字段

java - JMSXGroupId 的 RabbitMQ 解决方法

spring-boot - 未绑定(bind)的 Fanout Exchange 丢失数据

java - 模棱两可的构造函数(java 7)...解决此问题的唯一方法是构建器模式,对吗?