3.2 RabbitMQ整合Spring AMQP实战(五)-MessageListenerAdapter

MessageListenerAdapter 消息监听适配器

1.1 基本使用方式
修改RabbitMQConfig中的SimpleMessageListenerContainer代码

 @Bean
    public SimpleMessageListenerContainer messageContainer(ConnectionFactory connectionFactory) {
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
        //设置监听队列
        container.setQueues(queue001(), queue002(), queue003(), queue_image(), queue_pdf());
        container.setConcurrentConsumers(1);
        container.setMaxConcurrentConsumers(5);
        //是否有重复队列
        container.setDefaultRequeueRejected(false);
        //设置签收模式
        container.setAcknowledgeMode(AcknowledgeMode.AUTO);
        container.setExposeListenerChannel(true);
        //设置消费者标签
        container.setConsumerTagStrategy(new ConsumerTagStrategy() {
            @Override
            public String createConsumerTag(String queue) {
                return queue + "_" + UUID.randomUUID().toString();
            }
        });
        //设置默认消息监听
        /*container.setMessageListener(new ChannelAwareMessageListener() {
            @Override
            public void onMessage(Message message, Channel channel) throws Exception {
                String msg = new String(message.getBody());
                System.err.println("----------消费者: " + msg);
            }
        });*/
        //自定义消息监听适配器
        MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
        container.setMessageListener(adapter);
        return container;
    }

自定义适配器MessageDelegate代码

package com.star.rabbitmq.adapter;

/**
 * @Author likai
 * @Description 自定义适配器
 * @Date 2020/3/24 13:06
 **/
public class MessageDelegate {
    public void handleMessage(byte[] messageBody) {
        System.err.println("默认方法, 消息内容:" + new String(messageBody));
    }
/*

    public void consumeMessage(byte[] messageBody) {
        System.err.println("字节数组方法, 消息内容:" + new String(messageBody));
    }

    public void consumeMessage(String messageBody) {
        System.err.println("字符串方法, 消息内容:" + messageBody);
    }

    public void method1(String messageBody) {
        System.err.println("method1 收到消息内容:" + new String(messageBody));
    }

    public void method2(String messageBody) {
        System.err.println("method2 收到消息内容:" + new String(messageBody));
    }


    public void consumeMessage(Map messageBody) {
        System.err.println("map方法, 消息内容:" + messageBody);
    }

    public void consumeMessage(Order order) {
        System.err.println("order对象, 消息内容, id: " + order.getId() +
                ", name: " + order.getName() +
                ", content: "+ order.getContent());
    }

    public void consumeMessage(Packaged pack) {
        System.err.println("package对象, 消息内容, id: " + pack.getId() +
                ", name: " + pack.getName() +
                ", content: "+ pack.getDescription());
    }

    public void consumeMessage(File file) {
        System.err.println("文件对象 方法, 消息内容:" + file.getName());
    }
*/

}

启动测试类的发送消息的方法
3.2 RabbitMQ整合Spring AMQP实战(五)-MessageListenerAdapter_第1张图片
观察日志:消息在启动的时候已经被消费了,与我们自定义的消费方法日志内容一致。
1.2原理分析
打开MessageListenerAdapter源码
3.2 RabbitMQ整合Spring AMQP实战(五)-MessageListenerAdapter_第2张图片
默认的基础消费方法命名为:handleMessage

1.3 修改默认的处理方法

 //1.1 自定义消息监听适配器
        MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
        container.setMessageListener(adapter);
        adapter.setDefaultListenerMethod("consumeMessage");
        return container;

放开MessageDelegate中consumeMessage的注释,启动testSendMessage方法
3.2 RabbitMQ整合Spring AMQP实战(五)-MessageListenerAdapter_第3张图片
1.4 添加一个转换器

package com.star.rabbitmq.convert;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.support.converter.MessageConversionException;
import org.springframework.amqp.support.converter.MessageConverter;

/**
 * @Author likai
 * @Description 普通消息转换器
 * @Date 2020/3/24 14:24
 **/
public class TextMessageConverter implements MessageConverter {
    @Override
    public Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException {
        return new Message(object.toString().getBytes(), messageProperties);
    }

    @Override
    public Object fromMessage(Message message) throws MessageConversionException {
        String contentType = message.getMessageProperties().getContentType();
        //对头部消息带text的做转换处理
        if(null != contentType && contentType.contains("text")) {
            return new String(message.getBody());
        }
        return message.getBody();
    }
}

1.5 转换器错误测试
测试类中添加发送消息的代码

 /**
      * @Description: 测试适配器方式
      * @author kaili
      * @date 2019/4/23 22:02
     */
    @Test
    public void testSendMessageAdaptText() throws Exception {
        //1 创建消息
        MessageProperties messageProperties = new MessageProperties();
        messageProperties.setContentType("text/plain");
        Message message = new Message("mq 消息1234".getBytes(), messageProperties);
        rabbitTemplate.send("topic001", "spring.abc", message);
        rabbitTemplate.send("topic002", "rabbit.abc", message);
    }

