rabbitmq笔记

101 阅读5分钟

Rabbitmq

什么是rabbitmq?

一款基于AMQP(高级消息队列协议)用于软件之间通信的中间件,AMQP是一种二进制协议,它定义了一组规则和标准,以确保消息可以在不同的应用程序和平台之间传递并解释,AMQP协议包含四个核心组件:消息、交换机、队列、绑定

消息队列的应用场景

  • 应用解耦
  • 返回响应速度提高
  • 流量削峰

Rabbitmq四大核心

  • 生产者
  • 消费者
  • 队列
  • 交换机

消息队列的特点

  • 易用性
  • 扩展性
  • 高可用

消息队列的缺点

  • 降低系统的可用性:引入外部依赖越多,越可能出问题
  • 系统复杂度提高
  • 一致性问题

组成部分

  • Broker:接受和分发消息的应用,RabbitMQ Server就是Message Broker
    • Virtual host:虚拟主机,一个Borker中可以有对个虚拟主机,不同的虚拟主机中的exchange和queue名字可以一样,所以不同的用户访问同一个Border时可以创建独立的虚拟主机,然后在自己的虚拟主机中创建Exchange和Queue,实现不同用户之间的相互隔离。
      • Exchange:交换机,根据分发规则,匹配查询表中的routing key,分发消息到queue中。
      • Queue:队列,用来存放生产者发送的消息,消费者会将其中的消息消费掉
      • Binding:Exchange和queue之间的虚拟链接,包含routing key,Binding被保存在exchange中的查询表中,作为message分发的依据
  • Connection:消费者/生产者和Broker之间的TCP连接
    • Channel:消息通道,为了减少Connection连接的开销、提升效率,Channel实现了在Connection内部建立逻辑连接,可以每个线程创建单独的channel进行通讯,AMQP method包含了channel id帮助客户端和message Broker识别channel,channel是完全隔离的。

exchange交换机类型

  • direct:通过路由键(routing key)与队列(queue)绑定,完全匹配模式
  • fanout:通过广播的形式,将消息发送给所有绑定的队列
  • topic:通过对队列(routing key)的模糊绑定,进行消息传输

代码示例

导入依赖

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

消费者代码

public class Consumer {
    public static void main(String[] args) throws IOException, TimeoutException {
        //创建一个链接工厂
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("127.0.0.1");
        factory.setPort(5672);
        factory.setUsername("guest");
        factory.setPassword("guest");
        //创建链接
        Connection connection = factory.newConnection();
        //创建信道
        Channel channel = connection.createChannel();


        DeliverCallback deliverCallback = (s,d) -> System.out.println(new String(d.getBody(), StandardCharsets.UTF_8));
        CancelCallback cancelCallback = s -> System.out.println(s);
        /**
         * 消费消息
         * 1、队列名称
         * 2、是否自动应答
         * 3、获取消息回调函数
         * 4、取消消息回调函数
         */
        channel.basicConsume("xy_queue_name1",true,deliverCallback,cancelCallback);
        channel.basicConsume("xy_queue_name2",true,deliverCallback,cancelCallback);
        channel.basicConsume("xy_queue_name3",true,deliverCallback,cancelCallback);
        channel.basicConsume("xy_queue_name4",true,deliverCallback,cancelCallback);

        channel.close();
        connection.close();
    }
}
direct交换机类型

消息生产者代码

