5、SpringAMQP整合RabbitMq

 

POM文件中

<dependency>
    <groupId>org.springframework.amqp</groupId>
	<artifactId>spring-rabbit-test</artifactId>
	<scope>test</scope>
</dependency>
<dependency>
	<groupId>com.rabbitmq</groupId>
	<artifactId>amqp-client</artifactId>
	<version>5.5.3</version>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

通过bean的方式,将RabbitAdmin注入到容器中

/**
 * 在配置文件中,将RabbitAdmin加载到spring容器中
 */
@Configuration
@ComponentScan({"com.atguigu.rabbit.rabbitmqtest.spring.*"})
public class RabbitMQConfig {

     /**
     * 配置连接工厂
     */
    @Bean
    public ConnectionFactory connectionFactory(){
        CachingConnectionFactory factory=new CachingConnectionFactory();
        factory.setAddresses("192.168.1.60:5672");
        factory.setVirtualHost("/user_db");
        factory.setUsername("users");
        factory.setPassword("123");
        return factory;
    }

    /**
     * setAutoStartup必须设置为true。这样容器启动后,才会加载rabbitadmin
     * @param connectionFactory
     * @return
     */
    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
        RabbitAdmin rabbitAdmin=new RabbitAdmin(connectionFactory);
        rabbitAdmin.setAutoStartup(true);
        return rabbitAdmin;
    }
}

 

在配置文件中,声明交换机,队列。将队列和交换机进行绑定

@Configuration
@ComponentScan({"com.atguigu.rabbit.rabbitmqtest.spring.*"})
public class RabbitMQConfig {
    
    /**
     * 配置连接工厂
     */
    @Bean
    public ConnectionFactory connectionFactory(){
        CachingConnectionFactory factory=new CachingConnectionFactory();
        factory.setAddresses("192.168.1.60:5672");
        factory.setVirtualHost("/user_db");
        factory.setUsername("users");
        factory.setPassword("123");
        return factory;
    }

    /**
     * setAutoStartup必须设置为true。这样容器启动后,才会加载rabbitadmin
     * @param connectionFactory
     * @return
     */
    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
        RabbitAdmin rabbitAdmin=new RabbitAdmin(connectionFactory);
        rabbitAdmin.setAutoStartup(true);
        return rabbitAdmin;
    }

    /**
     * SpringAMQP声明队列、交换机、绑定
     */

    //声明Fanout交换机
    @Bean
    public FanoutExchange fanoutExchange(){
        return  new FanoutExchange("fanout_exchange_springAMQP",false,false);
    }

    //声明一个队列
    @Bean
    public Queue queue001(){
        return  new Queue("queue001_name",true);//队列持久化
    }

    //队列和交换机绑定
    @Bean
    public Binding binding(){
        return  BindingBuilder.bind(queue001()).to(fanoutExchange());
    }

    //声明topic交换机
    @Bean
    public TopicExchange topicExchange(){
        return new TopicExchange("topic_exchange_springAMQP",false,true);
    }

    @Bean
    public Queue queue002(){
        return new Queue("queue002_name",true);
    }
    //将002队列绑定到topic交换机上
    @Bean
    public Binding binding2(){
        return BindingBuilder.bind(queue002()).to(topicExchange()).with("spring.#");
    }

    @Bean
    public DirectExchange directExchange(){
        return new DirectExchange("direct_exchange_springAMQP",false,true);
    }
    @Bean
    public Queue queue003(){
        return new Queue("queue003_name",true);
    }

    //将002队列绑定到topic交换机上
    @Bean
    public Binding binding3(){
        return BindingBuilder.bind(queue003()).to(directExchange()).with("spring.send");
    }
}

 

RabbitTemplate消息模板

RabbitTemplate类提供了丰富的发送消息方法,包括可靠性投递消息方法、回调监听消息接口ConfiremCallback、返回值确认接口ReturnCallback等等。同样,这个类我们也要注入到Spring容器中,然后才能使用。

config配置类

    @Bean
    public ConnectionFactory connectionFactory(){
        CachingConnectionFactory factory=new CachingConnectionFactory();
        factory.setAddresses("192.168.1.60:5672");
        factory.setVirtualHost("/user_db");
        factory.setUsername("users");
        factory.setPassword("123");
        return factory;
    }

    /**
     * 注册rabbitTemplate消息模板
     */
    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
        return new RabbitTemplate(connectionFactory);
    }

