Spring Boot 集成 RabbitMQ的几种常见用法

Spring Boot 集成 RabbitMQ 非常简单,如果只是简单的使用配置非常少,Spring Boot 提供了spring-boot-starter-amqp 项目对消息各种支持。

简单使用

1、配置 Pom 包,主要是添加 spring-boot-starter-amqp 的支持

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

2、配置文件

配置 RabbitMQ 的安装地址、端口以及账户信息

  rabbitmq:
    virtual-host: /
    host: 127.0.0.1
    username: guest
    password: guest
    port: 5672
    publisher-confirms: true

3、队列配置(最简单的hello生产和消费实现(单生产者和单消费者))

package com.zoo.lion.modules.message.rabbitmq;

import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author: xf
 * @Date: 2019/6/12 13:49
 * @Version 1.0
 */
@Configuration
public class RabbitConfig {

   @Bean
    public Queue helloQueue() {
        return new Queue("helloQueue");
    }
}

3、发送者

rabbitTemplate 是 Spring Boot 提供的默认实现

package com.zoo.lion.modules.message.rabbitmq.fanout;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * 生产者
 */
@Component
public class Sender {

    @Autowired
    private AmqpTemplate rabbitTemplate;

    public void send() {
        String context = "Hello World" + new Date();
        System.out.println("Sender : " + context);
        this.rabbitTemplate.convertAndSend("helloQueue", context);
    }
}

4、接收者

package com.zoo.lion.modules.message.rabbitmq.fanout;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 消费者
 *
 */
@Component
@RabbitListener(queues = "helloQueue")
public class Receiver {

    @RabbitHandler
    public void process(String message) {
        System.out.println("Receiver message  : " + message);
    }
}

5、测试

package com.zoo.lion.modules.message.rabbitmq.controller;

import com.zoo.lion.common.bean.Resp;
import com.zoo.lion.modules.message.rabbitmq.fanout.Sender;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author: xf
 * @Date: 2019/7/17 13:19
 * @Version 1.0
 */
@RestController
@RequestMapping("/test/rabbit/")
public class RabbitController {

    @Autowired
    private Sender sender;

    //最简单的hello生产和消费实现(单生产者和单消费者)
    @RequestMapping("/test1")
    public Resp test1() {
        sender.send();
        return Resp.success("ok");
    }
}

注意,发送者和接收者的 queue name 必须一致,不然不能接收 

 多对多的使用

一个发送者,N 个接收者或者 N 个发送者和 N 个接收者会出现什么情况呢?

一对多发送

对上面的代码进行了小改造,接收端注册了两个 Receiver;Receiver1 和 Receiver2,发送端加入参数计数,接收端打印接收到的参数,下面是测试代码,发送10条消息,来观察两个接收端的执行效果:

package com.zoo.lion.modules.message.rabbitmq.fanout;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 消费者2
 *
 */
@Component
@RabbitListener(queues = "helloQueue")
public class Receiver1 {

    @RabbitHandler
    public void process(String message) {
        System.out.println("Receiver1 message  : " + message);
    }
}


package com.zoo.lion.modules.message.rabbitmq.fanout;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 消费者2
 *
 */
@Component
@RabbitListener(queues = "helloQueue")
public class Receiver2 {

    @RabbitHandler
    public void process(String message) {
        System.out.println("Receiver2 message  : " + message);
    }
}
    //单生产者-多消费者
    @RequestMapping("/oneToMany")
    public Resp oneToMany() {
        for (int i = 0; i < 10; i++) {
            sender.send("hello word" + i);
        }
        return Resp.success("ok");
    }

结果如下:

根据返回结果得到以下结论:

一个发送者,N个接受者,经过测试会均匀的将消息发送到N个接收者中 

多对多发送

复制了一份发送者,加入标记,在一百个循环中相互交替发送 

package com.zoo.lion.modules.message.rabbitmq.sender;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * 生产者1
 */
