RabbitMQ工作队列之主题模式(五)

RabbitMQ工作队列之主题模式(五)

本篇博文主要讲解RabbitMQ工作队列之主题模式,该模式基于发布/订阅模式的基础上,更加的灵活的使用消息与队列绑定。

在上一篇博文中,我们可以通过日志的级别进行控制消息的转发,也仅限于此类固定类型的type进行转发,假如我们需要做到更为复杂的业务,比如复合型消息转发,那么发布/订阅就不是很合适了

为了更好的理解,贴一下官方解释:
这里写图片描述

大意如下:

发送到主题交换的消息不能具有任意routing_key - 它必须是由点分隔的单词列表。 单词可以是任何内容,但通常它们指定与消息相关的一些功能。 一些有效的路由密钥示例:“stock.usd.nyse”,“nyse.vmw”,“quick.orange.rabbit”。 路由密钥中可以包含任意数量的单词,最多可达255个字节。绑定密钥也必须采用相同的形式。 主题交换背后的逻辑类似于直接交换 - 使用特定路由密钥发送的消息将被传递到与匹配绑定密钥绑定的所有队列。 但是,绑定键有两个重要的特殊情况:
*(星号)可以替代一个单词。
#(hash)可以替换零个或多个单词。

三种使用方式:

  • 基于原生client客户端连接使用
  • 基于spring xml配置文件集成使用
  • 基于spring boot集成使用

RabbitMQ官方模型图:

这里写图片描述

目录

[TOC]来生成目录:

1、基于原生client客户端连接使用

1、1 构建maven工程,pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>edurabbitmq-client</groupId>
    <artifactId>rabbitmq-client</artifactId>
    <version>1.0-SNAPSHOT</version>


    <dependencies>
        <!-- https://mvnrepository.com/artifact/com.rabbitmq/amqp-client -->
        <!--引入rbiitmq的连接工具包-->
        <dependency>
            <groupId>com.rabbitmq</groupId>
            <artifactId>amqp-client</artifactId>
            <version>5.3.0</version>
        </dependency>
    </dependencies>

</project>
1、2 定义生产者
package com.edu.topic;

import com.edu.rabbitmq.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @author : alex
 * @version :1.0.0
 * @Date : create by 2018/7/19 22:16
 * @description :消息生产者
 * @note 注意事项
 */
public class Sender {



    //定义交换器名称
    public static  String EXCHANGE_NAME = "test_origin_topic_exchange";

    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {

        //获取连接
        Connection connection = ConnectionUtils.getConnection();

        //从连接中获取一个通道
        Channel channel = connection.createChannel();

        /**
         *
         * 声明一个交换器
         *
         * 文档地址:https://rabbitmq.github.io/rabbitmq-java-client/api/current/com/rabbitmq/client/Channel.html#exchangeDeclare-java.lang.String-com.rabbitmq.client.BuiltinExchangeType-boolean-boolean-java.util.Map-
         * 该方法定义了许多的重载,拿出完整参数的方法来讲
         * AMQP.Exchange.DeclareOk exchangeDeclare​(String exchange,
         *                                         BuiltinExchangeType type,
         *                                         boolean durable,
         *                                         boolean autoDelete,
         *                                         Map<String,Object> arguments)
         *                                  throws IOException
         *
         *  @param exchange 交换器的名字
         *  @param type 交换器的类型:direct, topic, headers, fanout
         *  @param durable 是否持久化,true持久化,false不持久化
         *  @param autoDelete 服务器不再使用该队列时,是否自动删除,true删除,false不删除
         *  @param arguments 其他参数,其实是定义交换器的构造方法
         */
        channel.exchangeDeclare(EXCHANGE_NAME, "topic"); //topic

        /** 此处需要定义好匹配的规则,比如lazy.orange.rabbit ,那么官网模型匹配的就是全部 **/
        /** 比如lazy.orange.myRabbit 那么就排除官网模型中的*.*.rabbit **/

        /** so 首先清楚业务需要达到什么要求,需要如何定义topic中的routing key **/

        /** 下面分别发送三条消息,注意查看消费者接收到的消息,以便于理解 **/
        String msgLo = "lazy# and *.orange.* ";
        channel.basicPublish(EXCHANGE_NAME,"lazy.orange.myRabbit",null,msgLo.getBytes());

        String msgALl = "lazy# and *.orange.* and *.*.rabbit ";
        channel.basicPublish(EXCHANGE_NAME,"lazy.orange.rabbit",null,msgALl.getBytes());

        String msgLr = "lazy# and  *.*.rabbit ";
        channel.basicPublish(EXCHANGE_NAME,"lazy.banana.rabbit",null,msgLr.getBytes());

        /** 要注意:# 号和 * 号的区别 **/

        channel.close();//关闭通道
        connection.close();//关闭连接
    }

}
1、3 定义三个消费者 分别是:orange 、 rabbit 、 lazy

