目录
远程过程调用(RPC): 当客户端发送请求到远程服务器,远程服务器接收请求并处理结果,这时候将结果响应给客户端,这个过程被称为远程过程调用
队列
在整个过程中用会涉及到两个队列一个是专门保存请求的队列,称为rpc_queue,另一个队列被称为响应队列,专门用于保存服务器处理的响应结果,这个队列的名字是随机生成的字符串。
消息的基本属性BasicProperties
响应队列名字 回复(replyTo):是响应队列的名字,当服务器接收并处理好结果,这时候服务器需要知道将响应的信息发送到哪个队列中;
关联id(correlationId):是一个UUID值,发消息的时候会带上这个值,该值在客户端接收响应时用于判断接收到的响应消息是否是自己发出请求对应的响应; 客户端在发送请求时需要带上replyTo和correlationId两个属性。
过程描述
客户端发送消息到请求队列,在发送请求时需要指定两个值(replyTo和correlationId)----------->服务端为随时接受到请求消息,需要预先订阅请求队列(rpc_queue),,当服务端接收到请求消息时对请求进行处理,将处理结果发送到响应队列(随机队列)中--------------->客户端也需要预先订阅响应队列(随机队列),以便服务器发送响应消息到响应队列中,客户端能及时收到响应结果,服务器在将响应发送到响应队列中还要指定correlationId值(唯一标识),这样客户端接收到消息时就可以通过correlationId的值是否和发送请求的关联id值是否相同,如果相同就证明这个响应结果就是这个请求对应的响应结果。
注意:这个预先订阅响应队列的步骤需要在客户端中完成,最好在客户端发送请求消息前就完成。.
代码
服务端:
package com.ll.mq.hellomq.rpc;
import java.io.IOException;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
//ll
public class Service {
public static void main(String[] args) {
try {
// 创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
// 设置RabbitMQ地址
factory.setHost("127.0.0.1");
factory.setPort(5672);
factory.setUsername("kysc");
factory.setPassword("123456");
// 创建一个连接
Connection connection = factory.newConnection();
// 创建一个频道
final Channel channel = connection.createChannel();
String rpc_queuqu = "rpc_queue";
channel.queueDeclare(rpc_queuqu, false, false, false, null);
// DefaultConsumer类实现了Consumer接口,通过传入一个频道,告诉服务器我们需要那个频道的消息,如果频道中有消息,就会执行回调函数handleDelivery
DefaultConsumer consumer = 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");
// 服务器端接收到消息并处理消息
String response = "{'code': 200, 'data': '" + message+ "'}";
// // 将消息发布到reply_to响应队列中
AMQP.BasicProperties replyProperties = new AMQP.BasicProperties.Builder().
correlationId(properties.getCorrelationId()).build();
String replyTo = properties.getReplyTo();
channel.basicPublish("", replyTo, replyProperties, response.getBytes("UTF-8"));
System.out.println("服务端:请求已处理完毕,响应结果" + response + "已发送到响应队列中");
// // 手动应答
channel.basicAck(envelope.getDeliveryTag(), true);
}
};
// 自动回复队列应答
channel.basicConsume(rpc_queuqu, false, consumer);
} catch (Exception e) {
e.printStackTrace();
}
}
}
客户端
package com.ll.mq.hellomq.rpc;
import java.io.IOException;
import java.util.UUID;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
public class Client {
public static void main(String[] args) {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
factory.setPort(5672);
factory.setUsername("kysc");
factory.setPassword("123456");
try {
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
// 预先订阅响应结果的队列,先订阅响应队列,再发送消息到请求队列
String reyply_to_queue = channel.queueDeclare().getQueue();
final String correlationId = UUID.randomUUID().toString();
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
if (properties.getCorrelationId().equals(correlationId)) {
String message = new String(body, "UTF-8");
System.out.println("已接收到服务器的响应结果:" + message);
}
}
};
channel.basicConsume(reyply_to_queue, true, consumer);
// 将消息发送到请求队列中
String rpc_queuqu = "rpc_queue";
String message = "Hello RabbitMQ";
AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder().correlationId(correlationId).replyTo(reyply_to_queue).build();
channel.basicPublish("", rpc_queuqu, properties, message.getBytes("UTF-8"));
System.out.println("已发出请求请求消息:" + message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果
客户端
已发出请求请求消息:Hello RabbitMQ
已接收到服务器的响应结果:{'code': 200, 'data': 'Hello RabbitMQ'}
服务端
服务端:请求已处理完毕,响应结果{'code': 200, 'data': 'Hello RabbitMQ'}已发送到响应队列中