dubbo實戰之“動態調用服務”(實為“泛化調用”)探索


一、簡介

需求:Dubbo的調用方,在不引入服務接口類的情況下,遠程調用其他Dubbo服務。

二、項目依賴

SpringBoot整合Dubbo3.x關於curator和zookeeper版本選型的思考

經嘗試,

  • 一種方案是使用高版本組合(Curator 5.2.0 + ZooKeeper 3.6.3);
  • 另一種方案是選用低版本組合(Curator 4.2.0 + ZooKeeper 3.4.10)。

三、核心代碼

參考自 Apache Dubbo 高級用法 使用泛化調用

如果引用的是 Dubbo 3.0.5

import cn.hutool.core.util.StrUtil;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.utils.SimpleReferenceCache;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.service.GenericService;
import org.springframework.lang.Nullable;

/**
 * 功能描述: 基於 Dubbo 泛化調用特性的遠程調用
 *
 * @author geekziyu
 * @version 1.0.0
 */
class DubboRpc {

  private RegistryConfig registry;

  DubboRpc(ApplicationConfig application, RegistryConfig registry) {
    this.registry = registry;
    ApplicationModel.defaultModel().getApplicationConfigManager().setApplication(application);
  }

  Object genericInvoke(String interfaceClass, String methodName, String[] parameterTypes, Object[] args) {
    return genericInvoke(interfaceClass, methodName, parameterTypes, args, null, null);
  }

  Object genericInvoke(String interfaceClass, String methodName, String[] parameterTypes, Object[] args, @Nullable String group, @Nullable String version) {
    ReferenceConfig<GenericService> reference = new ReferenceConfig<>();
    reference.setRegistry(registry);
    reference.setInterface(interfaceClass); // 接口名
    reference.setGeneric("true"); // 聲明為泛化接口
    reference.setCheck(false); // 不檢查狀態
    if (StrUtil.isNotBlank(group)) { // NOSONAR
      reference.setGroup(group);
    }
    if (StrUtil.isNotBlank(version)) {// NOSONAR
      reference.setVersion(version);
    }

    // ReferenceConfig實例很重,封裝了與注冊中心的連接以及與提供者的連接,
    // 需要緩存,否則重復生成ReferenceConfig可能造成性能問題並且會有內存和連接泄漏。
    // API方式編程時,容易忽略此問題。
    // 這里使用dubbo內置的簡單緩存工具類進行緩存
    SimpleReferenceCache cache = SimpleReferenceCache.getCache();
    GenericService genericService = cache.get(reference);
    // 用com.alibaba.dubbo.rpc.service.GenericService可以替代所有接口引用
    return genericService.$invoke(methodName, parameterTypes, args);
  }
}

如果引用的是 Dubbo 3.0.1

import cn.hutool.core.util.StrUtil;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.utils.ReferenceConfigCache;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.service.GenericService;

import javax.annotation.Nullable;

/**
 * 功能描述: 基於 Dubbo 泛化調用特性的遠程調用
 *
 * @author 20024968@cnsuning.com
 * @version 1.0.0
 */
class DubboRpc {

  private RegistryConfig registry;

  DubboRpc(ApplicationConfig application, RegistryConfig registry) {
    this.registry = registry;
    ApplicationModel.getConfigManager().setApplication(application);
  }

  Object genericInvoke(String interfaceClass, String methodName, String[] parameterTypes, Object[] args) {
    return genericInvoke(interfaceClass, methodName, parameterTypes, args, null, null);
  }

  Object genericInvoke(String interfaceClass, String methodName, String[] parameterTypes, Object[] args, @Nullable String group, @Nullable String version) {
    referenceConfig<GenericService> reference = new ReferenceConfig<>();
    reference.setRegistry(registry);
    reference.setInterface(interfaceClass); // 接口名
    reference.setGeneric("true"); // 聲明為泛化接口
    reference.setCheck(false); // 不檢查狀態
    if (StrUtil.isNotBlank(group)) { // NOSONAR
      reference.setGroup(group);
    }
    if (StrUtil.isNotBlank(version)) {// NOSONAR
      reference.setVersion(version);
    }

    // ReferenceConfig實例很重,封裝了與注冊中心的連接以及與提供者的連接,
    // 需要緩存,否則重復生成ReferenceConfig可能造成性能問題並且會有內存和連接泄漏。
    // API方式編程時,容易忽略此問題。
    // 這里使用dubbo內置的簡單緩存工具類進行緩存
    ReferenceConfigCache cache = ReferenceConfigCache.getCache();
    GenericService genericService = cache.get(reference);
    // 用com.alibaba.dubbo.rpc.service.GenericService可以替代所有接口引用

    return genericService.$invoke(methodName, parameterTypes, args);
  }
}

至於這個 RegistryConfig 可以這樣:

@Service
public class RpcInvokerService implements InitializingBean {
  @Value("${dubbo.application.name}")
  private String applicationName;

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

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

  private DubboRpc rpc;

  @Override
  public void afterPropertiesSet() {
    ApplicationConfig application = new ApplicationConfig(applicationName);
    RegistryConfig registry = new RegistryConfig();
    registry.setProtocol(protocol);
    registry.setAddress(address);
    rpc = new DubboRpc(application, registry);
  }

  // ...
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM