zoukankan      html  css  js  c++  java
  • Dubbo学习笔记4:服务消费端泛化调用与异步调用

    本文借用dubbo.learn的Dubbo API方式来解释原理。

    服务消费端泛化调用

    前面我们讲解到,基于Spring和基于Dubbo API方式搭建简单的分布式系统时,服务消费端引入了一个SDK二方包,里面存放着服务提供端提供的所有接口类,之所以需要引入接口类是因为服务消费端一般是基于接口使用JDK代理实现远程调用的。

    泛化接口调用方式主要在服务消费端没有API接口类及模型类元(比如入参和出参的POJO类)的情况下使用。其参数及返回值中没有对应的POJO类,所以所有POJO均转换为Map表示。使用泛化调用时候服务消费模块不再需要引入SDK二方包。

    下面基于Dubbo API实现异步调用,在Consumer模块里面TestConsumerApiGeneric是泛化调用的方式,代码如下:

    public class TestConsumerApiGeneric(){
        public static void main(String[] args) throws IOException{
            // 当前应用配置
            ApplicationConfig application = new ApplicationConfig();
            application.setName("dubboConsumer");
            
            // 连接注册中心配置
            RegistryConfig registry = new RegistryConfig();
            registry.setAddress("127.0.0.1:2181");
            registry.setProtocol("zookeeper");
    
            // 泛型参数设置为GenericService
            ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();
            reference.setApplication(application);
            reference.setRegistry(registry);
            reference.setVersion("1.0.0");
            reference.setGroup("dubbo");
            reference.setTimeout(3000);
    
            // 设置为泛化
            reference.setInterface("com.test.UserServiceBo");
            reference.setGeneric(true);
    
            // 用com.alibaba.dubbo.rpc.service.GenericService替代所有接口引用
            GenericService userService = reference.get();
    
            // 基于类型以及Date/List/Map等不需要转换,直接调用,如果返回值为POJO也将自动转为Map
            Object result = userService.$invoke("sayHello",new String[]{"java.lang.String"},new Object[]{"哈哈哈"});
            
            System.out.println(JSON.json(result));
    
            // POJO参数转换为map
            Map<String,Object> map = new HashMap<String,Object>();
            map.put("class","com.test.PersonImpl");
            map.put("name","jiaduo");
            map.put("password","password");
    
            result = userService.$invoke("testPojo",new String[]{"com.test.Person"},new Object[]{map});
            System.out.println((result));
        }    
    }    

    上面代码中,由于sayHello的参数是String,没有很好的体现参数转换为Map,下面我们具体来说下POJO参数转换Map的含义。

    比如服务提供者提供的一个接口的 testPojo(Person person) 方法的参数为如下所示:

    package com.test;
    public class PersonImpl implements Person{
        private String name;
        private String password;
        public String getName(){
            return name;
        }
        public void setName(String name){
            this.name = name;
        }
        public String getPassword(){
            return password;
        }
        public void setPassword(String password){
            this.password = password;
        }
    }

    则POJO数据:

    Person person = new PersonImpl();
    person.setName("jiaduo");
    person.setPassword("password");

    正常情况下调用接口是使用:

    servicePerson.testPojo(person);

    泛化调用下需要首先转换person为Map,如下表示:

    Map<String,Object> map = new HashMap<String,Object>();
    // 注意:如果参数类型是接口,或者List等丢失泛型,可通过class属性指定类型。
    map.put("class","com.test.PersonImpl");
    map.put("name","jiaduo");
    map.put("password","password");

    然后使用下面方法进行泛化调用:

    servicePerson.$invoke("testPojo",new String[]{"com.test.Person"},new Object[]{map});

    泛化调用通常用于框架集成,比如:实现一个通用的服务测试框架,可通过GenericService调用所有服务实现,而不需要依赖服务实现方提供的接口类以及接口的入参和出参的POJO类。

    服务消费端异步调用

    无论前面我们讲解的正常调用还是泛化调用,都是同步调用,也就是服务消费方发起一个远程调用后,调用线程要被阻塞挂起,直到服务提供方返回。

    本节讲解下服务消费端异步调用,异步调用是指服务消费方发起一个远程调用后,不等服务提供方返回结果,调用方法就返回了,也就是当前线程不会被阻塞,这就允许调用方同时调用多个远程方法。

    在Consumer模块里面TestConsumerAsync是泛化调用,代码如下:

    public class TestConsumerAsync{
        public static void main(String[] args) throws InterruptedException,ExecutionException{
            // 当前应用配置
            ApplicationConfig application = new ApplicationConfig();
            application.setName("dubboConsumer");
    
            // 连接注册中心配置
            RegistryConfig registry = new RegistryConfig();
            registry.setAddress("127.0.0.1:2181");
            registry.setProtocol("zookeeper");
    
            // 引用远程服务
            ReferenceConfig<UserServiceBo> reference = new ReferenceConfig<UserServiceBo>();
            reference.setApplication(application);
            reference.setRegistry(registry);
            reference.setInterface(UserServiceBo.class);
            reference.setVersion("1.0.0");
            reference.setGroup("dubbo");
            reference.setTimeout(3000);
    
            // (1)设置为异步调用
            reference.setAsync(true);
            
            // 和本地bean一样使用xxxService
            UserServiceBo userService = reference.get();
            long startTime = System.currentTimeMillis() / 1000;
            
            // (2)因为异步调用,此处返回null
            System.out.println(userService.sayHello("哈哈哈"));
            // 拿到调用的Future引用,当结果返回后,会被通知和设置到此Futrue
            Future<String> userServiceFutureOne = RpcContext.getContext().getFuture();
            
            // (3)因为异步调用,此处返回null
            System.out.println(userService.sayHello2("哈哈哈2"));
            // 拿到调用的Future引用,当结果返回后,会被通知和设置到此Future
            Future<String> userServiceFutureTwo = RpcContext.getContext().getFuture();
            
            // (4)阻塞到get方法,等待结果返回
            System.out.println(userServiceFutureOne.get());
            System.out.println(userServiceFutureTwo.get());
            long endTime = System.currentTimeMillis() / 1000;
    
            System.out.println("costs:" + (endTime - startTime)); 
        }
    }

    运行上面代码,输出如下图所示:

    其中代码(2)(3)处输出null,说明开启异步调用后调用方直接返回null。

    输出costs:2说明异步调用生效了,因为sayHello和sayHello2方法内都sleep了2s,如果是顺序调用则会耗时至少4s,这里耗时2s说明两次调用是并发进行的。

    异步调用是基于nio的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对调用不同的服务使用不同线程来说开销较小。  

  • 相关阅读:
    Linux下常用程序的代理服务器(proxy)配置
    如何下载google play免费应用的apk文件
    sublime text多文件夹查找关键字
    linux下查看文件夹的大小
    使用virtualenv搭建独立的Python环境
    python代码中使用settings
    /lib /usr/lib /usr/local/lib区别
    修改setup.py的源
    Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
    使用Restful风格中的post使用过遇到前端数据传送不到后端
  • 原文地址:https://www.cnblogs.com/xhj123/p/9076530.html
Copyright © 2011-2022 走看看