RabbitMQ(第二次复习,整合springboot)

AMPQ(Advanced Message Queue)

是一个提供统一消息服务的应用层标准高级消息队列协议,是应用程协议的一个开放标准,为面向消息的中间件设计。定义在协议层,跨语言。RabbitMQ是遵循AMQP标准协议开发的MQ服务。

JMS(Java Message Service)

是一个java平台中关于面向消息中间件的API。用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信,与具体平台无关。是java语言专属的消息服务标准,只能用于java应用。

RabbitMQ工作原理

基本结构
在这里插入图片描述

  • Producer:消息生产者,将消息发送到MQ
  • Connection:TCP连接,可以包含多个消息通道
  • Broker:消息队列服务进程
    • Exchange:消息队列交换机,按照一定的规则将消息路由转发到某个队列,对消息进行过滤
    • Queue:消息队列,存储消息的队列,消息到达队列并转发给指定的消费者
  • Consumer:消息消费者,接收MQ转发的消息
RabbitMQ安装
  1. 安装erlang
  2. 安装RabbitMQ
  3. 安装管理插件
    在这里插入图片描述
    运行 rabbitmq-plugins.bat enable rabbitmq_management
  4. 登录 http://localhost:15672 账号密码都是guest

四个主要概念

  1. 虚拟主机(virtual host)或(vhost)
  2. 交换机(exchange)
  3. 队列(queue)
  4. 绑定器(bing)
虚拟主机

每个虚拟机都相当与一个独立的MQ

一组交换机、队列和绑定器 被称为 vhost
RabbitMQ server 可以说就是一个消息队列服务器实体(Broker),Broker当中可以有多个用户,而用户只能在虚拟主机的粒度进行权限控制,所以RabbitMQ中需要多个虚拟主机。每一个RabbitMQ服务器都有一个默认的虚拟主机“/”。

队列(queue)

队列是消息载体,每个消息都会被投入到一个或多个队列。试图创建一个已经存在的队列,RabbitMQ会直接忽略这个请求。(接收消息的实体)

交换机(exchange)

它指定消息按什么规则,路由到哪个队列。它可以被理解成具有路由表的路由程序。(发送消息的实体)
交换机可以存在多个,每个交换机在自己独立的进程当中执行,因此增加多个交换机就是增加多个进程,可以充分利用服务器上的CPU核以便达到更高的效率

交换机类型
  • direct【默认的类型】
  • fanout
  • topic
  • headers(headers不常用)

Direct: 根据路由键和交换器来找队列的,对消息路径进行全文匹配
通过精确匹配消息的路由关键字,将消息路由到零个或者多个队列中,绑定关键字用来将队列和交换器绑定到一起

Fanout: 广播模式,会忽略路由键Routingkey,将消息广播给绑定到该交换机的所有队列。 不论消息的路由关键字是什么,这条消息都会被路由到所有与该交换器绑定的队列中。
发布者向交换器发送一条消息。 消息被无条件的传递到所有和这个交换器绑定的消息队列中

Topic: 主题模式,处理路由键,按模式匹配路由键
模式符号:
“#” 表示一个或多个单词,"*" 仅匹配一个单词
如 “wood.#” 可匹配 “wood.palm.redwood”,但 “wood.*” 只匹配 “wood.deadwood”。
通过消息的路由关键字和绑定关键字的模式匹配,将消息路由到被绑定的队列中。这种路由器类型可以被用来支持经典的发布/订阅消息传输模型——使用主题名字空间作为消息寻址模式,将消息传递给那些部分或者全部匹配主题模式的多个消费者

绑定器(bind)

把exchange和queue按照路由规则绑定起来。(将交换器和队列连接起来,并且封装消息的路由信息)

channel.BasicPublish(exchange: “”, routingKey: “writeLog”, basicProperties: null, body: body);

每个消息都有一个称为路由关键字(routingKey)的属性,exchange根据这个关键字进行消息投递,其实就是一个简单的字符串

程序中连接与消息使用的两个关键概念
连接(Connection)

与RabbitMQ Server建立的一个连接,由ConnectionFactory创建,每个connection只与一个物理的Server进行连接,此连接是基于Socket进行连接的。AMQP一般使用TCP

通道 (Channel)

消息通道(主要进行相关定义,发送消息,获取消息,事务处理等),在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。