@Component
public class Sender1 {

    @Autowired
    private AmqpTemplate rabbitTemplate;

    public void send(String hello) {
        String context = hello + new Date();
        System.out.println("Sender1 : " + context);
        this.rabbitTemplate.convertAndSend("helloQueue", context);
    }
}
package com.zoo.lion.modules.message.rabbitmq.sender;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * 生产者2
 */
@Component
public class Sender2 {

    @Autowired
    private AmqpTemplate rabbitTemplate;

    public void send(String hello) {
        String context = hello + new Date();
        System.out.println("Sender2 : " + context);
        this.rabbitTemplate.convertAndSend("helloQueue", context);
    }
}
    //多生产者-多消费者
    @RequestMapping("/manyToMany")
    public Resp manyToMany() {
        for (int i = 0; i < 100; i++) {
            sender1.send("hello word" + i);
            sender2.send("hello word" + i);
        }
        return Resp.success("ok");
    }

测试结果如下:

结论:和一对多一样,接收端仍然会均匀接收到消息 

高级使用

对象的支持

Spring Boot 以及完美的支持对象的发送和接收,不需要格外的配置。

实体(必须实现序列化接口)

package com.zoo.lion.modules.message.rabbitmq.entity;

import lombok.Data;

import java.io.Serializable;

/**
 * @Author: xf
 * @Date: 2019/7/17 13:50
 * @Version 1.0
 */
@Data
public class User implements Serializable {
    private String name;
    private String pass;
}

配置(必须配置队列)

    @Bean
    public Queue userQueue() {
        return new Queue("userQueue");
    }

 生产者

package com.zoo.lion.modules.message.rabbitmq.sender;

import com.zoo.lion.modules.message.rabbitmq.entity.User;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @Author: xf
 * @Date: 2019/7/17 13:51
 * @Version 1.0
 */
@Component
public class UserSender {
    @Autowired
    private AmqpTemplate rabbitTemplate;

    public void send() {
        User user=new User();
        user.setName("谢飞");
        user.setPass("123456789");
        System.out.println("user send : " + user.getName()+"/"+user.getPass());
        this.rabbitTemplate.convertAndSend("userQueue", user);
    }
}

消费者

package com.zoo.lion.modules.message.rabbitmq.receiver;

import com.zoo.lion.modules.message.rabbitmq.entity.User;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * @Author: xf
 * @Date: 2019/7/17 13:54
 * @Version 1.0
 */
@Component
@RabbitListener(queues = "userQueue")
public class UserReceiver {

    @RabbitHandler
    public void process(User user) {
        System.out.println("user receive  : " + user.getName() + "/" + user.getPass());
    }

}

controller:

    //实体类传输测试
    @RequestMapping("/userTest")
    public Resp userTest() {
        userSender.send();
        return Resp.success("ok");
    }

测试结果:

Topic Exchange 

topic 是 RabbitMQ 中最灵活的一种方式,可以根据 routing_key 自由的绑定不同的队列

首先对 topic 规则配置,这里使用两个队列来测试(topic.message和topic.messages两个队列),

其中topic.message的bindting_key为“topic.message”,topic.messages的binding_key为“topic.#”;

配置:

package com.zoo.lion.modules.message.rabbitmq;

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author: xf
 * @Date: 2019/7/17 15:38
 * @Version 1.0
 */
@Configuration
public class TopicRabbitConfig {

    private final static String message = "topic.message";
    private final static String messages = "topic.messages";

    @Bean
    public Queue queueMessage() {
        return new Queue(TopicRabbitConfig.message);
    }

    @Bean
    public Queue queueMessages() {
        return new Queue(TopicRabbitConfig.messages);
    }

    @Bean
    TopicExchange exchange() {
        return new TopicExchange("exchange");
    }


    //将队列topic.message与exchange绑定,binding_key为topic.message,就是完全匹配
    @Bean
    Binding bindingExchangeMessage(Queue queueMessage, TopicExchange exchange) {
        return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message");
    }

