安装及配置
安装
1、安装erlang,以管理员身份运行。
2、安装rabbitmq-server,以管理员身份运行。
3、配置环境变量
配置:elang-home:,指定你的erlang的安装目录
添加到path:
cmd到rabbitmq-server的 sbin目录下 打开cmd命令行工具:
cd C:\Program Files\RabbitMQ Server\rabbitmq_server-3.7.4\sbin
执行命令:
rabbitmq-plugins.bat enable rabbitmq_management
重启rabbitmq服务器:
此电脑–>右击 点击管理界面–>双击服务和应用程序–>双击 服务–>点击重启按钮即可
浏览器中输入localhost:15672 输 guest/guest:
RabbitMq入门
示例工程
依赖
<dependency> <groupId>com.rabbitmq</groupId> <artifactId>amqp-client</artifactId> <version>5.6.0</version> </dependency>
生产者
//创建链接工厂对象 //设置RabbitMQ服务主机地址,默认localhost //设置RabbitMQ服务端口,默认5672 //设置虚拟主机名字,默认/ //设置用户连接名,默认guest //设置链接密码,默认guest //创建链接 //创建频道 //声明队列 //创建消息 //消息发送 //关闭资源
public class Producer { /*** * 消息生产者 * @param args * @throws IOException * @throws TimeoutException */ public static void main(String[] args) throws IOException, TimeoutException { //创建链接工厂对象 ConnectionFactory connectionFactory = new ConnectionFactory(); //设置RabbitMQ服务主机地址,默认localhost connectionFactory.setHost("localhost"); //设置RabbitMQ服务端口,默认5672 connectionFactory.setPort(5672); //设置虚拟主机名字,默认/ connectionFactory.setVirtualHost("/daryl"); //设置用户连接名,默认guest connectionFactory.setUsername("admin"); //设置链接密码,默认guest connectionFactory.setPassword("admin"); //创建链接 Connection connection = connectionFactory.newConnection(); //创建频道 Channel channel = connection.createChannel(); /** * 声明队列 * 参数1:队列名称 * 参数2:是否定义持久化队列 * 参数3:是否独占本次连接 * 参数4:是否在不使用的时候自动删除队列 * 参数5:队列其它参数 * **/ channel.queueDeclare("simple_queue",true,false,false,null); //创建消息 String message = "hello world!"; /** * 消息发送 * 参数1:交换机名称,如果没有指定则使用默认Default Exchage * 参数2:路由key,简单模式可以传递队列名称 * 参数3:消息其它属性 * 参数4:消息内容 */ channel.basicPublish("","simple_queue",null,message.getBytes()); //关闭资源 channel.close(); connection.close(); } }
在执行上述的消息发送之后;可以登录rabbitMQ的管理控制台,可以发现队列和其消息:
如果想查看消息,可以点击队列名称->Get Messages消费者
//创建链接工厂对象 //设置RabbitMQ服务主机地址,默认localhost //设置RabbitMQ服务端口,默认5672 //设置虚拟主机名字,默认/ //设置用户连接名,默认guest //设置链接密码,默认guest //创建链接 //创建频道 //创建队列 //创建消费者,并设置消息处理 //消息监听 //关闭资源(不建议关闭,建议一直监听消息)
public class Consumer { /*** * 消息消费者 * @param args * @throws IOException * @throws TimeoutException */ public static void main(String[] args) throws IOException, TimeoutException { //创建链接工厂对象 ConnectionFactory connectionFactory = new ConnectionFactory(); //设置RabbitMQ服务主机地址,默认localhost connectionFactory.setHost("localhost"); //设置RabbitMQ服务端口,默认5672 connectionFactory.setPort(5672); //设置虚拟主机名字,默认/ connectionFactory.setVirtualHost("/daryl"); //设置用户连接名,默认guest connectionFactory.setUsername("admin"); //设置链接密码,默认guest connectionFactory.setPassword("admin"); //创建链接 Connection connection = connectionFactory.newConnection(); //创建频道 Channel channel = connection.createChannel(); //创建队列 channel.queueDeclare("simple_queue",true,false,false,null); //创建消费者,并设置消息处理 DefaultConsumer defaultConsumer = new DefaultConsumer(channel){ /*** * @param consumerTag 消息者标签,在channel.basicConsume时候可以指定 * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志(收到消息失败后是否需要重新发送) * @param properties 属性信息 * @param body 消息 * @throws IOException */ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { //路由的key String routingKey = envelope.getRoutingKey(); //获取交换机信息 String exchange = envelope.getExchange(); //获取消息ID long deliveryTag = envelope.getDeliveryTag(); //获取消息信息 String message = new String(body,"UTF-8"); System.out.println("routingKey:"+routingKey+",exchange:"+exchange+",deliveryTag:"+deliveryTag+",message:"+message); } }; /** * 消息监听 * 参数1:队列名称 * 参数2:是否自动确认,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复会删除消息,设置为false则需要手动确认 * 参数3:消息接收到后回调 */ channel.basicConsume("simple_queue",true,defaultConsumer); //关闭资源(不建议关闭,建议一直监听消息) //channel.close(); //connection.close(); } }
上述的入门案例中中其实使用的是如下的简单模式:
RabitMq的工作模式
Work queues工作队列模式
Work Queues与入门程序的简单模式相比,多了一个或一些消费端,多个消费端共同消费同一个队列中的消息。
应用场景:对于 任务过重或任务较多情况使用工作队列可以提高任务处理的速度。
代码:
Work Queues与入门程序的简单模式的代码是几乎一样的;可以完全复制,并复制多一个消费者进行多个消费者同时消费消息的测试。
生产者:public class WorkProducer { /*** * 消息生产者 * @param args * @throws IOException * @throws TimeoutException */ public static void main(String[] args) throws IOException, TimeoutException { //创建链接 Connection connection = ConnectionUtil.getConnection(); //创建频道 Channel channel = connection.createChannel(); /** * 声明队列 * 参数1:队列名称 * 参数2:是否定义持久化队列 * 参数3:是否独占本次连接 * 参数4:是否在不使用的时候自动删除队列 * 参数5:队列其它参数 * **/ channel.queueDeclare("work_queue",true,false,false,null); for (int i = 0; i < 10; i++) { String message = "hello world"+i; channel.basicPublish("","work_queue",null,message.getBytes()); } //关闭资源 channel.close(); connection.close(); } }
消费者One:
public class WorkConsumerOne { /*** * 消息消费者 * @param args * @throws IOException * @throws TimeoutException */ public static void main(String[] args) throws IOException, TimeoutException { //创建链接 Connection connection = ConnectionUtil.getConnection(); //创建频道 Channel channel = connection.createChannel(); //创建队列 channel.queueDeclare("work_queue",true,false,false,null); //创建消费者,并设置消息处理 DefaultConsumer defaultConsumer = new DefaultConsumer(channel){ /*** * @param consumerTag 消息者标签,在channel.basicConsume时候可以指定 * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志(收到消息失败后是否需要重新发送) * @param properties 属性信息 * @param body 消息 * @throws IOException */ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { //路由的key String routingKey = envelope.getRoutingKey(); //获取交换机信息 String exchange = envelope.getExchange(); //获取消息ID long deliveryTag = envelope.getDeliveryTag(); //获取消息信息 String message = new String(body,"UTF-8"); System.out.println("Work-One:routingKey:"+routingKey+",exchange:"+exchange+",deliveryTag:"+deliveryTag+",message:"+message); } }; /** * 消息监听 * 参数1:队列名称 * 参数2:是否自动确认,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复会删除消息,设置为false则需要手动确认 * 参数3:消息接收到后回调 */ channel.basicConsume("work_queue",true,defaultConsumer); //关闭资源(不建议关闭,建议一直监听消息) //channel.close(); //connection.close(); } }
消费者Two:
public class WorkConsumerTwo { /*** * 消息消费者 * @param args * @throws IOException * @throws TimeoutException */ public static void main(String[] args) throws IOException, TimeoutException { //创建链接 Connection connection = ConnectionUtil.getConnection(); //创建频道 Channel channel = connection.createChannel(); //创建队列 channel.queueDeclare("work_queue",true,false,false,null); //创建消费者,并设置消息处理 DefaultConsumer defaultConsumer = new DefaultConsumer(channel){ /*** * @param consumerTag 消息者标签,在channel.basicConsume时候可以指定 * @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志(收到消息失败后是否需要重新发送) * @param properties 属性信息 * @param body 消息 * @throws IOException */ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { //路由的key String routingKey = envelope.getRoutingKey(); //获取交换机信息 String exchange = envelope.getExchange(); //获取消息ID long deliveryTag = envelope.getDeliveryTag(); //获取消息信息 String message = new String(body,"UTF-8"); System.out.println("Work-Two:routingKey:"+routingKey+",exchange:"+exchange+",deliveryTag:"+deliveryTag+",message:"+message); } }; /** * 消息监听 * 参数1:队列名称 * 参数2:是否自动确认,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复会删除消息,设置为false则需要手动确认 * 参数3:消息接收到后回调 */ channel.basicConsume("work_queue",true,defaultConsumer); //关闭资源(不建议关闭,建议一直监听消息) //channel.close(); //connection.close(); } }
测试:
启动两个消费者,然后再启动生产者发送消息;到IDEA的两个消费者对应的控制台查看是否竞争性的接收到消息。
小结:
在一个队列中如果有多个消费者,那么消费者之间对于同一个消息的关系是竞争的关系。订阅模式类型
前面2个案例中,只有3个角色:P:生产者,也就是要发送消息的程序 C:消费者:消息的接受者,会一直等待消息到来。 Queue:消息队列,图中红色部分
而在订阅模型中,多了一个exchange角色,而且过程略有变化:
P:生产者,也就是要发送消息的程序,但是不再发送到队列中,而是发给X(交换机) C:消费者,消息的接受者,会一直等待消息到来。 Queue:消息队列,接收消息、缓存消息。 Exchange:交换机,图中的X。一方面,接收生产者发送的消息。另一方面,知道如何处理消息,例如递交给某个特别队列、递交给所有队列、或是将消息丢弃。到底如何操作,取决于Exchange的类型。Exchange有常见以下3种类型: Fanout:广播,将消息交给所有绑定到交换机的队列 Direct:定向,把消息交给符合指定routing key 的队列 Topic:通配符,把消息交给符合routing pattern(路由模式) 的队列
Exchange(交换机)只负责转发消息,不具备存储消息的能力,因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息会丢失!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。