SpringBoot2.X整合RabbitMQ

SpringBoot2.X–RabbitMQ实战

maven导入mq包:

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-amqp</artifactId>
		</dependency>

mq配置:

spring.rabbitmq.addresses=127.0.0.1:5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/
spring.rabbitmq.connection-timeout=15000

spring.rabbitmq.publisher-confirms=true
spring.rabbitmq.publisher-returns=true
# return 的时候代表消息不可达,设置 broker 不自动删除该消息,
# 而是返回到生产端,让我们进行一些后续的处理
spring.rabbitmq.template.mandatory=true

MQ配置类:

@Configuration
public class RabbitMQConfig {

    public static final String QUEUE_SMS = "queue_inform_sms"; //短信队列名
    public static final String QUEUE_EMAIL = "queue_inform_email"; //邮件队列名
    public static final String ROUTINGKEY_SMS = "routingkey.#.sms.#"; //统配符匹配 短信队列key
    public static final String ROUTINGKEY_EMAIL = "routingkey.#.email.#"; //统配符匹配 邮件队列key
    public static final String EXCHANGE_ROUTING_INFORM = "exchange_topic_inform"; //交换机


    /**
     * 加载交换机组件
     * @return
     */
    @Bean(EXCHANGE_ROUTING_INFORM)
    public Exchange getExchange() {
        //创建交换机并设置模式
        ExchangeBuilder exchangeBuilder = ExchangeBuilder.topicExchange(EXCHANGE_ROUTING_INFORM);
        exchangeBuilder.durable(true); //是否持久化  默认为true
        Exchange exchange = exchangeBuilder.build();
        return exchange;
    }

    /**
     * 加载队列组件
     * @return
     */
    @Bean(QUEUE_SMS)
    public Queue getQueueSMS() {
        return new Queue(QUEUE_SMS,true);
    }

    /**
     * 加载队列组件
     * @return
     */
    @Bean(QUEUE_EMAIL)
    public Queue getQueueEMAIL() {
        return new Queue(QUEUE_EMAIL,true);
    }


    /**
     * 队列绑定交换机指定routingkey
     */
    @Bean
    public Binding bindingSMS(@Qualifier(QUEUE_SMS)Queue queue,
                                   @Qualifier(EXCHANGE_ROUTING_INFORM)Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(ROUTINGKEY_SMS).noargs();
    }


    /**
     * 队列绑定交换机指定routingkey
     */
    @Bean
    public Binding bindingEMAIL(@Qualifier(QUEUE_EMAIL)Queue queue,
                              @Qualifier(EXCHANGE_ROUTING_INFORM)Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(ROUTINGKEY_EMAIL).noargs();
    }

}

MQ生产者:

@Component
public class RabbitSender {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 监听MQ服务返回的确认请求,消息到达exchange,ack 就返回true
     * CorrelationData 获取生产者发送的消息
     * ack 判断消息是否到达MQ服务
     */
    final RabbitTemplate.ConfirmCallback confirmCallback = new RabbitTemplate.ConfirmCallback() {
        @Override
        public void confirm(CorrelationData correlationData, boolean ack, String cause) {
            if(!ack){ //判断消息是否发送成功
                String id = correlationData.getId(); //消息ID
                Message message = correlationData.getReturnedMessage(); //消息体
//                byte[] body = message.getBody(); //消息
                System.err.println("消息ID: " + id + " 发送至MQ服务失败...." + message);
            }
        }
    };
    /* 简化版
     private final RabbitTemplate.ConfirmCallback  confirmCallback = (correlationData, ack, cause) -> {
        System.out.println("correlationData:" + correlationData);
        System.out.println("ack:" + ack);
        if (!ack){
            System.out.println("补偿处理...");
        }
    };*/


