SpringBoot(十) 消息AMQP(RabbitMQ)

#1、概述

1.在大多应用中,我们系统之间需要进行异步通信,即异步消息。
2.异步消息中两个重要概念:

  • 消息代理(message broker)和目的地(destination)
  • 当消息发送者发送消息以后,将由消息代理接管,消息代理保证消息传递到指定目的地。

3.异步消息主要有两种形式的目的地

  • 1.队列(queue):点对点消息通信(point-to-point)
  • 2.主题(topic):发布(publish)/订阅(subscribe)消息通信

4.点对点式:

  • 消息发送者发送消息,消息代理将其放入一个队列中,消息接收者从队列中获取消息内容,消息读取后被移出队列
  • 消息只有唯一的发送者和接受者,但并不是说只能有一个接收者

5.发布订阅式:

  • 发送者(发布者)发送消息到主题,多个接收者(订阅者)监听(订阅)这个主题,那么就会在消息到达时同时收到消息

6.JMS(Java Message Service)java消息服务:

  • 基于JVM消息代理的规范。ActiveMQ、HornetMQ是JMS实现

7.AMQP(Advanced Message Queuing Protocol)

  • 高级消息队列协议,也是一个消息代理的规范,兼容JMS
  • RabbitMQ是AMQP的实现

8.Spring支持

  • spring-jms提供了对JMS的支持
  • spring-rabbit提供了对AMQP的支持
  • 需要ConnectionFactory的实现来连接消息代理
  • 提供JmsTemplate、RabbitTemplate来发送消息
  • @JmsListener(JMS)、@RabbitListener(AMQP)注解在方法上监听消息代理发布的消息
  • @EnableJms、@EnableRabbit开启支持

9.Spring Boot自动配置

  • JmsAutoConfiguration
  • RabbitAutoConfiguration

2、RabbitMQ

##2.1 RabbitMQ简介

RabbitMQ是一个由erlang开发的AMQP(Advanved Message Queue)的开源实现。
核心概念

  • Producer&Consumer:producer指的是消息生产者,consumer消息的消费者

  • Broker:它提供一种传输服务,它的角色就是维护一条从生产者到消费者的路线,保证数据能按照指定的方式进行传输;

  • Queue

    • 消息队列,提供了FIFO的处理机制,具有缓存消息的能力。rabbitmq中,队列消息可以设置为持久化,临时或者自动删除。
    • 设置为持久化的队列,queue中的消息会在server本地硬盘存储一份,防止系统crash,数据丢失
    • 设置为临时队列,queue中的数据在系统重启之后就会丢失
    • 设置为自动删除的队列,当不存在用户连接到server,队列中的数据会被自动删除
  • Exchange

    • 消息交换机,它指定消息按什么规则,路由到哪个队列。
    • Exchange有4种类型:direct(默认),fanout, topic, 和headers,不同类型的Exchange转发消息的策略有所区别:
  • Binding

    • 将一个特定的Exchange 和一个特定的Queue 绑定起来。
    • Exchange 和Queue的绑定可以是多对多的关系。
  • virtual host(vhosts )

    • 在rabbitmq server上可以创建多个虚拟的message broker,又叫做virtual hosts (vhosts)
    • 每一个vhost本质上是一个mini-rabbitmq server,分别管理各自的exchange,和bindings
    • vhost相当于物理的server,可以为不同app提供边界隔离
    • producer和consumer连接rabbit server需要指定一个vhost

RabbitMQ运行机制:

SpringBoot(十) 消息AMQP(RabbitMQ)_第1张图片

##2.2 安装RabbitMQ(docker)

在安装了docker的服务器上,执行命令:docker pull rabbitmq:3-management (management:表示带有管理界面的)

安装完成,执行命令运行:docker run -d -p 5672:5672 -p 15672:15672 --name myrabbitmq 镜像ID

2.3 访问RabbitMQ的管理界面

启动成功之后,就可以在浏览器访问:http://192.168.0.105:15672/

使用用户名和密码登录:guest/guest

就会进入到管理界面,可以使用可视化的界面进行相关的操作,具体自行学习。

SpringBoot(十) 消息AMQP(RabbitMQ)_第2张图片

SpringBoot(十) 消息AMQP(RabbitMQ)_第3张图片

#3、整合RabbitMQ

使用SpringBoot的向导创建工程springboot-02-amqp,选中web模块和RabbitMQ模块;SpringBoot的版本:2.2.6

3.1 pom文件


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.2.6.RELEASEversion>
        <relativePath/> 
    parent>
    <groupId>com.springboot.amqpgroupId>
    <artifactId>springboot-02-amqpartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <name>springboot-02-amqpname>
    <description>Demo project for Spring Bootdescription>

    <properties>
        <java.version>1.8java.version>
    properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-amqpartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintagegroupId>
                    <artifactId>junit-vintage-engineartifactId>
                exclusion>
            exclusions>
        dependency>
        <dependency>
            <groupId>org.springframework.amqpgroupId>
            <artifactId>spring-rabbit-testartifactId>
            <scope>testscope>
        dependency>
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <scope>testscope>
        dependency>
    dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>
