RabbitMQ的五种重要的工作模式和基础代码

消息中间件

概述

MQ全程message Queue,即消息队列,消息队列是应用程序和应用程序之间的通信方法。

RabbitMQ的使用

简单工作模式

  • 简单队列,直接提供者提供,消费者接受
    工作队列
  • 在工作队列中,每一个消费者默认平均分配提供者提供的消息。
  • 存在一个问题:两个消费者的处理能力不同
  • 工作队列的"能者多劳模式",由于性能不一样,通常需要配置成性能好的,快速消费,而不是等待性能慢的来消费.
    发布订阅模式
  • 发布/订阅队列模式,每个消费者监听自己的队列。
  • 中间需要交换机来实现功能(BuiltinExchangeType.FANOUT)
  • 生产者将消息发给broker,由交换机将消息转发到绑定此交换机的每个队列,每个绑定交换机的队列都将接收到消息

在这里插入图片描述

  • Routing路由模式,在发布订阅模式中每一个消费者都接受相同消息,但是在实际开发中,我们常常需要对消息进行不同的处理。例如:实际开发中,对日志信息的记录,对于error级别日志,我们可能既要保存日志,又要将它打印到控制台,而info,warning可能只需要打印在控制台,不需要保存到数据库中。

  • 采用交换机–BuiltinExchangeType.DIRECT
    路由模式特点:

    • 队列与交换机的绑定,不能是任意绑定了,而是要指定一个RoutingKey(路由key)
    • 消息的发送方在 向 Exchange发送消息时,也必须指定消息的 RoutingKey
    • Exchange不再把消息交给每一个绑定的队列,而是根据消息的Routing Key进行判断,只有队列的Routingkey与消息的 Routing key完全一致,才会接收到消息
      topic
      Topic类型与Direct相比,都是可以根据RoutingKey把消息路由到不同的队列。只不过Topic类型Exchange可以让队列在绑定Routing key 的时候使用通配符

Routingkey 一般都是有一个或多个单词组成,多个单词之间以”.”分割,例如: item.insert

通配符规则:

#:匹配一个或多个词

*:匹配不多不少恰好1个词

举例:

item.#:能够匹配item.insert.abc 或者 item.insert

item.*:只能匹配item.insert

三套api

原生java使用RabbitMQ

这里使用最简单的工作模式来进行案例。
简单工作模式

首先导入依赖,提供方和消费方的依赖一样

 <dependencies>
        <!--rabbitMQ的java客户端-->
        <dependency>
            <groupId>com.rabbitmq</groupId>
            <artifactId>amqp-client</artifactId>
            <version>5.6.0</version>
        </dependency>
        <dependency><!--解决运行时代码爆红,可以不要-->
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-nop</artifactId>
            <version>1.7.2</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

RabbitMQ运行

提供方代码

运行这段代码,会直接将信息传递到消息中间件中,由于没有消费者去取消息,此时消息会保存在消息中间件中,阻塞。
可以通过 http://localhost:15672/ 进入控制台进行查看。

package com.itheima.producer;

/*
 *@AUTHOR:LIUCHAO;
 *@DATE: 2020/10/12 20:51
 */
/*
* 原声api
* */
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

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

/*发送消息,*/
public class Producer_HelloWorld {
    
    
    public static void main(String[] args) throws IOException, TimeoutException {
    
    


        /*建立连接,通过工厂模式--所以先创建连接工厂*/
        ConnectionFactory factory = new ConnectionFactory();
        /*设置参数,   虚拟机,用户名,ip端口号*/
        factory.setHost("192.168.164.131");//ip地址  默认值是localhost
        factory.setPort(5672);//端口号 默认值是5672
        factory.setVirtualHost("/itcast");//虚拟机  默认值是 /
        factory.setUsername("heima");//用户名  默认值是guest
        factory.setPassword("heima");//用户名  默认值是guest
        /*获取连接,创建连接 connection*/
        Connection connection = factory.newConnection();
        /*创建channel*/
        Channel channel = connection.createChannel();
        /*如果不需要交换机,就直接创建队列Quene*/

        /*queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,
                                 Map<String, Object> arguments)
         参数:
                1.queue :  队列名称
                2.durable:  是否持久化,当mq重启之后,还在
                3.exclusive: 是否独占,只能有一个消费者监听这队列
                             当connection关闭时,是否删除队列
                             一般设置为false
                4.autoDelete: 是否自动删除,当没有consumer时,自动删除掉
                5.arguments:  参数 ,直接设置成null
                           */
        //如果没有一个队列名字叫hello_world,则会创建该队列,如果有则不会创建
        channel.queueDeclare("hello_world",true,false,false,null);
        /*发送消息*/
        /*
        * basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body)
         * exchange:  交换机名称,简单模式下交换机使用默认交换机  直接写 ""
         * routingKey: 路由名称,和上面的队列名称保持一致
        * props:配置信息
        * body:发送的消息 字节数组
        * */
        String body="hello rabbitmq~~~~~~~~~~~~~";
        channel.basicPublish("","hello_world",null,body.getBytes());

    /*释放资源*/
        channel.close();
        connection.close();

    }
}