public class Producer {
    public static void main(String[] args) throws IOException, TimeoutException {
        //创建一个链接工厂
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("127.0.0.1");
        factory.setPort(5672);
        factory.setUsername("guest");
        factory.setPassword("guest");
        //创建链接
        Connection connection = factory.newConnection();
        //创建信道
        Channel channel = connection.createChannel();
        /**
         * 创建交换机
         * 1、交换机名称
         * 2、交换机类型:direct,topic,fanout、headers
         * 3、指定交换机是否需要持久化
         * 4、在没有队列绑定时是否需要删除
         * 5、Map类型,用来指定交换机其他的结构化参数
         */
        String exchangeName = "xy_exchange_name";
        channel.exchangeDeclare(exchangeName, BuiltinExchangeType.DIRECT,true,false,null);
        /**
         * 生成队列
         * 1、队列名称
         * 2、队列信息是否要持久化(不是队列中消息的持久化)
         * 3、表示队列是否私有
         * 4、在没有消费者订阅的情况下是否自动删除
         * 5、队列的结构化信息
         */
        String queueName1 = "xy_queue_name1";
        String queueName2 = "xy_queue_name2";
        String queueName3 = "xy_queue_name3";
        String queueName4 = "xy_queue_name4";
        channel.queueDeclare(queueName1,true,false,false,null);
        channel.queueDeclare(queueName2,true,false,false,null);
        channel.queueDeclare(queueName3,true,false,false,null);
        channel.queueDeclare(queueName4,true,false,false,null);
        /**
         * 绑定交换机和队列
         */
        String key1 = "key1";
        String key2 = "key2";
        String key3 = "key3";
        String key4 = "key4";
        channel.queueBind(queueName1,exchangeName,key1);
        channel.queueBind(queueName2,exchangeName,key2);
        channel.queueBind(queueName3,exchangeName,key3);
        channel.queueBind(queueName4,exchangeName,key4);
        /**
         * 发送消息
         * 1、要发送到哪个交换机
         * 2、队列名称
         * 3、其他参数信息
         * 4、消息体
         */
        String message = "hello rabbitmq";
        channel.basicPublish(exchangeName,key1,null,message.getBytes(StandardCharsets.UTF_8));
        channel.basicPublish(exchangeName,key2,null,message.getBytes(StandardCharsets.UTF_8));
        channel.basicPublish(exchangeName,key3,null,message.getBytes(StandardCharsets.UTF_8));
        channel.basicPublish(exchangeName,key4,null,message.getBytes(StandardCharsets.UTF_8));

        //关闭连接
        channel.close();
        connection.close();
    }
}
fanout交换机类型
public class Producer {
    public static void main(String[] args) throws IOException, TimeoutException {
        //创建一个链接工厂
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("127.0.0.1");
        factory.setPort(5672);
        factory.setUsername("guest");
        factory.setPassword("guest");
        //创建链接
        Connection connection = factory.newConnection();
        //创建信道
        Channel channel = connection.createChannel();
        /**
         * 创建交换机
         * 1、交换机名称
         * 2、交换机类型:direct,topic,fanout、headers
         * 3、指定交换机是否需要持久化
         * 4、在没有队列绑定时是否需要删除
         * 5、Map类型,用来指定交换机其他的结构化参数
         */
        String exchangeName = "xy_exchange_name";
        channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT,true,false,null);
        /**
         * 生成队列
         * 1、队列名称
         * 2、队列信息是否要持久化(不是队列中消息的持久化)
         * 3、表示队列是否私有
         * 4、在没有消费者订阅的情况下是否自动删除
         * 5、队列的结构化信息
         */
        String queueName1 = "xy_queue_name1";
        String queueName2 = "xy_queue_name2";
        String queueName3 = "xy_queue_name3";
        String queueName4 = "xy_queue_name4";
        channel.queueDeclare(queueName1,true,false,false,null);
        channel.queueDeclare(queueName2,true,false,false,null);
        channel.queueDeclare(queueName3,true,false,false,null);
        channel.queueDeclare(queueName4,true,false,false,null);
        /**
         * 绑定交换机和队列
         */
        String key1 = "key1.key2.key3.*";
        String key2 = "key1.#";
        String key3 = "*.key2.*.key4";
        String key4 = "#.key3.key4";
        channel.queueBind(queueName1,exchangeName,key1);
        channel.queueBind(queueName2,exchangeName,key2);
        channel.queueBind(queueName3,exchangeName,key3);
        channel.queueBind(queueName4,exchangeName,key4);
        /**
         * 发送消息
         * 1、要发送到哪个交换机
         * 2、队列名称
         * 3、其他参数信息
         * 4、消息体
         */
        String message = "hello rabbitmq";
        channel.basicPublish(exchangeName,"key1",null,message.getBytes(StandardCharsets.UTF_8));

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

如果使用FANOUT,会使DIRECT和TOPIC相关的绑定配置失效

topic交换机类型
public class Producer {
    public static void main(String[] args) throws IOException, TimeoutException {
        //创建一个链接工厂
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("127.0.0.1");
        factory.setPort(5672);
        factory.setUsername("guest");
        factory.setPassword("guest");
        //创建链接
        Connection connection = factory.newConnection();
        //创建信道
        Channel channel = connection.createChannel();
        /**
         * 创建交换机
         * 1、交换机名称
         * 2、交换机类型:direct,topic,fanout、headers
         * 3、指定交换机是否需要持久化
         * 4、在没有队列绑定时是否需要删除
         * 5、Map类型,用来指定交换机其他的结构化参数
         */
        String exchangeName = "xy_exchange_name";
        channel.exchangeDeclare(exchangeName, BuiltinExchangeType.TOPIC,true,false,null);
        /**
         * 生成队列
         * 1、队列名称
         * 2、队列信息是否要持久化(不是队列中消息的持久化)
         * 3、表示队列是否私有
         * 4、在没有消费者订阅的情况下是否自动删除
         * 5、队列的结构化信息
         */
        String queueName1 = "xy_queue_name1";
        String queueName2 = "xy_queue_name2";
        String queueName3 = "xy_queue_name3";
        String queueName4 = "xy_queue_name4";
        channel.queueDeclare(queueName1,true,false,false,null);
        channel.queueDeclare(queueName2,true,false,false,null);
        channel.queueDeclare(queueName3,true,false,false,null);
        channel.queueDeclare(queueName4,true,false,false,null);
        /**
         * 绑定交换机和队列
         */
        String key1 = "key1.key2.key3.*";
        String key2 = "key1.#";
        String key3 = "*.key2.*.key4";
        String key4 = "#.key3.key4";
        channel.queueBind(queueName1,exchangeName,key1);
        channel.queueBind(queueName2,exchangeName,key2);
        channel.queueBind(queueName3,exchangeName,key3);
        channel.queueBind(queueName4,exchangeName,key4);
        /**
         * 发送消息
         * 1、要发送到哪个交换机
         * 2、队列名称
         * 3、其他参数信息
         * 4、消息体
         */
        String message = "hello rabbitmq";
        channel.basicPublish(exchangeName,"key1",null,message.getBytes(StandardCharsets.UTF_8));

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