Rabbitmq消息队列:HelloWorld消息直传模式简单应用
一、引入依赖
新建一个maven项目,在pom.xml配置文件中加入以下依赖。
<dependencies> <dependency> <groupId>com.rabbitmq</groupId> <artifactId>amqp-client</artifactId> <version>4.5.0</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.3.2</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>
二、封装工具类
新建一个用于rabbitmq连接工具类RabbitmqConUtil,内容如下:
package utils; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; public class RabbitmqConUtil { //rabbitmq服务器地址(此处的*应该为个人服务器的ip地址) private static String ipAddress = "*.*.*.*"; //rabbitmq端口 private static Integer port = 5672; //rabbitmq自建的测试专用用户名 private static String userName = "test"; //rabbitmq自建的测试专用用户密码 private static String password = "test"; //rabbitmq自建的测试虚拟主机地址 private static String virtualHost = "test"; //获取rabbitmq链接 public static Connection getConnection() throws Exception{ ConnectionFactory connectionFactory = new ConnectionFactory(); //给链接工厂配置信息 connectionFactory.setHost(ipAddress); connectionFactory.setPort(port); connectionFactory.setUsername(userName); connectionFactory.setPassword(password); connectionFactory.setVirtualHost(virtualHost); //实例化链接 Connection connection = connectionFactory.newConnection(); return connection; } }
三、测试HelloWorld直传模式
直传模式不需要交换机,只需要最基本的生产者和消费者。
1、生产者
创建一个Give类,先使用刚才编写的工具类来获取rabbitmq连接,再创建通道,声明使用的队列并发送内容。
package test.hello; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import utils.RabbitmqConUtil; public class Give { //本次测试使用的消息队列名称 private final static String QUEUE = "test-hello"; public static void main(String[] args) throws Exception{ //获取rabbitmq链接 Connection connection = RabbitmqConUtil.getConnection(); //创建通道 Channel channel = connection.createChannel(); //声明使用的队列 channel.queueDeclare(QUEUE,false,false,false,null); //发送内容 channel.basicPublish("",QUEUE,null,"生产者-》消费者".getBytes()); } }
在声明使用的队列时,注意要和消费者在同一个队列里,这样才能保证信息的正确传递。
channel.queueDeclare()方法中的参数分别为:
第一个参数:队列名称
第二个参数:是否持久化,boolean类型,如果持久化就会把消息存储到rabbitmq自带的数据库里,不持久化的话消息就会在rabbitmq重启后丢失
第三个参数:是否排外,如果为true,则只允许这个通道来使用这个队列,其他通道不允许访问
第四个参数:是否自动删除
第五个参数:自己额外想带的参数
channel.basicPublish()方法中的参数分别为:
第一个参数:要使用的交换机,此处为helloworld直传测试,所以不设置交换机 第二个参数:要用通道把消息内容发送到哪个队列,填写队列名称 第三个参数:要带的属性 第四个参数:消息内容(byte[]格式)
运行结果如下:
2、消费者
创建一个Get类,使用刚才编写的工具类来获取rabbitmq连接,再创建通道,声明使用的队列,定义DefaultConsumer类型的消费者并重写其内部的handleDelivery方法,在方法内部接受内容并处理和确认消息,防止数据丢失。
package test.hello; import com.rabbitmq.client.*; import utils.RabbitmqConUtil; import java.io.IOException; public class Get { //本次测试使用的消息队列名称 private final static String QUEUE = "test-hello"; public static void main(String[] args) throws Exception { //获取rabbitmq链接 Connection connection = RabbitmqConUtil.getConnection(); //创建通道 final Channel channel = connection.createChannel(); //声明使用的队列 channel.queueDeclare(QUEUE,false,false,false,null); //定义消费者 DefaultConsumer defaultConsumer = new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,byte[] body) throws IOException{ //收到消息并处理 String message = new String(body,"UTF-8"); //确认消息,防止丢失 channel.basicAck(envelope.getDeliveryTag(),false); System.out.println(message); } }; //接收消息 channel.basicConsume(QUEUE,false,defaultConsumer); } }
获取连接、创建通道、声明队列这块和生产者一致,因为用的是同一个连接下的同一个队列。
定义消费者的时候,使用DefaultConsumer(老版本的QueueingConsumer已过期,在后续版本可能会移除),这个比较新且能手动确认消息。手动确认消息的意义在于,数据安全性。如果是自动确认消息的话,在拿到消息到给到用户的过程中,如果有存在处理消息的逻辑一旦出现故障,用户还没有拿到消息,但此时rabbitmq已经自动确认并且自动删除的话就会造成消息数据的丢失。所以要在处理消息的逻辑走完之后,再去手动确认消息,保证数据安全。
handleDelivery方法中对接受的消息进行了处理,调整为UTF-8字符集。
handleDelivery为自循环的方法,只要不关闭通道和连接,它就会一直运行,Give类每次运行推出的消息,都会被它直接接收并显示。
channel.basicAck()方法是手动确认消息,false为确认收到消息,true为拒绝收到消息。
channel.basicConsume()方法中的参数分别为:
第一个参数:接受消息用的队列名称
第二个参数:是否自动接收消息,这里用false,因为在重写的方法里已经手动确认了,所以这里就不用自动接收
第三个参数:用来接收消息的消费者实例
运行结果如下:
四、暂存问题记录
学完这个之后突然发现一个问题,就是在发送和接收消息后,是否要对通道和连接进行关闭?
从内存上来说,应该要关闭的,否则会造成内存泄漏。
但是加上通道和连接的关闭之后,有两点问题。第一点是频繁的创建连接和通道,比较浪费资源,因为本身连接和通道是可以长期使用的,第二点就是在关闭通道和连接的过程中,可能接受发送或者接受消息的操作还没有执行完,这时候可能会造成执行失败或者是报错。这块还需要多了解一些,目前就是浅显的测试学会如何使用。