RPC,即远程过程调用,其流程如下:
RPC实现RPC,则需要客户端(生产者)发送请求消息,服务端(消费者)回复响应的消息,为了接受响应的消息,我们需要在请求消息中发送给一个回调队列。
流程图如下:
1.客户端启动时,创建一个匿名的回调队列,使用channel.queueDeclare().getQueue()创建一个默认的队列即可
2.客户端为RPC消息创建两个属性,一是ReplyTo即回调队列,二是correlationId,用来将消息和请求匹配。
3.请求被发送到rpc_queue队列中。
4.RPC服务端监听rpc_queue队列中的请求,当请求到来时,服务端会处理,并把带有结果的消息发送给客户端。接受的队列就是replyTo设置的回调队列。
5.客户端监听回调队列,当有消息时,检查correlationId属性,如果与请求匹配,那就是结果。
实现代码如下:
//服务端
public class RPCserver {
private static final String RPC_QUEUE_NAME="rpc_queue";
public static void main(String[] args) throws Exception {
//建立连接
Connection connection=ConnectionUtil.getConnection();
Channel channel=connection.createChannel();
//声明一个队列,该队列用于存储RPC消息
channel.queueDeclare(RPC_QUEUE_NAME,true,false,false,null);
//最多消费的信息个数,消费者接受到消息但是还没有向生产者回复确认之前,不会接受新的消息
channel.basicQos(1);
System.out.println("Waiting RPC request");
DefaultConsumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body) throws IOException{
AMQP.BasicProperties replyProps=new AMQP.BasicProperties
.Builder().
correlationId(properties.getCorrelationId()).
build();
String response="";
String message=new String(body);
int n=Integer.parseInt(message);
//产生回复,n+1
response=String.valueOf(n+1);
System.out.println(response);
channel.basicPublish("",properties.getReplyTo(),replyProps,response.getBytes());
channel.basicAck(envelope.getDeliveryTag(),false);
}
};
channel.basicConsume(RPC_QUEUE_NAME,false,consumer);
}
}
public class RPCClient {
private Connection connection;
private Channel channel;
private static final String RPC_QUEUE_NAME="rpc_queue";
public void creatClient(){
//获取连接
try {
connection=ConnectionUtil.getConnection();
channel=connection.createChannel();
//创建匿名的回调队列
String replyQueueName=channel.queueDeclare().getQueue();
//生成correlationID,用来判断该消息与哪个请求对应
final String uuid= UUID.randomUUID().toString();
AMQP.BasicProperties props=new AMQP.BasicProperties().builder().correlationId(uuid).replyTo(replyQueueName).build();
String message=String.valueOf(new Random().nextInt(100));
System.out.println("message:"+message);
channel.basicPublish("",RPC_QUEUE_NAME,props,message.getBytes());
//接受返回的结果
Consumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body)
throws IOException
{
while (true){
if(properties.getCorrelationId().equals(uuid)){
String serverResponse=new String(body);
System.out.println(" server response:"+serverResponse);
}
break;
}
}
};
channel.basicConsume(replyQueueName,true,consumer);
Thread.sleep(30000);
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
RPCClient client = new RPCClient();
client.creatClient();
}
}