测试发送消息的方式

@SpringBootTest
public class RabbitTemplateTest {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void testSendMessage(){
        /**
         *利用convertAndSend可以简单发送消息
         */
        rabbitTemplate.convertAndSend("topic_exchange_springAMQP","spring.send2","稍微简单的发送一个消息".getBytes());

        System.out.println("------------------------华丽的分割线---------------------------------");
        /**
         *rabbitTemplate.send的方式可以实现发送消息
         */
        MessageProperties messageProperties2=new MessageProperties();
        messageProperties2.getHeaders().put("type","消息类型");
        Message message2=new Message("Hello RabbitMq".getBytes(),messageProperties2);
        rabbitTemplate.send("topic_exchange_springAMQP","spring.send2",message2);


        System.out.println("------------------------华丽的分割线---------------------------------");
        /**
         * 以下是对消息属性进行设置。然后在发送消息
         */
        MessageProperties messageProperties=new MessageProperties();
        messageProperties.getHeaders().put("desc","消息的描述。。。。");
        messageProperties.getHeaders().put("type","消息类型");
       // messageProperties.setExpiration("10000");//10秒不被消费,自动删除
        //声明消息
        Message message=new Message("Hello RabbitMq".getBytes(),messageProperties);

        //设置发送到的交换机、路由key、消息、new MessagePostProcessor在发送之前,再对消息属性进行修改
        rabbitTemplate.convertAndSend("topic_exchange_springAMQP", "spring.send", message, new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                System.out.println("---------------消息发送之前,在对消息进行加工----------------------");
                message.getMessageProperties().getHeaders().put("desc","修改了消息描述");
                message.getMessageProperties().getHeaders().put("id","新增消息属性");
                return message;
            }
        });
    }
}

 

SimpleMessageListenerContainer简单消息监听容器

作用:

  • 可以监听队列(多个队列)、自动启动、自动声明等功能。
  • 也可以设置事务特性、事务管理器、事务属性、事务容量(并发)、是否开启事务、回滚消息等。
  • 设置消息确认和自动确认模式、是否重回队列、异常捕获handler函数。
  • 设置消费者标签生成策略、是否独占模式、消费者属性等。
  • 设置具体的监听器、消息转换器等等。

注意:

  • SimpleMessageListenerContainer可以进行动态设置。比如在运行中的应用可以动态修改其消费者的数量、接收消息的模式等。
/**
     * 注册消息监听容器
     * @param connectionFactory,将连接工厂当参数传过来。
     * @return
     */
    @Bean
    public SimpleMessageListenerContainer messageContainer(ConnectionFactory connectionFactory){
        //注册SimpleMessageListenerContainer
        SimpleMessageListenerContainer Container=new SimpleMessageListenerContainer(connectionFactory);
        //设置需要监听队列
        Container.setQueues(queue001(),queue002(),queue003());
        //当前消费者数量
        Container.setConcurrentConsumers(1);
        //最大的消费者数量
        Container.setMaxConcurrentConsumers(1);
        //是否重回队列
        Container.setDefaultRequeueRejected(false);
        //设置消息签收模式(AUTO自动签收)
        Container.setAcknowledgeMode(AcknowledgeMode.AUTO);
        //是否自动声明
        Container.setAutoDeclare(true);
        //设置消费端消费标签策略
        Container.setConsumerTagStrategy(new ConsumerTagStrategy() {
            @Override
            public String createConsumerTag(String queue) {
                return queue+"_"+ UUID.randomUUID().toString();
            }
        });
        //设置消息监听。new一个消息监听器
        Container.setMessageListener(new ChannelAwareMessageListener() {
            @Override
            public void onMessage(Message message, Channel channel) throws Exception {
                String msg=new String(message.getBody(),"UTF-8");
                System.out.println("============消费者-----》"+msg);
            }
        });

        //Container.set还有很多方法,适用很多地方。比如事务等等
        return Container;
    }
}

测试的话,请点击上面RabbitTemplate发送消息的测试类。点击发送,在控制台可以看到接收的消息。

 

MessageListenerAdapter消息监听适配器