Lazy消费者

package com.edu.topic;

import com.edu.rabbitmq.ConnectionUtils;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @author : alex
 * @version :1.0.0
 * @Date : create by 2018/7/19 22:16
 * @description :消息消费者Lazy
 * @note 注意事项
 */
public class CustomeriLazy {

    //队列名称
    public static String QUEUE_NAME = "test_origin_topic_queue_lazy";

    //定义交换器名称
    public static  String EXCHANGE_NAME = "test_origin_topic_exchange";

    public static void main(String[] args) throws IOException, TimeoutException {

        //创建连接
        Connection connection = ConnectionUtils.getConnection();

        //获取通道
        Channel channel = connection.createChannel();

        //获取交换器
        channel.exchangeDeclare(EXCHANGE_NAME, "topic");

        //创建消息声明
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);


        /**
         * 交换器绑定队列
         * 该方法定义了2个重载
         * AMQP.Queue.BindOk queueBind​(String queue,
         *                             String exchange,
         *                             String routingKey,
         *                             Map<String,Object> arguments)
         *                      throws IOException
         *
         *  @param queue 队列名称
         *  @param exchange 交换器名称
         *  @param routingKey 用于绑定的路由密钥
         *  @param arguments 其他参数,其实是定义交换器的构造方法
         */
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "lazy.#");

        //定义消费者
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
                    throws IOException {
                //获取并转成String
                String message = new String(body, "UTF-8");
                System.out.println("-->lazy消费者收到消息,msg:"+message);
            }
        };

        //监听队列
        channel.basicConsume(QUEUE_NAME, true, consumer);
    }

}

orange消费者

package com.edu.topic;

import com.edu.rabbitmq.ConnectionUtils;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @author : alex
 * @version :1.0.0
 * @Date : create by 2018/7/19 22:16
 * @description :消息消费者orange
 * @note 注意事项
 */
public class CustomeriOrange {

    //队列名称
    public static String QUEUE_NAME = "test_origin_topic_queue_orange";

    //定义交换器名称
    public static  String EXCHANGE_NAME = "test_origin_topic_exchange";

    public static void main(String[] args) throws IOException, TimeoutException {

        //创建连接
        Connection connection = ConnectionUtils.getConnection();

        //获取通道
        Channel channel = connection.createChannel();

        //获取交换器
        channel.exchangeDeclare(EXCHANGE_NAME, "topic");

        //创建消息声明
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);


        /**
         * 交换器绑定队列
         * 该方法定义了2个重载
         * AMQP.Queue.BindOk queueBind​(String queue,
         *                             String exchange,
         *                             String routingKey,
         *                             Map<String,Object> arguments)
         *                      throws IOException
         *
         *  @param queue 队列名称
         *  @param exchange 交换器名称
         *  @param routingKey 用于绑定的路由密钥
         *  @param arguments 其他参数,其实是定义交换器的构造方法
         */
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "*.orange.*");

        //定义消费者
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
                    throws IOException {
                //获取并转成String
                String message = new String(body, "UTF-8");
                System.out.println("-->orange消费者收到消息,msg:"+message);
            }
        };

        //监听队列
        channel.basicConsume(QUEUE_NAME, true, consumer);
    }

}

rabbit消费者

package com.edu.topic;

import com.edu.rabbitmq.ConnectionUtils;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @author : alex
 * @version :1.0.0
 * @Date : create by 2018/7/19 22:16
 * @description :消息消费者rabbit
 * @note 注意事项
 */
public class CustomeriRabbit {

