消息队列-RabbitMQ-发布订阅(Publish/Subscribe)模式(代码)-生产者

 前提是已经有可用的rabbitmq服务端,如果还没有 参考安装 

消息队列-RabbitMQ-Centos8安装RabbitMQ_if_icanfly的博客-CSDN博客1.环境安装使用PackageCloud Yum Repository安装依次执行下面这两条命令curl -s https://packagecloud.io/install/repositories/rabbitmq/rabbitmq-server/script.rpm.sh | sudo bashcurl -s https://packagecloud.io/install/repositories/rabbitmq/erlang/script.rpm.sh | sudo bhttps://blog.csdn.net/if_icanfly/article/details/123252256?spm=1001.2014.3001.5502

 发布订阅模式在工作队列的基础上 加上了交换机  它由多个交换机与多个队列组成 每个交换机可以绑定多个队列

1.普通maven项目整合MQ

 新建普通的maven项目 导入rabbitmq的依赖

        <dependency>
            <groupId>com.rabbitmq</groupId>
            <artifactId>amqp-client</artifactId>
            <version>5.9.0</version>
        </dependency>

代码如下


  public static void main(String[] args) throws IOException, TimeoutException {
        //1.创建连接工厂
        ConnectionFactory conn = new ConnectionFactory();
        //2.设置参数
        conn.setHost("127.0.0.1");
        conn.setPort(5672);
        conn.setVirtualHost("/");
        conn.setUsername("xiang");
        conn.setPassword("564409");
        //3.创建连接
        Connection connection = conn.newConnection();
        //4.创建channel
        Channel channel = connection.createChannel();
        //5.创建交换机
        /**
         * 参数说明
         * @param String exchange 交换机名称
         * @param String type 交换机类型
         *               DIRECT("direct"), 定向
         *               FANOUT("fanout"), 扇形
         *               TOPIC("topic"),通配符匹配
         *               HEADERS("headers") 参数匹配
         * @param boolean durable 是否持久化
         * @param boolean autoDelete 是否自动删除
         * @param Map<String, Object> arguments 参数
         */
        String exchangeName = "fanoutexchange";
        channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT, true, false, null);

        //6.创建队列
        /**
         * 参数说明:
         * @param String queue 队列名称
         * @param boolean durable 是否持久化
         * @param boolean exclusive 是否独占(只能有一个消费者)
         * @param boolean autoDelete 是否自动删除
         * @param Map<String, Object> arguments 参数()
         */
        String queue1Name = "queue1fanout";
        String queue2Name = "queue2fanout";
        channel.queueDeclare(queue1Name, true, false, false, null);
        channel.queueDeclare(queue2Name, true, false, false, null);

        //7.绑定队列
        /**
         * @param String queue, 队列名称
         * @param String exchange, 交换机名称
         * @param String routingKey, 路由key
         *               如果交换机类型为FANOUT("fanout")扇形 或者DIRECT("direct") 定向
         *               则不需要routingKey参数 即使指定了也无用.
         *               如果为TOPIC("topic"),通配符匹配 则需要指定
         * @param Map<String, Object> arguments
         */
        channel.queueBind(queue1Name,exchangeName,"",null);
        channel.queueBind(queue2Name,exchangeName,"",null);

        //6.发送消息
        /**
         * 参数说明
         * String exchange, 交换机名称
         * String routingKey, 路由键
         *        当交换机类型为TOPIC("topic"),通配符匹配时 需要填此参数
         * boolean mandatory,是否强制
         * boolean immediate,是否立即
         * BasicProperties props, 配置
         * byte[] body 消息体
         */
        channel.basicPublish(exchangeName, "", null, "ceshi".getBytes());

        channel.close();
        connection.close();
    }

 这里需要注意的是:

当交换机exchange的类型为direct 或者fanout时,在队列绑定交换机的时候是不需要指定routingKey参数的,即使制定了也不会起作用.

当交换机exchange的类型为topic的时候,在绑定交换机绑定队列的时候需要指定routingKey ,而且在发消息的时候,也要指定routingKey

headers模式未做了解 这里不解释