直接启动观察控制台消息,回发现报错信息

org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException: Failed to invoke target method 'consumeMessage' with argument type = [class java.lang.String], value = [{mq 消息1234}]
	at org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter.invokeListenerMethod(MessageListenerAdapter.java:385) ~[spring-rabbit-2.1.5.RELEASE.jar:2.1.5.RELEASE]
	at org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter.onMessage(MessageListenerAdapter.java:292) ~[spring-rabbit-2.1.5.RELEASE.jar:2.1.5.RELEASE]
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1552) ~[spring-rabbit-2.1.5.RELEASE.jar:2.1.5.RELEASE]
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1478) ~[spring-rabbit-2.1.5.RELEASE.jar:2.1.5.RELEASE]
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1466) ~[spring-rabbit-2.1.5.RELEASE.jar:2.1.5.RELEASE]
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:1461) ~[spring-rabbit-2.1.5.RELEASE.jar:2.1.5.RELEASE]
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1410) ~[spring-rabbit-2.1.5.RELEASE.jar:2.1.5.RELEASE]
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:870) [spring-rabbit-2.1.5.RELEASE.jar:2.1.5.RELEASE]
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:854) [spring-rabbit-2.1.5.RELEASE.jar:2.1.5.RELEASE]
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1600(SimpleMessageListenerContainer.java:78) [spring-rabbit-2.1.5.RELEASE.jar:2.1.5.RELEASE]
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.mainLoop(SimpleMessageListenerContainer.java:1137) [spring-rabbit-2.1.5.RELEASE.jar:2.1.5.RELEASE]
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1043) [spring-rabbit-2.1.5.RELEASE.jar:2.1.5.RELEASE]
	at java.lang.Thread.run(Thread.java:748) [na:1.8.0_171]
Caused by: java.lang.NoSuchMethodException: com.star.rabbitmq.adapter.MessageDelegate.consumeMessage(java.lang.String)
	at java.lang.Class.getMethod(Class.java:1786) ~[na:1.8.0_171]
	at org.springframework.util.MethodInvoker.prepare(MethodInvoker.java:181) ~[spring-core-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter.invokeListenerMethod(MessageListenerAdapter.java:362) ~[spring-rabbit-2.1.5.RELEASE.jar:2.1.5.RELEASE]
	... 12 common frames omitted

报错原因是以为在适配器方法中的处理参数是byte类型的,自定义的转换器将消息转换成了string类型,所以会报错,这也说明了转换器相关的代码生效了。

1.6 正常测试
3.2 RabbitMQ整合Spring AMQP实战(五)-MessageListenerAdapter_第4张图片
放开第三个方法,注释前两个方法
3.2 RabbitMQ整合Spring AMQP实战(五)-MessageListenerAdapter_第5张图片
重新运行testSendMessageAdaptText测试方法,观察控制台
3.2 RabbitMQ整合Spring AMQP实战(五)-MessageListenerAdapter_第6张图片
从控制台中可以看出,消息正常消费了。

MessageListenerAdapter适配器方式,队列名称和方法名称也可以进行一一的匹配。
step1 注释之前使用的自定义方法代码,添加如下代码:

/**
         * 2 适配器方式: 我们的队列名称 和 方法名称 也可以进行一一的匹配
         *
         * */
        MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
        adapter.setMessageConverter(new TextMessageConverter());
        Map<String, String> queueOrTagToMethodName = new HashMap<>();
        queueOrTagToMethodName.put("queue001", "method1");
        queueOrTagToMethodName.put("queue002", "method2");
        adapter.setQueueOrTagToMethodName(queueOrTagToMethodName);
        container.setMessageListener(adapter);

step 2 适配器MessageDelegate中的代码全部放开
在测试类中添加如下测试方法发送消息测试

/**
      * @Description: 测试适配器方式
      * @author kaili
      * @date 2019/4/23 22:02
     */
    @Test
    public void testSendMessageAdaptText() throws Exception {
        //1 创建消息
        MessageProperties messageProperties = new MessageProperties();
        messageProperties.setContentType("text/plain");
        Message message = new Message("mq 消息1234".getBytes(), messageProperties);
        rabbitTemplate.send("topic001", "spring.abc", message);
        rabbitTemplate.send("topic002", "rabbit.abc", message);
    }

step 3 启动测试类方法:
3.2 RabbitMQ整合Spring AMQP实战(五)-MessageListenerAdapter_第7张图片
打印的日志和适配器方法中的代码一致。

你可能感兴趣的:(RabbitMQ学习)