此时工作台
工作台

消费方代码

基本上和提供方代码差不多,只是在消费方会有一个回调方法,用来接受到提供方的消息后,自动执行该方法。
当代码运行时,如果消息中间件中没有消息,那么程序一直运行,对该队列进行监听;如果消息中间件中有消息就取出,继续监听。
当获取到提供方的消息后,监控平台中的消息显示被消费掉

package com.itheima.consumer;

/*
 *@AUTHOR:LIUCHAO;
 *@DATE: 2020/10/12 21:30
 */


import com.rabbitmq.client.*;

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

public class Consumer_HelloWorld {
    
    
    public static void main(String[] args) throws IOException, TimeoutException {
    
    
        /*建立连接,通过工厂模式--所以先创建连接工厂*/
        ConnectionFactory factory = new ConnectionFactory();
        /*设置参数,   虚拟机,用户名,ip端口号*/
        factory.setHost("192.168.164.131");//ip地址  默认值是localhost
        factory.setPort(5672);//端口号 默认值是5672
        factory.setVirtualHost("/itcast");//虚拟机  默认值是 /
        factory.setUsername("heima");//用户名  默认值是guest
        factory.setPassword("heima");//用户名  默认值是guest
        /*获取连接,创建连接 connection*/
        Connection connection = factory.newConnection();
        /*创建channel*/
        Channel channel = connection.createChannel();
        /*如果不需要交换机,就直接创建队列Quene*/

        /*queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,
                                 Map<String, Object> arguments)
         参数:
                1.queue :  队列名称
                2.durable:  是否持久化,当mq重启之后,还在
                3.exclusive: 是否独占,只能有一个消费者监听这队列
                             当connection关闭时,是否删除队列
                             一般设置为false
                4.autoDelete: 是否自动删除,当没有consumer时,自动删除掉
                5.arguments:  参数 ,直接设置成null
                           */
        //如果没有一个队列名字叫hello_world,则会创建该队列,如果有则不会创建--
        //生产者创建队列后,消费者可以不用创建,写起也没啥错
        channel.queueDeclare("hello_world",true,false,false,null);
        /*接受消息*/
        /*
        * basicConsume(String queue, boolean autoAck, Consumer callback)
        * queue:队列
        * autoAck:是否自动确认
        * callback:回调函数
        * */
        Consumer consumer=new DefaultConsumer(channel){
    
    
            /*回调方法,当收到消息后,会自动执行该方法*/
            @Override
            /*                                消息标识      获取一些信息,交换机,路由key             配置信息              正式数据     */
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
    
    
                System.out.println("consumerTag:"+consumerTag);//consumerTag:amq.ctag-mWgUgb4Zttu7ds1gjwSXTg
                System.out.println("envelope.getExchange() = " + envelope.getExchange());//envelope.getExchange() = 
                System.out.println("envelope.getRoutingKey() = " + envelope.getRoutingKey());//envelope.getRoutingKey() = hello_world
                System.out.println("properties = " + properties);//properties = #contentHeader<basic>(content-type=null, content-encoding=null, headers=null, delivery-mode=null, priority=null, correlation-id=null, reply-to=null, expiration=null, message-id=null, timestamp=null, type=null, user-id=null, app-id=null, cluster-id=null)
                System.out.println("body = " + new String(body));//body = hello rabbitmq~~~~~~~~~~~~~
            }
        };
         /*basicConsume(String queue, boolean autoAck, Consumer callback)
        * autoAck:  自动确认true,手动确认false
        *       确认后,会删除消息中间件中的消息(如果消费者发生异常,没有正常消费,但是消息中间件中的消息又
        * 已经删除,就是消息丢失)
        * */
        channel.basicConsume("hello_world",true,consumer);
        //是否关闭资源--不关闭,消费者相当于一直处于监听状态
    }
}

消费后

spring使用RabbitMQ
springBoot使用RabbitMQ

猜你喜欢

转载自blog.csdn.net/qq_34518487/article/details/109065622