rabbitmq几种工作模式_RabbitMQ的六种工作模式总结

精品推荐

  • 国内稀缺优秀Java全栈课程-Vue+SpringBoot通讯录系统全新发布!

作者:侧身左睡

https://www.cnblogs.com/xyfer1018/p/11581511.html

最近学习RabbitMQ的使用方式,记录下来,方便以后使用,也方便和大家共享,相互交流。

RabbitMQ的六种工作模式:

1、Work queues2、Publish/subscribe3、Routing4、Topics5、Header 模式6、RPC

一、Work queues

多个消费端消费同一个队列中的消息,队列采用轮询的方式将消息是平均发送给消费者;

0078808d58267f79257cb40cbae8c606.png

 特点:

1、一条消息只会被一个消费端接收;

2、队列采用轮询的方式将消息是平均发送给消费者的;

3、消费者在处理完某条消息后,才会收到下一条消息

生产端:

1、声明队列

2、创建连接

3、创建通道

4、通道声明队列

5、制定消息

6、发送消息,使用默认交换机

消费端:

1、声明队列

2、创建连接

3、创建通道

4、通道声明队列

5、重写消息消费方法

6、执行消息方法

新建两个maven工程,生产消息的生产端,消费消息的消费端;

pom.xml文件中依赖坐标如下:

<dependencies>    <dependency>            <groupId>org.springframework.bootgroupId>            <artifactId>spring-boot-starter-loggingartifactId>            <version>2.1.0.RELEASEversion>        dependency>        <dependency>            <groupId>com.rabbitmqgroupId>            <artifactId>amqp-clientartifactId>            <version>5.7.0version>        dependency>dependencies>

 生产端的代码如下:

package com.xyfer;import com.rabbitmq.client.BuiltinExchangeType;import com.rabbitmq.client.Channel;import com.rabbitmq.client.Connection;import com.rabbitmq.client.ConnectionFactory;import java.io.IOException;import java.util.concurrent.TimeoutException;/*1、声明队列2、创建连接3、创建通道4、通道声明队列5、制定消息6、发送消息,使用默认交换机*/public class Producer02 {    //声明队列    private static final String QUEUE ="queue";    public static void main(String[] args) {        Connection connection = null;        Channel channel = null;        try {            ConnectionFactory connectionFactory = new ConnectionFactory();            connectionFactory.setHost("127.0.0.1");//mq服务ip地址            connectionFactory.setPort(5672);//mq client连接端口            connectionFactory.setUsername("guest");//mq登录用户名            connectionFactory.setPassword("guest");//mq登录密码            connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务器            //创建与RabbitMQ服务的TCP连接            connection = connectionFactory.newConnection();            //创建与Exchange的通道,每个连接可以创建多个通道,每个通道代表一个会话任务            channel = connection.createChannel();            //通道绑定队列            /**             * 声明队列,如果Rabbit中没有此队列将自动创建             * param1:队列名称             * param2:是否持久化             * param3:队列是否独占此连接             * param4:队列不再使用时是否自动删除此队列             * param5:队列参数             * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map arguments             *             */            channel.queueDeclare(QUEUE,true,false,false,null);//通道绑定邮件队列            for(int i = 0;i<10;i++){                String message = new String("mq 发送消息。。。");                /**                  * 消息发布方法                  * param1:Exchange的名称,如果没有指定,则使用Default Exchange                  * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列                  * param3:消息包含的属性                  * param4:消息体                  * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定                  * 默认的交换机,routingKey等于队列名称                 */                //String exchange, String routingKey, BasicProperties props, byte[] body                channel.basicPublish("",QUEUE,null,message.getBytes("utf-8"));                System.out.println("mq消息发送成功!");            }        } catch (Exception e) {            e.printStackTrace();        } finally {            try {                channel.close();            } catch (IOException e) {                e.printStackTrace();            } catch (TimeoutException e) {                e.printStackTrace();            }            try {                connection.close();            } catch (IOException e) {                e.printStackTrace();            }        }    }}

消费端的代码如下:

package com.xyfer;import com.rabbitmq.client.*;import java.io.IOException;import java.util.concurrent.TimeoutException;/*1、声明队列2、创建连接3、创建通道4、通道声明队列5、重写消息消费方法6、执行消息方法*/public class Consumer02 {    private static final String QUEUE ="queue";    public static void main(String[] args) {        Connection connection = null;        Channel channel = null;        try {            ConnectionFactory connectionFactory = new ConnectionFactory();            connectionFactory.setHost("127.0.0.1");            connectionFactory.setPort(5672);            connection = connectionFactory.newConnection();            channel = connection.createChannel();            //通道绑定队列            /**             * 声明队列,如果Rabbit中没有此队列将自动创建             * param1:队列名称             * param2:是否持久化             * param3:队列是否独占此连接             * param4:队列不再使用时是否自动删除此队列             * param5:队列参数             * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map arguments             *             */            channel.queueDeclare(QUEUE,true,false,false,null);//通道绑定邮件队列            //String consumerTag, Envelope envelope, BasicProperties properties, byte[] body            DefaultConsumer consumer = new DefaultConsumer(channel) {                /**                  * 消费者接收消息调用此方法                  * @param consumerTag 消费者的标签,在channel.basicConsume()去指定                  * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志                    (收到消息失败后是否需要重新发送)                  * @param properties                  * @param body                  * @throws IOException                 * String consumerTag, Envelope envelope, BasicProperties properties, byte[] body                 */                @Override                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {                    //交换机                    String exchange = envelope.getExchange();                    //路由key                    String routingKey = envelope.getRoutingKey();                    envelope.getDeliveryTag();                    String msg = new String(body,"utf-8");                    System.out.println("mq收到的消息是:"+msg );                }            };            System.out.println("消费者启动成功!");            channel.basicConsume(QUEUE,true,consumer);        } catch (IOException e) {            e.printStackTrace();        } catch (TimeoutException e) {            e.printStackTrace();        }    }}

生产端启动后,控制台打印信息如下:

a060b11f43e40169a2d64cca4643f17a.png

 RabbitMQ中的已有消息:

f723c0610186e4f61c0d5322b8e8dea0.png

 queue中的消息正是生产端发送的消息:

bfd84c6f1156138f59e66fc38f5dd5ea.png

 二、Publish/subscribe 模式

这种模式又称为发布订阅模式,相对于Work queues模式,该模式多了一个交换机,生产端先把消息发送到交换机,再由交换机把消息发送到绑定的队列中,每个绑定的队列都能收到由生产端发送的消息。

8897b4ce870a761d4d988b7c80f0adda.png

发布订阅模式:

1、每个消费者监听自己的队列;

2、生产者将消息发给broker,由交换机将消息转发到绑定此交换机的每个队列,每个绑定交换机的队列都将接收到消息

应用场景:用户通知,当用户充值成功或转账完成系统通知用户,通知方式有短信、邮件多种方法;

生产端:

1、声明队列,声明交换机

2、创建连接

3、创建通道

4、通道声明交换机

5、通道声明队列

6、通过通道使队列绑定到交换机

7、制定消息

8、发送消息

消费端:

1、声明队列,声明交换机

2、创建连接

3、创建通道

4、通道声明交换机

5、通道声明队列

6、通过通道使队列绑定到交换机

7、重写消息消费方法

8、执行消息方法

Publish/subscribe 模式绑定两个消费端,因此需要有两个消费端,一个邮件消费端,一个短信消费端;

生产端的代码如下:

package com.xyfer;import com.rabbitmq.client.BuiltinExchangeType;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 Producer01 {    //声明两个队列和一个交换机    //Publish/subscribe发布订阅模式    private static final String QUEUE_EMAIL ="queueEmail";    private static final String QUEUE_SMS ="queueSms";    private static final String EXCHANGE = "messageChange";    public static void main(String[] args) {        Connection connection = null;        Channel channel = null;        try {            ConnectionFactory connectionFactory = new ConnectionFactory();            connectionFactory.setHost("127.0.0.1");//mq服务ip地址            connectionFactory.setPort(5672);//mq client连接端口            connectionFactory.setUsername("guest");//mq登录用户名            connectionFactory.setPassword("guest");//mq登录密码            connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务器            //创建与RabbitMQ服务的TCP连接            connection = connectionFactory.newConnection();            //创建与Exchange的通道,每个连接可以创建多个通道,每个通道代表一个会话任务            channel = connection.createChannel();            //通道绑定交换机            /**              * 参数明细              * 1、交换机名称              * 2、交换机类型,fanout、topic、direct、headers              */            //Publish/subscribe发布订阅模式            channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.FANOUT);            //通道绑定队列            /**             * 声明队列,如果Rabbit中没有此队列将自动创建             * param1:队列名称             * param2:是否持久化             * param3:队列是否独占此连接             * param4:队列不再使用时是否自动删除此队列             * param5:队列参数             * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map arguments             *             */            channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列            channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定短信队列            //交换机和队列绑定            /**             * 参数明细             * 1、队列名称             * 2、交换机名称             * 3、路由key             */            //Publish/subscribe发布订阅模式            channel.queueBind(QUEUE_EMAIL,EXCHANGE,"");            channel.queueBind(QUEUE_SMS,EXCHANGE,"");            for(int i = 0;i<10;i++){                String message = new String("mq 发送消息。。。");                /**                  * 消息发布方法                  * param1:Exchange的名称,如果没有指定,则使用Default Exchange                  * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列                  * param3:消息包含的属性                  * param4:消息体                  * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定                  * 默认的交换机,routingKey等于队列名称                 */                //String exchange, String routingKey, BasicProperties props, byte[] body                //Publish/subscribe发布订阅模式                channel.basicPublish(EXCHANGE,"",null,message.getBytes());                System.out.println("mq消息发送成功!");            }        } catch (Exception e) {            e.printStackTrace();        } finally {            try {                channel.close();            } catch (IOException e) {                e.printStackTrace();            } catch (TimeoutException e) {                e.printStackTrace();            }            try {                connection.close();            } catch (IOException e) {                e.printStackTrace();            }        }    }}

邮件消费端的代码如下:

package com.xyfer;import com.rabbitmq.client.*;import java.io.IOException;import java.util.concurrent.TimeoutException;public class Consumer01 {    //Publish/subscribe发布订阅模式    private static final String QUEUE_EMAIL ="queueEmail";    private static final String EXCHANGE = "messageChange";    public static void main(String[] args) {        Connection connection = null;        Channel channel = null;        try {            ConnectionFactory connectionFactory = new ConnectionFactory();            connectionFactory.setHost("127.0.0.1");            connectionFactory.setPort(5672);            connection = connectionFactory.newConnection();            channel = connection.createChannel();            //通道绑定交换机            /**              * 参数明细              * 1、交换机名称              * 2、交换机类型,fanout、topic、direct、headers              */            //Publish/subscribe发布订阅模式            channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.FANOUT);            //通道绑定队列            /**             * 声明队列,如果Rabbit中没有此队列将自动创建             * param1:队列名称             * param2:是否持久化             * param3:队列是否独占此连接             * param4:队列不再使用时是否自动删除此队列             * param5:队列参数             * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map arguments             *             */            channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列            //交换机和队列绑定            /**             * 参数明细             * 1、队列名称             * 2、交换机名称             * 3、路由key             */            //Publish/subscribe发布订阅模式            channel.queueBind(QUEUE_EMAIL,EXCHANGE,"");            //String consumerTag, Envelope envelope, BasicProperties properties, byte[] body            DefaultConsumer consumer = new DefaultConsumer(channel) {            /**              * 消费者接收消息调用此方法              * @param consumerTag 消费者的标签,在channel.basicConsume()去指定              * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志                (收到消息失败后是否需要重新发送)              * @param properties              * @param body              * @throws IOException              * String consumerTag, Envelope envelope, BasicProperties properties, byte[] body              */            @Override            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {                //交换机                String exchange = envelope.getExchange();                //路由key                String routingKey = envelope.getRoutingKey();                envelope.getDeliveryTag();                String msg = new String(body,"utf-8");                System.out.println("mq收到的消息是:"+msg );            }            };            System.out.println("消费者启动成功!");            channel.basicConsume(QUEUE_EMAIL,true,consumer);        } catch (IOException e) {            e.printStackTrace();        } catch (TimeoutException e) {            e.printStackTrace();        }    }}

短信消费端的代码如下:

package xyfer;import com.rabbitmq.client.*;import java.io.IOException;import java.util.concurrent.TimeoutException;public class Consumer01 {    //Publish/subscribe发布订阅模式    private static final String QUEUE_SMS ="queueSms";    private static final String EXCHANGE = "messageChange";    public static void main(String[] args) {        Connection connection = null;        Channel channel = null;        try {            ConnectionFactory connectionFactory = new ConnectionFactory();            connectionFactory.setHost("127.0.0.1");            connectionFactory.setPort(5672);            connection = connectionFactory.newConnection();            channel = connection.createChannel();            //通道绑定交换机            /**              * 参数明细              * 1、交换机名称              * 2、交换机类型,fanout、topic、direct、headers              */            //Publish/subscribe发布订阅模式            channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.FANOUT);            //通道绑定队列            /**             * 声明队列,如果Rabbit中没有此队列将自动创建             * param1:队列名称             * param2:是否持久化             * param3:队列是否独占此连接             * param4:队列不再使用时是否自动删除此队列             * param5:队列参数             * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map arguments             *             */            channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定短信队列            //交换机和队列绑定            /**             * 参数明细             * 1、队列名称             * 2、交换机名称             * 3、路由key             */            //Publish/subscribe发布订阅模式            channel.queueBind(QUEUE_SMS,EXCHANGE,"");            DefaultConsumer consumer = new DefaultConsumer(channel) {            /**              * 消费者接收消息调用此方法              * @param consumerTag 消费者的标签,在channel.basicConsume()去指定              * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志                (收到消息失败后是否需要重新发送)              * @param properties              * @param body              * @throws IOException              * String consumerTag, Envelope envelope, BasicProperties properties, byte[] body              */            @Override            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {                //交换机                String exchange = envelope.getExchange();                //路由key                String routingKey = envelope.getRoutingKey();                envelope.getDeliveryTag();                String msg = new String(body,"utf-8");                System.out.println("mq收到的消息是:"+msg );            }            };            System.out.println("消费者启动成功!");            channel.basicConsume(QUEUE_SMS,true,consumer);        } catch (IOException e) {            e.printStackTrace();        } catch (TimeoutException e) {            e.printStackTrace();        }    }}

三、Routing 路由模式

Routing 模式又称路由模式,该种模式除了要绑定交换机外,发消息的时候还要制定routing key,即路由key,队列通过通道绑定交换机的时候,需要指定自己的routing key,这样,生产端发送消息的时候也会指定routing key,通过routing key就可以把相应的消息发送到绑定相应routing key的队列中去。

2a95fa90d0a4b33389f2cf101678e856.png

路由模式:

1、每个消费者监听自己的队列,并且设置routingkey;2、生产者将消息发给交换机,由交换机根据routingkey来转发消息到指定的队列;

应用场景:用户通知,当用户充值成功或转账完成系统通知用户,通知方式有短信、邮件多种方法;

生产端:

1、声明队列,声明交换机

2、创建连接

3、创建通道

4、通道声明交换机

5、通道声明队列

6、通过通道使队列绑定到交换机并指定该队列的routingkey

7、制定消息

8、发送消息并指定routingkey

消费端:

1、声明队列,声明交换机

2、创建连接

3、创建通道

4、通道声明交换机

5、通道声明队列

6、通过通道使队列绑定到交换机并指定routingkey

7、重写消息消费方法

8、执行消息方法

按照假设的应用场景,同样,Routing 路由模式也是一个生产端,两个消费端,所不同的是,声明交换机的类型不同,队列绑定交换机的时候需要指定Routing key,发送消息的时候也需要指定Routing key,这样根据Routing key就能把相应的消息发送到相应的队列中去。

生产端的代码如下:

package com.xyfer;import com.rabbitmq.client.BuiltinExchangeType;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 Producer03 {    //声明两个队列和一个交换机    //Routing 路由模式    private static final String QUEUE_EMAIL ="queueEmail";    private static final String QUEUE_SMS ="queueSms";    private static final String EXCHANGE = "messageChange";    public static void main(String[] args) {        Connection connection = null;        Channel channel = null;        try {            ConnectionFactory connectionFactory = new ConnectionFactory();            connectionFactory.setHost("127.0.0.1");//mq服务ip地址            connectionFactory.setPort(5672);//mq client连接端口            connectionFactory.setUsername("guest");//mq登录用户名            connectionFactory.setPassword("guest");//mq登录密码            connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务器            //创建与RabbitMQ服务的TCP连接            connection = connectionFactory.newConnection();            //创建与Exchange的通道,每个连接可以创建多个通道,每个通道代表一个会话任务            channel = connection.createChannel();            //通道绑定交换机            /**             * 参数明细             * 1、交换机名称             * 2、交换机类型,fanout、topic、direct、headers             */            //Routing 路由模式            channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.DIRECT);            //通道绑定队列            /**             * 声明队列,如果Rabbit中没有此队列将自动创建             * param1:队列名称             * param2:是否持久化             * param3:队列是否独占此连接             * param4:队列不再使用时是否自动删除此队列             * param5:队列参数             * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map arguments             *             */            channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列            channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定短信队列            //交换机和队列绑定            /**             * 参数明细             * 1、队列名称             * 2、交换机名称             * 3、路由key             */            //Routing 路由模式            channel.queueBind(QUEUE_EMAIL,EXCHANGE,QUEUE_EMAIL);            channel.queueBind(QUEUE_SMS,EXCHANGE,QUEUE_SMS);            //给email队列发消息            for(int i = 0;i<10;i++){                String message = new String("mq 发送email消息。。。");                /**                  * 消息发布方法                  * param1:Exchange的名称,如果没有指定,则使用Default Exchange                  * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列                  * param3:消息包含的属性                  * param4:消息体                  * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定                  * 默认的交换机,routingKey等于队列名称                 */                //String exchange, String routingKey, BasicProperties props, byte[] body                //Routing 路由模式                channel.basicPublish(EXCHANGE,QUEUE_EMAIL,null,message.getBytes());                System.out.println("mq消息发送成功!");            }            //给sms队列发消息            for(int i = 0;i<10;i++){                String message = new String("mq 发送sms消息。。。");                /**                  * 消息发布方法                  * param1:Exchange的名称,如果没有指定,则使用Default Exchange                  * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列                  * param3:消息包含的属性                  * param4:消息体                  * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定                  * 默认的交换机,routingKey等于队列名称                 */                //String exchange, String routingKey, BasicProperties props, byte[] body                //Routing 路由模式                channel.basicPublish(EXCHANGE,QUEUE_SMS,null,message.getBytes());                System.out.println("mq消息发送成功!");            }        } catch (Exception e) {            e.printStackTrace();        } finally {            try {                channel.close();            } catch (IOException e) {                e.printStackTrace();            } catch (TimeoutException e) {                e.printStackTrace();            }            try {                connection.close();            } catch (IOException e) {                e.printStackTrace();            }        }    }}

邮件消费端的代码如下:

package com.xyfer;import com.rabbitmq.client.*;import java.io.IOException;import java.util.concurrent.TimeoutException;public class Consumer03 {    //Routing 路由模式    private static final String QUEUE_EMAIL ="queueEmail";    private static final String EXCHANGE = "messageChange";    public static void main(String[] args) {        Connection connection = null;        Channel channel = null;        try {            ConnectionFactory connectionFactory = new ConnectionFactory();            connectionFactory.setHost("127.0.0.1");            connectionFactory.setPort(5672);            connection = connectionFactory.newConnection();            channel = connection.createChannel();            //通道绑定交换机            /**              * 参数明细              * 1、交换机名称              * 2、交换机类型,fanout、topic、direct、headers              */            //Routing 路由模式            channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.DIRECT);            //通道绑定队列            /**             * 声明队列,如果Rabbit中没有此队列将自动创建             * param1:队列名称             * param2:是否持久化             * param3:队列是否独占此连接             * param4:队列不再使用时是否自动删除此队列             * param5:队列参数             * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map arguments             *             */            channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列            //交换机和队列绑定            /**             * 参数明细             * 1、队列名称             * 2、交换机名称             * 3、路由key             */            //Routing 路由模式            channel.queueBind(QUEUE_EMAIL,EXCHANGE,QUEUE_EMAIL);            //String consumerTag, Envelope envelope, BasicProperties properties, byte[] body            DefaultConsumer consumer = new DefaultConsumer(channel) {                /**                  * 消费者接收消息调用此方法                  * @param consumerTag 消费者的标签,在channel.basicConsume()去指定                  * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志                    (收到消息失败后是否需要重新发送)                  * @param properties                  * @param body                  * @throws IOException                 * String consumerTag, Envelope envelope, BasicProperties properties, byte[] body                 */                @Override                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {                    //交换机                    String exchange = envelope.getExchange();                    //路由key                    String routingKey = envelope.getRoutingKey();                    envelope.getDeliveryTag();                    String msg = new String(body,"utf-8");                    System.out.println("mq收到的消息是:"+msg );                }            };            System.out.println("消费者启动成功!");            channel.basicConsume(QUEUE_EMAIL,true,consumer);        } catch (IOException e) {            e.printStackTrace();        } catch (TimeoutException e) {            e.printStackTrace();        }    }}

短信消费端的代码如下:

package xyfer;import com.rabbitmq.client.*;import java.io.IOException;import java.util.concurrent.TimeoutException;public class Consumer03 {    //Routing 路由模式    private static final String QUEUE_SMS ="queueSms";    private static final String EXCHANGE = "messageChange";    public static void main(String[] args) {        Connection connection = null;        Channel channel = null;        try {            ConnectionFactory connectionFactory = new ConnectionFactory();            connectionFactory.setHost("127.0.0.1");            connectionFactory.setPort(5672);            connection = connectionFactory.newConnection();            channel = connection.createChannel();            //通道绑定交换机            /**              * 参数明细              * 1、交换机名称              * 2、交换机类型,fanout、topic、direct、headers              */            //Routing 路由模式            channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.DIRECT);            //通道绑定队列            /**             * 声明队列,如果Rabbit中没有此队列将自动创建             * param1:队列名称             * param2:是否持久化             * param3:队列是否独占此连接             * param4:队列不再使用时是否自动删除此队列             * param5:队列参数             * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map arguments             *             */            channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定短信队列            //交换机和队列绑定            /**             * 参数明细             * 1、队列名称             * 2、交换机名称             * 3、路由key             */            //Routing 路由模式            channel.queueBind(QUEUE_SMS,EXCHANGE,QUEUE_SMS);            DefaultConsumer consumer = new DefaultConsumer(channel) {                /**                  * 消费者接收消息调用此方法                  * @param consumerTag 消费者的标签,在channel.basicConsume()去指定                  * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志                    (收到消息失败后是否需要重新发送)                  * @param properties                  * @param body                  * @throws IOException                 * String consumerTag, Envelope envelope, BasicProperties properties, byte[] body                 */                @Override                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {                    //交换机                    String exchange = envelope.getExchange();                    //路由key                    String routingKey = envelope.getRoutingKey();                    envelope.getDeliveryTag();                    String msg = new String(body,"utf-8");                    System.out.println("mq收到的消息是:"+msg );                }            };            System.out.println("消费者启动成功!");            channel.basicConsume(QUEUE_SMS,true,consumer);        } catch (IOException e) {            e.printStackTrace();        } catch (TimeoutException e) {            e.printStackTrace();        }    }}

四、Topics 模式

Topics 模式和Routing 路由模式最大的区别就是,Topics 模式发送消息和消费消息的时候是通过通配符去进行匹配的。

b4c8df2914b0a16b2d721c1e13906178.png

路由模式:

1、每个消费者监听自己的队列,并且设置带统配符的routingkey

2、生产者将消息发给broker,由交换机根据routingkey来转发消息到指定的队列

应用场景:用户通知,当用户充值成功或转账完成系统通知用户,通知方式有短信、邮件多种方法;

生产端:

1、声明队列,声明交换机

2、创建连接

3、创建通道

4、通道声明交换机

5、通道声明队列

6、通过通道使队列绑定到交换机并指定该队列的routingkey(通配符)

7、制定消息

8、发送消息并指定routingkey(通配符)

消费端:

1、声明队列,声明交换机

2、创建连接

3、创建通道

4、通道声明交换机

5、通道声明队列

6、通过通道使队列绑定到交换机并指定routingkey(通配符)

7、重写消息消费方法

8、执行消息方法

按照假设的应用场景,Topics 模式也是一个生产端,两个消费端,生产端队列绑定交换机的时候,需要指定的routingkey是通配符,发送消息的时候绑定的routingkey也是通配符,消费端队列绑定交换机的时候routingkey也是通配符,这样就能根据通配符匹配到消息了。

生产端的代码如下:

package com.xyfer;import com.rabbitmq.client.BuiltinExchangeType;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 Producer04 {    //声明两个队列和一个交换机    //Topics 模式    private static final String QUEUE_EMAIL ="queueEmail";    private static final String QUEUE_SMS ="queueSms";    private static final String EXCHANGE = "messageChange";    public static void main(String[] args) {        Connection connection = null;        Channel channel = null;        try {            ConnectionFactory connectionFactory = new ConnectionFactory();            connectionFactory.setHost("127.0.0.1");//mq服务ip地址            connectionFactory.setPort(5672);//mq client连接端口            connectionFactory.setUsername("guest");//mq登录用户名            connectionFactory.setPassword("guest");//mq登录密码            connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务器            //创建与RabbitMQ服务的TCP连接            connection = connectionFactory.newConnection();            //创建与Exchange的通道,每个连接可以创建多个通道,每个通道代表一个会话任务            channel = connection.createChannel();            //通道绑定交换机            /**              * 参数明细              * 1、交换机名称              * 2、交换机类型,fanout、topic、direct、headers              */            //Topics 模式            channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.TOPIC);            //通道绑定队列            /**             * 声明队列,如果Rabbit中没有此队列将自动创建             * param1:队列名称             * param2:是否持久化             * param3:队列是否独占此连接             * param4:队列不再使用时是否自动删除此队列             * param5:队列参数             * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map arguments             *             */            channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列            channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定短信队列            //交换机和队列绑定            /**             * 参数明细             * 1、队列名称             * 2、交换机名称             * 3、路由key             */            channel.queueBind(QUEUE_EMAIL,EXCHANGE,"inform.#.email.#");            channel.queueBind(QUEUE_SMS,EXCHANGE,"inform.#.sms.#");            //给email队列发消息            for(int i = 0;i<10;i++){                String message = new String("mq 发送email消息。。。");                /**                  * 消息发布方法                  * param1:Exchange的名称,如果没有指定,则使用Default Exchange                  * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列                  * param3:消息包含的属性                  * param4:消息体                  * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定                  * 默认的交换机,routingKey等于队列名称                 */                //String exchange, String routingKey, BasicProperties props, byte[] body                channel.basicPublish(EXCHANGE,"inform.email",null,message.getBytes());                System.out.println("mq email 消息发送成功!");            }            //给sms队列发消息            for(int i = 0;i<10;i++){                String message = new String("mq 发送sms消息。。。");                /**                  * 消息发布方法                  * param1:Exchange的名称,如果没有指定,则使用Default Exchange                  * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列                  * param3:消息包含的属性                  * param4:消息体                  * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定                  * 默认的交换机,routingKey等于队列名称                 */                //String exchange, String routingKey, BasicProperties props, byte[] body                channel.basicPublish(EXCHANGE,"inform.sms",null,message.getBytes());                System.out.println("mq sms 消息发送成功!");            }            //给email和sms队列发消息            for(int i = 0;i<10;i++){                String message = new String("mq 发送email sms消息。。。");                /**                  * 消息发布方法                  * param1:Exchange的名称,如果没有指定,则使用Default Exchange                  * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列                  * param3:消息包含的属性                  * param4:消息体                  * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定                  * 默认的交换机,routingKey等于队列名称                 */                //String exchange, String routingKey, BasicProperties props, byte[] body                channel.basicPublish(EXCHANGE,"inform.email.sms",null,message.getBytes());                System.out.println("mq email sms 消息发送成功!");            }        } catch (Exception e) {            e.printStackTrace();        } finally {            try {                channel.close();            } catch (IOException e) {                e.printStackTrace();            } catch (TimeoutException e) {                e.printStackTrace();            }            try {                connection.close();            } catch (IOException e) {                e.printStackTrace();            }        }    }}

邮件消费端的代码如下:

package com.xyfer;import com.rabbitmq.client.*;import java.io.IOException;import java.util.concurrent.TimeoutException;public class Consumer04 {    private static final String QUEUE_EMAIL ="queueEmail";    private static final String EXCHANGE = "messageChange";    public static void main(String[] args) {        Connection connection = null;        Channel channel = null;        try {            ConnectionFactory connectionFactory = new ConnectionFactory();            connectionFactory.setHost("127.0.0.1");            connectionFactory.setPort(5672);            connection = connectionFactory.newConnection();            channel = connection.createChannel();            //通道绑定交换机            /**              * 参数明细              * 1、交换机名称              * 2、交换机类型,fanout、topic、direct、headers              */            channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.TOPIC);            //通道绑定队列            /**             * 声明队列,如果Rabbit中没有此队列将自动创建             * param1:队列名称             * param2:是否持久化             * param3:队列是否独占此连接             * param4:队列不再使用时是否自动删除此队列             * param5:队列参数             * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map arguments             *             */            channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列            //交换机和队列绑定            /**             * 参数明细             * 1、队列名称             * 2、交换机名称             * 3、路由key             */            channel.queueBind(QUEUE_EMAIL,EXCHANGE,"inform.#.email.#");            //String consumerTag, Envelope envelope, BasicProperties properties, byte[] body            DefaultConsumer consumer = new DefaultConsumer(channel) {                /**                  * 消费者接收消息调用此方法                  * @param consumerTag 消费者的标签,在channel.basicConsume()去指定                  * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志                    (收到消息失败后是否需要重新发送)                  * @param properties                  * @param body                  * @throws IOException                 * String consumerTag, Envelope envelope, BasicProperties properties, byte[] body                 */                @Override                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {                    //交换机                    String exchange = envelope.getExchange();                    //路由key                    String routingKey = envelope.getRoutingKey();                    envelope.getDeliveryTag();                    String msg = new String(body,"utf-8");                    System.out.println("mq收到的消息是:"+msg );                }            };            System.out.println("消费者启动成功!");            channel.basicConsume(QUEUE_EMAIL,true,consumer);        } catch (IOException e) {            e.printStackTrace();        } catch (TimeoutException e) {            e.printStackTrace();        }    }}

短信消费端的代码如下:

package xyfer;import com.rabbitmq.client.*;import java.io.IOException;import java.util.concurrent.TimeoutException;public class Consumer04 {    private static final String QUEUE_SMS ="queueSms";    private static final String EXCHANGE = "messageChange";    public static void main(String[] args) {        Connection connection = null;        Channel channel = null;        try {            ConnectionFactory connectionFactory = new ConnectionFactory();            connectionFactory.setHost("127.0.0.1");            connectionFactory.setPort(5672);            connection = connectionFactory.newConnection();            channel = connection.createChannel();            //通道绑定交换机            /**              * 参数明细              * 1、交换机名称              * 2、交换机类型,fanout、topic、direct、headers              */            channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.TOPIC);            //通道绑定队列            /**             * 声明队列,如果Rabbit中没有此队列将自动创建             * param1:队列名称             * param2:是否持久化             * param3:队列是否独占此连接             * param4:队列不再使用时是否自动删除此队列             * param5:队列参数             * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map arguments             *             */            channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定邮件队列            //交换机和队列绑定            /**             * 参数明细             * 1、队列名称             * 2、交换机名称             * 3、路由key             */            channel.queueBind(QUEUE_SMS,EXCHANGE,"inform.#.sms.#");            //String consumerTag, Envelope envelope, BasicProperties properties, byte[] body            DefaultConsumer consumer = new DefaultConsumer(channel) {                /**                  * 消费者接收消息调用此方法                  * @param consumerTag 消费者的标签,在channel.basicConsume()去指定                  * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志                    (收到消息失败后是否需要重新发送)                  * @param properties                  * @param body                  * @throws IOException                 * String consumerTag, Envelope envelope, BasicProperties properties, byte[] body                 */                @Override                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {                    //交换机                    String exchange = envelope.getExchange();                    //路由key                    String routingKey = envelope.getRoutingKey();                    envelope.getDeliveryTag();                    String msg = new String(body,"utf-8");                    System.out.println("mq收到的消息是:"+msg );                }            };            System.out.println("消费者启动成功!");            channel.basicConsume(QUEUE_SMS,true,consumer);        } catch (IOException e) {            e.printStackTrace();        } catch (TimeoutException e) {            e.printStackTrace();        }    }}

由于生产端同时发送了email的消息(10条),sms的消息(10条),email和sms同时收到的消息(10条),所以每个消费端都应收到各自的10条消息,加上同时都能收到的10条消息,每个消费端应该收到20条消息;

生产端控制台打印:

1d56e749f7f5a0ddb3cc32851d1207f2.png

 邮件消费端控制台打印:

8b19245e27264680446405bf2662b43b.png

 短信消费端的控制台打印:

7b103e49ab5e5339ffa64e5ff5b6a0ea.png

 生产端执行后,RabbitMQ上的消息队列情况:

137c05c73bf52584c2f534c65d838ad5.png

 两个消费端执行完后,RabbitMQ上的消息队列情况:

123cb4fbb2612960e85ca81cc607e3d6.png

 五、Header 模式

header模式与routing不同的地方在于,header模式取消routingkey,使用header中的 key/value(键值对)匹配队列。

案例:

根据用户的通知设置去通知用户,设置接收Email的用户只接收Email,设置接收sms的用户只接收sms,设置两种通知类型都接收的则两种通知都有效。

根据假设使用场景,需要一个生产端,两个消费端,不同的是,生产端声明交换机时,交换机的类型不同,是headers类型,生产端队列绑定交换机时,不使用routingkey,而是使用header中的 key/value(键值对)匹配队列,发送消息时也是使用header中的 key/value(键值对)匹配队列。

消费端同样是声明交换机时,交换机的类型不同,是headers类型,消费端队列绑定交换机时,不使用routingkey,而是使用header中的 key/value(键值对)匹配队列,消费消息时也是使用header中的 key/value(键值对)匹配队列。

生产端的代码如下:

package com.xyfer;import com.rabbitmq.client.*;import java.io.IOException;import java.util.Hashtable;import java.util.Map;import java.util.concurrent.TimeoutException;public class Producer05 {    //声明两个队列和一个交换机    //Header 模式    private static final String QUEUE_EMAIL ="queueEmail";    private static final String QUEUE_SMS ="queueSms";    private static final String EXCHANGE = "messageChange";    public static void main(String[] args) {        Connection connection = null;        Channel channel = null;        try {            ConnectionFactory connectionFactory = new ConnectionFactory();            connectionFactory.setHost("127.0.0.1");//mq服务ip地址            connectionFactory.setPort(5672);//mq client连接端口            connectionFactory.setUsername("guest");//mq登录用户名            connectionFactory.setPassword("guest");//mq登录密码            connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务器            //创建与RabbitMQ服务的TCP连接            connection = connectionFactory.newConnection();            //创建与Exchange的通道,每个连接可以创建多个通道,每个通道代表一个会话任务            channel = connection.createChannel();            //通道绑定交换机            /**              * 参数明细              * 1、交换机名称              * 2、交换机类型,fanout、topic、direct、headers              */            //Header 模式            channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.HEADERS);            //通道绑定队列            /**             * 声明队列,如果Rabbit中没有此队列将自动创建             * param1:队列名称             * param2:是否持久化             * param3:队列是否独占此连接             * param4:队列不再使用时是否自动删除此队列             * param5:队列参数             * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map arguments             *             */            channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列            channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定短信队列            //交换机和队列绑定            /**             * 参数明细             * 1、队列名称             * 2、交换机名称             * 3、路由key             * 4、             * String queue, String exchange, String routingKey, Map arguments             */            Map<String,Object> headers_email = new Hashtable<String,Object>();            headers_email.put("inform_type","email");            Map<String,Object> headers_sms = new Hashtable<String, Object>();            headers_sms.put("inform_type","sms");            channel.queueBind(QUEUE_EMAIL,EXCHANGE,"",headers_email);            channel.queueBind(QUEUE_SMS,EXCHANGE,"",headers_sms);            //给email队列发消息            for(int i = 0;i<10;i++){                String message = new String("mq 发送email消息。。。");                Map<String,Object> headers = new Hashtable<String,Object>();                headers.put("inform_type","email");//匹配email通知消费者绑定的header                /**                  * 消息发布方法                  * param1:Exchange的名称,如果没有指定,则使用Default Exchange                  * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列                  * param3:消息包含的属性                  * param4:消息体                  * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定                  * 默认的交换机,routingKey等于队列名称                 */                //String exchange, String routingKey, BasicProperties props, byte[] body                AMQP.BasicProperties.Builder properties = new AMQP.BasicProperties.Builder();                properties.headers(headers);                //Email通知                channel.basicPublish(EXCHANGE,"",properties.build(),message.getBytes());                System.out.println("mq email 消息发送成功!");            }            //给sms队列发消息            for(int i = 0;i<10;i++){                String message = new String("mq 发送sms消息。。。");                Map<String,Object> headers = new Hashtable<String,Object>();                headers.put("inform_type","sms");//匹配sms通知消费者绑定的header                /**                  * 消息发布方法                  * param1:Exchange的名称,如果没有指定,则使用Default Exchange                  * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列                  * param3:消息包含的属性                  * param4:消息体                  * 这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显示绑定或解除绑定                  * 默认的交换机,routingKey等于队列名称                 */                //String exchange, String routingKey, BasicProperties props, byte[] body                AMQP.BasicProperties.Builder properties = new AMQP.BasicProperties.Builder();                properties.headers(headers);                //sms通知                channel.basicPublish(EXCHANGE,"",properties.build(),message.getBytes());                System.out.println("mq sms 消息发送成功!");            }        } catch (Exception e) {            e.printStackTrace();        } finally {            try {                channel.close();            } catch (IOException e) {                e.printStackTrace();            } catch (TimeoutException e) {                e.printStackTrace();            }            try {                connection.close();            } catch (IOException e) {                e.printStackTrace();            }        }    }}

邮件消费端的代码如下:

package com.xyfer;import com.rabbitmq.client.*;import java.io.IOException;import java.util.Hashtable;import java.util.Map;import java.util.concurrent.TimeoutException;public class Consumer05 {    private static final String QUEUE_EMAIL ="queueEmail";    private static final String EXCHANGE = "messageChange";    public static void main(String[] args) {        Connection connection = null;        Channel channel = null;        try {            ConnectionFactory connectionFactory = new ConnectionFactory();            connectionFactory.setHost("127.0.0.1");            connectionFactory.setPort(5672);            connection = connectionFactory.newConnection();            channel = connection.createChannel();            //通道绑定交换机            /**                          * 参数明细                          * 1、交换机名称                          * 2、交换机类型,fanout、topic、direct、headers                          */            channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.HEADERS);            //通道绑定队列            /**             * 声明队列,如果Rabbit中没有此队列将自动创建             * param1:队列名称             * param2:是否持久化             * param3:队列是否独占此连接             * param4:队列不再使用时是否自动删除此队列             * param5:队列参数             * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map arguments             *             */            channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);//通道绑定邮件队列            //交换机和队列绑定            /**             * 参数明细             * 1、队列名称             * 2、交换机名称             * 3、路由key             * 4、             * String queue, String exchange, String routingKey, Map arguments             */            Map<String,Object> headers_email = new Hashtable<String,Object>();            headers_email.put("inform_email","email");            channel.queueBind(QUEUE_EMAIL,EXCHANGE,"",headers_email);            //String consumerTag, Envelope envelope, BasicProperties properties, byte[] body            DefaultConsumer consumer = new DefaultConsumer(channel) {                /**                  * 消费者接收消息调用此方法                  * @param consumerTag 消费者的标签,在channel.basicConsume()去指定                  * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志                    (收到消息失败后是否需要重新发送)                  * @param properties                  * @param body                  * @throws IOException                 * String consumerTag, Envelope envelope, BasicProperties properties, byte[] body                 */                @Override                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {                    //交换机                    String exchange = envelope.getExchange();                    //路由key                    String routingKey = envelope.getRoutingKey();                    envelope.getDeliveryTag();                    String msg = new String(body,"utf-8");                    System.out.println("mq收到的消息是:"+msg );                }            };            System.out.println("消费者启动成功!");            channel.basicConsume(QUEUE_EMAIL,true,consumer);        } catch (IOException e) {            e.printStackTrace();        } catch (TimeoutException e) {            e.printStackTrace();        }    }}

短信消费端的代码如下:

package xyfer;import com.rabbitmq.client.*;import java.io.IOException;import java.util.Hashtable;import java.util.Map;import java.util.concurrent.TimeoutException;public class Consumer05 {    private static final String QUEUE_SMS ="queueSms";    private static final String EXCHANGE = "messageChange";    public static void main(String[] args) {        Connection connection = null;        Channel channel = null;        try {            ConnectionFactory connectionFactory = new ConnectionFactory();            connectionFactory.setHost("127.0.0.1");            connectionFactory.setPort(5672);            connection = connectionFactory.newConnection();            channel = connection.createChannel();            //通道绑定交换机            /**              * 参数明细              * 1、交换机名称              * 2、交换机类型,fanout、topic、direct、headers              */            channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.HEADERS);            //通道绑定队列            /**             * 声明队列,如果Rabbit中没有此队列将自动创建             * param1:队列名称             * param2:是否持久化             * param3:队列是否独占此连接             * param4:队列不再使用时是否自动删除此队列             * param5:队列参数             * String queue, boolean durable, boolean exclusive, boolean autoDelete, Map arguments             *             */            channel.queueDeclare(QUEUE_SMS,true,false,false,null);//通道绑定邮件队列            //交换机和队列绑定            /**             * 参数明细             * 1、队列名称             * 2、交换机名称             * 3、路由key             * 4、             * String queue, String exchange, String routingKey, Map arguments             */            Map<String,Object> headers_email = new Hashtable<String,Object>();            headers_email.put("inform_email","sms");            channel.queueBind(QUEUE_SMS,EXCHANGE,"",headers_email);            //String consumerTag, Envelope envelope, BasicProperties properties, byte[] body            DefaultConsumer consumer = new DefaultConsumer(channel) {                /**                  * 消费者接收消息调用此方法                  * @param consumerTag 消费者的标签,在channel.basicConsume()去指定                  * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志                    (收到消息失败后是否需要重新发送)                  * @param properties                  * @param body                  * @throws IOException                 * String consumerTag, Envelope envelope, BasicProperties properties, byte[] body                 */                @Override                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {                    //交换机                    String exchange = envelope.getExchange();                    //路由key                    String routingKey = envelope.getRoutingKey();                    envelope.getDeliveryTag();                    String msg = new String(body,"utf-8");                    System.out.println("mq收到的消息是:"+msg );                }            };            System.out.println("消费者启动成功!");            channel.basicConsume(QUEUE_SMS,true,consumer);        } catch (IOException e) {            e.printStackTrace();        } catch (TimeoutException e) {            e.printStackTrace();        }    }}

生产端启动后RabbitMQ上面的消息队列情况:

585981bd05987b99c56db3f5edc681e2.png

六、RPC 模式

a10a8e9829590ea3f383a5a161bd40d3.png

 RPC即客户端远程调用服务端的方法 ,使用MQ可以实现RPC的异步调用,基于Direct交换机实现,流程如下:

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

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

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

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

至此,RabbitMQ的六种工作模式已经介绍完毕,手动代码实现,实际体验六种工作模式的不同。

长按关注锋哥微信公众号,非常感谢;

dfe365bcbf43b0c2d29e000a3e17b3ec.png

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值