MQ及rabbitMQ的介绍:
1. 没有使用MQ, 系统中可能存在的一些问题:
以电商系统为例, 如下图所示:
在系统中, 用户下了一个订单, 会有很多业务需要处理, 如果这些业务比较耗时, 会导致给用户的响应非常慢, 影响用户体验;
另外, 这种模式还存在耦合性不好以及可扩展性差的问题. 使用MQ可以解决这些问题, 因此我们需要学习和使用MQ.
上述问题的解决方案如下图所示:
添加MQ消息中间件, 监听各个微服务系统的消息, 同时进行响应, 耗时的操作都转移到了各个微服务进行异步操作. 响应给用户信息的速度很快.
同时也实现了订单系统和各个微服务系统之间的解耦, 提升了系统的可扩展性.
MQ及rabbitMQ的介绍: 1.MQ是什么? MQ:Message Queue,也称为消息队列,消息中间件.就是一个软件,实现应用程序和应用程序之间的通信. 可以将MQ形象的理解为秘书,负责老板和各部门经理之间(各个微服务系统)的消息传递. 2.为什么要使用MQ? 在项目中,可将一些无需即时返回且耗时的操作提取出来,进行异步处理,而这种异步处理的方式大大 的节省了服务器的请求响应时间,从而提高了系统的吞吐量。 3.MQ的使用场景: 1、任务异步处理 将不需要同步处理的并且耗时长的操作由消息队列通知消息接收方进行异步处理。提高了应用程序的响应时间。 2、应用程序解耦合 MQ相当于一个中介,生产方通过MQ与消费方交互,它将应用程序进行解耦合。 4.AMQP与JMS MQ是消息通信的模型,实现MQ的大致有两种主流方式:AMQP、JMS。 AMQP与JMS的区别: JMS是定义了统一的接口,来对消息操作进行统一;AMQP是通过规定协议来统一数据交互的格式; JMS限定了必须使用Java语言;AMQP只是协议,不规定实现方式,因此是跨语言的。 JMS规定了两种消息模式;而AMQP的消息模式更加丰富. 5.实现MQ的产品: 目前市面上成熟主流的MQ有Kafka 、RocketMQ、RabbitMQ. RabbitMQ的优势主要在于:RabbitMQ支持很多的协议:AMQP,XMPP, SMTP,STOMP,同时它的消息网络延迟非常低(微秒级别). 6.MQ中的一些概念: 生产者:发送消息的一方; 消费者:接收消息的一方; MQ服务器(broker):就是一个软件,用来存储消息; 虚拟机:用于存储消息的组件(目的是区分不同的业务,用于不同的消息存储),名称一般以"/"开头; 队列(queue):虚拟机内部有多个存储消息的队列,队列是真正存储消息的组件; 交换机: 7.rabbitMQ的入门: 简单模式:一个生产者,一个消费者 1.创建工程it-rabbitmq-day01,导入依赖: <dependencies> <dependency> <groupId>com.rabbitmq</groupId> <artifactId>amqp-client</artifactId> <version>5.6.0</version> </dependency> </dependencies> 2.创建生产者,发送消息: package com.it.simple; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; /** * 生产者,使用简单模式发送消息 * * @author Lyle * @date 2020/4/5 */ public class SimpleProducer { public static void main(String[] args) throws Exception{ //创建链接工厂对象 ConnectionFactory connectionFactory = new ConnectionFactory(); //设置rabbitMQ服务主机地址,默认localhost connectionFactory.setHost("localhost"); //设置rabbitMQ服务端口号:默认5672 connectionFactory.setPort(5672); //设置虚拟机名字,默认/ connectionFactory.setVirtualHost("/lyle"); //设置用户连接名字,默认guest connectionFactory.setUsername("lyle"); //设置连接密码,默认guest connectionFactory.setPassword("lyle"); //创建连接 Connection connection = connectionFactory.newConnection(); //创建频道 Channel channel = connection.createChannel(); //声明队列 /** * simple_queue1:指定/创建队列的名称 * 参数2:是否需要持久化 * 参数3:是否独占本次连接 * 参数4:是否自动删除消息 * 参数5:是否需要传递额外的参数 */ channel.queueDeclare("simple_queue1",true,false,false,null); //创建消息 String message="I come from producer"; //发送消息 /** * 参数1:指定交换机,简单模式可以不设置,使用默认的交换机 * 参数2:指定routekey,简单模式可以使用队列名 * 参数3:发送消息时,是否需要设置额外的数据 * 参数4:消息本身,字节数组 */ channel.basicPublish("","simple_queue1",null,message.getBytes()); //关闭资源 channel.close(); connection.close(); } } 3.创建消费者获取消息: package com.it.simple; import com.rabbitmq.client.*; import java.io.IOException; /** * 消费者,使用简单模式接收消息 * * @author Lyle * @date 2020/4/5 */ public class SimpleConsumer { public static void main(String[] args) throws Exception{ //创建链接工厂对象 ConnectionFactory connectionFactory = new ConnectionFactory(); //设置rabbitMQ服务主机地址,默认localhost connectionFactory.setHost("localhost"); //设置rabbitMQ服务端口号:默认5672 connectionFactory.setPort(5672); //设置虚拟机名字,默认/ connectionFactory.setVirtualHost("/lyle"); //设置用户连接名字,默认guest connectionFactory.setUsername("lyle"); //设置连接密码,默认guest connectionFactory.setPassword("lyle"); //创建连接 Connection connection = connectionFactory.newConnection(); //创建频道 Channel channel = connection.createChannel(); //声明队列 /** * simple_queue1:指定/创建队列的名称 * 参数2:是否需要持久化 * 参数3:是否独占本次连接 * 参数4:是否自动删除消息 * 参数5:是否需要传递额外的参数 */ channel.queueDeclare("simple_queue1",true,false,false,null); //创建消费者,设置消息处理 DefaultConsumer defaultConsumer = new DefaultConsumer(channel){ /** * * @param consumerTag 指定消费者的标签 * @param envelope 生产者发过来的:消息的id,交换机,routingkey等信息 * @param properties 额外的数据,此处未设置,为null * @param body 消息本身 * @throws IOException */ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { //自己定义消息处理方式 System.out.println("consumerTag:"+consumerTag); System.out.println("消息的id:"+envelope.getDeliveryTag()+";exchange:"+envelope.getExchange()+";routingkey:"+envelope.getRoutingKey()); System.out.println("消息本身:"+new String(body)); } }; //监听消息 //参数1:指定要监听哪一个队列 //参数2:是否设置为自动应答 //参数3:指定谁来处理消息 channel.basicConsume("simple_queue1",true,defaultConsumer); //关闭资源,一般不建议关闭,一直监听 } } 工具类的抽取: package com.it.util; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import java.io.IOException; /** * ToDo * * @author Lyle * @date 2020/4/5 */ public class ConnectionUtils { /*** * 创建链接对象 * @return * @throws IOException * @throws */ public static Connection getConnection() throws Exception { //创建链接工厂对象 ConnectionFactory connectionFactory = new ConnectionFactory(); //设置RabbitMQ服务主机地址,默认localhost connectionFactory.setHost("localhost"); //设置RabbitMQ服务端口,默认5672 connectionFactory.setPort(5672); //设置虚拟主机名字,默认/ connectionFactory.setVirtualHost("/lyle"); //设置用户连接名,默认guest connectionFactory.setUsername("lyle"); //设置链接密码,默认guest connectionFactory.setPassword("lyle"); //创建链接 Connection connection = connectionFactory.newConnection(); return connection; } } 工作者模式:一个生产者,多个消费者 注意:一个消息只能被一个消费者消费; 生产者: package com.it.simple.work; import com.it.util.ConnectionUtils; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; /** * 生产者,使用简单模式发送消息 * * @author Lyle * @date 2020/4/5 */ public class WorkProducer { public static void main(String[] args) throws Exception{ Connection connection = ConnectionUtils.getConnection(); Channel channel = connection.createChannel(); //声明队列 /** * simple_queue1:指定/创建队列的名称 * 参数2:是否需要持久化 * 参数3:是否独占本次连接 * 参数4:是否自动删除消息 * 参数5:是否需要传递额外的参数 */ channel.queueDeclare("work_queue1",true,false,false,null); for (int i = 0; i < 20; i++) { //创建消息 String message="I come from producer work模式"+i; //发送消息 /** * 参数1:指定交换机,简单模式可以不设置,使用默认的交换机 * 参数2:指定routekey,简单模式可以使用队列名 * 参数3:发送消息时,是否需要设置额外的数据 * 参数4:消息本身,字节数组 */ channel.basicPublish("","work_queue1",null,message.getBytes()); } //关闭资源 channel.close(); connection.close(); } } 消费者1: package com.it.simple.work; import com.it.util.ConnectionUtils; import com.rabbitmq.client.*; import java.io.IOException; /** * 消费者,使用简单模式接收消息 * * @author Lyle * @date 2020/4/5 */ public class WorkConsumer1 { public static void main(String[] args) throws Exception{ //工具类的使用 Connection connection = ConnectionUtils.getConnection(); //创建频道 Channel channel = connection.createChannel(); //声明队列 /** * simple_queue1:指定/创建队列的名称 * 参数2:是否需要持久化 * 参数3:是否独占本次连接 * 参数4:是否自动删除消息 * 参数5:是否需要传递额外的参数 */ channel.queueDeclare("work_queue1",true,false,false,null); //创建消费者,设置消息处理 DefaultConsumer defaultConsumer = new DefaultConsumer(channel){ /** * * @param consumerTag 指定消费者的标签 * @param envelope 生产者发过来的:消息的id,交换机,routingkey等信息 * @param properties 额外的数据,此处未设置,为null * @param body 消息本身 * @throws IOException */ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { //自己定义消息处理方式 System.out.println("1111111111111111111111"); System.out.println("consumerTag:"+consumerTag); System.out.println("消息的id:"+envelope.getDeliveryTag()+";exchange:"+envelope.getExchange()+";routingkey:"+envelope.getRoutingKey()); System.out.println("消息本身:"+new String(body)); } }; //监听消息 //参数1:指定要监听哪一个队列 //参数2:是否设置为自动应答 //参数3:指定谁来处理消息 channel.basicConsume("work_queue1",true,defaultConsumer); //关闭资源,一般不建议关闭,一直监听 } } 消费者2: package com.it.simple.work; import com.it.util.ConnectionUtils; import com.rabbitmq.client.*; import java.io.IOException; /** * 消费者,使用简单模式接收消息 * * @author Lyle * @date 2020/4/5 */ public class WorkConsumer2 { public static void main(String[] args) throws Exception{ //工具类的使用 Connection connection = ConnectionUtils.getConnection(); //创建频道 Channel channel = connection.createChannel(); //声明队列 /** * simple_queue1:指定/创建队列的名称 * 参数2:是否需要持久化 * 参数3:是否独占本次连接 * 参数4:是否自动删除消息 * 参数5:是否需要传递额外的参数 */ channel.queueDeclare("work_queue1",true,false,false,null); //创建消费者,设置消息处理 DefaultConsumer defaultConsumer = new DefaultConsumer(channel){ /** * * @param consumerTag 指定消费者的标签 * @param envelope 生产者发过来的:消息的id,交换机,routingkey等信息 * @param properties 额外的数据,此处未设置,为null * @param body 消息本身 * @throws IOException */ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { //自己定义消息处理方式 System.out.println("2222222222222222"); System.out.println("consumerTag:"+consumerTag); System.out.println("消息的id:"+envelope.getDeliveryTag()+";exchange:"+envelope.getExchange()+";routingkey:"+envelope.getRoutingKey()); System.out.println("消息本身:"+new String(body)); } }; //监听消息 //参数1:指定要监听哪一个队列 //参数2:是否设置为自动应答 //参数3:指定谁来处理消息 channel.basicConsume("work_queue1",true,defaultConsumer); //关闭资源,一般不建议关闭,一直监听 } } 发布订阅模式: 特点: 消息先发送到交换机,由交换机转发到各个队列; 交换机和队列要先进行绑定; -----广播模式(Fanout):消息通过交换机转发到所有与交换机绑定的队列 生产者: 创建队列; 创建交换机; 将队列绑定到交换机; 创建消息; 发送消息到指定交换机 package com.it.ps.fanout; import com.it.util.ConnectionUtils; import com.rabbitmq.client.BuiltinExchangeType; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; /** * 生产者,发布订阅模式的广播模式,多个消费者同时受到同一个消息 * * @author Lyle * @date 2020/4/5 */ public class FanoutProducer { public static void main(String[] args) throws Exception{ Connection connection = ConnectionUtils.getConnection(); Channel channel = connection.createChannel(); //声明队列 /** * simple_queue1:指定/创建队列的名称 * 参数2:是否需要持久化 * 参数3:是否独占本次连接 * 参数4:是否自动删除消息 * 参数5:是否需要传递额外的参数 */ channel.queueDeclare("fanout_queue1",true,false,false,null); channel.queueDeclare("fanout_queue2",true,false,false,null); //创建交换机 /** * 参数1:交换机名称 * 参数2:指定模式为广播模式 */ channel.exchangeDeclare("exchange_fanout", BuiltinExchangeType.FANOUT); //将交换机和队列进行绑定 /** * 参数1:需要绑定的队列名称 * 参数2:队列需要绑定到哪个交换机 * 参数3:routingkey,在广播模式中可以不写 */ channel.queueBind("fanout_queue1","exchange_fanout",""); channel.queueBind("fanout_queue2","exchange_fanout",""); //创建消息 String message="I come from producer fanout"; //发送消息 /** * 参数1:指定交换机,简单模式可以不设置,使用默认的交换机 * 参数2:指定routekey,简单模式可以使用队列名 * 参数3:发送消息时,是否需要设置额外的数据 * 参数4:消息本身,字节数组 */ channel.basicPublish("exchange_fanout","",null,message.getBytes()); //关闭资源 channel.close(); connection.close(); } } 消费者1: 创建队列; 定义处理消息的方法; 指定监听哪一个消息队列; package com.it.ps.fanout; import com.it.util.ConnectionUtils; import com.rabbitmq.client.*; import java.io.IOException; /** * 消费者,使用简单模式接收消息 * * @author Lyle * @date 2020/4/5 */ public class FanoutConsumer1 { public static void main(String[] args) throws Exception{ //工具类的使用 Connection connection = ConnectionUtils.getConnection(); //创建频道 Channel channel = connection.createChannel(); //声明队列 /** * simple_queue1:指定/创建队列的名称 * 参数2:是否需要持久化 * 参数3:是否独占本次连接 * 参数4:是否自动删除消息 * 参数5:是否需要传递额外的参数 */ channel.queueDeclare("fanout_queue1",true,false,false,null); //创建消费者,设置消息处理 DefaultConsumer defaultConsumer = new DefaultConsumer(channel){ /** * * @param consumerTag 指定消费者的标签 * @param envelope 生产者发过来的:消息的id,交换机,routingkey等信息 * @param properties 额外的数据,此处未设置,为null * @param body 消息本身 * @throws IOException */ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { //自己定义消息处理方式 System.out.println("1111111111111111111111"); System.out.println("consumerTag:"+consumerTag); System.out.println("消息的id:"+envelope.getDeliveryTag()+";exchange:"+envelope.getExchange()+";routingkey:"+envelope.getRoutingKey()); System.out.println("消息本身:"+new String(body)); } }; //监听消息 //参数1:指定要监听哪一个队列 //参数2:是否设置为自动应答 //参数3:指定谁来处理消息 channel.basicConsume("fanout_queue1",true,defaultConsumer); //关闭资源,一般不建议关闭,一直监听 } } 消费者2: 创建队列; 定义处理消息的方法; 指定监听哪一个消息队列; package com.it.ps.fanout; import com.it.util.ConnectionUtils; import com.rabbitmq.client.*; import java.io.IOException; /** * 消费者,使用简单模式接收消息 * * @author Lyle * @date 2020/4/5 */ public class FanoutConsumer2 { public static void main(String[] args) throws Exception{ //工具类的使用 Connection connection = ConnectionUtils.getConnection(); //创建频道 Channel channel = connection.createChannel(); //声明队列 /** * simple_queue1:指定/创建队列的名称 * 参数2:是否需要持久化 * 参数3:是否独占本次连接 * 参数4:是否自动删除消息 * 参数5:是否需要传递额外的参数 */ channel.queueDeclare("fanout_queue2",true,false,false,null); //创建消费者,设置消息处理 DefaultConsumer defaultConsumer = new DefaultConsumer(channel){ /** * * @param consumerTag 指定消费者的标签 * @param envelope 生产者发过来的:消息的id,交换机,routingkey等信息 * @param properties 额外的数据,此处未设置,为null * @param body 消息本身 * @throws IOException */ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { //自己定义消息处理方式 System.out.println("22222222222222222"); System.out.println("consumerTag:"+consumerTag); System.out.println("消息的id:"+envelope.getDeliveryTag()+";exchange:"+envelope.getExchange()+";routingkey:"+envelope.getRoutingKey()); System.out.println("消息本身:"+new String(body)); } }; //监听消息 //参数1:指定要监听哪一个队列 //参数2:是否设置为自动应答 //参数3:指定谁来处理消息 channel.basicConsume("fanout_queue2",true,defaultConsumer); //关闭资源,一般不建议关闭,一直监听 } } -----路由模式(Direct): 绑定队列到交换机的时候,指定一个固定的routingkey; 当发送方发送消息的时候指定routingkey,如果匹配上,则将消息转发到对应的队列中; 生产者: package com.it.ps.direct; import com.it.util.ConnectionUtils; import com.rabbitmq.client.BuiltinExchangeType; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; /** * 生产者,发布订阅模式的路由模式: * 绑定队列到交换机的时候,指定一个固定的routingkey; * 当发送方发送消息的时候指定routingkey,如果匹配上,则将消息转发到对应的队列中; * * @author Lyle * @date 2020/4/5 */ public class DirectProducer { public static void main(String[] args) throws Exception{ Connection connection = ConnectionUtils.getConnection(); Channel channel = connection.createChannel(); //声明队列 /** * simple_queue1:指定/创建队列的名称 * 参数2:是否需要持久化 * 参数3:是否独占本次连接 * 参数4:是否自动删除消息 * 参数5:是否需要传递额外的参数 */ channel.queueDeclare("direct_queue1",true,false,false,null); channel.queueDeclare("direct_queue2",true,false,false,null); //创建交换机 /** * 参数1:交换机名称 * 参数2:指定模式为路由模式 */ channel.exchangeDeclare("exchange_direct", BuiltinExchangeType.DIRECT); //将交换机和队列进行绑定 /** * 参数1:需要绑定的队列名称 * 参数2:队列需要绑定到哪个交换机 * 参数3:routingkey,路由模式需要制定具体的routingkey */ channel.queueBind("direct_queue1","exchange_direct","item.insert");//新增 channel.queueBind("direct_queue2","exchange_direct","item.update");//更新 //创建消息 String message1="我要新增..."; String message2="我要更新..."; //发送消息 /** * 参数1:指定交换机,简单模式可以不设置,使用默认的交换机 * 参数2:指定routekey,简单模式可以使用队列名 * 参数3:发送消息时,是否需要设置额外的数据 * 参数4:消息本身,字节数组 */ channel.basicPublish("exchange_direct","item.insert",null,message1.getBytes()); channel.basicPublish("exchange_direct","item.update",null,message2.getBytes()); //关闭资源 channel.close(); connection.close(); } } 消费者1: package com.it.ps.direct; import com.it.util.ConnectionUtils; import com.rabbitmq.client.*; import java.io.IOException; /** * 消费者,使用简单模式接收消息 * * @author Lyle * @date 2020/4/5 */ public class DirectConsumer1 { public static void main(String[] args) throws Exception{ //工具类的使用 Connection connection = ConnectionUtils.getConnection(); //创建频道 Channel channel = connection.createChannel(); //声明队列 /** * simple_queue1:指定/创建队列的名称 * 参数2:是否需要持久化 * 参数3:是否独占本次连接 * 参数4:是否自动删除消息 * 参数5:是否需要传递额外的参数 */ channel.queueDeclare("direct_queue1",true,false,false,null); //创建消费者,设置消息处理 DefaultConsumer defaultConsumer = new DefaultConsumer(channel){ /** * * @param consumerTag 指定消费者的标签 * @param envelope 生产者发过来的:消息的id,交换机,routingkey等信息 * @param properties 额外的数据,此处未设置,为null * @param body 消息本身 * @throws IOException */ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { //自己定义消息处理方式 System.out.println("我是专门负责处理新增的........"); System.out.println("consumerTag:"+consumerTag); System.out.println("消息的id:"+envelope.getDeliveryTag()+";exchange:"+envelope.getExchange()+";routingkey:"+envelope.getRoutingKey()); System.out.println("消息本身:"+new String(body)); } }; //监听消息 //参数1:指定要监听哪一个队列 //参数2:是否设置为自动应答 //参数3:指定谁来处理消息 channel.basicConsume("direct_queue1",true,defaultConsumer); //关闭资源,一般不建议关闭,一直监听 } } 消费者2: package com.it.ps.direct; import com.it.util.ConnectionUtils; import com.rabbitmq.client.*; import java.io.IOException; /** * 消费者,使用简单模式接收消息 * * @author Lyle * @date 2020/4/5 */ public class DirectConsumer2 { public static void main(String[] args) throws Exception{ //工具类的使用 Connection connection = ConnectionUtils.getConnection(); //创建频道 Channel channel = connection.createChannel(); //声明队列 /** * simple_queue1:指定/创建队列的名称 * 参数2:是否需要持久化 * 参数3:是否独占本次连接 * 参数4:是否自动删除消息 * 参数5:是否需要传递额外的参数 */ channel.queueDeclare("direct_queue2",true,false,false,null); //创建消费者,设置消息处理 DefaultConsumer defaultConsumer = new DefaultConsumer(channel){ /** * * @param consumerTag 指定消费者的标签 * @param envelope 生产者发过来的:消息的id,交换机,routingkey等信息 * @param properties 额外的数据,此处未设置,为null * @param body 消息本身 * @throws IOException */ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { //自己定义消息处理方式 System.out.println("我是专门负责处理更新的........"); System.out.println("consumerTag:"+consumerTag); System.out.println("消息的id:"+envelope.getDeliveryTag()+";exchange:"+envelope.getExchange()+";routingkey:"+envelope.getRoutingKey()); System.out.println("消息本身:"+new String(body)); } }; //监听消息 //参数1:指定要监听哪一个队列 //参数2:是否设置为自动应答 //参数3:指定谁来处理消息 channel.basicConsume("direct_queue2",true,defaultConsumer); //关闭资源,一般不建议关闭,一直监听 } } -----通配符模式(Topics): 绑定队列到交换机的时候,指定一个包含通配符的routingkey; 当发送方发送消息的时候指定routingkey,如果匹配上了通配符表达式,则将消息转发到对应的队列中; 通配符规则: `#`:匹配一个或多个词,例如:item.#`:能够匹配`item.insert.abc` 或者 `item.insert` `*`:匹配不多不少恰好1个词,例如: item.*`:只能匹配`item.insert` 生产者: package com.it.ps.topic; import com.it.util.ConnectionUtils; import com.rabbitmq.client.BuiltinExchangeType; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; /** * 生产者,发布订阅模式的通配符模式: * 绑定队列到交换机的时候,指定一个包含通配符的routingkey; * 当发送方发送消息的时候指定routingkey,如果匹配上通配符表达式,则将消息转发到对应的队列中; * * @author Lyle * @date 2020/4/5 */ public class TopicProducer { public static void main(String[] args) throws Exception{ Connection connection = ConnectionUtils.getConnection(); Channel channel = connection.createChannel(); //声明队列 /** * simple_queue1:指定/创建队列的名称 * 参数2:是否需要持久化 * 参数3:是否独占本次连接 * 参数4:是否自动删除消息 * 参数5:是否需要传递额外的参数 */ channel.queueDeclare("topic_queue1",true,false,false,null); channel.queueDeclare("topic_queue2",true,false,false,null); //创建交换机 /** * 参数1:交换机名称 * 参数2:指定模式为通配符模式 */ channel.exchangeDeclare("exchange_topic", BuiltinExchangeType.TOPIC); //将交换机和队列进行绑定 /** * 参数1:需要绑定的队列名称 * 参数2:队列需要绑定到哪个交换机 * 参数3:routingkey,路由模式需要制定具体的routingkey */ channel.queueBind("topic_queue1","exchange_topic","item.*");//新增 channel.queueBind("topic_queue2","exchange_topic","order.*");//更新 //创建消息 String message1="我要item..."; String message3="我要item2..."; String message2="我要order..."; //发送消息 /** * 参数1:指定交换机,简单模式可以不设置,使用默认的交换机 * 参数2:指定routekey,简单模式可以使用队列名 * 参数3:发送消息时,是否需要设置额外的数据 * 参数4:消息本身,字节数组 */ channel.basicPublish("exchange_topic","item.insert",null,message1.getBytes()); channel.basicPublish("exchange_topic","item.update",null,message3.getBytes()); channel.basicPublish("exchange_topic","order.update",null,message2.getBytes()); //关闭资源 channel.close(); connection.close(); } } 消费者1: package com.it.ps.topic; import com.it.util.ConnectionUtils; import com.rabbitmq.client.*; import java.io.IOException; /** * 消费者,使用简单模式接收消息 * * @author Lyle * @date 2020/4/5 */ public class TopicConsumer1 { public static void main(String[] args) throws Exception{ //工具类的使用 Connection connection = ConnectionUtils.getConnection(); //创建频道 Channel channel = connection.createChannel(); //声明队列 /** * simple_queue1:指定/创建队列的名称 * 参数2:是否需要持久化 * 参数3:是否独占本次连接 * 参数4:是否自动删除消息 * 参数5:是否需要传递额外的参数 */ channel.queueDeclare("topic_queue1",true,false,false,null); //创建消费者,设置消息处理 DefaultConsumer defaultConsumer = new DefaultConsumer(channel){ /** * * @param consumerTag 指定消费者的标签 * @param envelope 生产者发过来的:消息的id,交换机,routingkey等信息 * @param properties 额外的数据,此处未设置,为null * @param body 消息本身 * @throws IOException */ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { //自己定义消息处理方式 System.out.println("我是专门负责处理item的........"); System.out.println("consumerTag:"+consumerTag); System.out.println("消息的id:"+envelope.getDeliveryTag()+";exchange:"+envelope.getExchange()+";routingkey:"+envelope.getRoutingKey()); System.out.println("消息本身:"+new String(body)); } }; //监听消息 //参数1:指定要监听哪一个队列 //参数2:是否设置为自动应答 //参数3:指定谁来处理消息 channel.basicConsume("topic_queue1",true,defaultConsumer); //关闭资源,一般不建议关闭,一直监听 } } 消费者2: package com.it.ps.topic; import com.it.util.ConnectionUtils; import com.rabbitmq.client.*; import java.io.IOException; /** * 消费者,使用简单模式接收消息 * * @author Lyle * @date 2020/4/5 */ public class TopicConsumer2 { public static void main(String[] args) throws Exception{ //工具类的使用 Connection connection = ConnectionUtils.getConnection(); //创建频道 Channel channel = connection.createChannel(); //声明队列 /** * simple_queue1:指定/创建队列的名称 * 参数2:是否需要持久化 * 参数3:是否独占本次连接 * 参数4:是否自动删除消息 * 参数5:是否需要传递额外的参数 */ channel.queueDeclare("topic_queue2",true,false,false,null); //创建消费者,设置消息处理 DefaultConsumer defaultConsumer = new DefaultConsumer(channel){ /** * * @param consumerTag 指定消费者的标签 * @param envelope 生产者发过来的:消息的id,交换机,routingkey等信息 * @param properties 额外的数据,此处未设置,为null * @param body 消息本身 * @throws IOException */ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { //自己定义消息处理方式 System.out.println("我是专门负责处理order的........"); System.out.println("consumerTag:"+consumerTag); System.out.println("消息的id:"+envelope.getDeliveryTag()+";exchange:"+envelope.getExchange()+";routingkey:"+envelope.getRoutingKey()); System.out.println("消息本身:"+new String(body)); } }; //监听消息 //参数1:指定要监听哪一个队列 //参数2:是否设置为自动应答 //参数3:指定谁来处理消息 channel.basicConsume("topic_queue2",true,defaultConsumer); //关闭资源,一般不建议关闭,一直监听 } }