2.spring整合MQ

 1.新建maven羡项目 并添加spring与spring整合mq的依赖(版本自己定了)

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.amqp</groupId>
            <artifactId>spring-rabbit</artifactId>
            <version>2.3.10</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
            <scope>test</scope>
        </dependency>

配置文件 mq.properties 与 spring-rabbitma.xml

mq.properties

mq.host=127.0.0.1
mq.username=xiang
mq.password=564409
mq.port=5672
mq.vhost=/

 spring-rabbitma.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"
       xmlns:context="http://www.springframework.org/schema/context"
       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/context
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/rabbit
       http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
    <!--加载配置文件-->
    <context:property-placeholder location="classpath:rabbitmq.properties"/>

    <!-- 定义rabbitmq connectionFactory -->
    <rabbit:connection-factory id="connectionFactory" host="${mq.host}"
                               port="${mq.port}"
                               username="${mq.username}"
                               password="${mq.password}"
                               virtual-host="${mq.vhost}"/>
    <!--定义管理交换机、队列-->
    <rabbit:admin connection-factory="connectionFactory"/>

    <!--================= 交换机类型 direct-exchange=======================-->
    <rabbit:direct-exchange name="directExchange" durable="true" auto-declare="true">
        <rabbit:bindings>
            <rabbit:binding queue="direct1queue"/>
        </rabbit:bindings>
    </rabbit:direct-exchange>
    <rabbit:queue id="direct1queue" name="direct1queue"  durable="true"  auto-declare="true"/>

    <!--================= 交换机类型 fanout-exchange=======================-->
    <rabbit:fanout-exchange name="fanoutExchange" auto-declare="true" durable="true">
        <rabbit:bindings>
            <rabbit:binding queue="fanout1queue"/>
            <rabbit:binding queue="fanout2queue"/>
        </rabbit:bindings>
    </rabbit:fanout-exchange>
    <rabbit:queue id="fanout1queue" name="fanout1queue"  durable="true"  auto-declare="true"/>
    <rabbit:queue id="fanout2queue" name="fanout2queue"  durable="true"  auto-declare="true"/>

    <!--================= 交换机类型 topic-exchange=======================-->
    <rabbit:topic-exchange name="topicExchange" auto-declare="true" durable="true">
        <rabbit:bindings>
            <rabbit:binding pattern="topic1.#" queue="topic1queue"></rabbit:binding>
            <rabbit:binding pattern="topic2.#" queue="topic2queue"></rabbit:binding>
        </rabbit:bindings>
    </rabbit:topic-exchange>

    <rabbit:queue id="topic1queue" name="topic1queue"  durable="true"  auto-declare="true"/>
    <rabbit:queue id="topic2queue" name="topic2queue"  durable="true"  auto-declare="true"/>

    <!--定义rabbitTemplate对象操作可以在代码中方便发送消息-->
    <rabbit:template id="rabbitTemplate" connection-factory="connectionFactory"/>
</beans>

测试代码


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationcontext.xml")
public class daxiang {

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Test
    public void test(){
        // direct类型的交换机 这里的routingKey必须与交换机绑定的队列名称完全匹配 否则消息无法到达服务端 
        //rabbitTemplate.convertAndSend("directExchange","direct1queue","测试简单模式");

        //fanout类型的交换机 这里的routingKey不需要指定
        //rabbitTemplate.convertAndSend("fanoutExchange","","测试简单模式");

        // topic类型的交换机 这里的routingKey需要指定
        //rabbitTemplate.convertAndSend("topicExchange","topic1.123","测试简单模式");
    }
}

注意:

这里的direct类型的交换机与上面的普通整合有所区别  这里的direct类型的交换机能绑定多个队列  但是发送消息的时候必须要指定routingKey 而且需要完全匹配  意味着每次只能向一个队列发送消息, 而普通整合不需要指定routingkey 绑定的多个队列都能收到消息.很纳闷

3.springboot整合MQ 

新建springboot项目 导入依赖

        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-amqp -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
            <version>2.6.4</version>
        </dependency>

配置类文件中 添加mq连接的配置

spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=xiang
spring.rabbitmq.password=564409
spring.rabbitmq.virtual-host=/

添加mq的配置类

package com.example.demo.config;

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

@Configuration
public class RabbitMqConfig {

