【RabbitMQ-工作模式】

一、Simple Queue:简单队列模式

1.1 基础

介绍

最简单的工作队列,其中一个生产者,一个消费者,一个队列,也称为点对点模式。(用的是默认交换机

图示

1.2 代码 

生产者

public static void main(String[] args) throws Exception {
    // 创建ConnectionFactory
    ConnectionFactory connectionFactory = new ConnectionFactory();
    connectionFactory.setHost("127.0.0.1");
    connectionFactory.setPort(5672);
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");
    // 设置虚拟主机
    connectionFactory.setVirtualHost("/");
    // 创建Connection
    Connection connection = connectionFactory.newConnection();
    // 创建Channel
    Channel channel = connection.createChannel();
    // 通过通道创建队列,后续所有的操作都是基于channel实现。(队列也可以由消费方创建)
    channel.queueDeclare("queueName",false,false,false,null);
    // 发送消息
    String msg = "RabbitMQ Simple Queue TEST";
    // 向队列中发送消息:
    // 参数1:为" "表示为default exchange
    // 参数2:(当声明为默认交换机时)队列的名称(因为当使用默认交换机时,生产者是通过指定队列的名称直接发送的)
    channel.basicPublish("","queueName",null,msg.getBytes());
    channel.close();
    connection.close();
}

 消费者

public static void main(String[] args) throws Exception {
    ConnectionFactory connectionFactory = new ConnectionFactory();
    connectionFactory.setHost("127.0.0.1");
    connectionFactory.setPort(5672);
    connectionFactory.setVirtualHost("/");
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");
    connectionFactory.setAutomaticRecoveryEnabled(true);
    connectionFactory.setNetworkRecoveryInterval(3000);
    Connection connection = connectionFactory.newConnection();
    Channel channel = connection.createChannel();
    // 监听队列中的消息(消费的是队列,而不是交换机)
    channel.basicConsume("queueName", true, new DefaultConsumer(channel) {
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
            System.out.println("消费者获得消息为:" + new String(body, "utf-8"));
        }
    });
    // 消费方不需要关闭连接,保持一直监听队列状态。
    //connection.close();
}

二、Work Queues:工作队列模式

2.1 基础

介绍

一个生产者,一个消息队列,多个消费者。同样也称为点对点模式。(用的是默认交换机

一个消息只能被一个消费者消费,资源的竞争。(通过轮询或其他方式分配给消费者)

默认情况下,rabbitmq将会按顺序派发每个任务给下一个消费者,平均而言,每个消费者将获得相同数量的消息,这种分发消息的方式称为轮询。

图示

 特点

 Work Queue相比于简单队列模式,在于工作队列模式有多个消费者,但是一个消息只能被一个消费者消费,而简单队列模式只有一个消费者。

2.2 代码

生产者

public static void main(String[] args) throws Exception {
    // 创建ConnectionFactory
    ConnectionFactory connectionFactory = new ConnectionFactory();
    connectionFactory.setHost("127.0.0.1");
    connectionFactory.setPort(5672);
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");
    // 设置虚拟主机
    connectionFactory.setVirtualHost("/");
    // 创建Connection
    Connection connection = connectionFactory.newConnection();
    // 创建Channel
    Channel channel = connection.createChannel();
    // 通过通道创建队列,后续所有的操作都是基于channel实现。(队列也可以由消费方创建)
    channel.queueDeclare("queueName", false, false, false, null);
    // 向队列中发送消息:
    // 参数1:为" "表示为default exchange
    // 参数2:(当声明为默认交换机时)队列的名称(因为当使用默认交换机时,生产者是通过指定队列的名称直接发送的)
    for (int i = 1; i <= 10; i++) {
        channel.basicPublish("", "queueName", null, ("Hello RabbitMQ!!!" + i).getBytes());
    }
    channel.close();
    connection.close();
}

消费者1

public static void main(String[] args) throws Exception {
    ConnectionFactory connectionFactory = new ConnectionFactory();
    connectionFactory.setHost("127.0.0.1");
    connectionFactory.setPort(5672);
    connectionFactory.setVirtualHost("/");
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");
    connectionFactory.setAutomaticRecoveryEnabled(true);
    connectionFactory.setNetworkRecoveryInterval(3000);
    Connection connection = connectionFactory.newConnection();
    Channel channel = connection.createChannel();
    // 监听队列中的消息(消费的是队列,而不是交换机)
    channel.basicConsume("queueName", true, new DefaultConsumer(channel) {
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
            System.out.println("消费者1获得消息为:" + new String(body, "utf-8"));
        }
    });
    // 消费方不需要关闭连接,保持一直监听队列状态。
    //connection.close();
}

