SpringBoot集成RabbitMQ

Docker安装RabbitMQ

下载带有管理界面的RabbitMQ Docker镜像

docker pull rabbitmq:3.7.7-management

然后创建并运行RabbitMQ容器

docker run -d --name rabbitmq3.7.7 -p 5672:5672 -p 15672:15672 -v `pwd`/data:/var/lib/rabbitmq --hostname myRabbit -e RABBITMQ_DEFAULT_VHOST=my_vhost  -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin rabbitmq:3.7.7-management  
docker run -d --hostname rabbitmqhost --name rabbitmq3.6 --restart always -p 5672:5672  -p 15672:15672 -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin rabbitmq:3.6.15-management

-d:后台运行
--hostname:设置容器的主机名
--name:容器命名
--restart always:开机启动
-p:端口号映射,前面是宿主机端口,后面是容器端口
-v:挂载宿主机目录到容器目录
-e:设置容器环境变量

游览器访问:http://服务器ip地址:15672
输入启动容器是设置的用户名密码登录就进去管理页面啦

先关概念

交换机

交换机的主要功能是接收消息并转发到绑定的队列,交换机自身不存储消息,当启动ack模式后,交换机找不到指定的队列会返回错误。交换机类型有Direct、topic、 Headers、Fanout四种类型

Direct Exchange交换机

Direct Exchange 是 RabbitMQ 默认的交换机模式,也是最简单的模式,根据key全文匹配去寻找队列。发送消息是设置一个routing_key,当routing_key匹配时才将消息传送到绑定的队列中。

Topic Exchange交换机

Topic Exchange跟Direct Exchange类似,在匹配上增加了模式概念,从以点分开的routing_key形式中,可用使用2中统配符:*表示一个单词,#表示0个或者多个单词

Headers Exchange交换机

Headers Exchange是一个自定义匹配规则的类型,在交换器与队列绑定时,会制定一组键值对规则,发送消息时也会制定一组规则,当这些键值对有一对或者多对匹配时,消息会传送到对应的队列中。

Fanout Exchange交换机

Fanout Exchange用的是消息广播模式,设置路由建无效,它会把消息传送给交换机下的所有队列。

SpringBoot集成RabbitMQ

简单使用

创建一个主工程:spring-boot-rabbitmq,添加如下内容:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <!--<version>2.1.5.RELEASE</version>-->
    <version>1.5.20.RELEASE</version>
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
    <spring-boot.version>1.5.20.RELEASE</spring-boot.version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring-boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

在spring-boot-rabbitmq主工程中创建一个RabbitMQ配置的Maven module:rabbitmq-config
添加如下依赖:

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

创建一个配置类:RabbitConfig.java,添加如下内容

@Configuration
public class RabbitConfig {

    //创建一个hello-queue消息队列
    @Bean
    public Queue helloQueue() {
        return new Queue("hello-queue");
    }
}