project>

##3.2 application.yml

对RabbitMQ做一个简单的配置:

spring:
  rabbitmq:
    host: 192.168.0.105
    username: guest
    password: guest

3.3 定义MessageConventer

导入AMQP的启动器之后,默认给我们注入的是SimpleMessageConverter,它的序列化方式是使用Jdk序列化成二进制数据,不易读取,所以我们要定义一个序列化为json的MessageConverter:

package com.springboot.amqp.config;

import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyAMQPConfig {

    //定义一个序列化为JSON的MessageConverter,添加导容器中
    @Bean
    public MessageConverter messageConverter(){
        return new Jackson2JsonMessageConverter();
    }
}

3.4 编写JaveBean

package com.springboot.amqp.bean;

import java.util.Date;

public class Person {
    private int id;
    private String name;
    private boolean gender;
    private Date birthday;

    //无参构造一定要加
    public Person() {
    }

    public Person(int id, String name, boolean gender, Date birthday) {
        this.id = id;
        this.name = name;
        this.gender = gender;
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender=" + gender +
                ", birthday=" + birthday +
                '}';
    }
	//get/set方法
}

注意:添加了有参构造,无参构造也一定要加上,否则后面会出错。这也是一个习惯,无参构造不能省,很多的框架都是使用反射技术的,都会用到无参构造,如果没有就会抛异常

3.5 监听队列:@RabbitListener

package com.springboot.amqp.service;

import com.springboot.amqp.bean.Person;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;

@Service
public class PersonService {

    @RabbitListener(queues = "zdw.news")
    public void receive(Person person){
        try {
            Thread.sleep(6000*2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("从zdw.news队列接收的消息:"+person);
    }

    @RabbitListener(queues = "zxh.news")
    public void receive2(Message message){
        try {
            Thread.sleep(6000*2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(message.getBody().toString());
        System.out.println(message.getMessageProperties());
    }
}

使用注解@RabbitListener 来监听队列,只要队列中有消息,并且该方法本身是空闲的时候,就会从队列中获取消息进行消费。

##3.6 启动类添加注解@EnableRabbot

@EnableRabbit :开启基于注解的RabbitMQ模式

package com.springboot.amqp;

import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 自动配置
 *  1、RabbitAutoConfiguration
 *  2、有自动配置了连接工厂ConnectionFactory;
 *  3、RabbitProperties 封装了 RabbitMQ的配置
 *  4、 RabbitTemplate :给RabbitMQ发送和接受消息;
 *  5、 AmqpAdmin : RabbitMQ系统管理功能组件;
 *  	AmqpAdmin:创建和删除 Queue,Exchange,Binding
 *  6、@EnableRabbit +  @RabbitListener 监听消息队列的内容
 *
 */
@EnableRabbit  //开启基于注解的RabbitMQ模式
@SpringBootApplication
public class Springboot02AmqpApplication {

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

3.7 测试类

package com.springboot.amqp;

import com.springboot.amqp.bean.Person;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

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

    @Autowired
    RabbitTemplate rabbitTemplate;

    //测试发送字符串和map以及list
    @Test
    public void contextLoads() {
        //rabbitTemplate.convertAndSend("zdw.direct","zdw","我的第一个消息");
        Map<String,Object> map = new HashMap<>();
        map.put("msg","这是第一个JSON消息");
        map.put("data", Arrays.asList("RabbitMq",10000,true));
        rabbitTemplate.convertAndSend("zdw.fanout","aaa",map);
    }

    //测试发送对象
    @Test
    public void testObject() {
        Person person = new Person(1001,"张无忌",true,new Date());

        rabbitTemplate.convertAndSend("zdw.topic","*.news",person);
    }

    //测试接收消息
    @Test
    public void testReceive() {
        Object o = rabbitTemplate.receiveAndConvert("zxh.news");
        System.out.println(o.getClass());
        System.out.println(o);
    }

    @Autowired
    AmqpAdmin amqpAdmin;

    //测试创建交换机等操作
    @Test
    public void testAdminAmqp(){
        //创建交换机
        amqpAdmin.declareExchange(new DirectExchange("amqpadmin.exchange"));
		System.out.println("创建交换机完成");
        //创建队列
		amqpAdmin.declareQueue(new Queue("amqpadmin.queue",true));
        System.out.println("创建队列完成");
        //创建绑定规则,把队列绑定到交换机
		amqpAdmin.declareBinding(new Binding("amqpadmin.queue", Binding.DestinationType.QUEUE,"amqpadmin.exchange","amqp.haha",null));
        System.out.println("交换机和队列绑定成功...");
    }
}

你可能感兴趣的:(SpringBoot)