java实现dubbo代码远程调用-泛化调用 方式

学习目标:

通过纯java代码实现dubbo的调用,只涉及消费者部分调用。

tips:不涉及spring的版本


学习内容:

本人通过dubbo的泛化调用,结合网上的一些参考文档,总结了本文章。
dubbo中文文档:
https://cn.dubbo.apache.org/zh/docs3-v2/java-sdk/advanced-features-and-usage/service/generic-reference/
参考其他大佬分享的文档:
https://zhuanlan.zhihu.com/p/68903627


学习时间:

在开发中,有的时候苦于API没有实时同步或者其他因素,导致mock的时候会有各种奇葩问题,经过学习,发现可以用泛化调用完成dubbo的测试。
具体做法如下:

1、先设计开发通用的调用接口和请求类,与生产者那边保持一致(包结构)

在这里插入图片描述

2、设计一个dubbo的utils类,用于实际的调用

  1. 在设置 ReferenceConfig 时,使用 setGeneric("true") 来开启泛化调用
  2. 在设置 ReferenceConfig 时,使用 setGeneric("true") 来开启泛化调用
  3. 配置完 ReferenceConfig 后,使用 referenceConfig.get() 获取到 GenericService 类的实例
  4. 使用其 $invoke 方法获取结果
  5. 其他设置与正常 Api 服务启动一致即可
public class DubboUtils {
    
    

    //todo 正常,zk、host、groupId、version都是从springcontext中获取的
    private static final String zk = "zookeeper://127.0.0.1:2181";

    /**
     * 获取Dubbo服务
     * @param dubboService
     * @param version
     * @param host
     * @param groupId
     * @param <T>
     * @return
     */
    public static <T> T getService(Class dubboService, String version, String host,String groupId) {
    
    
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(dubboService);
        //手动实现泛化调用
        enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
    
    
            ReferenceConfig<GenericService> referenceConfig = getReferenceConfig(dubboService, version, host,groupId);
            GenericService genericService = referenceConfig.get();
            //$invoke方法 参数说明:调用的远程方法名、参数类型数组、参数列表数组
            return genericService.$invoke(method.getName(), getMethodParamType(method), args);
        });
        return (T) enhancer.create();
    }


    private static <T> ReferenceConfig<T> getReferenceConfig(Class<?> clazz, String version, String host, String groupId) {
    
    
        ReferenceConfig<T> referenceConfig = new ReferenceConfig<>();

        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName(clazz.getName());
        referenceConfig.setApplication(applicationConfig);
        //远程调用的dubbo地址   dubbo://1270.0.1:8105
        referenceConfig.setUrl(host);
        //dubbo的api调用接口
        referenceConfig.setInterface(DubboService.class);
        //开启泛化调用
        referenceConfig.setGeneric(Constants.GENERIC_SERIALIZATION_DEFAULT);
        //版本号
        referenceConfig.setVersion(version);
        //超时时间
        referenceConfig.setTimeout(20000);
        //dubbo分组
        referenceConfig.setGroup(groupId);

        RegistryConfig registryConfig = new RegistryConfig();
        //zk地址
        registryConfig.setAddress(zk);
        referenceConfig.setRegistry(registryConfig);

        return referenceConfig;
    }

    /**
     * 获取method中的所有 参数类型
     * @param method
     * @return
     */
    private static String[] getMethodParamType(Method method) {
    
    
        Class<?>[] parameterTypes = method.getParameterTypes();
        String[] paramTypeArray = new String[parameterTypes.length];
        for (int i = 0; i < parameterTypes.length; i++) {
    
    
            paramTypeArray[i] = parameterTypes[i].getTypeName();
        }
        return paramTypeArray;
    }
}

对部分内容做补充说明:
我只是将核心代码贴出,至于参数中的zk地址、version管理、groupId分组、具体你请求的生产者模块的dubbo地址,都根据实际业务或者具体学习情况进行调整,参数列表灵活进行修改即可。
其次,大家也应该发现了,$invoke方法使用cglig这种方式进行调用的,官网给的是用 CompletableFuture 这种方式进行的,也就是异步回调响应结果,因人而异,条条大路通罗马嘛。
还有就是我省略了生产者模块以及注册zk的那部分代码,大家可以去官网一览。

3、编写测试类

这里注意,host地址,要将对应的api接口也就是DubboService的包路径也带上,DubboRequest也要保证和生产者的DubboRequest包路径一致,因为哦都是通过反射最后去获取嘛,你想想mybatis的xml映射,mapper放的路径不也得和dao层的mapper一致嘛。一个道理。
因为DubboService、DubboRequest里面东西比较少,我就不贴了,大家根据实际情况自己从项目的api直接拿过来就行了。

public static void main(String[] args) {
    
    
        //BankDubboService是已经注册到zookeeper注册中心的Dubbo服务,这里不指定调用特定服务实例
        BankDubboService service = DubboUtils.getService(DubboService.class, "1.0.0","dubbo://127.0.0.1:38105/cn.sk.dubbo.DubboService","groupId");
        DubboRequest dubboRequest = new DubboRequest();
        //todo 根据实际情况赋予req内容即可
        dubboRequest.setXmlRequest(reqXml.toString());
        Map<String,Object> DubboResponse = service.doSomething(dubboRequest);
        System.out.println(DubboResponse.get("result"));
    }

注意事项:
这里我是用的Map<String,Object>去接收的,因为使用泛化调用,对于自定义bean是有一些特殊处理的,我暂时没有做过多的研究,官网给的说明如下:
1、如果参数为基本类型或者 Date,List,Map 等,则不需要转换,直接调用。
2、如果参数为其他 POJO,则使用 Map 代替。
3、对于其他序列化格式,需要特殊配置

可以看到,我的DubboResponse就是其他POJO的,所以dubbo调用完成后会直接用map去解析,获取里面的值也是通过map.get(key)来完成的。
如果强行用自己的response接受的话,会报错map无法转化为对应的实体类,已经替大家跳过坑了,不用再试了。。。

简单了解了一下,可以借助重写Filter实现自定义序列化,这个后面看时间安排补充吧,大家可以先自行百度学习~

到此完成consumer端的泛化版dubbo调用,可以快速的做mock等测试了,当然一切以实际为主哈。

文中难免有些理解不到位的,说的不太清楚的地方,欢迎大家一起讨论研究~

猜你喜欢

转载自blog.csdn.net/qq_38653981/article/details/128716289