消费者2

public static void main(String[] args) throws Exception {
    ConnectionFactory connectionFactory = new ConnectionFactory();
    connectionFactory.setHost("127.0.0.1");
    connectionFactory.setPort(5672);
    connectionFactory.setVirtualHost("/");
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");
    connectionFactory.setAutomaticRecoveryEnabled(true);
    connectionFactory.setNetworkRecoveryInterval(3000);
    Connection connection = connectionFactory.newConnection();
    Channel channel = connection.createChannel();
    // 监听队列中的消息(消费的是队列,而不是交换机)
    channel.basicConsume("queueName", true, new DefaultConsumer(channel) {
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
            System.out.println("消费者1获得消息为:" + new String(body, "utf-8"));
        }
    });
    // 消费方不需要关闭连接,保持一直监听队列状态。
    //connection.close();
}

三、Publish/Subscribe:发布与订阅模式

3.1 基础

介绍

将消息发送给不同类型的消费者。做到发布一次,消费多个。(用的是Fanout Exchange交换机

场景举例

用户注册:用户在注册完后一般都会发送消息通知用户注册成功(失败)。如果在一个系统中,用户注册信息有邮箱、手机号,那么在注册完后会向邮箱和手机号都发送注册完成信息。利用MQ实现业务异步处理,如果是用工作队列的话,就会声明一个注册信息队列。注册完成之后生产者会向队列提交一条注册数据,消费者取出数据同时向邮箱以及手机号发送两条消息。但是实际上邮箱和手机号信息发送实际上是不同的业务逻辑,不应该放在一块处理。这个时候就可以利用发布/订阅模式将消息发送到转换机(EXCHANGE),声明两个不同的队列(邮箱、手机),并绑定到交换机。这样生产者只需要发布一次消息,两个队列都会接收到消息发给对应的消费者。

图示

3.2 代码 

生产者

public static void main(String[] args) throws Exception {
    // 创建ConnectionFactory
    ConnectionFactory connectionFactory = new ConnectionFactory();
    connectionFactory.setHost("127.0.0.1");
    connectionFactory.setPort(5672);
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");
    // 设置虚拟主机
    connectionFactory.setVirtualHost("/");
    // 创建Connection
    Connection connection = connectionFactory.newConnection();
    // 创建Channel
    Channel channel = connection.createChannel();
    // 创建交换机(交换机没有存储数据的能力,数据存储在队列上。如果有交换机没队列的情况下,数据会丢失。)  
    // 参数一:交换机名称;参数二:交换机类型。
    channel.exchangeDeclare("fanout_exchange_name", "fanout");
    // 向队列中发送消息
    for (int i = 1; i <= 10; i++) {
        // 因为fanout exchange与routing key无关,所以设置为空字符串。
        channel.basicPublish("fanout_exchange_name", "", null, ("Hello RabbitMQ!!!" + i).getBytes());
    }
    channel.close();
    connection.close();
}

 消费者1

public static void main(String[] args) throws Exception {
    ConnectionFactory connectionFactory = new ConnectionFactory();
    connectionFactory.setHost("127.0.0.1");
    connectionFactory.setPort(5672);
    connectionFactory.setVirtualHost("/");
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");
    connectionFactory.setAutomaticRecoveryEnabled(true);
    connectionFactory.setNetworkRecoveryInterval(3000);
    Connection connection = connectionFactory.newConnection();
    Channel channel = connection.createChannel();
    // 创建队列
    channel.queueDeclare("fanout_queue1_name", false, false, false, null);
    // 给队列绑定交换机
    channel.queueBind("fanout_queue1_name", "fanout_exchange_name", "");
    // 监听队列中的消息
    channel.basicConsume("fanout_queue1_name", true, new DefaultConsumer(channel) {
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
            System.out.println("消费者1获得消息为:" + new String(body, "utf-8"));
        }
    });
    // 消费方不需要关闭连接,保持一直监听队列状态。
    //connection.close();
}

消费者2