    //队列名称
    public static String QUEUE_NAME = "test_origin_topic_queue_rabbit";

    //定义交换器名称
    public static  String EXCHANGE_NAME = "test_origin_topic_exchange";

    public static void main(String[] args) throws IOException, TimeoutException {

        //创建连接
        Connection connection = ConnectionUtils.getConnection();

        //获取通道
        Channel channel = connection.createChannel();

        //获取交换器
        channel.exchangeDeclare(EXCHANGE_NAME, "topic");

        //创建消息声明
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);


        /**
         * 交换器绑定队列
         * 该方法定义了2个重载
         * AMQP.Queue.BindOk queueBind​(String queue,
         *                             String exchange,
         *                             String routingKey,
         *                             Map<String,Object> arguments)
         *                      throws IOException
         *
         *  @param queue 队列名称
         *  @param exchange 交换器名称
         *  @param routingKey 用于绑定的路由密钥
         *  @param arguments 其他参数,其实是定义交换器的构造方法
         */
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "*.*.rabbit");

        //定义消费者
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
                    throws IOException {
                //获取并转成String
                String message = new String(body, "UTF-8");
                System.out.println("-->rabbit消费者收到消息,msg:"+message);
            }
        };

        //监听队列
        channel.basicConsume(QUEUE_NAME, true, consumer);
    }

}
1、4 运行效果图

这里写图片描述

这里写图片描述

这里写图片描述

1、5 管控台页面

这里写图片描述

这里写图片描述

2、基于spring xml配置文件集成使用

2、1 构建maven项目,pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>edurabbitmq-ps-springxml</groupId>
    <artifactId>ps-springxml</artifactId>
    <version>1.0-SNAPSHOT</version>


    <dependencies>

        <!--引入rbiitmq的连接工具包-->
        <dependency>
            <groupId>com.rabbitmq</groupId>
            <artifactId>amqp-client</artifactId>
            <version>4.0.0</version>
        </dependency>
        <!-- 引入spring集成rabbit的包 -->
        <dependency>
            <groupId>org.springframework.amqp</groupId>
            <artifactId>spring-rabbit</artifactId>
            <version>1.7.3.RELEASE</version>
        </dependency>

        <!-- spring核心库 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.0.7.RELEASE</version>
        </dependency>

        <!-- springbean库 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.0.7.RELEASE</version>
        </dependency>

        <!-- 上下文 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.7.RELEASE</version>
        </dependency>
    </dependencies>

</project>
2、2 spring主配置文件 contxt.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    
    <!--加载topic模式-->
    <import resource="classpath:rabbitmq-topic.xml" />

</beans>
2、3 RabbitMQ的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:rabbit="http://www.springframework.org/schema/rabbit"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/rabbit
    http://www.springframework.org/schema/rabbit/spring-rabbit-1.7.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">

    <!--配置connection-factory,指定连接rabbit server参数 -->
    <rabbit:connection-factory id="connectionFactory" virtual-host="/test_vh" username="root"
                               password="123456" host="192.168.199.128" port="5672" />


    <!--MQ的管理,包括队列,交换器,声明等-->
    <rabbit:admin connection-factory="connectionFactory"   />

    <!--定义rabbit模版,指定连接工厂以及定义exchange-->
    <rabbit:template id="amqpTemplate" connection-factory="connectionFactory" exchange="topicExchangeName"  />

    <!--定义队列,自动声明(可以用于发消息和监听使用)-->
    <!--定义queue  说明:durable:是否持久化 exclusive: 仅创建者可以使用的私有队列,断开后自动删除 auto_delete: 当所有消费客户端连接断开后,是否自动删除队列-->
    <rabbit:queue id="test_topic_spring_xml_rabbit" name="test_topic_spring_xml_rabbit" auto-declare="true" />
    <!--定义队列-->
    <rabbit:queue id="test_topic_spring_xml_orange" name="test_topic_spring_xml_orange" auto-declare="true" />
    <!--定义队列-->
    <rabbit:queue id="test_topic_spring_xml_lazy" name="test_topic_spring_xml_lazy" auto-declare="true" />


    <!--定义direct交换器,并且队列绑定交换器,记住生产者发送消息的时候,使用的是这个交换器的name-->
    <rabbit:topic-exchange id="topicExchangeName" name="test_topic_spring_exchange">
        <rabbit:bindings>
            <rabbit:binding pattern="*.*.rabbit" queue="test_topic_spring_xml_rabbit"/>
            <rabbit:binding pattern="*.orange.*" queue="test_topic_spring_xml_orange"/>
            <rabbit:binding pattern="lazy.#" queue="test_topic_spring_xml_lazy"/>
        </rabbit:bindings>
    </rabbit:topic-exchange>
    

    <!--定义消费者-->
    <bean id="myLazy" class="topic.CustomerLazy"/>
    <bean id="myOrange" class="topic.CustomerOrange"/>
    <bean id="myRabbit" class="topic.CustomerRabbit"/>

    <!--队列监听 acknowledge应答方式:auto,manual,none -->
    <rabbit:listener-container connection-factory="connectionFactory" >
        <rabbit:listener ref="myLazy" method="listen" queue-names="test_topic_spring_xml_lazy"  />
        <rabbit:listener ref="myOrange" method="listen" queue-names="test_topic_spring_xml_orange"  />
        <rabbit:listener ref="myRabbit" method="listen" queue-names="test_topic_spring_xml_rabbit"  />
    </rabbit:listener-container>