    /**
     * 监听exchange 是否将消息转发至对应的队列中(routingKey可能找不到对应的queue)
     */
    final RabbitTemplate.ReturnCallback returnCallback = new RabbitTemplate.ReturnCallback() {
        @Override
        public void returnedMessage(Message message, int replyCode, String replyText,
                                    String exchange, String routingKey) {
            if("NO_ROUTE".equals(replyText)) { //replyCode: 312, replyText: NO_ROUTE
                System.err.println("交换机转发消息至队列异常:{ Exchange" + exchange + ", RoutingKey: " + routingKey + " }");
            }
        }
    };
    /* 简化版
    private final RabbitTemplate.ReturnCallback returnCallback = (message, replyCode, replyText,
                                                                  exchange, routingKey) -> System.out.println("return exchange:" + exchange + ", routingKey:" + routingKey +
            ", replyText:" + replyText);*/



    /**
     * Rabbitmq 发送消息
     * @param obj 参数
     */
    public void sendOrder(Object obj) {
        //监听MQ服务回调
        rabbitTemplate.setConfirmCallback(confirmCallback);
        //监听Exchange回调
        rabbitTemplate.setReturnCallback(returnCallback);
        //发布者的基类
        CorrelationData cd = new CorrelationData();
        // 消息唯一标识
        String id = UUID.randomUUID().toString();
        cd.setId(id);
        /**
         * String exchange,  交换机
           String routingKey, 路由key
           Object object, 消息
           CorrelationData correlationData
           关联发布者的基类确认已发送的消息。使用org.springframework.amqp.rabbit.core。包含其中一个作为参数的RabbitTemplate方法;当收到发布者confirm时,将使用ack/nack返回CorrelationData。
         */
        rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_ROUTING_INFORM, "routingkey.sms", obj, cd);
    }

}

MQ消费者:

@Component
public class RabbitConsumer {
    /**
     * @RabbitListener注解指定目标方法来作为消费消息的方法,通过注解参数指定所监听的队列或者Binding
     * @QueueBinding 定义队列并绑定交换机
     * @Queue 队列
     * @Exchange 交换机
     */
    @RabbitListener(bindings =
       @QueueBinding(value =@Queue(value = RabbitMQConfig.QUEUE_SMS, durable = "true"),
                    exchange = @Exchange(value = RabbitMQConfig.EXCHANGE_ROUTING_INFORM,
                                    durable = "true",
                                    type = "topic",
                                    ignoreDeclarationExceptions = "true"),
            key = RabbitMQConfig.ROUTINGKEY_SMS)
    )
    @RabbitHandler
    public void onOrderMessage(@Payload Object obj, @Headers Map<String, Object> properties, Channel channel) throws Exception {
        System.out.println("消费端 order:" + obj);
        // deliveryTag: 确认消息的条数,一般为1
        Long deliveryTag = (Long) properties.get(AmqpHeaders.DELIVERY_TAG);
        System.out.println("deliveryTag:" + deliveryTag);
        // 限流处理:消息体大小不限制,每次限制消费一条,只作用于该Consumer层,不作用于Channel
        channel.basicQos(0, 1, false);
        // 手工ACK,不批量ack
        channel.basicAck(deliveryTag, false);
    }
}

测试类:

@SpringBootTest
@RunWith(SpringRunner.class)
public class RabbitMQProduceSend {

    @Autowired
    public RabbitTemplate rabbitTemplate;

    @Autowired
    public RabbitSender sender;

    @Test
    public void sendMsg() {
//        String msg = "send msg...";
//        rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_ROUTING_INFORM,"routingkey.sms",msg);
        HashMap<String,Object> params = new HashMap<>();
        params.put("title","测试");
        params.put("body","哈哈哈。。。");
        sender.sendOrder(params);
    }
}

在这里插入图片描述

发布了19 篇原创文章 · 获赞 8 · 访问量 944
展开阅读全文

spring boot整合rabbitmq ack出现异常

09-29

