手动实现简易版RPC(三)

发布于:2024-05-02 ⋅ 阅读:(33) ⋅ 点赞:(0)

手动实现简易版RPC(三)

往期内容

前言

接上两篇博客我们实现了最简易RPC框架,接下来的几期重点在简易版的rpc框架上继续深耕。本文主要介绍简易版RPC 中mock假数据相关的内容。


RPC(Remote Procedure Call)框架的核心在于通过网络实现远程过程调用,使得调用远程服务如同调用本地服务一样方便。但是在实际开发中,可能在调用远程过程中不会特别的顺利,会遇到一些不可控的问题,比如网络不通?服务不稳定等不可预测的问题。

那么为了保证我们这边的开发顺利性,可能会使用mock这一服务来模拟远程返回的数据,进行更好的业务联调。

什么是mock?

简单介绍一下mock

"MOCK"通常指的是创建一个模拟的对象或功能,以替代实际的对象或功能,从而进行测试或其他操作。这样做的主要目的是隔离测试环境,使其只关注被测试的部分,而不受其他依赖项的影响。通过使用MOCK,开发者或测试人员可以模拟外部系统、数据库、网络请求或其他难以直接控制的依赖项,从而更容易地控制测试环境,确保测试的准确性和可靠性。

举个🌰

public class CatServiceImpl {
   void test(){
       doSomething();
       CatService.getCat();
       doSomething();
   }
}

在上述代码中,如果CatService.getCat()尚未开发完成或者由于一些不可控原因调不通,那么在测试这段代码的时候,整个流程是走不通的,只能注释掉CatService.getCat()这个方法。而mock的作用是能够模拟出一个CatService并调用它的getCat()方法。这样一来的话,可以比较顺了的跑通整个流程。

为什么支持mock?

虽然 mock 服务并不是 RPC 框架的核心能力,但是它的开发成本并不高。而且给 RPC 框架支持 mock后,开发者就可以轻松调用服务接口、跑通业务流程,不必依赖真实的远程服务,提高使用体验,何乐而不为呢?

我们希望能够用最简单的方式 – 比如一个配置,就让开发者使用 mock 服务。

设计方案

上文也讲到了mock旨在创建一个模拟对象,供调用方使用。

但是怎么调用产生一个模拟对象呢?

在这里插入图片描述

仔细想想,是不是可以通过动态代理的方式,产生一个对象,在调用方调用该对象的时候,返回一个固定的返回值,这样是不是就🆗了?

具体实现

1- 我们实现mock是可配置的,通过读取配置信息来获取用户是否开启mock。在之前的RpcConf中添加一个mock属性

....
 /***
     * 是否开启模拟数据模式
     * 默认不开启mock
     */
    private boolean mock = false;

2-在proxy包中添加MockServiceProxy类,用于生成mock模拟服务。其中通过自定义方法getDefaultObject根据方法返回值的类型进行默认值的返回,比如返回值类型为 int的方法,默认返回0,返回值为boolean的方法返回值默认为false。

/**
 * @version 1.0
 * @Author jerryLau
 * @Date 2024/4/12 15:42
 * @注释 MockServiceProxy 类
 * 采用JDK动态代理
 * 开启Mock服务代理
 */
@Slf4j
public class MockServiceProxy implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        Class<?> returnType = method.getReturnType();
        log.info("MockServiceProxy invoke method: {}, returnType: {}", method.getName(), returnType.getName());

        return getDefaultObject(returnType);
    }


    /***
     * 根据返回类型返回默认值
     * @param returnType
     * @return
     */
    public Object getDefaultObject(Class<?> returnType) {
        log.info("MockServiceProxy getDefaultObject returnType: {}", returnType.getName());
        if (returnType == int.class) {
            return 0;
        } else if (returnType == long.class) {
            return 0L;
        } else if (returnType == double.class) {     // double 类型默认值是 0.0
            return 0.0;
        } else if (returnType == boolean.class) {
            return false;        // boolean 类型默认值是 false
        } else if (returnType == Short.class) {
            return (short) 0;
        }
        //对象返回null
        return null;
    }
}

3-在代理工厂类ServiceProxyFactory中添加关于mock的判定以及返回一个mock代理对象,通过获取配置管理器中用户是否开启了mock,如果开启了mock,则返回一个mock代理对象。

//配置管理器中是否开启Mock模式
        if (RPCGlobalConfHolder.getRpcConfig().isMock()) {
            return (T) getMockProxy(serviceClass);
        }

/***
     * get mock proxy
     * @param serviceClass
     * @return
     * @param <T>
     */
    public static <T> T getMockProxy(Class<T> serviceClass) {
        return (T) Proxy.newProxyInstance(
                serviceClass.getClassLoader(),
                new Class[]{serviceClass}
                , new MockServiceProxy()
        );
    }

简单测试

上述过程简单实现了mock的自定义配置,接下来我们可以简单的进行测试。

1-将example-common模块中的获取cat接口中添加一个默认方法getCatCount,用于获取猫的数量

/**
     * 获取猫咪数量
     * @return
     */
    default int getCatCount() {
        return 100;
    }

在默认不开启mock的情况下,在example-consumerEasyConsumer简单消费者中调用获取猫咪数量的方法

在默认不开启mock的时候,可以看到获取到的猫咪数量是默认的数量100

在这里插入图片描述

修改application.yml文件 配置mock属性为 true,开启mock

RPC:
  name: "ape-rpc1"
  serverPort: 8080
  version: "1.0.0"
  serverHost: "localhost233"
  mock: true

在此运行消费者程序,发现获取到的猫咪的数量是0,而不是100,说明mock生效。

在这里插入图片描述


至此,我们实现了简易版的PRC框架中的mock功能

码字不易,希望大家能够一键三连🌝⭐🌟


代码仓库 ape-rpc: 轮子项目,手动实现rpc github🌐 || ape-rpc: 轮子项目,手动实现rpc gitee🌐