</beans>
2、4 定义生产者
package com.rabbit;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author: Alex
 * @DateTime: 2018/8/22 19:40
 * @Description: 生产者
 * @Version: 1.0.0
 **/
public class SendTopic {

    //交换器名称,这里的exchange名称要和rabbitmq.xml里面配置对应
    private static String EXCHANGE_NAME = "test_topic_spring_exchange";

    public static void main(String[] args) throws InterruptedException {


        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:context.xml");

        //获取rabbit模版(等价于@Autowired)
        RabbitTemplate bean = context.getBean(RabbitTemplate.class);

        /** 此处需要定义好匹配的规则,比如lazy.orange.rabbit ,那么官网模型匹配的就是全部 **/
        /** 比如lazy.orange.myRabbit 那么就排除官网模型中的*.*.rabbit **/

        /** so 首先清楚业务需要达到什么要求,需要如何定义topic中的routing key **/

        /** 下面分别发送三条消息,注意查看消费者接收到的消息,以便于理解 **/

        /** 要注意:# 号和 * 号的区别 **/

        bean.convertAndSend(EXCHANGE_NAME,"lazy.orange.rabbit","三个消费者都能收到");
        bean.convertAndSend(EXCHANGE_NAME,"lazy.banana.rabbit","lazy消费者 和 rabbit消费者 能收到");
        bean.convertAndSend(EXCHANGE_NAME,"lazy.orange.pig","lazy 和 orange 能收到");

        Thread.sleep(10000);//休眠2秒后,关闭spring容器
        context.close();

    }
}

2、5 定义三个消费者 分别是:lazy 、 orange 、 rabbit

lazy消费者

package topic;

/**
 * @author : alex
 * @version :1.0.0
 * @Date : create by 2018/7/19 23:39
 * @description :我的消费者Lazy
 * @note 注意事项
 */
public class CustomerLazy {

    public void listen(String foo){
        System.out.println("我的消费者Lazy,获取消息msg:"+foo);
    }

}

orange消费者

package topic;

/**
 * @author : alex
 * @version :1.0.0
 * @Date : create by 2018/7/19 23:39
 * @description :我的消费者orange
 * @note 注意事项
 */
public class CustomerOrange {

    public void listen(String foo){
        System.out.println("我的消费者orange,获取消息msg:"+foo);
    }

}

rabbit消费者

package topic;

/**
 * @author : alex
 * @version :1.0.0
 * @Date : create by 2018/7/19 23:39
 * @description :我的消费者rabbit
 * @note 注意事项
 */
public class CustomerRabbit {

    public void listen(String foo){
        System.out.println("我的消费者rabbit,获取消息msg:"+foo);
    }

}
2、6 运行效果图

这里写图片描述

3、基于spring boot集成使用

3、1 构建maven项目,pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.rabbitmq.edu</groupId>
    <artifactId>rabbitmq_spring_boot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>rabbitmq_spring_boot</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

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

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

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

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

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

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

