RabbitMQ学习(五)—— 实现RPC

RPC

  先说下什么是rpc,rpc(remote procedure call)即远程过程调用,相对的是本地过程调用,本地调用就像你在一个单体系统中的用户模块去调用订单的接口。而rpc就是把系统之间调用用户系统与订单系统互不影响,而订单系统开放了接口,用户系统通过某种通信协议去调用该接口。一般我们称调用方为客户端,提供接口的一方称为服务端。

当然,rpc的框架也有很多,比如spring cloud、阿里的dubbo、Facebook 的 Thrift、Google 的 gRPC、Twitter 的 Finagle等,此处不详细讲,知道这个意即可,仅为我们通过RabbitMQ实现rpc铺路。

RabbitMQ实现rpc流程

客户端发送请求到请求队列,这里有个correlationId,这个参数是用来标记这个完整的请求,因为如果没有这个参数,你从回复队列中获取的数据不知道是哪个请求回复的数据。而当客户端发送请求和服务端返回数据指定相同的correlationId,我们只要在客户端判断correlationId则知道是哪一个请求。
客户端代码:

@Slf4j
public class MyRpcClient {
    private Connection conn= RabbitmqUtil.conn();
    private Set<String> correlationIds=new HashSet<>();
    public void sendAndReceive() {
        try (Channel channel=conn.createChannel()){
            //声明回复队列
            channel.queueDeclare("replyQueue1",true,false,false,null);
            //声明请求队列
            channel.queueDeclare("rpcQ1",true,false,false,null);
            String correlationId= UUID.randomUUID().toString();
            correlationIds.add(correlationId);
            channel.basicConsume("replyQueue1",false,new DefaultConsumer(channel){
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    super.handleDelivery(consumerTag, envelope, properties, body);
                    log.info("收到服务端响应");
                    correlationIds.forEach(s->{
                        if (s.equals(properties.getCorrelationId())){
                            log.info("{}:{}","相应数据",new String(body));
                        }
                    });
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            });
            AMQP.BasicProperties basicProperties=new AMQP.BasicProperties().builder()
                    .contentType(MessageProperties.PERSISTENT_TEXT_PLAIN.getContentType())
                    .correlationId(correlationId)
                    .replyTo("replyQueue1")
                    .build();
            //默认交换器"",是direct类型。且当声明队列的时候都会绑定到默认队列。so这里没有绑定的代码
            channel.basicPublish("","rpcQ1",basicProperties,"我要你返回我hello".getBytes());
            log.info("client发送请求");
            Thread.sleep(60*1000);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            RabbitmqUtil.close(conn);
        }
    }
}

服务端代码:

public class MyRpcServer {
    private Connection conn= RabbitmqUtil.conn();
    public void receiveAndReply() {
        try (Channel channel=conn.createChannel()){
            //声明请求队列
            channel.queueDeclare("rpcQ1",true,false,false,null);
            channel.basicConsume("rpcQ1",false,new DefaultConsumer(channel){
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    super.handleDelivery(consumerTag, envelope, properties, body);
                    AMQP.BasicProperties basicProperties=new AMQP.BasicProperties().builder()
                            .contentType(MessageProperties.PERSISTENT_TEXT_PLAIN.getContentType())
                            .correlationId(properties.getCorrelationId())
                            .build();
                    channel.basicPublish("",properties.getReplyTo(),basicProperties,"hello".getBytes());
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            });
            Thread.sleep(60*1000);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            RabbitmqUtil.close(conn);
        }
    }
}

测试代码:

  @Test
  private void test() {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        executorService.submit(() -> {
            new MyRpcServer().receiveAndReply();
        });
        executorService.submit(() -> {
            new MyRpcClient().sendAndReceive();
        });
        try {
            Thread.sleep(60*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

看下运行结果

后话

虽然我们使用RabbitMQ实现了rpc,但是在现实场景大多不会使用这种方式进行RPC,当我们要调用多个接口,甚至所调用的接口在去调用其他的接口,其实现的复杂度较高。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈大侠在江湖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值