在注册SimpleMessageListenerContainer 的时候,不用消息监听器的方法,自己创建一个消息监听适配器。将这个类。放入SimpleMessageListenerContainer监听容器中。

 /**
     * 注册消息监听容器
     * @param connectionFactory
     * @return
     */
    @Bean
    public SimpleMessageListenerContainer messageContainer(ConnectionFactory connectionFactory){
        //注册SimpleMessageListenerContainer
        SimpleMessageListenerContainer Container=new SimpleMessageListenerContainer(connectionFactory);
       
       /* //设置消息监听   ****这种方法不用了。
        Container.setMessageListener(new ChannelAwareMessageListener() {
            @Override
            public void onMessage(Message message, Channel channel) throws Exception {
                String msg=new String(message.getBody(),"UTF-8");
                System.out.println("============消费者-----》"+msg);
            }
        });*/

       /**
         * 第1种:用适配的方式,写一个消息监听适配器。
         */
        MessageListenerAdapter messageListenerAdapter=new MessageListenerAdapter(new MyMessageListenerAdapter());
        //设置指定方法
        messageListenerAdapter.setDefaultListenerMethod("consumeMessage");
        Container.setMessageListener(messageListenerAdapter);
        
        return Container;
    }

自定义的消息适配器

public class MyMessageListenerAdapter {

    /**
     * 这个方法名字(handleMessage)是固定的,
     * 如果配置类中没有指定默认方法,mq就会指定这个方法为默认方法。
     * 如果指定其他方法,可以在配置类中使用messageListenerAdapter.setDefaultListenerMethod("consumeMessage");
     */
    public void handleMessage(byte[] messageBody) {
        System.err.println("默认方法, 消息内容:" + new String(messageBody));
    }

    /**
     * 覆盖默认的消息接收方法;
     */
    public void consumeMessage(byte[] messageBody) {
        System.err.println("字节数组方法, 消息内容:" + new String(messageBody));
    }
}

MessageListenerAdapter第二种方法:

queueOrTagToMethodName:将方法和队列进行绑定

 /**
     * 注册消息监听容器
     * @param connectionFactory
     * @return
     */
    @Bean
    public SimpleMessageListenerContainer messageContainer(ConnectionFactory connectionFactory){
        //注册SimpleMessageListenerContainer
        SimpleMessageListenerContainer Container=new SimpleMessageListenerContainer(connectionFactory);
       
       /* //设置消息监听   ****这种方法不用了。
        Container.setMessageListener(new ChannelAwareMessageListener() {
            @Override
            public void onMessage(Message message, Channel channel) throws Exception {
                String msg=new String(message.getBody(),"UTF-8");
                System.out.println("============消费者-----》"+msg);
            }
        });*/

        /*//第1种:用适配的方式,写一个消息监听适配器。
        MessageListenerAdapter messageListenerAdapter=new MessageListenerAdapter(new MyMessageListenerAdapter());
        //设置指定方法
        messageListenerAdapter.setDefaultListenerMethod("consumeMessage");
        Container.setMessageListener(messageListenerAdapter);*/


        //第2种:我们可以将队列名称和方法名称进行一一对应
        MessageListenerAdapter adapter =new MessageListenerAdapter(new MyMessageListenerAdapter());
        Map<String,String> queueOrTagToMethodName=new HashMap<>();
        //key是**队列名称,不是上面定义的bean的名称**,value是方法名称。方法定义在自己写的适配器中
        queueOrTagToMethodName.put("queue003_name","method3");
        queueOrTagToMethodName.put("queue002_name","method2");
        adapter .setQueueOrTagToMethodName(queueOrTagToMethodName);
        Container.setMessageListener(adapter);
        
        return Container;
    }

自定义的适配器,添加method2和method3两个方法

public class MyMessageListenerAdapter {

    /**
     * 这个方法名字(handleMessage)是固定的,
     * 如果配置类中没有指定默认方法,mq就会指定这个方法为默认方法。
     * 如果指定其他方法,可以在配置类中使用messageListenerAdapter.setDefaultListenerMethod("consumeMessage");
     */
    public void handleMessage(byte[] messageBody) {
        System.err.println("默认方法, 消息内容:" + new String(messageBody));
    }

    /**
     * 覆盖默认的消息接收方法;
     */
    public void consumeMessage(byte[] messageBody) {
        System.err.println("字节数组方法, 消息内容:" + new String(messageBody));
    }

    public void method3(byte[] messageBody) {
        System.err.println("方法3,绑定在队列3上-------:" + new String(messageBody));
    }