public static void main(String[] args) throws Exception {
    ConnectionFactory connectionFactory = new ConnectionFactory();
    connectionFactory.setHost("127.0.0.1");
    connectionFactory.setPort(5672);
    connectionFactory.setVirtualHost("/");
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");
    connectionFactory.setAutomaticRecoveryEnabled(true);
    connectionFactory.setNetworkRecoveryInterval(3000);
    Connection connection = connectionFactory.newConnection();
    Channel channel = connection.createChannel();
    // 创建队列
    channel.queueDeclare("fanout_queue2_name", false, false, false, null);
    // 给队列绑定交换机
    channel.queueBind("fanout_queue2_name", "fanout_exchange_name", "");
    // 监听队列中的消息
    channel.basicConsume("fanout_queue2_name", true, new DefaultConsumer(channel) {
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
            System.out.println("消费者2获得消息为:" + new String(body, "utf-8"));
        }
    });
    // 消费方不需要关闭连接,保持一直监听队列状态。
    //connection.close();
}

四、Route:路由模式

4.1 基础

介绍

在发布订阅模式的基础上,根据routing key有选择地转发消息到匹配queue。(用的是Direct Exchange交换机

图示

4.2 代码 

生产者

public static void main(String[] args) throws Exception {
    // 创建ConnectionFactory
    ConnectionFactory connectionFactory = new ConnectionFactory();
    connectionFactory.setHost("127.0.0.1");
    connectionFactory.setPort(5672);
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");
    // 设置虚拟主机
    connectionFactory.setVirtualHost("/");
    // 创建Connection
    Connection connection = connectionFactory.newConnection();
    // 创建Channel
    Channel channel = connection.createChannel();
    // 创建交换机(交换机没有存储数据的能力,数据存储在队列上。如果有交换机没队列的情况下,数据会丢失)  
    // 参数一:交换机名称;参数二:交换机类型。
    channel.exchangeDeclare("direct_exchange_name", "direct");
    // 向队列中发送消息
    for (int i = 1; i <= 10; i++) {
        // 设置路由键为"insert"
        channel.basicPublish("direct_exchange_name", "insert", null, ("Hello RabbitMQ!!!" + i).getBytes());
    }
    channel.close();
    connection.close();
}

 消费者1

public static void main(String[] args) throws Exception {
    ConnectionFactory connectionFactory = new ConnectionFactory();
    connectionFactory.setHost("127.0.0.1");
    connectionFactory.setPort(5672);
    connectionFactory.setVirtualHost("/");
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");
    connectionFactory.setAutomaticRecoveryEnabled(true);
    connectionFactory.setNetworkRecoveryInterval(3000);
    Connection connection = connectionFactory.newConnection();
    Channel channel = connection.createChannel();
    // 创建队列
    channel.queueDeclare("direct_queue1_name", false, false, false, null);
    // 给队列绑定交换机,并设置路由键(binding key)。
    channel.queueBind("direct_queue1_name", "direct_exchange_name", "select");
    channel.queueBind("direct_queue1_name", "direct_exchange_name", "insert");
    // 监听队列中的消息
    channel.basicConsume("direct_queue1_name", true, new DefaultConsumer(channel) {
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
            System.out.println("消费者1获得消息为:" + new String(body, "utf-8"));
        }
    });
    // 消费方不需要关闭连接,保持一直监听队列状态。
    //connection.close();
}

消费者2

public static void main(String[] args) throws Exception {
    ConnectionFactory connectionFactory = new ConnectionFactory();
    connectionFactory.setHost("127.0.0.1");
    connectionFactory.setPort(5672);
    connectionFactory.setVirtualHost("/");
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");
    connectionFactory.setAutomaticRecoveryEnabled(true);
    connectionFactory.setNetworkRecoveryInterval(3000);
    Connection connection = connectionFactory.newConnection();
    Channel channel = connection.createChannel();
    // 创建队列
    channel.queueDeclare("direct_queue2_name", false, false, false, null);
    // 给队列绑定交换机,并设置路由键(binding key)。
    channel.queueBind("direct_queue2_name", "direct_exchange_name", "select");
    channel.queueBind("direct_queue2_name", "direct_exchange_name", "delete");
    // 监听队列中的消息
    channel.basicConsume("direct_queue2_name", true, new DefaultConsumer(channel) {
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
            System.out.println("消费者2获得消息为:" + new String(body, "utf-8"));
        }
    });
    // 消费方不需要关闭连接,保持一直监听队列状态。
    //connection.close();
}