3、2 程序入口
package cn.rabbitmq.edu.rabbitmq_spring_boot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class RabbitmqSpringBootApplication {

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

3、3 application.yml配置文件
spring:
  rabbitmq:
    username: root
    password: 123456
    host: 192.168.199.128
    port: 5672
    virtual-host: /test_vh


rabbitMQconfig:
  queueName:
    lazy: test_spring_boot_topic_lazy
    rabbit: test_spring_boot_topic_rabbit
    orange: test_spring_boot_topic_orange
  exchangeName:
    topicName: test_spring_boot_exchange_topic


server:
  port: 9999
3、4 静态参数类
package cn.rabbitmq.edu.rabbitmq_spring_boot.utils;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author: Alex
 * @DateTime: 2018/8/23 11:19
 * @Description: 静态参数类
 * @Version: 1.0.0
 **/
@Component
public class ParamUtil {

    @Value("${rabbitMQconfig.queueName.lazy}")
    public String queueNameLazy;

    @Value("${rabbitMQconfig.queueName.orange}")
    public String queueNameOrange;

    @Value("${rabbitMQconfig.queueName.rabbit}")
    public String queueNameRabbit;

    @Value("${rabbitMQconfig.exchangeName.topicName}")
    public String topicName;
}

3、5 RabbitMQ配置文件
package cn.rabbitmq.edu.rabbitmq_spring_boot.utils;


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

/**
 * @author: Alex
 * @DateTime: 2018/8/23 10:52
 * @Description: rabbitMQ配置声明
 * @Version: 1.0.0
 **/
@Configuration
public class RabbitMQDeclareUtil {

    @Autowired
    private ParamUtil paramUtil;

    @Bean
    Queue getQueueLazy() {
        //定义第一个队列队列,Ctrl+鼠标左键,点击Queue可以看到定义
        return new Queue(paramUtil.queueNameLazy);
    }

    @Bean
    Queue getQueueRabbit() {
        //定义第二个队列
        return new Queue(paramUtil.queueNameRabbit);
    }

    @Bean
    Queue getQueueOrange() {
        //定义第三个队列
        return new Queue(paramUtil.queueNameOrange);
    }

    @Bean
    TopicExchange getExchange() {
        //定义一个TopicExchange交换器
        return new TopicExchange(paramUtil.topicName);
    }


    /**
     * lazy队列与交换器绑定,指定routingKey为lazy.#
     *
     * @param getQueueLazy 定义的lazy队列
     * @param getExchange  定义的交换器
     * @return
     */
    @Bean
    Binding bindingInfo(Queue getQueueLazy, TopicExchange getExchange) {

        return BindingBuilder.bind(getQueueLazy).to(getExchange).with("lazy.#");
    }

    /**
     * orange队列与交换器绑定,指定routingKey为*.orange.*
     *
     * @param getQueueOrange   定义的orange队列
     * @param getExchange 定义的交换器
     * @return
     */
    @Bean
    Binding bindingInfo1(Queue getQueueOrange, TopicExchange getExchange) {
        return BindingBuilder.bind(getQueueOrange).to(getExchange).with("*.orange.*");
    }

    /**
     * rabbit队列与交换器绑定,指定routingKey为*.*.rabbit
     *
     * @param getQueueRabbit   定义的第一个队列
     * @param getExchange 定义的交换器
     * @return
     */
    @Bean
    Binding bindingInfo2(Queue getQueueRabbit, TopicExchange getExchange) {
        return BindingBuilder.bind(getQueueRabbit).to(getExchange).with("*.*.rabbit");
    }

}

3、6 使用web访问模拟生产者
package cn.rabbitmq.edu.rabbitmq_spring_boot.controller;

import cn.rabbitmq.edu.rabbitmq_spring_boot.utils.ParamUtil;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author: Alex
 * @DateTime: 2018/8/17 16:36
 * @Description: web访问模拟发送
 * @Version: 1.0.0
 **/
@RestController
public class IndexController {

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Autowired
    private ParamUtil paramUtil;

    /**
     * 使用AmqpTemplate
     * @return
     * @throws Exception
     */
    @PostMapping("/amqpSend")
    public String amqpSend() throws Exception{

        /** 此处需要定义好匹配的规则,比如lazy.orange.rabbit ,那么官网模型匹配的就是全部 **/
        /** 比如lazy.orange.myRabbit 那么就排除官网模型中的*.*.rabbit **/

        /** so 首先清楚业务需要达到什么要求,需要如何定义topic中的routing key **/

        /** 下面分别发送三条消息,注意查看消费者接收到的消息,以便于理解 **/

        /** 要注意:# 号和 * 号的区别 **/

        amqpTemplate.convertAndSend(paramUtil.topicName,"lazy.orange.rabbit","三个消费者都能收到");//根据指定的exchange发送数据
        amqpTemplate.convertAndSend(paramUtil.topicName,"lazy.banana.rabbit","lazy消费者 和 rabbit消费者 能收到");//根据指定的exchange发送数据
        amqpTemplate.convertAndSend(paramUtil.topicName,"lazy.orange.pig","lazy 和 orange 能收到");//根据指定的exchange发送数据
        return "success";
    }
}

3、7 定义lazy消费者
package cn.rabbitmq.edu.rabbitmq_spring_boot.customer;

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * @author: Alex
 * @DateTime: 2018/8/17 16:35
 * @Description: 模拟消费者1
 * @Version: 1.0.0
 **/
@Component
//监听的队列
@RabbitListener(queues = "test_spring_boot_topic_lazy")
public class CustomerMsg {

    /**
     * 进行接收处理
     * @param string
     */
    @RabbitHandler
    public void onMessage(String string,Channel channel, Message message) throws IOException, InterruptedException {
        System.out.println("消费者lazy,接收时间:"+System.currentTimeMillis()+",收到消息,消息: " + string);
//        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);//手动确认
        //丢弃这条消息
        //channel.basicNack(message.getMessageProperties().getDeliveryTag(), false,false);
    }

}

3、8 定义rabbit消费者
package cn.rabbitmq.edu.rabbitmq_spring_boot.customer;

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * @author: Alex
 * @DateTime: 2018/8/17 16:35
 * @Description: 模拟消费者2
 * @Version: 1.0.0
 **/
@Component
//监听的队列
@RabbitListener(queues = "test_spring_boot_topic_rabbit")
public class CustomerMsg2 {

    /**
     * 进行接收处理
     * @param string
     */
    @RabbitHandler
    public void onMessage(String string,Channel channel, Message message) throws IOException, InterruptedException {
        System.out.println("消费者rabbit,接收时间:"+System.currentTimeMillis()+",收到消息,消息: " + string);
//        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);//手动确认
        //丢弃这条消息
        //channel.basicNack(message.getMessageProperties().getDeliveryTag(), false,false);
    }

}

3、9 定义orange消费者
package cn.rabbitmq.edu.rabbitmq_spring_boot.customer;

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * @author: Alex
 * @DateTime: 2018/8/17 16:35
 * @Description: 模拟消费者2
 * @Version: 1.0.0
 **/
@Component
//监听的队列
@RabbitListener(queues = "test_spring_boot_topic_orange")
public class CustomerMsg3 {

    /**
     * 进行接收处理
     * @param string
     */
    @RabbitHandler
    public void onMessage(String string,Channel channel, Message message) throws IOException, InterruptedException {
        System.out.println("消费者orange,接收时间:"+System.currentTimeMillis()+",收到消息,消息: " + string);
//        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);//手动确认
        //丢弃这条消息
        //channel.basicNack(message.getMessageProperties().getDeliveryTag(), false,false);
    }

}

3、10 运行效果图

这里写图片描述

4、小结

又到喜闻乐见的小结啦。
截止目前为止,我们学习了fanout、dirct、topic三种exchange模型,简单队列,竞争消费者队列。
一共学习了5中工作队列。

topic模型最为强大,启用匹配模式适用于复杂的业务逻辑

dirct模型适合实用于日之类管理

fanout比较简单,无脑发送,全部绑定都接收到

简单队列一对一关系

竞争消费者 一对多关系

接下来的博文,大概就要讲一下集成spring cloud啦

并且需要详细讲解一下消息确认机制,以及如何保障我们的消息

下回见

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值