先贴一下我的代码,配置类 ``` @Configuration public class RabbitConfig { @Autowired RedisService redisService; @Bean public Queue queue() { return new Queue(MqConstant.QUEUE_NAME); } @Bean public Queue BQueue() { return new Queue(MqConstant.BQUEUE_NAME); } /** * 消费者数量,默认10 */ private static final int DEFAULT_CONCURRENT = 10; /** * 每个消费者获取最大投递数量,默认50 */ private static final int DEFAULT_PREFETCH_COUNT = 5; /** * 初始化环境参数 */ private void initEnv() { SwitchTool.initEnv(redisService); } @Bean public MessageConverter jsonMessageConverter(ObjectMapper objectMapper) { return new Jackson2JsonMessageConverter(objectMapper); } @Bean public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) { RabbitTemplate template = new RabbitTemplate(connectionFactory); template.setMessageConverter(new Jackson2JsonMessageConverter()); return template; } @Bean public SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory( SimpleRabbitListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory) { // 初始化环境参数 initEnv(); // 初始化环境参数-end SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); factory.setPrefetchCount(DEFAULT_PREFETCH_COUNT); factory.setConcurrentConsumers(DEFAULT_CONCURRENT); factory.setAcknowledgeMode(AcknowledgeMode.MANUAL); configurer.configure(factory, connectionFactory); return factory; } } ``` 然后是消费者类,消费者1: ``` @RabbitListener(queues = MqConstant.QUEUE_NAME, containerFactory = "simpleRabbitListenerContainerFactory") @RabbitHandler public void process(@Payload MessageBody messageBody, @Headers Map<String, Object> headers, Channel channel) throws Exception {.....} ``` 消费者2: ``` @RabbitListener(queues = MqConstant.BQUEUE_NAME,containerFactory = "simpleRabbitListenerContainerFactory") @RabbitHandler public void process(@Payload MessageBody messageBody, @Headers Map<String, Object> headers, Channel channel) throws Exception { log.info("get enter msg:"+messageBody); Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG); channel.basicAck(deliveryTag,false); } ``` 如果我只写消费者1,不写消费者2的话是完全没有问题的,当我写两个消费者的时候,启动就报错了,如下: ``` 2019-09-29 14:35:48.307 WARN 4380 --- [cTaskExecutor-1] s.a.r.l.ConditionalRejectingErrorHandler : Execution of Rabbit message listener failed. org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException: Listener method could not be invoked with the incoming message Endpoint handler details: Method [public void com.chinamobile.cmic.rcsoa.wishsms.component.EnterClient.process(com.chinamobile.cmic.rcsoa.wishsms.dto.MessageBody,java.util.Map<java.lang.String, java.lang.Object>,com.rabbitmq.client.Channel) throws java.lang.Exception] Bean [com.chinamobile.cmic.rcsoa.wishsms.component.EnterClient@6fbfd28b] at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:129) at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:106) at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:856) at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:779) at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$001(SimpleMessageListenerContainer.java:105) at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$1.invokeListener(SimpleMessageListenerContainer.java:208) at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.invokeListener(SimpleMessageListenerContainer.java:1349) at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:760) at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:1292) at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:1262) at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1800(SimpleMessageListenerContainer.java:105) at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1518) at java.lang.Thread.run(Thread.java:748) Caused by: org.springframework.amqp.support.converter.MessageConversionException: Cannot handle message ... 13 common frames omitted Caused by: org.springframework.messaging.converter.MessageConversionException: Cannot convert from [[B] to [com.chinamobile.cmic.rcsoa.wishsms.dto.MessageBody] for GenericMessage [payload=byte[298], headers={amqp_receivedDeliveryMode=PERSISTENT, amqp_receivedRoutingKey=legalize.enter.queue, amqp_deliveryTag=2, amqp_consumerQueue=legalize.enter.queue, amqp_redelivered=true, id=f8b6a47d-baa1-eded-60f9-0b83554c56c0, amqp_consumerTag=amq.ctag-QgKSp5nfJeTaRNyWogyBbw, contentType=application/x-java-serialized-object, timestamp=1569738948306}] at org.springframework.messaging.handler.annotation.support.PayloadArgumentResolver.resolveArgument(PayloadArgumentResolver.java:142) at org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:112) at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:135) at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:107) at org.springframework.amqp.rabbit.listener.adapter.HandlerAdapter.invoke(HandlerAdapter.java:49) at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:126) ... 12 common frames omitted ``` 希望大佬们可以帮我看看这怎么解决。QAQ 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览