这是我参与8月更文挑战的第15天,活动详情查看:8月更文挑战
RabbitMQ入门程序
- 新建一个Maven项目,导入rabbitMq的maven依赖(java原生依赖)
<!-- https://mvnrepository.com/artifact/com.rabbitmq/amqp-client -->
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.10.0</version>
</dependency>
-
生产者往RabbitMQ中投递消息及消费者要从队列中消费消息,首先要和RabbitMQ取得连接然后创建交换机、声明队列等一系列步骤才能完成消息的投递和消费,主要分为以下几个步骤:
1、创建连接工厂
2、创建连接Connection
3、通过连接获取Channel信道
4、通过创建交换机,声明队列、绑定关系、路由key、发送消息、接收消息
5、准备消息内容
6、发送消息给队列queue
7、关闭Channel通道
8、关闭Connection连接
- 下面将获取连接、获取信道和最后关闭连接和信道封装到工具类中
public class RabbitMQUtil {
public static Connection getChannel(String connectionName) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.180.130");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
//2、创建连接Connection
Connection connection = connectionFactory.newConnection(connectionName);
return connection;
}
public static void close(Channel channel,Connection connection) throws IOException, TimeoutException {
//7、关闭通道
if(channel!=null&& channel.isOpen()){
channel.close();
}
//8、关闭连接
if(connection!=null&& connection.isOpen()){
connection.close();
}
}
}
生产者
public class Producer {
public static void main(String[] args) throws IOException, TimeoutException {
//获取连接
Connection connection = RabbitMQUtil.getChannel("生产者");
//根据连接获取Channel
Channel channel = connection.createChannel();
//定义一个队列名称
String queueName = "queue3";
/**
* @params1 队列的名称
* @params2(durable) 是否持久化durable-false ,即消息是否存盘,非持久化队列会存盘,但当MQ服务器重启之后,非持久化队列会被移除,消息会丢失
* @params3 (exclusive)排他性、是否是独占独立
* @params4 (autoDelete)是否自动删除,随着最后一个消费者把消息消费完毕后是否把队列自动删除
* @params5 (arguments)携带附属参数
*/
//4.1声明队列
channel.queueDeclare(queueName, true, false, false, null);
//5、准备消息内容
String message = "不喝奶茶的Programmer";
//6、发送消息给队列queue
/**
* basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body)
* String exchange:交换机
* String routingKey :路由key
* BasicProperties props: 封装有待发送消息的相关属性
* byte[] body params4:消息主体
*/
channel.basicPublish("", queueName, null, message.getBytes());
RabbitMQUtil.close(channel,connection);
}
}
以上涉及到的两个方法:
-
queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)方法使用来声明队列的,其中每个参数表示如下:String queue队列的名称boolean durable是否持久化,即消息是否存盘,durable=true表示消息会存盘。如果durable=false,表示声明的是一个非持久化队列,当MQ服务器重启之后,非持久化队列会被移除,消息会丢失。boolean exclusive是否是排他的,当exclusive=true表示队列是排他的,那么该队列仅对首次声明它的连接可见, 并在连接断开时自动删除。boolean autoDelete是否自动删除,如果autodelete=true时,当至少有一个消费者连接到这个队列,之后所有与这个队列连接的消费者都断开时,该队列会被自动删除掉。Map<String, Object> arguments设置队列的其他一些参数,
-
basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body)方法是生产者用来发送消息的。其中每个参数表示如下:-
String exchange交换机名称。这里我们传进去的是一个空字符串,代表使用默认的交换机AMQP default(默认的交换机类型为Direct),当我们创建一个队列时,默认的都会有一个和新建队列同名的routing key(也可以说是binding key)绑定到这个默认的exchange上去。 -
String routingKey路由键。第二个参数我们传入是队列名称其实就是routing key,因为我们用空字符串去声明一个exchange,所以会使用默认的交换机,因此投递消息时采用的routing key就是与默认交换机绑定的队列的名称。 -
BasicProperties props传递消息额外设置 -
byte[] body消息主体
-
消费者
public class Consumer {
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = RabbitMQUtil.getChannel("消费者");
//通过连接获取channel
Channel channel = connection.createChannel();
//4、推模式,接收消息,从queue3队列中接收消息
channel.basicConsume("queue3", true, new DeliverCallback() {
//消费者回调函数,处理发送过来的消息
public void handle(String s, Delivery message) throws IOException {
System.out.println("收到的消息是:" + new String(message.getBody(), "UTF-8"));
}
}, new CancelCallback(){
//消费者取消订阅时的回调方法。
public void handle(String s) throws IOException {
System.out.println("");
}
});
}
}
以上涉及的方法:
-
basicConsume(String queue, boolean autoAck, DeliverCallback deliverCallback, CancelCallback cancelCallback)方法是消费者用来接收消息的。在RabbitMQ中,消费者可以以推模式和拉模式两种方式来消费消息,basicConsume方法代表的是一种推模式,由服务端主动推送消息到消费者,消费者在回调方法中处理消息,然后响应服务端。basicGet方法代表的是一种拉模式,消费者每次主动从队列中拉起单条消息消费,然后响应服务端。-
String queue队列名称,指定从哪个队列中获取消息 -
boolean autoAck是否自动回复ACK(mq的ACK主要是确认消息被消费者消费完成后通知服务器将队列里面的消息清除,手动确认的情况下,消费者每消费一条消息都需要手动发送ACK给Mq服务器后,才能继续消费下一条消息,如果此时没有进行手动确认,会进行阻塞Unacked,当消费者关闭后,已被消费的消息会重回队列), 当auto=true,表示消费者接收到传递过来的消息后自动应答服务器,当auto=false,表示接收到消息后不应答服务器,如果这时不进行手动ACK,即使消费者断开连接后,消息仍然会一直存在消息队列中,造成消息堆积。调用手动ACK方法👉channel.basicAck(deliveryTag消息序列号,multiple是否手动ACK多条消息); -
DeliverCallback deliverCallback消费者回调函数,处理发送过来的消息 -
CancelCallback cancelCallback消费者取消订阅时的回调方法。
-
-
完成上面的生产者和消费者代码编写后,先启动生产者程序,当生产者成功执行后,我们从Web端可以看到RabbitMQ新建了一个
queue3队列,并且我们成功往queue3队列中投递了消息不喝奶茶的Programmer,从下图也可以看到投递到我们的queue3队列的交换机是默认交换机AMQP default,如下图
从下图可以看到,我们没有声明一个交换机的情况下,会将队列queue3绑定到默认的交换机AMQP default上。
- 紧接着我们启动消费者程序,从queue3中获取消息,消息获取后,会调用回调函数,输出我们获取的消息内容,程序输出如下:
收到的消息是:不喝奶茶的Programmer
🚨🚨注意:如果遇到以下错误,则是RabbitMQ服务器没有开放对应的端口
Caused by: com.rabbitmq.client.ShutdownSignalException:connection error;
protocol method: #method<connection.close>(reply-code=530, reply-text=NOT_ALLOWED - access to vhost '/' refused for user 'admin', class-id=10, method-id=40)
万事不要慌😋!只需要到终端开放一下端口的就OK啦
systemctl status firewalld
firewall-cmd --list-ports
firewall-cmd --zone=public --add-port=5672/tcp --permanent
firewall-cmd --zone=public --add-port=15672/tcp --permanent
firewall-cmd --zone=public --add-port=15674-15675/tcp --permanent
firewall-cmd --zone=public --add-port=1883/tcp --permanent
firewall-cmd --reload
🏁以上就是对RabbitMQ入门程序的详细解释,如果有错误的地方,还请留言指正,如果觉得本文对你有帮助那就点个赞👍吧😋😻😍