dubbo泛化实现与引用

2020-11-19 15:00:58 浏览数 (1)

现在分布式架构盛行,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泛化引用和泛化实现,希望给大家在日常开发中带来帮助!

0 人点赞