前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >dubbo泛化实现与引用

dubbo泛化实现与引用

作者头像
叔牙
发布2020-11-19 15:00:58
5490
发布2020-11-19 15:00:58
举报

现在分布式架构盛行,RPC框架也被大家熟知,目前就国内而言,dubbo可以说是中小型企业的首选。我们先看一下官网上的一张图:

这张图从架构的角度展现了,dubbo框架的关键组件和实现方式。那么我们在日常开发中的使用方式大概如下图:

也就是说服务提供者,有一个interface(也叫client),还有一个服务实现,interface给消费者依赖。这样做没问题,我们分析一下,这种方式有优点也会优缺点:

优点:1)消费端像调用本地服务一样调用远程服务,使用简单

缺点:1)服务端interface会带过来一些依赖可能和消费端某些依赖冲突 2)服务端interface也许会把自己的配置传递到消费端,导致 消费端平白无故要多配置完全和自己无关或者不关心的项

假如我有一下这些场景:

1)消费端只依赖了服务端一个服务(或者说很少)

2)消费端不想把interface的依赖带过来,导致需要花费人力成本去排包,让依 赖变得特别重

3)消费端只依赖服务,只关心它所以来的服务调用方式和返回结果,完全不关心你服务怎么实现的,你依赖什么配置,你把这些配置传递给我,我是无法接受的

基于上述问题和描述的应用场景,dubbo提供了泛化引用。

何谓泛化引用?

官网给了如下解释:

泛化接口调用方式主要用于客户端没有 API 接口及模型类元的情况,参数及返回值中的所有 POJO 均用 Map 表示,通常用于框架集成,比如:实现一个通用的服务测试框架,可通过 GenericService 调用所有服务实现。

我自己的理解是,不直接依赖服务提供者,利用dubbo框架层的特性来实现远程服务调用:

接下来就一步一步实现dubbo服务的泛型引用。

I 服务端编写与启动

服务端结构如下图:

具体实现参考徒手搭建dubbo服务

II 消费端编写与测试

消费端工程如下图:

1)dubbo-consumer-interface层定义service和响应service:

public interface ImitateConsumerService {

/**

* 客户端查询用户信息

*

* @param id

* @return

*/

ResponseBase doQueryUserById(Long id);

}

response:

/**

* 响应

*

* @author Typhoon

*

*/

public class ResponseBase implements Serializable {

private static final long serialVersionUID = 7825036327382479394L;

public static final String SUCCESS = "4001";

public static final String ERROR_CODE = "4000";

private String code = "4001";

private String reason;

private String result;

private Object content;

······

}

2)dubbo-consumer-provider编写服务引用与测试

consumer只依赖基本的dubbo和spring。dubbo泛化引用有两种实现方式:

①通过 Spring 使用泛化调用

<dubbo:reference interface="com.typhoon.service.UserService" url="dubbo://localhost:20289" id="userService" protocol="dubbo" timeout="30000" generic="true" />

服务引用具体实现

@Service("imitateConsumerService")

public class ImitateConsumerServiceImpl implements ImitateConsumerService,ApplicationContextAware {

private GenericService genericService ;

@Override

public ResponseBase doQueryUserById(Long id) {

ResponseBase resp = new ResponseBase();

String methodName = "queryByPK";

String[] paramTypes = new String[1];

paramTypes[0] = "java.lang.Long";

Object[] params = new Object[1];

params[0] = id;

Object result = this.genericService.$invoke(methodName,paramTypes,params);

resp.setAttach(result);

return resp;

}

@Override

public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

if(null == applicationContext) {

throw new IllegalArgumentException("applicationContext未注入");

}

this.genericService = (GenericService)applicationContext.getBean("userService");

}

}

将dubbo-server端启动,在消费端编写单元测试

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration({"classpath:spring-root.xml"})

public class Test1 {

@Resource

ImitateConsumerService imitateConsumerService;

@Test

public void testA() {

try {

ResponseBase resp = this.imitateConsumerService.doQueryUserById(1L);

System.out.println(JSON.toJSONString(resp));

} catch (Exception e) {

e.printStackTrace();

}

}

}

运行单元测试

②通过 API 方式使用泛化调用

改造①中ImitateConsumerServiceImpl的setApplicationContext方法:

再次运行①中的单元测试,结果如下:

可以看到两种方式都实现了泛型引用调用rpc服务的效果。

泛化引用应用场景

1)服务端暴露client层比较重,富客户端或者带过来很多配置和依赖

2)消费端对服务端依赖比较轻,依赖单个或很少个服务,不想承担引入服务端接口带来的成本开销

3)只关心服务,完全不关心服务端实现

泛化实现

本篇幅重点讲述了dubbo泛化引用,但是还有泛化实现的概念,泛化实现在真是项目场景中应用不是太多,反正我是尚未见过。此处简单过一下。

官网解释:

泛接口实现方式主要用于服务器端没有API接口及模型类元的情况,参数及返回值中的所有POJO均用Map表示,通常用于框架集成,比如:实现一个通用的远程服务Mock框架,可通过实现GenericService接口处理所有服务请求。

在 Java 代码中实现 GenericService 接口:

package com.foo;

public class MyGenericService implements GenericService {

public Object $invoke(String methodName, String[] parameterTypes, Object[] args) throws GenericException {

if ("sayHello".equals(methodName)) {

return "Welcome " + args[0];

}

}

}

同样,泛化实现也有两种实现方式:

1)通过 Spring 暴露泛化实现

在 Spring 配置申明服务的实现:

<bean id="genericService" class="com.foo.MyGenericService" />

<dubbo:service interface="com.foo.BarService" ref="genericService" />

2)通过 API 方式暴露泛化实现

...

// 用com.alibaba.dubbo.rpc.service.GenericService可以替代所有接口实现

GenericService xxxService = new XxxGenericService();

// 该实例很重量,里面封装了所有与注册中心及服务提供方连接,请缓存

ServiceConfig<GenericService> service = new ServiceConfig<GenericService>();

// 弱类型接口名

service.setInterface("com.xxx.XxxService");

service.setVersion("1.0.0");

// 指向一个通用服务实现

service.setRef(xxxService);

// 暴露及注册服务

service.export();

总结

此篇我们根据真实业务场景讲解了dubbo泛化引用和泛化实现,希望给大家在日常开发中带来帮助!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-07-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 PersistentCoder 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
微服务引擎 TSE
微服务引擎(Tencent Cloud Service Engine)提供开箱即用的云上全场景微服务解决方案。支持开源增强的云原生注册配置中心(Zookeeper、Nacos 和 Apollo),北极星网格(腾讯自研并开源的 PolarisMesh)、云原生 API 网关(Kong)以及微服务应用托管的弹性微服务平台。微服务引擎完全兼容开源版本的使用方式,在功能、可用性和可运维性等多个方面进行增强。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档