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的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对调用不同的服务使用不同线程来说开销较小。
Dubbo学习笔记4:服务消费端泛化调用与异步调用的更多相关文章
- Angular JS 学习笔记(自定义服务:factory,Promise 模式异步请求查询:$http,过滤器用法filter,指令:directive)
刚学没多久,作了一个小项目APP,微信企业号开发与微信服务号的开发,使用的是AngularJS开发,目前项目1.0版本已经完结,但是项目纯粹为了赶工,并没有发挥AngularJS的最大作用,这几天项目 ...
- Dubbo学习笔记0:RPC框架Dubbo介绍
整体来说,一个公司业务系统的演进流程基本都是从单体应用到多应用.在单体应用时,不同业务模块相互调用直接在本地JVM进程内就可以完成,而变为多个应用时,相互之间进行通信就不能简单的进行本地调用了,因为不 ...
- Dubbo学习笔记2:Dubbo服务提供端与消费端应用的搭建
Demo结构介绍 Demo使用Maven聚合功能,里面有三个模块,目录如下: 其中Consumer模块为服务消费者,里面TestConsumer和consumer.xml组成了基于Spring配置方式 ...
- Dubbo学习笔记10:Dubbo服务消费方启动流程源码分析
同理我们看下服务消费端启动流程时序图: 在<Dubbo整体架构分析>一文中,我们提到服务消费方需要使用ReferenceConfig API来消费服务,具体是调用代码(1)get()方法来 ...
- 源码分析Dubbo服务消费端启动流程
通过前面文章详解,我们知道Dubbo服务消费者标签dubbo:reference最终会在Spring容器中创建一个对应的ReferenceBean实例,而ReferenceBean实现了Spring生 ...
- Dubbo学习笔记1:使用Zookeeper搭建服务治理中心
Zookeeper是Apache Hadoop的子项目,是一个树形的目录服务,支持变更推送,适合作为Dubbo服务的注册中心,工业强度较高,推荐生成环境使用. , 下面结合上图介绍Zookeeper在 ...
- dubbo源码之服务消费
消费端启动初始化过程: 消费端的代码解析也是从配置文件解析开始的,服务发布对应的<dubbo:service,解析xml的时候解析了一个ServiceBean,并且调用ServiceConfig ...
- Dubbo学习笔记11:使用Dubbo中需要注意的一些事情
指定方法异步调用 前面我们讲解了通过设置ReferenceConfig的setAsync()方法来让整个接口里的所有方法变为异步调用,那么如何指定某些方法为异步调用呢?下面讲解下如何正确地设置默写方法 ...
- Dubbo学习笔记7:Dubbo的集群容错与负载均衡策略
Dubbo的集群容错策略 正常情况下,当我们进行系统设计时候,不仅要考虑正常逻辑下代码该如何走,还要考虑异常情况下代码逻辑应该怎么走.当服务消费方调用服务提供方的服务出现错误时候,Dubbo提供了多种 ...
随机推荐
- 用Spring.Services整合 thrift0.9.2生成的wcf中间代码-复杂的架构带来简单的代码和高可维护性
最近一直在看关于thrift的相关文章,涉及到的内容的基本都是表层的.一旦具体要用到实际的项目中的时候就会遇到各种问题了! 比如说:thrift 的服务器端载体的选择.中间代码的生成options(a ...
- 设计模式 笔记 装饰模式 Decorator
//---------------------------15/04/17---------------------------- //Decorator 装饰模式----对象结构型模式 /* 1:意 ...
- Android与单片机通信常用数据转换方法(汇总)
下面直接贴代码 1. 将GB2312转化为中文,如BAFAC2DCB2B7→胡萝卜,两个字节合成一个文字 public static String stringToGbk(String string ...
- 《unity 3D 游戏开发 第二版》宣雨松 分享 pdf下载
链接:https://pan.baidu.com/s/1LfRTGUmaE_lGdcmd6QiZkg 提取码:e2sn
- kubeadm安装K8S单master双节点集群
宿主机:master:172.16.40.97node1:172.16.40.98node2:172.16.40.99 # 一.k8s初始化环境:(三台宿主机) 关闭防火墙和selinux syste ...
- 假设检验,alpha,p值 通俗易懂的的理解。
假设检验: 一般原假设H0 :表是为 XXX和YYYY无显著差异,H1,是有显著差异. 如果我们定义alpha的值是0.05.意味着我们接受H0是真的但是我们却认为他是假的的概率. 这里你想想,这个值 ...
- 第二十次ScrumMeeting博客
第二十次ScrumMeeting博客 本次会议于12月11日(一)22时整在3公寓725房间召开,持续20分钟. 与会人员:刘畅.辛德泰.张安澜.赵奕.方科栋. 1. 每个人的工作(有Issue的内容 ...
- 实现项目WC
软件的需求分析 程序处理用户需求的模式为: wc.exe [parameter][filename] 在[parameter]中,用户通过输入参数与程序交互,需实现的功能如下: 1.基本功能 支持 - ...
- ElasticSearch 2 (25) - 语言处理系列之同义词
ElasticSearch 2 (25) - 语言处理系列之同义词 摘要 词干提取有助于通过简化屈折词到它们词根的形式来扩展搜索的范围,而同义词是通过关联概念和想法来扩展搜索范围的.或许没有文档能与查 ...
- 从零开始学Kotlin-控制语句(4)
从零开始学Kotlin基础篇系列文章 条件控制-if var a=10 var b=20 if(a>b) print(a) if(a>b){ print(a) }else{ print(b ...