五、Topic:主题模式

5.1 基础

介绍

主题模式可以指定queuebinding key规则,消息携带的routing keybinding key进行模式匹配,消息将会转发到匹配的queue。(用的是Topic Exchange交换机

图示

5.2 代码 

生产者

public static void main(String[] args) throws Exception {
    // 创建ConnectionFactory
    ConnectionFactory connectionFactory = new ConnectionFactory();
    connectionFactory.setHost("127.0.0.1");
    connectionFactory.setPort(5672);
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");
    // 设置虚拟主机
    connectionFactory.setVirtualHost("/");
    // 创建Connection
    Connection connection = connectionFactory.newConnection();
    // 创建Channel
    Channel channel = connection.createChannel();
    // 创建交换机(交换机没有存储数据的能力,数据存储在队列上。如果有交换机没队列的情况下,数据会丢失。)  
    // 参数一:交换机名称;参数二:交换机类型。
    channel.exchangeDeclare("topic_exchange_name", "topic");
    // 向队列中发送消息
    for (int i = 1; i <= 10; i++) {
        // 设置路由键为"emp.hello world"  
        // #:匹配0-n个单词(之间以.区分,两点之间算一个单词,可以匹配hello world空格的情况。)
        // *:匹配一个单词
        channel.basicPublish("topic_exchange_name", "emp.hello world", null, ("Hello RabbitMQ!!!" + i).getBytes());
    }
    channel.close();
    connection.close();
}

消费者1 

public static void main(String[] args) throws Exception {
    ConnectionFactory connectionFactory = new ConnectionFactory();
    connectionFactory.setHost("127.0.0.1");
    connectionFactory.setPort(5672);
    connectionFactory.setVirtualHost("/");
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");
    connectionFactory.setAutomaticRecoveryEnabled(true);
    connectionFactory.setNetworkRecoveryInterval(3000);
    Connection connection = connectionFactory.newConnection();
    Channel channel = connection.createChannel();
    // 创建队列
    channel.queueDeclare("topic_queue1_name", false, false, false, null);
    // 绑定交换机(routing key:路由键) 
    // #:匹配0-n个单词(之间以.区分,两点之间算一个单词。)
    channel.queueBind("topic_queue1_name", "topic_exchange_name", "emp.#");
    // 监听队列中的消息
    channel.basicConsume("topic_queue1_name", true, new DefaultConsumer(channel) {
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
            System.out.println("消费者1获得消息为:" + new String(body, "utf-8"));
        }
    });
    // 消费方不需要关闭连接,保持一直监听队列状态。
    //connection.close();
}

消费者2

public static void main(String[] args) throws Exception {
    ConnectionFactory connectionFactory = new ConnectionFactory();
    connectionFactory.setHost("127.0.0.1");
    connectionFactory.setPort(5672);
    connectionFactory.setVirtualHost("/");
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");
    connectionFactory.setAutomaticRecoveryEnabled(true);
    connectionFactory.setNetworkRecoveryInterval(3000);
    Connection connection = connectionFactory.newConnection();
    Channel channel = connection.createChannel();
    // 创建队列
    channel.queueDeclare("topic_queue2_name", false, false, false, null);
    // 绑定交换机(routing key:路由键)   
    // *:匹配1个单词(之间以.区分,两点之间算一个单词。)
    channel.queueBind("topic_queue2_name", "topic_exchange_name", "emp.*");
    // 监听队列中的消息
    channel.basicConsume("topic_queue2_name", true, new DefaultConsumer(channel) {
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
            System.out.println("消费者2获得消息为:" + new String(body, "utf-8"));
        }
    });
    // 消费方不需要关闭连接,保持一直监听队列状态。
    //connection.close();
}

六、RPC:远程调用模式

6.1 基础

介绍

RPC即客户端远程调用服务端的方法 ,使用MQ可以实现RPC的异步调用。(用的是Direct Exchange交换机

  • 客户端即是生产者也是消费者,向RPC请求队列发送RPC调用消息,同时监听RPC响应队列。

  • 服务端监听RPC请求队列的消息,收到消息后执行服务端的方法,得到方法返回的结果。

  • 服务端将RPC方法的结果发送到RPC响应队列

  • 客户端(RPC调用方)监听RPC响应队列,接收到RPC调用结果。

6.2 代码

七、Header模式

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值