美文网首页
Dubbo服务分组及多版本、动态调用实现

Dubbo服务分组及多版本、动态调用实现

作者: Zal哥哥 | 来源:发表于2021-01-31 11:54 被阅读0次

问题提出

Dubbo常用使用方式大家都比较熟悉,确定好服务的与服务之间调用关系,确定好相关接口参数,基于spring配置好,启动provider,然后启动consumer去调用相关服务。但有这样的一种场景:

所有的Provider的接口都相同,但每个系统有自己的不同实现。例如系统A和B都提供com.HelloService服务,但具体实现不一样,需要Consumer端根据传入参数来区分开来并调用
Dubbo的Consumer端需要在运行时才知道调用具体的Dubbo服务,而这个<dubbo:reference/>并没有在spring的bean中配置

解决方案

同一个服务不同实现版本---group分组方法

先来看第一种场景,可以通过配置group 的方式实现同一个服务的不同实现版本:

提供者dubbo端配置:
<dubbo:service interface="com.HelloService" group="groupA" ref="helloService" />
消费者consumer配置:
<dubbo:reference id="helloService"interface="com.HelloService" group="groupA"/>

说明:只有相同group的才能进行匹配,若要实现消费者任意调用提供者的某个服务,只需要把group设置为“”,即:
<dubbo:reference interface="com.HelloService" group="
" id="helloService"/>

同一个服务不同实现版本---多版本号

当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。
可以按照以下的步骤进行版本迁移:
在低压力时间段,先升级一半提供者为新版本
再将所有消费者升级为新版本
然后将剩下的一半提供者升级为新版本

老版本服务提供者配置:
<dubbo:service interface="com.foo.BarService" version="1.0.0" ref="barServiceV1"/>
新版本服务提供者配置:
<dubbo:service interface="com.foo.BarService" version="2.0.0" ref="barServiceV2"/>
老版本服务消费者配置:
<dubbo:reference id="barServiceV1" interface="com.foo.BarService" version="1.0.0" />
新版本服务消费者配置:
<dubbo:reference id="barServiceV2" interface="com.foo.BarService" version="2.0.0" />
如果不需要区分版本,可以按照以下的方式配置(2.2.0 以上版本支持)
<dubbo:reference id="barService" interface="com.foo.BarService" version="*" />
注:如果服务提供者使用了版本,消费者引入该服务时候,version字段不能为空。

动态调用

需要在实际使用时,构造出Consumer端的服务类,并通过上述的group的方式区分不同的服务实现,如下:

public HelloService getInvokeService(String group) {
        ApplicationConfig application = new ApplicationConfig();
        application.setName("dubboConsumer");
        
        RegistryConfig registry = new RegistryConfig();
        registry.setAddress("127.0.0.1:2181");
        registry.setProtocol("zookeeper");

        ReferenceConfig<HelloService> referenceConfig = new ReferenceConfig<>();
        referenceConfig.setApplication(application);
        referenceConfig.setRegistry(registry);
        referenceConfig.setGroup(group);
        referenceConfig.setInterface(HelloService.class);
       return referenceConfig.get();
    }
性能优化

上述实现已经可以满足我们提出的两个要求,但是存在性能问题,因为每次调用该方法,都需要重新生成一个新的ReferenceConfig,并且调用get()方法获取一个代理的实现,该实现封装了与注册中心的连接以及与提供者的连接。为了能够重用该连接,可以将其缓存,这里使用dubbo内置的简单缓存工具类进行缓存,实现代码如下:

 public HelloService getInvokeService(String group) {
        ApplicationConfig application = new ApplicationConfig();
        application.setName("dubboConsumer");
        
        RegistryConfig registry = new RegistryConfig();
        registry.setAddress("127.0.0.1:2181");
        registry.setProtocol("zookeeper");

        ReferenceConfig<HelloService> referenceConfig = new ReferenceConfig<>();
        referenceConfig.setApplication(application);
        referenceConfig.setRegistry(registry);
        referenceConfig.setGroup(group);
        referenceConfig.setInterface(HelloService.class);
         ReferenceConfigCache cache = ReferenceConfigCache.getCache();
       return cache.get(referenceConfig);
    }
根据url动态调用
    @Test
    @Disabled
    public void doGetServiceByUrlTest() {
        String url = "dubbo://127.0.0.1:22880/com.ccc.ddd.domain.XxxService ?anyhost=true&application=xxx&bean.name=xxx&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&group=xxx&interface=xxx&methods=notify&owner=xxx&pid=66088®ister=true&release=2.7.3&revision=1.0.0-SNAPSHOT&serverApplicationName=xxx&service.filter=catTransaction&side=provider&threads=500&timeout=10000×tamp=1611977670756";
        XxxService xxxService= (XxxService ) dubboRealReferenceService.getServiceByUrl(url, XxxService .class);
        assertThat(xxxService).isNotNull();

        ResponseData responseData = xxxService.mmm("");
        assertThat(responseData.getCode()).isEqualTo(0);
    }
