RabbitMQ消息队列之RPC调用

我们知道现在市面上的RPC框架很多,但是如何用我们的RabbitMQ去实现一个RPC调用呢?这就是我们这篇文章所要讲解的内容。
如果有阅读过我写的博客的大兄弟们,可能会知道,我有个习惯就是学习技术喜欢去看官方文档,同样对于RabbitMQ如何去实现RPC调用,我们先来看看官方文档怎么说。
在这里插入图片描述
在这里插入图片描述
如上图,进入RabbitMQ官网,找到get Started,然后里面会有很多基本使用方式(其他几种使用方式在我的另一篇博文里面有详细介绍:https://blog.youkuaiyun.com/baomw/article/details/84847769),找到我们的RPC,然后点及java。
在这里插入图片描述
来看官网说的这句话,什么意思呢,就是在我们声明一个客户端,然后去通过call方法去调用我们的服务端,然后实时去接收我们服务端处理后返回的结果值,显示在控制台。
在这里插入图片描述
这里呢大致说了下使用rpc调用的一些注意的地方,以及rpc调用的方法的一些不足,容易造成系统混乱,等等。旨在提醒我猿们,在开发rpc调用实现的时候需要明确调用及依赖关系。
在这里插入图片描述
当然由于我们是需要接受服务端处理结果并返回的,所有客户端这边还需要声明一个接受回调信息的回调队列。

好了下面我们来实现一个具体的rpc调用例子。首先声明我们的服务端,代码如下;

public class RPCServer {

    private static final String RPC_QUEUE_NAME = "rpc_queue";

    private static int fib(int n) {
        if (n == 0) return 0;
        if (n == 1) return 1;
        return fib(n - 1) + fib(n - 2);
    }

    public static void main(String[] argv) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");

        try (Connection connection = factory.newConnection();
             Channel channel = connection.createChannel()) {
            channel.queueDeclare(RPC_QUEUE_NAME, false, false, false, null);
            channel.queuePurge(RPC_QUEUE_NAME);

            channel.basicQos(1);

            System.out.println(" [x] Awaiting RPC requests");

            Object monitor = new Object();
            DeliverCallback deliverCallback = (consumerTag, delivery) -> {
                AMQP.BasicProperties replyProps = new AMQP.BasicProperties
                        .Builder()
                        .correlationId(delivery.getProperties().getCorrelationId())
                        .build();

                String response = "";

                try {
                    String message = new String(delivery.getBody(), "UTF-8");
                    int n = Integer.parseInt(message);

                    System.out.println(" [.] fib(" + message + ")");
                    response += fib(n);
                } catch (RuntimeException e) {
                    System.out.println(" [.] " + e.toString());
                } finally {
                    channel.basicPublish("", delivery.getProperties().getReplyTo(), replyProps, response.getBytes("UTF-8"));
                    channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
                    // RabbitMq consumer worker thread notifies the RPC server owner thread
                    synchronized (monitor) {
                        monitor.notify();
                    }
                }
            };

            channel.basicConsume(RPC_QUEUE_NAME, false, deliverCallback, (consumerTag -> { }));
            // Wait and be prepared to consume the message from RPC client.
            while (true) {
                synchronized (monitor) {
                    try {
                        monitor.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

里面声明一个方法fib(int i),递归调用自己,有点算法基础的大兄弟们可能知道,这个是算我们的斐波那契数列求和。

public class RPCClient implements AutoCloseable {

    private Connection connection;
    private Channel channel;
    private String requestQueueName = "rpc_queue";

    public RPCClient() throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");

        connection = factory.newConnection();
        channel = connection.createChannel();
    }

    public static void main(String[] argv) {
        try (RPCClient fibonacciRpc = new RPCClient()) {
            for (int i = 0; i < 32; i++) {
                String i_str = Integer.toString(i);
                System.out.println(" [x] Requesting fib(" + i_str + ")");
                String response = fibonacciRpc.call(i_str);
                System.out.println(" [.] Got '" + response + "'");
            }
        } catch (IOException | TimeoutException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    public String call(String message) throws IOException, InterruptedException {
        final String corrId = UUID.randomUUID().toString();

        String replyQueueName = channel.queueDeclare().getQueue();
        AMQP.BasicProperties props = new AMQP.BasicProperties
                .Builder()
                .correlationId(corrId)
                .replyTo(replyQueueName)
                .build();

        channel.basicPublish("", requestQueueName, props, message.getBytes("UTF-8"));

        final BlockingQueue<String> response = new ArrayBlockingQueue<>(1);

        String ctag = channel.basicConsume(replyQueueName, true, (consumerTag, delivery) -> {
            if (delivery.getProperties().getCorrelationId().equals(corrId)) {
                response.offer(new String(delivery.getBody(), "UTF-8"));
            }
        }, consumerTag -> {
        });

        String result = response.take();
        channel.basicCancel(ctag);
        return result;
    }

    public void close() throws IOException {
        connection.close();
    }
   }

客户端这边呢循环调用我们的call方法,在call方法中,实时去调用服务端并返回response,
然后String result = response.take(); 获取到我们的返回结果。
到这里呢我们也就大致可以看出来,首先客户端发出一个数给服务端,服务端算出该数对应的斐波那契数并返回给我客户端打印到控制台,我们来看下具体实现效果。
在这里插入图片描述
在这里插入图片描述
可以看到,我们服务端处有31次打印,说明方法执行了31次调用,客户端对应有31个返回值打印出来。

由此,便利用我们的RabbitMQ实现了一个简单的rpc调用了!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值