RabbitMq之RPC实现

本文详细介绍了如何在RabbitMQ中实现远程过程调用(RPC)。通过客户端和服务端的交互,展示了消息的请求与响应流程,包括消息的发布、处理及结果返回。客户端通过设置correlation_id和reply_to来确保请求的唯一性和结果的正确返回。

在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();
            }
        }
    }
}
 

转载于:https://my.oschina.net/sky2008/blog/2245980

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值