3.接口Mock

接口Mock

通过给RPC框架支持mock后,开发者就可以轻松调用服务接口、跑通业务流程,不必依赖真实的远程服务,提高使用体验,通过动态代理创建一个调用方法时返回固定值的对象

执行流程

1.加载全局配置并初始化RPC框架

2.注册服务

3.启动HTTP服务器,等待请求

4.通过加载全局配置并初始化rpc框架获取代理对象并调用代理对象的方法,mock为true执行mockserviceproxy代理,mock为false,执行正常代理

5.指定序列化器,构造RPC Request

6.将请求序列化为字节数组,发送HTTP请求

7.等待接收HTTP响应

8.通过web服务器监听并接收consumer的请求

9.经过请求处理器将请求反序列化RPC Request

10.使用本地服务注册器查询 provider 中的对应服务并进行反射调用

11.将 provider 返回的结果构造为RPC Response,并将RPC Response序列化为字节数组

12.rpc发送HTTP响应

13.consumer接收响应

14.consumer将响应反序列化为RPC Request

15.consumer获取响应中的结果,mock为true返回默认结果,为false返回实际结果

接口Mock

1.开发实现

1.1修改RpcConfig

/**
 * 模拟调用
 */
private boolean mock = false;

1.2 创建Mock 服务代理(MockServiceProxy)

/**
 * Mock 代理
 */
@Slf4j
public class MockServiceProxy implements InvocationHandler {
    /**
     * 调用代理
     *
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 根据方法的返回值类型,生成特定的默认值对象
        Class<?> methodReturnType = method.getReturnType();
        log.info("mock invoke {}", method.getName());
        return getDefaultObject(methodReturnType);
    }

    /**
     * 生成指定类型的默认值对象
     * @param methodReturnType
     * @return
     */
    private Object getDefaultObject(Class<?> methodReturnType) {
        if(methodReturnType.isPrimitive()){
            // 基本类型
            if(methodReturnType == boolean.class){
                return false;
            }else if(methodReturnType == short.class){
                return (short)0;
            }else if(methodReturnType == int.class){
                return 0;
            }else if(methodReturnType == long.class){
                return 0L;
            }else if(methodReturnType == float.class){
                return 0.0f;
            }else if(methodReturnType == double.class){
                return 0.0d;
            }else if(methodReturnType == byte.class){
                return (byte)0;
            }else if(methodReturnType == char.class){
                return '\u0000';
            }else if(methodReturnType == String.class){
                return "";
            }
        }
        return null;
    }
}

1.3 创建Mock 服务代理工厂(MockServiceProxyFactory)

/**
 * Mock 代理工厂
 */
public class MockServiceProxyFactory {

    /**
     * 根据服务类获取代理对象
     *
     * @param serviceClass
     * @param <T>
     * @return
     */
    public static <T> T getProxy(Class<T> serviceClass) {
        if (RpcApplication.getRpcConfig().isMock()) {
            return getMockProxy(serviceClass);
        }

        return (T) Proxy.newProxyInstance(
                serviceClass.getClassLoader(),
                new Class[]{serviceClass},
                new JdkServiceProxy());
    }

    /**
     * 根据服务类获取代理对象
     * @param serviceClass
     * @return
     * @param <T>
     */
    public static<T> T getMockProxy(Class<T> serviceClass){
        T t = (T) Proxy.newProxyInstance(
                serviceClass.getClassLoader(),
                new Class[]{serviceClass},
                new MockServiceProxy());
        return t;
    }
}

1.4 测试-修改common 接口

/**
 * 新方法 - 获取数字
 */
default short getNumber() {
    return 1;
}

1.5 测试-修改properties文档

rpc.name=todaysaturdayrpc
rpc.version=2.0
rpc.serverPort=8081
rpc.mock = true

1.6 创建ConsumerExample类

/**
 * 服务消费者启动类
 *
 */
public class MockConsumerExample {
    public static void main( String[] args ){
        // 创建静态代理
//        UserService userService = new UserServiceProxy();
        // 创建JDK动态代理
//        UserService userService = JdkServiceProxyFactory.getProxy(UserService.class);
        // 创建CGlib动态代理
//        UserService userService = CGlibServiceProxyFactory.getProxy(UserService.class);
        // 创建Mock代理
        UserService userService = MockServiceProxyFactory.getProxy(UserService.class);
        User user = new User();
        user.setName("todaysaturday");

        User newUser = userService.getUser(user);
        if (newUser != null) {
            System.out.println(newUser.getName());
        } else {
            System.out.println("user == null");
        }
        long number = userService.getNumber();
        System.out.println(number);

    }
}

2.扩展

2.1 引入faker依赖

<dependency>
    <groupId>com.github.javafaker</groupId>
    <artifactId>javafaker</artifactId>
    <version>1.0.2</version>
</dependency>

2.2 随机生成

/**
 * 生成指定类型的默认值对象
 * @param methodReturnType
 * @return
 */
private Object getDefaultObject(Class<?> methodReturnType) {
    if(methodReturnType.isPrimitive()){
        Faker faker = new Faker();

        // 基本类型
        if(methodReturnType == boolean.class){
            return faker.bool().bool();
        }else if(methodReturnType == short.class){
            return (short)faker.number().numberBetween(1, 1000);
        }else if(methodReturnType == int.class){
            return faker.number().numberBetween(1, 100000);
        }else if(methodReturnType == long.class){
            return faker.number().numberBetween(1L, 1000000L);
        }else if(methodReturnType == float.class){
            return (float) faker.number().randomDouble(5, Long.MIN_VALUE, Long.MAX_VALUE);
        }else if(methodReturnType == double.class){
            return faker.number().randomDouble(4, 1, 10000);
        }else if(methodReturnType == byte.class){
            return (byte)faker.number().numberBetween(1, 127);
        }else if(methodReturnType == char.class){
            return faker.lorem().character();
        }else if(methodReturnType == String.class){
            return faker.lorem().sentence();
        }
    }
    return null;
}