RabbitMQ入门

RabbitMQ简介

官方定义:RabbitMQ是一种消息中间件,用于处理来自客户端的异步消息。服务端将要发送的消息放入到队列池中。接收端可以根据RabbitMQ配置的转发机制接收服务端发来的消息。RabbitMQ依据指定的转发规则进行消息的转发、缓冲和持久化操作,主要用在多服务器间或单服务器的子系统间进行通信,是分布式系统标准的配置。RabbitMQ是使用 Erlang语言来编写的,并且RabbitMQ是基于AMQP协议的

RabbitMQ整体架构
在这里插入图片描述
RabbitMQ核心概念
Server:又称Broker,接受客户端的连接,实现AMQP实体服务
Connection:连接,应用程序与Broker的网络连接
Channel:网络信道,几乎所有的操作都在Channel中进行,Channel是进行消息读写的通道。客户端可建立多个Channel,每个Channel代表一个会话任务
Message:消息,服务器和应用程序之间传送的数据,由Properties和Body组成。Properties可以对消息进行修饰,比如消息的优先级、延迟等高级特性;Body则是消息体的内容
Virtual host:虚拟地址,用于进行逻辑隔离,最上层的消息路由。同一个Virtual Host里面不能有相同名称的Exchange或Queue
Exchange:交换机,接收消息,根据路由键转发消息到绑定的队列
Binding:Exchange和Queue之间的虚拟连接,binding中可以包含routing key
Routing key:一个路由规则,虚拟机可用它确定如何路由一个特定消息
Queue:也称为Message Queue,消息队列,保存消息并将它们转发给消费者

MQ的优点
1、异步处理 - 相比于传统的串行、并行方式,提高了系统吞吐量。
2、应用解耦 - 系统间通过消息通信,不用关心其他系统的处理。
3、流量削锋 - 可以通过消息队列长度控制请求量;可以缓解短时间内的高并发请求,一般在秒杀活动中应用广泛 。

发送消息的过程
1、生产者和Broker通过TCP连接建立通道。
2、生产者通过通道消息发送给Broker,由Exchange将消息进行转发。
3、Exchange通过Routing Key将消息转发到指定的Queue(队列)

接收消息的过程
1、生产者和Broker通过TCP连接建立通道。
2、消费者监听指定的Queue(队列)
3、当有消息到达Queue时Broker默认将消息推送给消费者。
4、消费者接收到消息。

RabbitMQ入门

环境:SpringBoot+RabbitMQ 5.8.0

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

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

创建消息生产者,不指定交换机

public class ProducerDemo {
    public static void main(String[] args) throws IOException, TimeoutException {
        //创建工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //通过工厂创建连接
        Connection connection = connectionFactory.newConnection();

        //通过连接创建通道
        Channel channel = connection.createChannel();

        String exchangeName = "";
        String routingKey= "defaultQueue";
        String data = "hello";
        
        //通过通道发送信息,第三个参数是消息属性,可以配置消息的过期时间
        channel.basicPublish(exchangeName,routingKey,null,data.getBytes());

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

创建消息消费者,不指定交换机

public class ConsumerDemo {
    public static void main(String[] args) throws IOException, TimeoutException {
        //创建工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //通过工厂创建连接
        Connection connection = connectionFactory.newConnection();

        //通过连接创建通道
        Channel channel = connection.createChannel();

        String queueName = "defaultQueue";

        /**
         * 配置监听的队列
         * 第一个参数 队列名
         * 第二个参数 durable 是否持久化
         * 第三个参数 exclusive 是否独占的  相当于加了一把锁
         * 第四个参数 autoDelete 是否自动删除
         * 第五个参数 map类型,表示对队列中的消息进行详细设置,例如绑定死信队列
         */
        channel.queueDeclare(queueName,true,false,false,null);

        //创建消费者
        Consumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg = new String(body);
                System.out.println(msg);
            }
        };

        //对消息作出应答,第二个参数表示自动ACK
        channel.basicConsume(queueName,true,consumer);
    }
}