    //将队列topic.messages与exchange绑定,binding_key为topic.#,模糊匹配
    @Bean
    Binding bindingExchangeMessages(Queue queueMessages, TopicExchange exchange) {
        return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#");
    }
}

生产者:

package com.zoo.lion.modules.message.rabbitmq.sender;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @Author: xf
 * @Date: 2019/7/17 15:42
 * @Version 1.0
 */
@Component
public class TopicSender {

    @Autowired
    private AmqpTemplate rabbitTemplate;

    public void send1() {
        String context = "hi, i am message 1";
        System.out.println("Sender : " + context);
        this.rabbitTemplate.convertAndSend("exchange", "topic.message", context);
    }

    public void send2() {
        String context = "hi, i am messages 2";
        System.out.println("Sender : " + context);
        this.rabbitTemplate.convertAndSend("exchange", "topic.messages", context);
    }
}

消费者1(topic.message)

package com.zoo.lion.modules.message.rabbitmq.receiver;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * @Author: xf
 * @Date: 2019/7/17 15:44
 * @Version 1.0
 */
@Component
@RabbitListener(queues = "topic.message")
public class TopicReceiver1 {

    @RabbitHandler
    public void process(String msg) {
        System.out.println("topicMessageReceiver1  : " +msg);
    }

}

消费者2(topic.messages)

package com.zoo.lion.modules.message.rabbitmq.receiver;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * @Author: xf
 * @Date: 2019/7/17 15:44
 * @Version 1.0
 */
@Component
@RabbitListener(queues = "topic.messages")
public class TopicReceiver2 {

    @RabbitHandler
    public void process(String msg) {
        System.out.println("topicMessageReceiver2  : " +msg);
    }

}

controller:

    //topic exchange类型rabbitmq测试
    @RequestMapping("/topicTest")
    public void topicTest() {
        topicSender.send1();
        topicSender.send2();
    }

测试结果:

Fanout Exchange

Fanout 就是我们熟悉的广播模式或者订阅模式,给Fanout转发器发送消息,绑定了这个转发器的所有队列都收到这个消息。

这里使用三个队列来测试(也就是在Application类中创建和绑定的fanout.A、fanout.B、fanout.C)这三个队列都和Application中创建的fanoutExchange转发器绑定。

这里使用了 A、B、C 三个队列绑定到 Fanout 交换机上面,发送端的 routing_key 写任何字符都会被忽略:

配置:

package com.zoo.lion.modules.message.rabbitmq;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author: xf
 * @Date: 2019/7/17 15:53
 * @Version 1.0
 */
@Configuration
public class FanoutRabbitConfig {
    @Bean
    public Queue AMessage() {
        return new Queue("fanout.A");
    }

    @Bean
    public Queue BMessage() {
        return new Queue("fanout.B");
    }

    @Bean
    public Queue CMessage() {
        return new Queue("fanout.C");
    }

    @Bean
    FanoutExchange fanoutExchange() {
        return new FanoutExchange("fanoutExchange");
    }

    @Bean
    Binding bindingExchangeA(Queue AMessage, FanoutExchange fanoutExchange) {
        return BindingBuilder.bind(AMessage).to(fanoutExchange);
    }

    @Bean
    Binding bindingExchangeB(Queue BMessage, FanoutExchange fanoutExchange) {
        return BindingBuilder.bind(BMessage).to(fanoutExchange);
    }

    @Bean
    Binding bindingExchangeC(Queue CMessage, FanoutExchange fanoutExchange) {
        return BindingBuilder.bind(CMessage).to(fanoutExchange);
    }
}

生产者:

package com.zoo.lion.modules.message.rabbitmq.sender;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @Author: xf
 * @Date: 2019/7/17 15:56
 * @Version 1.0
 */
@Component
public class FanoutSender {
    @Autowired
    private AmqpTemplate rabbitTemplate;