    /**
     * 三种交换机名称
     */
    private String EXCHANGE_DIRECT = "exchange_direct";
    private String EXCHANGE_FANOUT = "exchange_fanout";
    private String EXCHANGE_TOPIC = "exchange_topic";

    /**
     * 队列名称
     */
    private String QUEUE_DIRECT_1 = "queue_direct_1";
    private String QUEUE_FANOUT_1 = "queue_fanout_1";
    private String QUEUE_FANOUT_2 = "queue_fanout_2";
    private String QUEUE_TOPIC_1 = "queue_topic_1";
    private String QUEUE_TOPIC_2 = "queue_topic_2";

    /**
     * =================5个队列=========================
     * 
     */
    
    @Bean("queue_direct_1")
    public Queue queueDirect1() {
        return QueueBuilder.durable(QUEUE_DIRECT_1).build();
    }

    @Bean("queue_fanout_1")
    public Queue queueFanout1() {
        return QueueBuilder.durable(QUEUE_FANOUT_1).build();
    }

    @Bean("queue_fanout_2")
    public Queue queueFanout2() {
        return QueueBuilder.durable(QUEUE_FANOUT_2).build();
    }

    @Bean("queue_topic_1")
    public Queue queueTopic1() {
        return QueueBuilder.durable(QUEUE_TOPIC_1).build();
    }

    @Bean("queue_topic_2")
    public Queue queueTopic2() {
        return QueueBuilder.durable(QUEUE_TOPIC_2).build();
    }

    /**
     * =================3个交换机=========================
     *
     */
    @Bean("exchange_direct")
    public Exchange directExchange() {
        return ExchangeBuilder.directExchange(EXCHANGE_DIRECT).durable(true).build();
    }

    @Bean("exchange_fanout")
    public Exchange fanoutExchange() {
        return ExchangeBuilder.fanoutExchange(EXCHANGE_FANOUT).durable(true).build();
    }

    @Bean("exchange_topic")
    public Exchange topicExchange() {
        return ExchangeBuilder.topicExchange(EXCHANGE_TOPIC).durable(true).build();
    }


    /**
     * =================5次绑定=========================
     *
     */
    @Bean
    public Binding bindingQueueExchange1() {
        return BindingBuilder.bind(queueDirect1()).to(directExchange()).with("").noargs();
    }

    @Bean
    public Binding bindingQueueExchange2() {
        return BindingBuilder.bind(queueFanout1()).to(fanoutExchange()).with("").noargs();
    }

    @Bean
    public Binding bindingQueueExchange3() {
        return BindingBuilder.bind(queueFanout2()).to(fanoutExchange()).with("").noargs();
    }

    @Bean
    public Binding bindingQueueExchange4() {
        return BindingBuilder.bind(queueTopic1()).to(topicExchange()).with("topic1.#").noargs();
    }

    @Bean
    public Binding bindingQueueExchange5() {
        return BindingBuilder.bind(queueTopic2()).to(topicExchange()).with("topic2.#").noargs();
    }

}

代码比较多 是因为我配置了3种交换机 5个队列 绑定了5次

测试类:

@SpringBootTest
class DemoApplicationTests {

    @Resource
    private RabbitTemplate rabbitTemplate;

    private String EXCHANGE_DIRECT = "exchange_direct";
    private String EXCHANGE_FANOUT = "exchange_fanout";
    private String EXCHANGE_TOPIC = "exchange_topic";

    @Test
    void contextLoads() {

        // fanout 类型的交换机 在发送消息的时候不需要指定routingKey 绑定的队列都能收到消息 指定了也不起作用
        //rabbitTemplate.convertAndSend(EXCHANGE_FANOUT,"22","nihao ");

        //direct 类型的交换机 也不需要指定routingKey 如果指定 则消息无法到达队列
        //rabbitTemplate.convertAndSend(EXCHANGE_DIRECT,"","nihao ");

        // topic类型的交换机 需要指定routingKey 前缀匹配
        //rabbitTemplate.convertAndSend(EXCHANGE_TOPIC,"topic1.1","nihao");
    }

}

 测试结果:

 绑定关系是成功的,消息也能正确到达队列

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值