import com.xxx.ApplicationContextHelper;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.spring.ReferenceBean;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class DubboRealReferenceService {

    /*
    @Value("${dubbo.registry.protocol}")
    private String registryProtocol;

    @Value("${dubbo.registry.address}")
    private String registryAddress;
    */

    @Autowired
    private RegistryConfig registry;

    private final Map<String, ReferenceBean<T>> referenceBeanMap = new ConcurrentHashMap<>();

    public Object getServiceByGroup(String group, Class cls) {
        /*
        RegistryConfig registry = new RegistryConfig();
        registry.setAddress(registryAddress);
        registry.setProtocol(registryProtocol);
        */

        ReferenceBean<T> referenceBean = referenceBeanMap.get(group);
        if (referenceBean != null){
            return referenceBean.get();
        }

        ReferenceBean<T> referenceBean = new ReferenceBean<T>();
        referenceBean.setApplicationContext(ApplicationContextHelper.getApplicationContext());
        referenceBean.setInterface(cls);
        referenceBean.setGroup(group);
        referenceBean.setRegistry(registry);

        try {
            referenceBean.afterPropertiesSet();
            return referenceBean.get();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }


    public Object getServiceByUrl(String url, Class cls) {
        ReferenceBean<T> referenceBean = new ReferenceBean<T>();
        referenceBean.setApplicationContext(ApplicationContextHelper.getApplicationContext());
        referenceBean.setInterface(cls);
        referenceBean.setUrl(url);

        try {
            referenceBean.afterPropertiesSet();
            return referenceBean.get();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public GenericService getGenericServiceByGroup(String group, Class cls) {
        /*
        RegistryConfig registry = new RegistryConfig();
        registry.setAddress(registryAddress);
        registry.setProtocol(registryProtocol);
        */

        // 普通编码配置方式
        ApplicationConfig application = new ApplicationConfig();
        application.setName("xxx");

        ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();
        reference.setApplication(application);
        reference.setRegistry(registry);
        reference.setGroup(group);
        reference.setInterface(cls);
        reference.setGeneric(true);

        ReferenceConfigCache cache = ReferenceConfigCache.getCache();
        GenericService genericService = cache.get(reference);

        return genericService;
    }

}
    @Test
    public void doGetGenericServiceByGroupTest() {
        GenericService genericService = dubboRealReferenceService.getGenericServiceByGroup("xxx", IDomainEventService.class);
        Object responseObject = genericService.$invoke(SERVICE_METHOD_NAME, PARAM_TYPES, new Object[]{domainEvent});
        Map repsoneMap = (HashMap)responseObject;

        assertThat(responseObject).isNotNull();
        assertThat(repsoneMap.get("code")).isEqualTo(0);
    }

refer to:
https://my.oschina.net/u/3729778/blog/2054809
https://www.imooc.com/wenda/detail/504332

相关文章

  • Dubbo服务分组及多版本、动态调用实现

    问题提出 Dubbo常用使用方式大家都比较熟悉,确定好服务的与服务之间调用关系,确定好相关接口参数,基于sprin...

  • Dubbo使用了CompletableFuture,实现了真异步

    Dubbo在服务调用时支持同步调用和异步调用等方式。 在Dubbo2.6版本及之前的版本在实现异步调用时存在一定的...

  • 服务暴露过程

    版本 2.5.7 服务暴露过程过程 dubbo的服务注册、调用等都是通过SPI实现的,即都需要通过Extensio...

  • Dubbo

    Dubbo(服务治理框架) RPC 各服务都要实现rpc协议,才能实现服务间的调用 rpc:远程过程调用协议,是一...

  • netty4.x学习六使netty实现自己的RPC

    一提到netty实现rpc,就让人情不自禁的想起Dubbo服务间的调用。下面就根据问题实现rpc。 dubbo服务...

  • Dubbo剖析-服务分组与服务版本号

    一、前言 在Dubbo中接口类并不能唯一确定一个服务,在dubbo中接口+服务分组+版本号才能唯一确定一个服务,本...

  • Java进阶-Dubbo-进阶

    一、服务调用过程 1.1 服务调用方式   Dubbo 服务调用过程:   Dubbo 支持同步和异步两种调用方式...

  • java面试中经常会被问到分布式面试题

    1、Dubbo的底层实现原理和机制 –高性能和透明化的RPC远程服务调用方案 –SOA服务治理方案 Dubbo缺省...

  • java面试中经常会被问到分布式面试题

    1、Dubbo的底层实现原理和机制 –高性能和透明化的RPC远程服务调用方案 –SOA服务治理方案 Dubbo缺省...

  • Dubbo

    Dubbo简介 Dubbo是Alibaba提供的一款分布式服务治理框架。其中主要的流程如下 动态代理:生成需要调用...

网友评论

      本文标题:Dubbo服务分组及多版本、动态调用实现

      本文链接:https://www.haomeiwen.com/subject/srxrtltx.html