在spring-boot-rabbitmq主工程中创建一个消息发送方的SpringBoot module:rabbitmq-sender
在pom文件中添加如下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>com.alyshen</groupId>
    <artifactId>rabbitmq-config</artifactId>
    <version>${project.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

在resource目录下创建配置文件:application.properties,添加如下内容:

############### 服务配置 #############
server.port=9000
spring.application.name=rabbitmq-sender

############### RabbitMQ配置 ##############
spring.rabbitmq.host=192.168.86.101
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=admin

创建工程启动类:RabbitmqSenderApplication.java,添加如下内容:

@SpringBootApplication
public class RabbitmqSenderApplication {

    public static void main(String[] args) {
        SpringApplication.run(RabbitmqSenderApplication.class,args);
    }
}

创建一个消息生产者:HelloQueueSender.java

@Component
public class HelloQueueSender {

    @Autowired
    private AmqpTemplate amqpTemplate;

    public void send(String msg) {
        String context = msg + ",sender date:" + new Date();
        System.out.println("Sender to hello-queue: " + context);
        this.amqpTemplate.convertAndSend("hello-queue", context);//使用hello-queue队列
    }
}

创建一个HelloSenderController供浏览器发送消息,添加如下内容:

@RestController
public class HelloSenderController {

    @Autowired
    private HelloQueueSender helloQueueSender;

    @RequestMapping(value = "/senderMessage")
    public String senderMessage(@PathParam(value = "msg") String msg){
        helloQueueSender.send(msg);
        return "sender ok...";
    }
}

运行项目rabbitmq-sender,访问:
http://localhost:9000/senderMessage?msg=消息内容
这时消息内容保存到rabbitmq队列中待消息消费方获取

创建一个消息接收方的SpringBoot工程:rabbitmq-receiver
在pom文件中添加如下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>com.alyshen</groupId>
    <artifactId>rabbitmq-config</artifactId>
    <version>${project.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

在resource目录下创建配置文件:application.properties,添加如下内容:

############### 服务配置 #############
server.port=9100
spring.application.name=rabbitmq-receiver

############### RabbitMQ配置 ##############
spring.rabbitmq.host=192.168.86.101
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=admin

创建工程启动类:RabbitmqReceiverApplication.java
添加如下内容:

@SpringBootApplication
public class RabbitmqReceiverApplication {

    public static void main(String[] args) {
        SpringApplication.run(RabbitmqReceiverApplication.class,args);
    }
}

在rabbitmq-receiver的pom文件中加入rabbitmq-config工程依赖

创建一个消息处理者:HelloQueueReceiver.java

@Component
@RabbitListener(queues = "hello-queue")
public class HelloQueueReceiver {

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

启动工程rabbitmq-receiver,输出内容:
Receiver:消息内容,……

即获取到消息内容

多对多使用

一对多使用

将rabbitmq-sender中的HelloSenderController内容修改成如下所示:

@RestController
public class HelloSenderController {

    @Autowired
    private HelloQueueSender helloQueueSender;

    @RequestMapping(value = "/senderMessage")
    public String senderMessage(@PathParam(value = "msg") String msg) {
        for (int i = 1; i <= 20; i++) {
            helloQueueSender.send(i + "," + msg);
        }
        return "sender ok...";
    }
}

把rabbitmq-receiver中的HelloQueueReceiver.java复制一份,分别改成如下:
HelloQueueReceiver.java

@Component
@RabbitListener(queues = "hello-queue")
public class HelloQueueReceiver {

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

HelloQueueReceiver2.java

@Component
@RabbitListener(queues = "hello-queue")
public class HelloQueueReceiver2 {

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

将rabbitmq-sender和rabbitmq-receiver运行起来
访问http://localhost:9000/senderMessage?msg=消息内容

rabbitmq-sender控制台输出:
Sender to hello-queue: 1,消息内容,……
Sender to hello-queue: 2,消息内容,……
Sender to hello-queue: 3,消息内容,……
Sender to hello-queue: 4,消息内容,……
Sender to hello-queue: 5,消息内容,……
Sender to hello-queue: 6,消息内容,……
Sender to hello-queue: 7,消息内容,……
Sender to hello-queue: 8,消息内容,……
Sender to hello-queue: 9,消息内容,……
Sender to hello-queue: 10,消息内容,……
Sender to hello-queue: 11,消息内容,……
Sender to hello-queue: 12,消息内容,……
Sender to hello-queue: 13,消息内容,……
Sender to hello-queue: 14,消息内容,……
Sender to hello-queue: 15,消息内容,……
Sender to hello-queue: 16,消息内容,……
Sender to hello-queue: 17,消息内容,……
Sender to hello-queue: 18,消息内容,……
Sender to hello-queue: 19,消息内容,……
Sender to hello-queue: 20,消息内容,……

rabbitmq-receiver控制台输出:

Receiver 1:1,消息内容,……
Receiver 2:2,消息内容,……
Receiver 1:3,消息内容,……
Receiver 2:4,消息内容,……
Receiver 1:5,消息内容,……
Receiver 2:6,消息内容,……
Receiver 1:7,消息内容,……
Receiver 2:8,消息内容,……
Receiver 1:9,消息内容,……
Receiver 2:10,消息内容,……
Receiver 1:11,消息内容,……
Receiver 2:12,消息内容,……
Receiver 1:13,消息内容,……
Receiver 2:14,消息内容,……
Receiver 1:15,消息内容,……
Receiver 2:16,消息内容,……
Receiver 1:17,消息内容,……
Receiver 2:18,消息内容,……
Receiver 1:19,消息内容,……
Receiver 2:20,消息内容,……

可以看出消息消费方是轮流有序的获取消息的

多对多使用

将rabbitmq-sender中的HelloQueueSender复制一份创建HelloQueueSender2,就类名不一样,其他都一样
改造一下rabbitmq-sender工程中的HelloSenderController,改成入下:

@RestController
public class HelloSenderController {

    @Autowired
    private HelloQueueSender helloQueueSender;
    @Autowired
    private HelloQueueSender2 helloQueueSender2;

    @RequestMapping(value = "/senderMessage")
    public String senderMessage(@PathParam(value = "msg") String msg) {
        for (int i = 1; i <= 20; i++) {
            helloQueueSender.send("sender1 " + i + "." + msg);
            helloQueueSender2.send("sender2 " + i + "." + msg);
        }
        return "sender ok...";
    }
}

运行rabbitmq-sender
访问http://localhost:9000/senderMessage?msg=消息内容

rabbitmq-sender控制台输出
Sender to hello-queue: sender1 1.消息内容,……
Sender to hello-queue: sender2 1.消息内容,……
Sender to hello-queue: sender1 2.消息内容,……
Sender to hello-queue: sender2 2.消息内容,……
Sender to hello-queue: sender1 3.消息内容,……
Sender to hello-queue: sender2 3.消息内容,……
Sender to hello-queue: sender1 4.消息内容,……
Sender to hello-queue: sender2 4.消息内容,……
Sender to hello-queue: sender1 5.消息内容,……
Sender to hello-queue: sender2 5.消息内容,……
Sender to hello-queue: sender1 6.消息内容,……
Sender to hello-queue: sender2 6.消息内容,……
Sender to hello-queue: sender1 7.消息内容,……
Sender to hello-queue: sender2 7.消息内容,……
Sender to hello-queue: sender1 8.消息内容,……
Sender to hello-queue: sender2 8.消息内容,……
Sender to hello-queue: sender1 9.消息内容,……
Sender to hello-queue: sender2 9.消息内容,……
Sender to hello-queue: sender1 10.消息内容,……
Sender to hello-queue: sender2 10.消息内容,……
Sender to hello-queue: sender1 11.消息内容,……
Sender to hello-queue: sender2 11.消息内容,……
Sender to hello-queue: sender1 12.消息内容,……
Sender to hello-queue: sender2 12.消息内容,……
Sender to hello-queue: sender1 13.消息内容,……
……

rabbitmq-receiver的控制台输出:
Receiver 1:sender1 1.消息内容,……
Receiver 2:sender2 1.消息内容,……
Receiver 1:sender1 2.消息内容,……
Receiver 2:sender2 2.消息内容,……
Receiver 1:sender1 3.消息内容,……
Receiver 2:sender2 3.消息内容,……
Receiver 1:sender1 4.消息内容,……
Receiver 2:sender2 4.消息内容,……
Receiver 1:sender1 5.消息内容,……
Receiver 2:sender2 5.消息内容,……
Receiver 1:sender1 6.消息内容,……
Receiver 2:sender2 6.消息内容,……
Receiver 1:sender1 7.消息内容,……
Receiver 2:sender2 7.消息内容,……
Receiver 1:sender1 8.消息内容,……
Receiver 2:sender2 8.消息内容,……
Receiver 1:sender1 9.消息内容,……
Receiver 2:sender2 9.消息内容,……
Receiver 2:sender2 10.消息内容,……
Receiver 1:sender1 10.消息内容,……
Receiver 1:sender1 11.消息内容,……
Receiver 2:sender2 11.消息内容,……
Receiver 1:sender1 12.消息内容,……
Receiver 2:sender2 12.消息内容,……
Receiver 2:sender1 13.消息内容,……
Receiver 1:sender2 13.消息内容,……

可以看出在多对多情况下消息依然是有序取出的

高级使用

对象的使用

在spring-boot-rabbitmq主工程中创建一个model module:rabbitmq-model
添加一个model:User
内容如下:

public class User implements Serializable {

    public static final Long serialVersionUID = 1L;

    private String username;
    private String passwd;
    private int age;

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", passwd='" + passwd + '\'' +
                ", age=" + age +
                '}';
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

分别在rabbitmq-sender和rabbitmq-receiver工程中加入rabbitmq-model依赖

<dependency>
    <groupId>com.alyshen</groupId>
    <artifactId>rabbitmq-model</artifactId>
    <version>${project.version}</version>
</dependency>

在rabbitmq-config工程中的配置类RabbitmqConfig.java加入方法:

 //创建一个user-queue消息队列
@Bean
public Queue userQueue() {
    return new Queue("user-queue");
}

在rabbitmq-sender工程中参加一个生产方:UserSender.java,内容如下:

@Component
public class UserSender {
    @Autowired
    private AmqpTemplate amqpTemplate;

    public void senderUser(User user) {
        System.out.println("Sender to user-queue: " + user);
        amqpTemplate.convertAndSend("user-queue",user);
    }
}

在添加一个Controller:UserSenderController.java,内容如下:

@RestController
public class UserSenderController {

    @Autowired
    UserSender userSender;

    @RequestMapping(value = "/sendUser")
    public String senduser() {
        User user = new User();
        user.setUsername("zhangshan");
        user.setPasswd("zzzpwd");
        user.setAge(20);
        userSender.senderUser(user);
        return "sender user ok ...";
    }
}

运行rabbitmq-sender工程,浏览器访问:http://localhost:9000/sendUser,控制台输出:
Sender to user-queue: User{username='zhangshan', passwd='zzzpwd', age=20}

一个username为zhangshan的User就加入了user-queue队列中

现在rabbitmq-receiver工程中创建一个User消息接收方:UserReceiver.java,内容如下:

@Component
public class UserReceiver {

    //    @RabbitHandler
    @RabbitListener(queues = "user-queue")
    public void process(User user) {
        System.out.println("Receiver user:" + user);
    }
}

运行rabbitmq-receiver工程,控制台输出:
Receiver user:User{username='zhangshan', passwd='zzzpwd', age=20}

User信息接收成功

Topic Exchange的使用

在rabbitmq-config工程中创建配置类TopicRabbitConfig.java,内容如下:

@Configuration
public class TopicRabbitConfig {

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

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

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

    /**
     * @Title exchange
     * @Description 创建个Topic交换机
     */
    @Bean
    TopicExchange exchange() {
        return new TopicExchange("topicExchange");
    }
    /**
     * @Title bindingExchangeMessage
     * @Description 交换机和路由建绑定
     */
    @Bean
    Binding bindingExchangeMessage(Queue queueMessage, TopicExchange exchange) {
        return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message");
    }

    @Bean
    Binding bindingExchangeMessages(Queue queueMessages, TopicExchange exchange) {
        return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#");
    }
}

在rabbitmq-sender工程中添加topic消息发送方:TopicSender.java,添加如下内容:

@Component
public class TopicSender {

	@Autowired
	private AmqpTemplate rabbitTemplate;

	public void sender() {
		String context = "消息1...";
		System.out.println("Sender : " + context);
		this.rabbitTemplate.convertAndSend("topicExchange", "topic.xxx", context);
	}

	public void sender2() {
		String context = "消息2...";
		System.out.println("Sender : " + context);
		this.rabbitTemplate.convertAndSend("topicExchange", "topic.message", context);
	}

	public void sender3() {
		String context = "消息3...";
		System.out.println("Sender : " + context);
		this.rabbitTemplate.convertAndSend("topicExchange", "topic.messages", context);
	}
}

再创建一个TopicSenderController,添加如下内容:

@RestController
public class TopicSenderController {

    @Autowired
    private TopicSender topicSender;

    @RequestMapping(value = "/topic")
    public String topic() {
        topicSender.sender();
        return "sender ok...";
    }

    @RequestMapping(value = "/topic2")
    public String topic2() {
        topicSender.sender2();
        return "sender ok...";
    }

    @RequestMapping(value = "/topic3")
    public String topic3() {
        topicSender.sender3();
        return "sender ok...";
    }
}

在rabbitmq-receiver工程中创建topic消息接收端:TopicReceiver1.java,添加如下内容:

@Component
public class TopicReceiver1 {
    //    @RabbitHandler
    @RabbitListener(queues = "topic.message")
    public void process(String message) {
        System.out.println("Topic Receiver 1:" + message);
    }
}

在创建一个topic消息接收端:TopicReceiver2.java,添加如下内容:

@Component
public class TopicReceiver2 {

//    @RabbitHandler
    @RabbitListener(queues = "topic.messages")
    public void process(String message) {
        System.out.println("Topic Receiver 2:" + message);
    }

}

运行rabbitmq-sender和rabbitmq-receiver
浏览器访问:http://localhost:9000/topic
发现只有Receiver 2接收到消息1,说明topic.xxx匹配的是topic.#这个规则

浏览器访问:http://localhost:9000/topic2
发现Receiver 1和Receiver 2都接收到了消息2,说明topic.message匹配的是topic.message和topic.#这两个规则

浏览器访问:http://localhost:9000/topic3
发现只有Receiver 2都接收到了消息3,说明topic.messages匹配的是topic.#这个规则

fanout Exchange的使用

在rabbitmq-config工程中创建配置类FanoutRabbitConfig.java,添加如下内容:

@Configuration
public class FanoutRabbitConfig {

    //创建队列a
    @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");
    }

//    创建Fanout 交换机
    @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);
    }

}

在rabbitmq-sender工程中添加fanout消息发送方:FanoutSender.java,添加如下内容:

@Component
public class FanoutSender {
    @Autowired
    private AmqpTemplate rabbitTemplate;

    public void sender() {
        String context = "fanout 消息内容...";
        System.out.println("Sender : " + context);
        this.rabbitTemplate.convertAndSend("fanoutExchange", "", context);
    }
}

再创建一个FanoutSenderController,添加如下内容:

@RestController
public class FanoutSenderController {
    @Autowired
    private FanoutSender fanoutSender;

    @RequestMapping(value = "/fanout")
    public String topic() {
        fanoutSender.sender();
        return "sender ok...";
    }
}

在rabbitmq-receiver工程中创建fanout消息接收端:FanoutReceiver.java,添加如下内容:

@Component
public class FanoutReceiver {
    //    @RabbitHandler
    @RabbitListener(queues = "fanout.A")
    public void process(String message) {
        System.out.println("fanout Receiver A:" + message);
    }

    @RabbitListener(queues = "fanout.B")
    public void process2(String message) {
        System.out.println("fanout Receiver B:" + message);
    }

    @RabbitListener(queues = "fanout.C")
    public void process3(String message) {
        System.out.println("fanout Receiver C:" + message);
    }
}

运行rabbitmq-sender和rabbitmq-receiver
浏览器访问:http://localhost:9000/fanout

在rabbitmq-receiver工程的控制台下输出:
fanout Receiver B:fanout 消息内容...
fanout Receiver C:fanout 消息内容...
fanout Receiver A:fanout 消息内容...

说明绑定到fanout交换机上的队列都接收到了消息

posted @ 2019-07-02 00:47  Aick  阅读(211)  评论(0编辑  收藏  举报