Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring注解@Retryable-如何设置拦截器_Java_Spring_Spring Rabbit_Spring Retry - Fatal编程技术网

Java Spring注解@Retryable-如何设置拦截器

Java Spring注解@Retryable-如何设置拦截器,java,spring,spring-rabbit,spring-retry,Java,Spring,Spring Rabbit,Spring Retry,我正在@Service类中的方法上使用@Retryable注释 @Service @EnableRetry public class PushService { @Retryable(maxAttempts=5) public Result pushIt(myMessage messageIn) { ... } } 它的工作原理就像一个charme:我直接从RabbitMQ收到一条消息,直到没有错误或者尝试次数达到5次,消息才会被确认,此时消息会直接

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

@Service
@EnableRetry 
public class PushService {

    @Retryable(maxAttempts=5)
    public Result pushIt(myMessage messageIn) {
        ...
    }
}
它的工作原理就像一个charme:我直接从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
2015-04-08 07:12:10970 GMT[SimpleAsynctaskeExecutor-1](ConditionalRejectingErrorHandler.java:67)警告侦听器。ConditionalRejectingErrorHandler:执行兔子消息侦听器失败。
org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException:侦听器引发异常
位于org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.wrapToListenerExecutionFailedExceptionIfNeeded(AbstractMessageListenerContainer.java:864)
位于org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:802)
位于org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:690)
位于org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$001(SimpleMessageListenerContainer.java:82)
位于org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$1.invokeListener(SimpleMessageListenerContainer.java:167)
位于org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.invokeListener(SimpleMessageListenerContainer.java:1241)
位于org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:660)
位于org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:1005)
位于org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:989)
位于org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$700(SimpleMessageListenerContainer.java:82)
位于org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1103)
运行(Thread.java:745)
原因:java.lang.ArrayIndexOutOfBoundsException:1
位于org.springframework.amqp.rabbit.config.StatefureOperationsInterceptorFactoryBean$3.getKey(StatefureRetryOperationsInterceptorFactoryBean.java:103)
位于org.springframework.retry.interceptor.statefurretryoperationinterceptor.invoke(statefurretryoperationinterceptor.java:132)
在org.springframework.retry.annotation.annotationawaretryoperationsinterceptor.invoke(annotationawaretryoperationsinterceptor.java:118)
在org.springframework.aop.framework.ReflectiveMethodInvocation.procedue(ReflectiveMethodInvocation.java:179)上
位于org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
在com.acme.push.service.PushService$$EnhancerBySpringCGLIB$$9d503bc1.pushMessage()上
位于com.acme.push.receiver.PushListener.onMessage(PushListener.java:42)
位于org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.DoInvokeStener(AbstractMessageListenerContainer.java:799)
... 10多

我很确定我把它保持得太简单了,但我只是没有线索知道什么会导致这个错误以及如何解决它,任何人都知道发生了什么?

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

它的用途是与
SimpleRableBitListenerContainerFactory
类的通知链一起使用。 请参阅参考文档和他
SimpleMessageListenerContainer#invokeListener
签名:

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

只要您使用适当的
RetryInterceptor

配置通知链,您的注释就没有用了。我最终在不使用
@Retryable
注释的情况下获得了所需的灵活性

我创建了一个
RetryAdvice
,其中包含延迟和最大尝试次数的参数:

@Bean
public MethodInterceptor retryAdvice() {
    FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
    backOffPolicy.setBackOffPeriod(delay);
    return RetryInterceptorBuilder.stateless().backOffPolicy(backOffPolicy)
            .maxAttempts(maxAttempts).build();
}
我将建议插入到
ListenerContainer

@Bean
public SimpleMessageListenerContainer replyListenerContainer() {
    SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
    container.setConnectionFactory(pushConnectionFactory());
    container.setQueues(pushQueue());
    container.setMessageListener(pushListener());

    Advice[] adviceChain = new Advice[] { retryAdvice() };
    container.setAdviceChain(adviceChain);

    return container;
}
这样,无论何时我的听众都会

throw new AmqpRejectAndDontRequeueException(cause);

这将导致容器以所需的延迟重试指定的次数,之后将传播异常,并在DLQ中传递消息

它至少需要一个具有2个参数的方法,第二个参数类型为
org.springframework.amqp.core.message
。我不知道为什么。。。Javadoc和引用似乎不包含任何信息……确切地说,我正在调试,我刚刚看到了它。此外,
Message
必须具有messageId属性,否则将出现异常:
org.springframework.amqp.rabbit.listener.exception.FatalListenerExecutionException:消息中的非法空id。无法管理邮件的重试:谢谢Nicolas,但是如果目的不是在
@Retryable
中使用,我不希望在类中有一个专用参数(参见javadoc)。。。应该有办法让它工作。。。仍在努力寻找答案:(如果您想将注释与自定义拦截器一起使用,您应该使用
org.springframework.retry.Interceptor.RetryInterceptorBuilder
而不是
org.springframework.amqp.rabbit.config.RetryInterceptorBuilder
。我认为最后一个应该只与
SimpleRableBitListenerContainerFac一起使用