    public void method2(byte[] messageBody) {
        System.err.println("方法2,绑定在队列2上-------:" + new String(messageBody));
    }
}

测试类

 @Test
    public void testmessage2(){
        rabbitTemplate.convertAndSend("topic_exchange_springAMQP","spring.save","应该是发送到方法2上".getBytes());
        rabbitTemplate.convertAndSend("direct_exchange_springAMQP","direct.save","发送到方法3上".getBytes());
    }

 

MessageConverter消息转换器

解析:我们在发送消息的时候,正常情况下消息体为二进制的数据方法(getBytes),如果我们内部需要转换,或者指定自定义转换器,就需要用到MessageConverter。

将字节转换成字符串

1.自定义转换器类

/**
 * 自定义转换器类,实现MessageConverter接口,重写tomessage和frommessage两个方法。将字节转换成字符串。
 */
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 {
		return new String(message.getBody());
	}
}

2.config类

/**
     * 注册消息监听容器
     * @param connectionFactory
     * @return
     */
    @Bean
    public SimpleMessageListenerContainer messageContainer(ConnectionFactory connectionFactory){
         //注册SimpleMessageListenerContainer
        SimpleMessageListenerContainer Container=new SimpleMessageListenerContainer(connectionFactory);

        /**
         * 1 适配器方式. 默认是有自己的方法名字的:handleMessage
         */
         MessageListenerAdapter adapter = new MessageListenerAdapter(new MyMessageListenerAdapter());
         //下面的consumeMessage方法,就可以直接用string接收
         adapter.setDefaultListenerMethod("consumeString");
        //set设置消息转换器,接收的消息就不在是字节数据,可以是字符串直接输出
        adapter.setMessageConverter(new TextMessageConverter());
         Container.setMessageListener(adapter);
        return Container;
    }

3.在自定义消息监听器类中,定义接收方法

public class MyMessageListenerAdapter {


    public void handleMessage(byte[] messageBody) {
        System.err.println("默认方法, 消息内容:" + new String(messageBody));
    }

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

    /**
     *以上方法的接收都是字节。
     * 消息转换器,将字节转成字符串。
     */
    public void consumeString(String messageBody) {
        System.err.println("测试字节转换成字符串:" + messageBody);
    }
}

4.定义测试方法。

 @Test
    public void testSendMessageSting(){
        rabbitTemplate.convertAndSend("topic_exchange_springAMQP","spring.send","测试消息转换成string".getBytes());

    }

支持json转换器

1.config类

/**
     * 注册消息监听容器
     * @param connectionFactory
     * @return
     */
    @Bean
    public SimpleMessageListenerContainer messageContainer(ConnectionFactory connectionFactory){
         //注册SimpleMessageListenerContainer
        SimpleMessageListenerContainer Container=new SimpleMessageListenerContainer(connectionFactory);
   
     /**
         * 定义支持json格式的转换器
         */
        MessageListenerAdapter adapter = new MessageListenerAdapter(new MyMessageListenerAdapter());
        //接收的方法,参数必须是map格式
        adapter.setDefaultListenerMethod("consumeJson");
        //new 一个Jackson2JsonMessageConverter,并将这个类,set到消息监听器中
        Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();
        adapter.setMessageConverter(jackson2JsonMessageConverter);
        
        Container.setMessageListener(adapter);
        return Container;
    }

2.在自定义消息监听器类中,定义接收方法。接收参数必须是map

public class MyMessageListenerAdapter {

    public void handleMessage(byte[] messageBody) {
        System.err.println("默认方法, 消息内容:" + new String(messageBody));
    }
    public void consumeMessage(byte[] messageBody) {
        System.err.println("字节数组方法, 消息内容:" + new String(messageBody));
    }
    public void consumeString(String messageBody) {
        System.err.println("测试字节转换成字符串:" + messageBody);
    }
    /**
     * 定义接收json格式数据
     * @param messageBody
     */
    public void consumeJson(Map messageBody) {
        System.err.println("测试字节转换成json格式:" + messageBody);
    }
}

3.定义测试方法

   @Test
    public void testSendMessageJson() throws JSONException {
        JSONObject jsonObject=new JSONObject();
        jsonObject.put("desc","111");
        jsonObject.put("id","32");
        rabbitTemplate.convertAndSend("topic_exchange_springAMQP","spring.send",jsonObject.toString().getBytes());
    }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值