最近在项目开发中需要使用到dubbo泛化调用功能 ,以前使用一直用xml配置方式,没研究过dubbo泛化调用。通过查看官方文档、网上查找dubbo泛化调用资料最终完成了dubbo泛化调用功能。在此总结一下dubbo泛化调用开发过程及遇到的一些问题以及处理方法,还有部分问题尚未成功处理,欢迎大家有兴趣的朋友留言讨论
dubbo版本:2.8.4
1、dubbo泛化功能说明
dubbo泛化调用就是服务消费端不需要引入接口jar包,通过GenericService接口就能处理完成所有服务的调用,参数及返回值中的所有POJO均用Map表示。
2、dubbo泛化调用功能实现代码
public class DubboServiceFactory {
public static Logger logger = LoggerFactory.getLogger(DubboServiceFactory.class);
private ApplicationConfig application;
private RegistryConfig registry;
private String version;
private static class SingletonHolder {
private static DubboServiceFactory INSTANCE = new DubboServiceFactory();
}
public static DubboServiceFactory getInstance() {
return SingletonHolder.INSTANCE;
}
private DubboServiceFactory() {
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName("");
applicationConfig.setVersion("");
// 这里配置了dubbo的application信息*(demo只配置了name)*,因此demo没有额外的dubbo.xml配置文件
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("");
registryConfig.setFile("/tmp/dubbo.cachr");
// 这里配置dubbo的注册中心信息,因此demo没有额外的dubbo.xml配置文件
this.application = applicationConfig;
this.registry = registryConfig;
}
public Object genericInvoke(String interfaceClass, String methodName, String parameterType, Object param) {
ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();
reference.setApplication(application);
reference.setRegistry(registry);
reference.setVersion(version);
reference.setInterface(interfaceClass); // 接口名
reference.setGeneric(true); // 声明为泛化接口
// ReferenceConfig实例很重,封装了与注册中心的连接以及与提供者的连接,
// 需要缓存,否则重复生成ReferenceConfig可能造成性能问题并且会有内存和连接泄漏。
// API方式编程时,容易忽略此问题。
// 这里使用dubbo内置的简单缓存工具类进行缓存
ReferenceConfigCache cache = ReferenceConfigCache.getCache();
GenericService genericService = cache.get(reference);
if (genericService == null) {
cache.destroy(reference);
throw new IllegalStateException("服务不可用");
}
if (parameterType == null) {
return genericService.$invoke(methodName, new String[] {}, new Object[] {});
}
return genericService.$invoke(methodName, new String[] { parameterType }, new Object[] { param });
}
}
只需要配置应用名、版本、注册中心地址。
Object result = DubboServiceFactory.getInstance().genericInvoke(interfaceClass, methodName, parameterType, object);
3、问题总结
a、
1、问题:若泛化调用服务消费端先启动,在服务提供端未启动之前,泛化调用服务消费端某接口(a)进行了一次调用,在后续即使服务提供端成功启动,泛化调用服务消费端依然不能正常访问某接口(a)
2、原因:因为ReferenceConfig实例很重,封装了与注册中心的连接以及与提供者的连接,需要缓存,否则重复生成ReferenceConfig可能造成性能问题并且会有内存和连接泄漏。所以在调用服务时,不论服务提供端接口服务是否存在,ReferenceConfigCache都会缓存ReferenceConfig实例(若调用服务提供端不存在,ReferenceConfig实例的ref参数为空,即不能生成GenericService对象),再下次请求时,即使服务提供端正常提供服务,但因为ReferenceConfigCache已经缓存了ReferenceConfig实例,所以不会再重新创建链接,直接从ReferenceConfigCach缓存中获取GenericService对象,导致GenericService实例一直报空指针(因为ref参数为空),最终导致一直调用不到真正的服务
3、处理方法:在GenericService对象调用方法($invoke)之前,先判断GenericService是否为空,若为空,则调用ReferenceConfigCache对象的destroy方法,下次调用时即会重新生成ReferenceConfig实例,不会再从缓存中取。
b、
1、问题:在正常调用过程中,若服务提供端中断,再重启,即使服务提供端已经重新正常提供服务,但泛化调用服务消费端仍会有一断时间无法成功消费服务
2、原因:
3、处理方法: