要想使用RabbitMQ客户端的API,首先要引入依赖。
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.10.0</version>
</dependency>
</dependencies>
无论是生产消息还是消费消息,都要先获取RabbitMQ
的连接!
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("49.232.202.201");
//factory.setPort(5672);//默认端口是5672可以不设置
factory.setUsername("gosuncn");
factory.setPassword("123456");
factory.setVirtualHost("/gosuncn");//根据虚拟主机权限设置,设置具有可访问权限的虚拟主机。
创建一个连接工厂,设置主机、端口、用户名、密码、虚拟主机
等信息。
Connection connection = factory.newConnection();
通过连接工厂,获取一个信道 Channel
,通过信道进行数据传输;那么信道是什么?
我们知道:RabbitMQ通过TCP连接实现AMQP协议数据的交换,但TCP连接的创建和销毁都是非常消耗资源的!于是,RabbitMQ就通过信道的方式进行数据传输,具体来说,如果把TCP连接比作是一个大的管道,那么信道就是TCP这个大管道中的一个小管道。
Channel channel = connection.createChannel();
信道可以声明一个队列:如果声明的队列不存在,就创建一个队列;若已存在,就不创建。
/**
* String queue 队列名称
* boolean durable 是否持久化
* boolean exclusive 是否排外[比如:一个消费者已经连接该队列,如果设置为true,其他消费者就无法连接该队列]
* boolean autoDelete 是否自动删除[没有信道连接该队列时,是否自动删除该队列]
* Map<String, Object> arguments 参数
*/
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
Tip:若一个队列已经声明被创建,那么队列的属性就不可以更改,否则抛出异常。
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
再执行以下代码就会,抛出异常!
channel.queueDeclare(QUEUE_NAME, false, true, false, null);
属性不可再更改了!
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class SendMessage {
private final static String QUEUE_NAME = "hello";
private final static String MESSAGE = "Hello World";
public static void main(String[] args) {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("49.232.202.201");
//factory.setPort(5672);//默认端口是5672可以不设置
factory.setUsername("gosuncn");
factory.setPassword("123456");
factory.setVirtualHost("/gosuncn");//根据虚拟主机权限设置,设置具有可访问权限的虚拟主机。
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
/**
* String queue 队列名称
* boolean durable 是否持久化
* boolean exclusive 是否排外[比如:一个消费者已经连接该队列,如果设置为true,其他消费者就无法连接该队列]
* boolean autoDelete 是否自动删除[没有信道连接该队列时,是否自动删除该队列]
* Map<String, Object> arguments 参数
*/
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.basicPublish("", QUEUE_NAME, null, MESSAGE.getBytes());
System.out.println("message [" + MESSAGE + "] be sent");
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
将连接和信道声明在try
后的括号中,可自动调用关闭方法。
上面代码,第一次运行会创建一个名为hello
的队列,第二次运行就不会创建了,这样可以保证虚拟主机中有一个名为hello
的队列。
channel.basicPublish("", QUEUE_NAME, null, MESSAGE.getBytes());
第一个参数是交换机的名称,""
表示默认交换机,类型其实是属于直连交换机
,以后会具体介绍交换机类型。
第二个参数是路由的名称,在连接默认交换机时,路由键其实就是队列的名称。
第三个参数是属性对象。
第四个参数是发送的消息字节数组。
运行结果:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
message [Hello World] be sent
Process finished with exit code 0
接下来,我们再看看消费者代码
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 ReceiveMessage {
private final static String QUEUE_NAME = "hello";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("49.232.202.201");
//factory.setPort(5672);//默认端口是5672可以不设置
factory.setUsername("gosuncn");
factory.setPassword("123456");
factory.setVirtualHost("/gosuncn");//根据虚拟主机权限设置,设置具有可访问权限的虚拟主机。
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
/**
* String queue 队列名称
* boolean durable 是否持久化
* boolean exclusive 是否排外[比如:一个消费者已经连接该队列,如果设置为true,其他消费者就无法连接该队列]
* boolean autoDelete 是否自动删除[没有信道连接该队列时,是否自动删除该队列]
* Map<String, Object> arguments 参数
*/
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.basicConsume(QUEUE_NAME, true, (consumerTag, message) -> {
System.out.println("DeliverCallback's consumerTag is {" + consumerTag + "}");
System.out.println("消费消息的内容 = " + new String(message.getBody()));
}, consumerTag -> System.out.println("CancelCallback's consumerTag is {" + consumerTag + "}"));
}
}
前面都是同样的声明,不同的是:
第一个:我们并没有将Connection和Channel写在try的括号里。因为,我们不能关闭消费者,我们需要等待接收消息到来。
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
第二个:同样是要声明一个队列,来确保虚拟主机中,有这么一个队列存在,不然会抛出异常!但是不同的是我们需要消费消息:
channel.basicConsume(QUEUE_NAME, true, (consumerTag, message) -> {
System.out.println("DeliverCallback's consumerTag is {" + consumerTag + "}");
System.out.println("消费消息的内容 = " + new String(message.getBody()));
}, consumerTag -> System.out.println("CancelCallback's consumerTag is {" + consumerTag + "}"));
第一个参数:队列的名称。
第二个参数:是否自动确认消息。
第三个参数:收到消息后的消息回调。
第四个参数:消息被取消时的回调。
ReceiveMessage程序启动后,将进入阻塞状态,一直等待消息!
测试运行,第一步将ReceiveMessage程序启动,程序阻塞
第二步:运行SendMessage程序
图中,看到程序结束,消息被发送到了RabbitMQ中。紧接着,之前的ReceiveMessage程序收到消息,并输出的消息内容,如图:
第三步:再运行SendMessage程序一次,ReceiveMessage程序又收到一条消息
客官!到这里,RabbitMQ基本的操作和运行就结束了。拜拜~~