Channel在.net的客户端程序里应该是叫“Model”,采用IModel CreateModel()创建的,但是其他语言的客户端都叫Channel。需要注意:一个Connection可以有多个Channel

入门程序例子

导入依赖

<dependency>
	<groupId>com.rabbitmq</groupId>
	<artifactId>amqp‐client</artifactId>
	<version>4.0.3</version><!‐‐此版本与spring boot 1.5.9版本匹配‐‐>
</dependency>

生产者

public class Producer {
    //队列名称
    private static final String QUEUE = "helloworld";

    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = null;
        Channel channel = null;
        try {
        	//通过连接工厂创建新的连接和mq建立连接
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("localhost");
            factory.setPort(5672);
            factory.setUsername("guest");
            factory.setPassword("guest");
            //rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务器
            factory.setVirtualHost("/");
            //创建与RabbitMQ服务的TCP连接
            connection = factory.newConnection();
            //创建与Exchange的通道,每个连接可以创建多个通道,每个通道代表一个会话任务
            channel = connection.createChannel();
            /**
             * 声明队列,如果Rabbit中没有此队列将自动创建
             * param1:队列名称
             * param2:是否持久化,持久化后mq重启队列仍存在
             * param3:队列是否独占此连接,队列只在该连接中存在,connection断开,队列删除
             * param4:队列不再使用时是否自动删除此队列
             * param5:队列扩展参数,比如 mq的存活时间等
             * 		x-message-ttl 发送到队列的消息在丢弃之前可以存活多长时间(毫秒)。
					x-expires 队列在被自动删除(毫秒)之前可以使用多长时间。
					x-max-length 队列在开始从头部删除之前可以包含多少就绪消息。
					x-max-length-bytes 队列在开始从头部删除之前可以包含的就绪消息的总体大小。
					x-dead-letter-exchange 设置队列溢出行为。这决定了在达到队列的最大长度时消息会发生什么。有效值为drop-head或reject-publish。交换的可选名称,如果消息被拒绝或过期,将重新发布这些名称。
					x-dead-letter-routing-key 可选的替换路由密钥,用于在消息以字母为单位时使用。如果未设置,将使用消息的原始路由密钥。
					x-max-priority 队列支持的最大优先级数;如果未设置,队列将不支持消息优先级。
					x-queue-mode 将队列设置为延迟模式,在磁盘上保留尽可能多的消息以减少内存使用;如果未设置,队列将保留内存缓存以尽快传递消息。
					 x-queue-master-locator 将队列设置为主位置模式,确定在节点集群上声明时队列主机所在的规则
             */
            channel.queueDeclare(QUEUE, true, false, false, null);
            String message = "helloworld小明" + System.currentTimeMillis();
            /**
             * 消息发布方法
             * param1:Exchange的名称,如果没有指定,则使用Default Exchange
             * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
             * param3:消息属性
             * param4:消息体
             */
            /**
             * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显 示绑定或解除绑定
             * 默认的交换机,routingKey等于队列名称
             */
            channel.basicPublish("", QUEUE, null, message.getBytes());
            System.out.println("Send Message is:'" + message + "'");
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            if (channel != null) {
                channel.close();
            }
            if (connection != null) {
                connection.close();
            }
        }
    }
}

消费者

public class Consumer {
    private static final String QUEUE = "helloworld";

    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        //设置MabbitMQ所在服务器的ip和端口
        factory.setHost("127.0.0.1");
        factory.setPort(5672);
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        //声明队列
          /**
             * 声明队列,如果Rabbit中没有此队列将自动创建
             * param1:队列名称
             * param2:是否持久化,持久化后mq重启队列仍存在
             * param3:队列是否独占此连接,队列只在该连接中存在,connection断开,队列删除
             * param4:队列不再使用时是否自动删除此队列
             * param5:队列参数
             */
        channel.queueDeclare(QUEUE, true, false, false, null);
        //定义消费方法
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            /**
             * 消费者接收消息调用此方法
             * @param consumerTag 消费者的标签,在channel.basicConsume()去指定
             * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志
            (收到消息失败后是否需要重新发送)
             * @param properties
             * @param body
             * @throws IOException
             */
            @Override
            public void handleDelivery(String consumerTag,
                                       Envelope envelope,
                                       AMQP.BasicProperties properties,
                                       byte[] body)
                    throws IOException {
                //交换机
                String exchange = envelope.getExchange();
                //路由key
                String routingKey = envelope.getRoutingKey();
                //消息id
                long deliveryTag = envelope.getDeliveryTag();
                //消息内容
                String msg = new String(body, "UTF-8");
                System.out.println("receive message.." + msg);
            }
        };
        /**
         * 监听队列String queue, boolean autoAck,Consumer callback
         * 参数明细
         * 1、队列名称
         * 2、是否自动回复,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复会删除消息,设置
         为false则需要手动回复
         * 3、消费消息的方法,消费者接收到消息后调用此方法
         */
        channel.basicConsume(QUEUE, true, consumer);
    }
}
RabbitMQ工作模式
  1. Work queues 工作队列
  2. Publish/Subscribe 发布订阅
  3. Routing 路由
  4. Topics 通配符
  5. Header Header转发器
  6. RPC 远程过程调用
