简单模式(Simple)
在这一部分中,我们将用Java编写两个程序;
一个是生产者发送单个消息,另一个是接收消息并将其打印出来的消费者。
P:生产者;红色部分:队列;C:消费者
The Java client library
RabbitMQ支持多种协议。本教程使用AMQP 0-9-1,它是一种开放的,通用的消息传递协议。
RabbitMQ有许多不同语言的客户端。我们将使用RabbitMQ提供的Java客户端。
下载客户端库及其依赖项(SLF4J API和SLF4J Simple)。
请注意SLF4J Simple足以用于教程,但您应该使用像生产中的Logback这样的完整日志库。
(RabbitMQ Java客户端也位于Maven中央存储库中,包含groupId com.rabbitmq和artifactId amqp-client。)
现在我们有了Java客户端及其依赖项,我们可以编写一些代码。
Sending
我们消息发布者(sender)定义为对象Send,消息消费者(接收者)定义为对象Recv。发布者将连接到RabbitMQ,发送单个消息,然后退出。
导入相关依赖:
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
</dependency>
获取MQ连接:
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class ConnectionUtils {
public static Connection getConnection() throws Exception{
//定义连接工厂
ConnectionFactory factory=new ConnectionFactory();
//设置服务地址
factory.setHost("localhost");
//设置端口
factory.setPort(5672);
//设置账号信息:用户名、密码、vhost
factory.setVirtualHost("testhost");
factory.setUsername("admin");
factory.setPassword("123456");
//通过工程获取连接
Connection connection=factory.newConnection();
return connection;
}
}
生产者发送消息到队列:
public class Send {
private final static String QUEUE_NAME="hello"; //命名队列
public static void main(String[] args) throws Exception{
try (Connection connection= ConnectionUtils.getConnection(); Channel channel=connection.createChannel()){
//声明队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
String message="hello rabbitMQ!";
channel.basicPublish("",QUEUE_NAME,null,message.getBytes());
System.out.println("[x] Sent '"+message+"'");
}
}
}
获取连接后创建一个频道,这是完成任务的大部分API所在的位置。注意我们可以使用try-with-resources语句,因为Connection和Channel都实现了java.io.Closeable。
这样我们就不需要在代码中明确地关闭它们。
声明队列是幂等的 —— 只有在它不存在的情况下才会创建它。
管理工具中查看消息
Send代码运行之后,可以在管理工具中看到消息
点击上面的Name对应的名称,查询具体的队列中的信息:
Receiving
刚才的是发布者(publisher)。我们的消费者应该一直监听来自RabbitMQ的消息,因此与发布单个消息的发布者不同,我们将保持其运行以监听消息并将其打印出来。
消费者从队列中获取消息:
public class Recv {
private final static String QUEUE_NAME="hello";
public static void main(String[] args) throws Exception{
//获取连接以及频道
Connection connection= ConnectionUtils.getConnection();
Channel channel=connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
DeliverCallback callback=(consumerTag,delivery)->{
String message=new String(delivery.getBody(),"UTF-8");
System.out.println(" [x] Received '" + message + "'");
};
//监听队列
channel.basicConsume(QUEUE_NAME,true,callback,consumerTag->{});
}
}
请注意,我们也在这里声明了队列。因为我们可能在发布者之前启动消费者,所以我们希望在使用消息之前确保队列存在。
为什么我们这里不使用try-with-resource语句来自动关闭通道和连接?
如果这样做,程序会先运行,然后关闭所有连接,然后退出!这将是尴尬的,因为我们希望在消费者异步监听消息到达时,该进程保持活动状态。
我们要告诉服务器把队列中的消息传递给我。因为它会异步地向我们发送消息,所以我们以对象的形式提供一个回调,它将缓冲消息,直到我们准备好使用它们。这就是DeliverCallback的作用。