Direct Exchange(直连交换机)

direct为默认的交换器类型,如果路由键匹配的话,消息就投递到相应的队列。有一个需要注意的地方:如果找不到指定的exchange,就会报错。但routing key找不到的话,不会报错,这条消息会直接丢失,所以此处要小心。
大致流程,有一个队列绑定到一个直连交换机上,同时赋予一个路由键 routing key 。
然后当一个消息携带着路由键为X,这个消息通过生产者发送给交换机时,交换机就会根据这个路由值X去寻找绑定值也是X的队列。

创建消息生产者,使用Direct Exchange

public class PeoducerDirectExchange {
    public static void main(String[] args) throws IOException, TimeoutException {
        //创建工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //通过工厂创建连接
        Connection connection = connectionFactory.newConnection();

        //通过连接创建通道
        Channel channel = connection.createChannel();

        String exchangeName = "directExchange";
        String exchangeType = "direct";
        String routingKey = "directKey";
        String data = "hello";

        //声明交换机
        channel.exchangeDeclare(exchangeName,exchangeType,true,false,false,null);
        //指定routingKey
        channel.basicPublish(exchangeName,routingKey,null,data.getBytes());

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


创建消息消费者,使用Direct Exchange

public class ConsumerDirectExchange {
    public static void main(String[] args) throws IOException, TimeoutException {
        //创建工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //通过工厂创建连接
        Connection connection = connectionFactory.newConnection();

        //通过连接创建通道
        Channel channel = connection.createChannel();

        String exchangeName = "directExchange";
        String exchangeType = "direct";
        String queueName = "directQueue";
        String routingKey = "directKey";

        //声明一个direct类型的交换机
        channel.exchangeDeclare(exchangeName,exchangeType,true,false,false,null);
        //声明一个队列
        channel.queueDeclare(queueName,true,false,false,null);
        //建立绑定关系,所有发送到Direct Exchange的消息被转发到RouteKey指定的Queue
        channel.queueBind(queueName,exchangeName,routingKey);

        //创建消费者
        Consumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg = new String(body);
                System.out.println(msg);
            }
        };

        channel.basicConsume(queueName,true,consumer);
    }
}

Topic Exchange(主题交换机)

这个交换机其实跟直连交换机流程差不多,但是它的特点就是在它的路由键和绑定键之间是有规则的。

创建消息生产者,使用Topic Exchange

public class ProducerTopicExchange {

    public static void main(String[] args) throws IOException, TimeoutException {
        //创建工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //通过工厂创建连接
        Connection connection = connectionFactory.newConnection();

        //通过连接创建通道
        Channel channel = connection.createChannel();

        //使用exchangeName交换器
        String exchangeName = "topicExchange";
        String exchangeType = "topic";
        //指定routingKey
        String routingKey1 = "user.topicKey1";
        String routingKey2 = "user.topicKey2";
        String routingKey3 = "user.topicKey3";

        //声明一个topic类型的交换机
        channel.exchangeDeclare(exchangeName,exchangeType,true,false,false,null);

        //这里发送三条消息,指定三个routingKey
        channel.basicPublish(exchangeName,routingKey1,null,"hello1".getBytes());
        channel.basicPublish(exchangeName,routingKey2,null,"hello2".getBytes());
        channel.basicPublish(exchangeName,routingKey3,null,"hello3".getBytes());

        channel.close();
        connection.close();
    }
}
        channel.basicPublish(exchangeName,routingKey3,null,"hello3".getBytes());

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

创建消息消费者,使用Topic Exchange