    public void send() {
        String msgString = "fanoutSender :hello i am hzb";
        System.out.println(msgString);
        this.rabbitTemplate.convertAndSend("fanoutExchange", "abcd.ee", msgString);
    }


}

消费者A:

package com.zoo.lion.modules.message.rabbitmq.receiver;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * @Author: xf
 * @Date: 2019/7/17 15:57
 * @Version 1.0
 */
@Component
@RabbitListener(queues = "fanout.A")
public class FanoutReceiverA {
    @RabbitHandler
    public void process(String msg) {
        System.out.println("FanoutReceiverA  : " + msg);
    }

}

消费者B:

package com.zoo.lion.modules.message.rabbitmq.receiver;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * @Author: xf
 * @Date: 2019/7/17 15:57
 * @Version 1.0
 */
@Component
@RabbitListener(queues = "fanout.B")
public class FanoutReceiverB {
    @RabbitHandler
    public void process(String msg) {
        System.out.println("FanoutReceiverB  : " + msg);
    }

}

消费者C:
 

package com.zoo.lion.modules.message.rabbitmq.receiver;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * @Author: xf
 * @Date: 2019/7/17 15:57
 * @Version 1.0
 */
@Component
@RabbitListener(queues = "fanout.C")
public class FanoutReceiverC {
    @RabbitHandler
    public void process(String msg) {
        System.out.println("FanoutReceiverC  : " + msg);
    }

}

 controller:


    //fanout exchange类型rabbitmq测试
    @RequestMapping("/fanoutTest")
    public void fanoutTest() {
        fanoutSender.send();
    }

结果如下:

结果说明,绑定到 fanout 交换机上面的队列都收到了消息

带callback的消息发送 

增加回调处理,这里不再使用application.yml默认配置的方式,会在程序中显示的使用文件中的配置信息。

该示例中没有新建队列和exchange,用的是topic.messages队列和exchange转发器。消费者是之前的topicReceiver2

配置类:

    @Bean
    public ConnectionFactory connectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setAddresses("127.0.0.1" + ":" + "5672");
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        connectionFactory.setVirtualHost("/");
        /** 如果要进行消息回调,则这里必须要设置为true */
        connectionFactory.setPublisherConfirms(true);
        return connectionFactory;
    }

    @Bean
    /** 因为要设置回调类,所以应是prototype类型,如果是singleton类型,则回调类为最后一次设置 */
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public RabbitTemplate rabbitTemplatenew() {
        RabbitTemplate template = new RabbitTemplate(connectionFactory());
        return template;
    }

生产者:

package com.zoo.lion.modules.message.rabbitmq.sender;

import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.UUID;

/**
 * @Author: xf
 * @Date: 2019/7/17 16:08
 * @Version 1.0
 */
@Component
public class CallBackSender implements RabbitTemplate.ConfirmCallback {
    @Override
    public void confirm(CorrelationData correlationData, boolean b, String s) {
        System.out.println("callbakck confirm: " + correlationData.getId());
    }


    @Autowired
    private RabbitTemplate rabbitTemplatenew;
    public void send() {

        rabbitTemplatenew.setConfirmCallback(this);
        String msg="callbackSender : i am callback sender";
        System.out.println(msg );
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        System.out.println("callbackSender UUID: " + correlationData.getId());
        this.rabbitTemplatenew.convertAndSend("exchange", "topic.messages", msg, correlationData);
    }

}

消费者:

package com.zoo.lion.modules.message.rabbitmq.receiver;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * @Author: xf
 * @Date: 2019/7/17 15:44
 * @Version 1.0
 */
@Component
@RabbitListener(queues = "topic.messages")
public class TopicReceiver2 {

    @RabbitHandler
    public void process(String msg) {
        System.out.println("topicMessageReceiver2  : " +msg);
    }

}

controller:

    @RequestMapping("/callback")
    public void callbak() {
        callBackSender.send();
    }

结果:

(完。) 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值