我们正在使用Spring Rabbitmq进行项目开发。目前,对于收听者,我们使用确认模式进行手动操作。在这种情况下,当发生异常时,我们无法将确认发送给RabbitMQ。
我们的代码是: 软件包com.highq.listener;
import java.io.IOException;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.config.DirectRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.listener.RabbitListenerEndpoint;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.util.ErrorHandler;
import com.highq.workflow.helper.RuleEngine;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
/**
* The Class RabbitMQListenerConfig.
*/
@Configuration
@Slf4j
@EnableRabbit
public class RabbitMQListenerConfig
{
/** The rule engine. */
@Autowired
RuleEngine ruleEngine;
private RabbitAdmin currentQueueAdmin = null;
public RabbitAdmin getRabbitAdmin()
{
return currentQueueAdmin;
}
/**
* This method will listen message from rabbitmq.
*
* @param message the message
* @param channel - Channel created for particular listener
* @param queue - Specified queue to which this listener will listen message
* @param deliveryTag - Delivery Tag to be used when sending acknowledgement
* @throws IOException - Exception in case of sending acknowledgement
*/
@RabbitListener(queues = "${queue.name}")
public void listen(byte[] msg, Channel channel, @Header(AmqpHeaders.CONSUMER_QUEUE) String queue, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws IOException
{
try
{
String message = new String(msg, "UTF-8");
log.info(message);
ruleEngine.evaluateRule(message);
}
catch (Exception e)
{
log.error(e.toString());
log.error(e.getMessage(), e);
}
finally
{
channel.basicAck(deliveryTag, false);
}
}
/**
* Error handler.
*
* @return the error handler
*/
@Bean
public ErrorHandler errorHandler()
{
return new RabbitExceptionHandler(new RabbitFatalExceptionStrategy(), this.currentQueueAdmin);
}
/**
* Bean will create from this with given name.
*
* @param name - Queue name- will be instance id
* @return the queue
*/
@Bean
public Queue queue(@Value("${queue.name}") String name)
{
return new Queue(name);
}
/**
* Rabbit listener container factory.
*
* @param connectionFactory the connection factory
* @return the direct rabbit listener container factory
*/
@Bean
public DirectRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory)
{
DirectRabbitListenerContainerFactory factory = new DirectRabbitListenerContainerFactory();
factory.setPrefetchCount(1);
factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
factory.setConnectionFactory(connectionFactory);
factory.setErrorHandler(errorHandler());
return factory;
}
@Bean
public RabbitListenerAroundAdvice rabbitListenerAroundAdvice()
{
return new RabbitListenerAroundAdvice();
}
/**
* RabbitAdmin Instance will be created which is required to create new Queue.
*
* @param cf - Connection factory
* @return the rabbit admin
*/
@Bean
public RabbitAdmin admin(ConnectionFactory cf)
{
this.currentQueueAdmin = new RabbitAdmin(cf);
return this.currentQueueAdmin;
}
}
@ Slf4j 公共类RabbitExceptionHandler扩展ConditionalRejectingErrorHandler { 私人RabbitAdmin rabbitAdmin;
public RabbitExceptionHandler()
{
super();
}
/**
* Create a handler with the supplied {@link FatalExceptionStrategy} implementation.
*
* @param exceptionStrategy The strategy implementation.
*/
public RabbitExceptionHandler(FatalExceptionStrategy exceptionStrategy, RabbitAdmin rabbitAdmin)
{
super(exceptionStrategy);
this.rabbitAdmin = rabbitAdmin;
}
@Override
public void handleError(Throwable t)
{
try
{
super.handleError(t);
}
catch (Exception e)
{
if (e instanceof AmqpRejectAndDontRequeueException)
{
Throwable t1 = new Throwable("Some message", e.getCause());
log.error(e.getMessage(), e);
ImmediateAcknowledgeAmqpException newAmqp = new ImmediateAcknowledgeAmqpException("Some message", t1);
throw newAmqp;
}
}
}
}
package com.highq.listener;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactoryUtils;
import org.springframework.amqp.rabbit.listener.ConditionalRejectingErrorHandler;
import org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
/**
* The Class RabbitFatalExceptionStrategy.
*/
@Slf4j
public class RabbitFatalExceptionStrategy extends ConditionalRejectingErrorHandler.DefaultExceptionStrategy
{
/*
* (non-Javadoc)
* @see org.springframework.amqp.rabbit.listener.ConditionalRejectingErrorHandler.DefaultExceptionStrategy#isFatal(java.lang.Throwable)
*/
@Override
public boolean isFatal(Throwable t)
{
boolean finalResult = super.isFatal(t);
if (t instanceof ListenerExecutionFailedException)
{
ListenerExecutionFailedException lefe = (ListenerExecutionFailedException) t;
lefe.getFailedMessage().getMessageProperties().getDeliveryTag());
log.error("\n Error occured while handling message with Queue named : "
+
lefe.getFailedMessage().getMessageProperties().getConsumerQueue() + " Message not processed is FATAL or NOT : " + finalResult
+ ";\n Failed message: " + lefe.getFailedMessage());
}
if (!log.isWarnEnabled() || !finalResult)
{
log.error(t.getMessage(), t);
}
return true;
}
}
在上述情况下,我们没有在异常处理程序中的任何地方获取通道,因此,如何在发生异常时手动确认。
答案 0 :(得分:1)
您不能;使用手动确认时,所有确认逻辑都必须位于侦听器中。
由于通常容器可以提供AUTO所需的所有灵活性,因此很少使用手动支架。
需要使用MANACK的用例是什么?