在RabbitMQ中RPC的实现也是很简单高效的,现在我们的客户端、服务端都是消息发布者与消息接收者。
首先客户端通过RPC向服务端发出请求
我这里有一堆东西需要你给我处理一下,correlation_id:这是我的请求标识,erply_to:你处理完过后把结果返回到这个队列中。
服务端拿到了请求,开始处理并返回
correlation_id:这是你的请求标识 ,原封不动的给你。 这时候客户端用自己的correlation_id与服务端返回的id进行对比。是我的,就接收。
服务端代码:
package com.sky.study.rpc;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.sky.study.ConnectionUtil;
public class RpcServer {
private static final String RPC_QUEUE_NAME = "rpc_queue";
public static void main(String[] args) {
execute();
}
public static void execute() {
Connection connection = null;
try {
// 建立TCP连接
connection = ConnectionUtil.getConnection();
// 在TCP连接的基础上创建通道
final Channel channel = connection.createChannel();
// 声明一个rpc_queue队列
channel.queueDeclare(RPC_QUEUE_NAME, false, false, false, null);
// 设置同时最多只能获取一个消息
channel.basicQos(1);
System.out.println(" [RpcServer] Awaiting RPC requests");
// 定义消息的回调处理类
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
byte[] body) throws IOException {
// 生成返回的结果,关键是设置correlationId值
AMQP.BasicProperties replyProps = new AMQP.BasicProperties.Builder()
.correlationId(properties.getCorrelationId()).build();
// 生成返回
String response = generateResponse(body);
// 回复消息,通知已经收到请求
channel.basicPublish("", properties.getReplyTo(), replyProps, response.getBytes("UTF-8"));
// 对消息进行应答
channel.basicAck(envelope.getDeliveryTag(), false);
// 唤醒正在消费者所有的线程
synchronized (this) {
this.notify();
}
}
};
// 消费消息
channel.basicConsume(RPC_QUEUE_NAME, false, consumer);
// 在收到消息前,本线程进入等待状态
while (true) {
synchronized (consumer) {
try {
consumer.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 空值判断,为了代码简洁略
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 暂停10s,并返回结果
*
* @param body
* @return
*/
private static String generateResponse(byte[] body){
try {
String result =new String(body,"UTF-8");
System.out.println(" [RpcServer] receive requests: " + result);
Thread.sleep(1000 * 1);
return "response:" + result + "-" + System.currentTimeMillis();
}catch (Exception e) {
e.printStackTrace();
}
return "no body";
}
}
客户端代码:
package com.sky.study.rpc;
import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.sky.study.ConnectionUtil;
public class RpcClient {
private static final String RPC_QUEUE_NAME = "rpc_queue";
public static void main(String[] args) {
execute("客户端:请求");
}
public static void execute(String message) {
Connection connection = null;
Channel channel = null;
try {
// 建立TCP连接
connection = ConnectionUtil.getConnection();
// 在TCP连接的基础上创建通道
channel = connection.createChannel();
// 定义临时队列,并返回生成的队列名称
String replyQueueName = channel.queueDeclare().getQueue();
// 唯一标志本次请求
String corrId = UUID.randomUUID().toString();
// 生成发送消息的属性
AMQP.BasicProperties props = new AMQP.BasicProperties.Builder().correlationId(corrId) // 唯一标志本次请求
.replyTo(replyQueueName) // 设置回调队列
.build();
// 发送消息,发送到默认交换机
channel.basicPublish("", RPC_QUEUE_NAME, props, message.getBytes("UTF-8"));
System.out.println(" [RpcClient] Requesting : " + message);
// 阻塞队列,用于存储回调结果
final BlockingQueue<String> response = new ArrayBlockingQueue<String>(1);
// 定义消息的回退方法
channel.basicConsume(replyQueueName, true, new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
byte[] body) throws IOException {
if (properties.getCorrelationId().equals(corrId)) {
response.offer(new String(body, "UTF-8"));
}
}
});
// 获取回调的结果
String result = response.take();
System.out.println(" [RpcClient] Result:'" + result + "'");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 空值判断,为了代码简洁略
channel.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}