Work queues 工作队列

在这里插入图片描述
上边的入门程序是一个生产者,一个消费者。work queues跟入门程序比,区别就是多了消费者。多个消费者监听同一个队列。
特点:

  • 一个消息只会被一个消费者接收
  • 采用轮询方式将消息平均发给消费者
  • 消费者在处理完某条消息后。才会收到下一条消息
发布订阅模式

在这里插入图片描述

  • 生产者将消息发送给交换机
  • 由交换机将消息转发到绑定此交换机的每个队列,每个绑定交换机的队列都将接收到消息
  • 与交换价绑定的队列有多个,每个消费者监听自己的队列

与work queues相比

发布订阅模式可以定义一个交换机绑定多个队列,一个消息发送给多个队列
work queues无需定义交换机(但是会默认存在),一个消息只能发送给一个队列

例如:向用户发送通知。通知方式有短信、邮件多种方式
生产者

与入门代码比较

  1. 因为有交换机和多个队列,所以比入门代码多了定义交换机的方法exchangeDeclare(String exchange,BuiltinExchangeTypetype),队列定义还是相同的,只是定义多个
  2. 将队列绑定到交换机queueBind(String queue,String exchange, String key)
  3. 向交换机发送消息,不直接向队列发送。
public class Producer{
    //队列名称
    private static final String QUEUE_INFORM_EMAIL = "queue_inform_email";
    private static final String QUEUE_INFORM_SMS = "queue_inform_sms";
    private static final String EXCHANGE_FANOUT_INFORM="exchange_fanout_inform";
    public static void main(String[] args) {
        Connection connection = null;
        Channel channel = null;
        try {
            //创建一个与MQ的连接
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("127.0.0.1");
            factory.setPort(5672);
            factory.setUsername("guest");
            factory.setPassword("guest");
            //rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务器
            factory.setVirtualHost("/");
            //创建一个连接
            connection = factory.newConnection();
            //创建与交换机的通道,每个通道代表一个会话
            channel = connection.createChannel();
            //声明交换机 String exchange, BuiltinExchangeType type
            /**
             * 参数明细
             * 1、交换机名称
             * 2、交换机类型,fanout、topic、direct、headers,对应各自的工作模式
             * fanout:发布订阅模式
             * topic:通配符模式
             * direct:路由模式
             * headers:转发器模式
             */
            channel.exchangeDeclare(EXCHANGE_FANOUT_INFORM, BuiltinExchangeType.FANOUT);
            //声明队列
            // (String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
            /**
             * 参数明细:
             * 1、队列名称
             * 2、是否持久化
             * 3、是否独占此队列
             * 4、队列不用是否自动删除
             * 5、参数
             */
            channel.queueDeclare(QUEUE_INFORM_EMAIL, true, false, false, null);
            channel.queueDeclare(QUEUE_INFORM_SMS, true, false, false, null);
            //交换机和队列绑定String queue, String exchange, String routingKey
            /**
             * 参数明细
             * 1、队列名称
             * 2、交换机名称
             * 3、路由key,作用是交换机根据路由key的值将消息发送到指定的队列中。发布订阅模式不使用,设置为""。
             */
            channel.queueBind(QUEUE_INFORM_EMAIL,EXCHANGE_FANOUT_INFORM,"");
            channel.queueBind(QUEUE_INFORM_SMS,EXCHANGE_FANOUT_INFORM,"");
            //发送消息
            for (int i=0;i<10;i++){
                String message = "inform to user"+i;
                //向交换机发送消息 String exchange, String routingKey, BasicProperties props, byte[] body
                /**
                 * 参数明细
                 * 1、交换机名称,不指令使用默认交换机名称 Default Exchange
                 * 2、routingKey(路由key),根据key名称将消息转发到具体的队列,这里填写队列名称表示消
                 息将发到此队列
                 * 3、消息扩展属性
                 * 4、消息内容
                 */
                channel.basicPublish(EXCHANGE_FANOUT_INFORM, "", null, message.getBytes());
                System.out.println("Send Message is:'" + message + "'");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }finally{
            if(channel!=null){
                try {
                    channel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (TimeoutException e) {
                    e.printStackTrace();
                }
            }
            if(connection!=null){
                try {
                    connection.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

消费者

写法大部分和入门程序的消费者相同
只是多了队列和交换机的绑定

邮件发送消费者

public class Consumer02_subscribe_email {
    //队列名称
    private static final String QUEUE_INFORM_EMAIL = "inform_queue_email";
    private static final String EXCHANGE_FANOUT_INFORM = "inform_exchange_fanout";

    public static void main(String[] args) throws IOException, TimeoutException {
        //创建一个与MQ的连接
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("127.0.0.1");
        factory.setPort(5672);
        factory.setUsername("guest");
        factory.setPassword("guest");
        factory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务器
        //创建一个连接
        Connection connection = factory.newConnection();
        //创建与交换机的通道,每个通道代表一个会话
        Channel channel = connection.createChannel();
        //声明交换机 String exchange, BuiltinExchangeType type
        /**
         * 参数明细
         * 1、交换机名称
         * 2、交换机类型,fanout、topic、direct、headers,对应各自的工作模式
         */
        channel.exchangeDeclare(EXCHANGE_FANOUT_INFORM, BuiltinExchangeType.FANOUT);
        //声明队列
        // channel.queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
        /**
         * 参数明细:
         * 1、队列名称
         * 2、是否持久化
         * 3、是否独占此队列
         * 4、队列不用是否自动删除
         * 5、参数
         */
        channel.queueDeclare(QUEUE_INFORM_EMAIL, true, false, false, null);
        //交换机和队列绑定String queue, String exchange, String routingKey
        /**
         * 参数明细
         * 1、队列名称
         * 2、交换机名称
         * 3、路由key
         */
        channel.queueBind(QUEUE_INFORM_EMAIL, EXCHANGE_FANOUT_INFORM, "");
        //定义消费方法
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties, byte[] body) throws IOException {
                long deliveryTag = envelope.getDeliveryTag();
                String exchange = envelope.getExchange();
                //消息内容
                String message = new String(body, "UTF-8");
                System.out.println(message);
            }
        };
        /**
         * 监听队列String queue, boolean autoAck,Consumer callback
         * 参数明细
         * 1、队列名称
         * 2、是否自动回复,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复会删除消息,设置
         为false则需要手动回复
         * 3、消费消息的方法,消费者接收到消息后调用此方法
         */
        channel.basicConsume(QUEUE_INFORM_EMAIL, true, defaultConsumer);
    }
}

短信消费者写法相同

Routing 路由模式

在这里插入图片描述

  • 生产者向交换机发送消息,并设置routingkey
  • 交换机根据routingkey来转发消息到指定的交换机
  • 每个监听器监听自己的队列,并设置routingkey

生产者

写法和发布订阅模式相似
多了定义routingkey,交换机类型改为direct

public class Producer {
    //队列名称
    private static final String QUEUE_INFORM_EMAIL = "queue_inform_email";
    private static final String QUEUE_INFORM_SMS = "queue_inform_sms";
    private static final String EXCHANGE_ROUTING_INFORM = "exchange_routing_inform";

    public static void main(String[] args) {
        Connection connection = null;
        Channel channel = null;
        try {
            //创建一个与MQ的连接
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("127.0.0.1");
            factory.setPort(5672);
            factory.setUsername("guest");
            factory.setPassword("guest");
            factory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务器
            //创建一个连接
            connection = factory.newConnection();
            //创建与交换机的通道,每个通道代表一个会话
            channel = connection.createChannel();
            //声明交换机 String exchange, BuiltinExchangeType type
            /**
             * 参数明细
             * 1、交换机名称
             * 2、交换机类型,fanout、topic、direct、headers
             */
            channel.exchangeDeclare(EXCHANGE_ROUTING_INFORM, BuiltinExchangeType.DIRECT);
            //声明队列
            // channel.queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
            /**
             * 参数明细:
             * 1、队列名称
             * 2、是否持久化
             * 3、是否独占此队列
             * 4、队列不用是否自动删除
             * 5、参数
             */
            channel.queueDeclare(QUEUE_INFORM_EMAIL, true, false, false, null);
            channel.queueDeclare(QUEUE_INFORM_SMS, true, false, false, null);
            //交换机和队列绑定String queue, String exchange, String routingKey
            /**
             * 参数明细
             * 1、队列名称
             * 2、交换机名称
             * 3、路由key
             */
            channel.queueBind(QUEUE_INFORM_EMAIL, EXCHANGE_ROUTING_INFORM, QUEUE_INFORM_EMAIL);
            channel.queueBind(QUEUE_INFORM_SMS, EXCHANGE_ROUTING_INFORM, QUEUE_INFORM_SMS);
            //发送邮件消息
            for (int i = 0; i < 10; i++) {
                String message = "email inform to user" + i;
                //向交换机发送消息 String exchange, String routingKey, BasicProperties props, byte[] body
                /**
                 * 参数明细
                 * 1、交换机名称,不指令使用默认交换机名称 Default Exchange
                 * 2、routingKey(路由key),根据key名称将消息转发到具体的队列,这里填写队列名称表示消
                 息将发到此队列
                 * 3、消息属性
                 * 4、消息内容
                 */
                channel.basicPublish(EXCHANGE_ROUTING_INFORM, QUEUE_INFORM_EMAIL, null,
                        message.getBytes());
                System.out.println("Send Message is:'" + message + "'");
            }
            //发送短信消息
            for (int i = 0; i < 10; i++) {
                String message = "sms inform to user" + i;
                //向交换机发送消息 String exchange, String routingKey, BasicProperties props,byte[] body
                channel.basicPublish(EXCHANGE_ROUTING_INFORM, QUEUE_INFORM_SMS, null,
                        message.getBytes());
                System.out.println("Send Message is:'" + message + "'");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        } finally {
            if (channel != null) {
                try {
                    channel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (TimeoutException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

消费者
消费者指明routingkey

Topics 通配符工作模式

在这里插入图片描述

  • 和Routing模式相似,Routing是完全匹配,topics是通配符匹配
  • 符号 # :匹配多个词,每个词中间用 . 分割
  • 符号 * :只能匹配一个词

用法和Routing相似,将交换机类型换为 topic
不同的地方在于

  • 绑定交换机的时候可以使用通配符

    channel.queueBind(QUEUE_INFORM_EMAIL,EXCHANGE_TOPICS_INFORM,“inform.#.email.#”);

  • 向交换机发送消息时,指定的routingKey会去匹配绑定交换机时指定的routingKey

    channel.basicPublish(EXCHANGE_TOPICS_INFORM, “inform.sms.email”, null,message.getBytes());

    channel.basicPublish(EXCHANGE_TOPICS_INFORM, “inform.email”, null,message.getBytes());

    发送的这两条消息都会匹配到QUEUE_INFORM_EMAIL队列

Header模式

取消了routingKey,使用key/value匹配队列

假如设置接收邮件的只接收邮件,设置接收信息的只接收信息,两种都设置的才都接收

生产者
绑定交换机的时候,routingKey为"",参数和Routing模式多了个参数Map<java.lang.String, java.lang.Object> map
绑定交换机

Map<String, Object> headers_email = new Hashtable<String, Object>();
headers_email.put("inform_type", "email");
Map<String, Object> headers_sms = new Hashtable<String, Object>();
headers_sms.put("inform_type", "sms");
channel.queueBind(QUEUE_INFORM_EMAIL,EXCHANGE_HEADERS_INFORM,"",headers_email);
channel.queueBind(QUEUE_INFORM_SMS,EXCHANGE_HEADERS_INFORM,"",headers_sms);

发送通知

String message = "email inform to user"+i;
Map<String,Object> headers = new Hashtable<String, Object>();
headers.put("inform_type", "email");//匹配email通知消费者绑定的header
//headers.put("inform_type", "sms");//匹配sms通知消费者绑定的header

AMQP.BasicProperties.Builder properties = new AMQP.BasicProperties.Builder();
properties.headers(headers);

//Email通知
channel.basicPublish(EXCHANGE_HEADERS_INFORM, "", properties.build(), message.getBytes());

消费消息

channel.exchangeDeclare(EXCHANGE_HEADERS_INFORM, BuiltinExchangeType.HEADERS);
Map<String, Object> headers_email = new Hashtable<String, Object>();
headers_email.put("inform_email", "email");
//交换机和队列绑定
channel.queueBind(QUEUE_INFORM_EMAIL,EXCHANGE_HEADERS_INFORM,"",headers_email);
//指定消费队列
channel.basicConsume(QUEUE_INFORM_EMAIL, true, consumer);
RPC 客户端远程调用服务段

客户端即是消费者也是生产者
客户端发送消息A队列,同时监听B队列,
服务端监听A队列,将处理结果发送到B队列
客户端收到B队列消息。

SpringBoot整合RabbitMQ

springboot增加RabbitMQ依赖

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

配置application.yml

spring:
	application:
		name: test‐rabbitmq‐producer
	rabbitmq:
		host: 127.0.0.1
		port: 5672
		username: guest
		password: guest
		virtualHost: /

定义RabbitConfig类,配置Exchange、Queue、及绑定交换机。

@Configuration
public class RabbitmqConfig {
    public static final String QUEUE_INFORM_EMAIL = "queue_inform_email";
    public static final String QUEUE_INFORM_SMS = "queue_inform_sms";
    public static final String EXCHANGE_TOPICS_INFORM = "exchange_topics_inform";

    /**
     * 交换机配置
     * ExchangeBuilder提供了fanout、direct、topic、header交换机类型的配置
     *
     * @return the exchange
     */
    @Bean(EXCHANGE_TOPICS_INFORM)
    public Exchange EXCHANGE_TOPICS_INFORM() {
        //durable(true)持久化,消息队列重启后交换机仍然存在
        return ExchangeBuilder.topicExchange(EXCHANGE_TOPICS_INFORM).durable(true).build();
    }

    //声明队列
    @Bean(QUEUE_INFORM_SMS)
    public Queue QUEUE_INFORM_SMS() {
        Queue queue = new Queue(QUEUE_INFORM_SMS);
        return queue;
    }

    //声明队列
    @Bean(QUEUE_INFORM_EMAIL)
    public Queue QUEUE_INFORM_EMAIL() {
        Queue queue = new Queue(QUEUE_INFORM_EMAIL);
        return queue;
    }

    /**
     * channel.queueBind(INFORM_QUEUE_SMS,"inform_exchange_topic","inform.#.sms.#");
     * 绑定队列到交换机 .
     *
     * @param queue    the queue
     * @param exchange the exchange
     * @return the binding
     */
    @Bean
    public Binding BINDING_QUEUE_INFORM_SMS(@Qualifier(QUEUE_INFORM_SMS) Queue queue,
                                            @Qualifier(EXCHANGE_TOPICS_INFORM) Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with("inform.#.sms.#").noargs();
    }

    @Bean
    public Binding BINDING_QUEUE_INFORM_EMAIL(@Qualifier(QUEUE_INFORM_EMAIL) Queue queue,
                                              @Qualifier(EXCHANGE_TOPICS_INFORM) Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with("inform.#.email.#").noargs();
    }
}

生产消息

    @Autowired
    RabbitTemplate rabbitTemplate;
     public void sendByTopics() {
        for (int i = 0; i < 5; i++) {
            String message = "sms email inform to user" + i;
            rabbitTemplate.convertAndSend(RabbitmqConfig.EXCHANGE_TOPICS_INFORM, "inform.sms.email", message);
            System.out.println("Send Message is:'" + message + "'");
        }
    }

去调用sendByTopics()方法就可以生产消息

消费消息

@Component
public class ReceiveHandler {
    //监听email队列
    /**
      *msg
      *Message :
      *Channel:
      *都存有消息
      */
    @RabbitListener(queues = {RabbitmqConfig.QUEUE_INFORM_EMAIL})
    public void receive_email(String msg, Message message, Channel channel) {
        System.out.println(msg);
    }

    //监听sms队列
    @RabbitListener(queues = {RabbitmqConfig.QUEUE_INFORM_SMS})
    public void receive_sms(String msg, Message message, Channel channel) {
        System.out.println(msg);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值