public class ConsumerTopicExchange {
    public static void main(String[] args) throws IOException, TimeoutException {
        //创建工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //通过工厂创建连接
        Connection connection = connectionFactory.newConnection();

        //通过连接创建通道
        Channel channel = connection.createChannel();

        String exchangeName = "topicExchange";
        String exchangeType = "topic";
        String queueName = "topicQueue";
        //这里routingKey使用模糊匹配
        String routingKey = "user.#";

        //声明一个topic类型的交换机
        channel.exchangeDeclare(exchangeName,exchangeType,true,false,false,null);
        //声明一个队列
        channel.queueDeclare(queueName,true,false,false,null);
        //建立绑定关系
        channel.queueBind(queueName,exchangeName,routingKey);

        //创建消费者
        Consumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg = new String(body);
                System.out.println(msg);
            }
        };

        channel.basicConsume(queueName,true,consumer);
    }
}

routingKey中的通配符
符号* 用来表示一个单词.
符号# 用来表示任意数量(零个或多个)单词
例如:user.* 可以匹配 user.topicKey1,user.topicKey2
user.#可以匹配user.topicKey1, user.topicKey1.add

Fanout Exchange(扇型交换机)

扇形交换机把消息发送给它所知道的所有队列,不处理路由键,所以Fanout交换机转发消息是最快的

创建消息生产者,使用Fanout Exchange

public class ProducerFanoutExchange {
    public static void main(String[] args) throws IOException, TimeoutException {
        //创建工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //通过工厂创建连接
        Connection connection = connectionFactory.newConnection();

        //通过连接创建通道
        Channel channel = connection.createChannel();

        String exchangeName = "fanoutExchange";
        String exchangType = "fanout";
        //不需要指定路由key
        String routingKey = "";
        String data = "hello";
        
        //声明一个fanout类型的交换机
        channel.exchangeDeclare(exchangeName,exchangType,true,false,false,null);

        channel.basicPublish(exchangeName,routingKey,null,data.getBytes());

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

创建消息消费者,使用Fanout Exchange

public class ConsumerFanoutExchange1 {
    public static void main(String[] args) throws IOException, TimeoutException {
        //创建工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //通过工厂创建连接
        Connection connection = connectionFactory.newConnection();

        //通过连接创建通道
        Channel channel = connection.createChannel();

        String exchangeName = "fanoutExchange";
        String exchangeType = "fanout";
        String queueName = "fanoutQueue1";
        //不需要指定路由key
        String routingKey = "";

        //声明一个fanout类型的交换机
        channel.exchangeDeclare(exchangeName,exchangeType,true,false,false,null);
        //声明一个队列
        channel.queueDeclare(queueName,true,false,false,null);
        //建立绑定关系
        channel.queueBind(queueName,exchangeName,routingKey);

        //创建消费者
        Consumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg = new String(body);
                System.out.println(msg);
            }
        };

        channel.basicConsume(queueName,true,consumer);
    }
}

创建消息生产者2

public class ConsumerFanoutExchange2 {
    public static void main(String[] args) throws IOException, TimeoutException {
        //创建工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        //通过工厂创建连接
        Connection connection = connectionFactory.newConnection();

        //通过连接创建通道
        Channel channel = connection.createChannel();

        String exchangeName = "fanoutExchange";
        String exchangeType = "fanout";
        String queueName = "fanoutQueue2";
        //不需要指定路由key
        String routingKey = "";

        //声明一个fanout类型的交换机
        channel.exchangeDeclare(exchangeName,exchangeType,true,false,false,null);
        //声明一个队列
        channel.queueDeclare(queueName,true,false,false,null);
        //建立绑定关系
        channel.queueBind(queueName,exchangeName,routingKey);

        //创建消费者
        Consumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg = new String(body);
                System.out.println(msg);
            }
        };

        channel.basicConsume(queueName,true,consumer);
    }
}

注意:1、如果交换机、队列属性发生改变,需要去控制台将之前的交换机、队列删除,才能重新启动成功
2、上面所有的例子都是持久化消息,先启动生产者,消息会被保存到消息队列,登消费者上线可以进行消费。消息队列中必须要有交换机和队列的绑定信息才能被持久化。

项目代码:项目代码
相关阅读:
SpringBoot整合RabbitMQ
RabbitMQ的消息确认机制,消息重试机制
RabbitMQ的死信队列与延时队列

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值