ServiceComb使用Consul开源开发任务总结

举报
yd_255530874 发表于 2025/01/07 15:47:45 2025/01/07
346 0 0
【摘要】 Apache ServiceComb Java Chassis 给开发者提供一个快速构建微服务的JAVA SDK,本文讲解了使用consul作为注册中心、配置中心的实现过程,同时也讲解了提交PR的过程
简介

Apache ServiceComb Java Chassis 给开发者提供一个快速构建微服务的JAVA SDK。它包含如下特性:

  1. 基于Open API的契约优先(API First)开发模式,满足开发过程可管理、开发规范可验证要求。
  2. 多种开发风格,REST(JAX-RS、Spring MVC)和RPC等,高效支持遗留系统迁移和新系统开发场景。
  3. 多种通信协议, HTTP over Vert.x、Http Over Servlet、Highway等,满足不同场景对于性能、韧性的需求。
  4. 统一一致的服务提供者、服务消费者处理链,易于扩展新功能。
    提供服务发现、配置管理、熔断、限流、灰度发布等开箱即用的服务治理能力。
在github上Fork servicecomb-java-chassis 代码,并下载代码
consul服务注册、发现实现
  1. 创建registry-consul模块:
  2. 在pom中添加相关依赖,与consul有关的依赖如下:
    <dependency>
      <groupId>org.kiwiproject</groupId>
      <artifactId>consul-client</artifactId>
      <version>1.4.2</version>
    </dependency>
    
  3. 实现注册功能
    1)构建ConsulRegistrationInstance实例:consulInstance
    2)利用consulInstance的信息构建NewService的实例newServie
    3)使用consul-api提供的方法注册newServie
    示例代码如下:
    @Override
    public ConsulRegistrationInstance getMicroserviceInstance() {
    	return new ConsulRegistrationInstance(consulInstance);
    }
    @Override
    public void init() {
        String instanceId = registrationId.getInstanceId();
    consulInstance = new ConsulInstance();
    consulInstance.setInstanceId(instanceId);
    consulInstance.setEnvironment(env); consulInstance.setApplication(BootStrapProperties.readApplication(environment)); consulInstance.setServiceName(BootStrapProperties.readServiceName(environment));
    }
    @Override
    public void run() {
        LOGGER.info("ConsulRegistration run");
    ImmutableRegistration.Builder registrationBuilder = ImmutableRegistration.builder()
        .name(consulInstance.getServiceName());
    List<String> endpoints = consulInstance.getEndpoints();
    for (String endpoint : endpoints) {
      Endpoint temp = EndpointUtils.parse(endpoint);
      if (temp.getAddress() instanceof URIEndpointObject) {
        String hostOrIp = ((URIEndpointObject) temp.getAddress()).getHostOrIp();
        int port = ((URIEndpointObject) temp.getAddress()).getPort();
        String serviceId = hostOrIp + ":" + port;
        consulDiscoveryProperties.setServiceId(serviceId);
        consulInstance.setServiceId(serviceId);
        registrationBuilder.id(serviceId);
        registrationBuilder.address(hostOrIp);
        registrationBuilder.port(port);
        break;
      }
    }
    List<String> tags = consulDiscoveryProperties.getTags();
    if (CollectionUtils.isEmpty(tags)) {
      tags.add(consulInstance.getServiceName());
    }
    registrationBuilder.tags(tags);
    Gson gson = new GsonBuilder().disableHtmlEscaping().create();
    Map<String, String> meta = new HashMap<>();
    meta.put("meta", gson.toJson(consulInstance));
    registrationBuilder.meta(meta);
    ImmutableRegistration newService = registrationBuilder.build();
    AgentClient agentClient = consulClient.agentClient();
    agentClient.register(newService);
    LOGGER.info("ConsulRegistration newService");
    }
    
  4. 实现服务发现功能
    1) 查找Consul中的Service实例
    2) 将Consul的Service实例转换为ConsulInstance,示例代码如下:
    @Override
    public List<ConsulDiscoveryInstance> findServiceInstances(String application, String serviceName) {
      logger.info("findServiceInstances application: {}, serviceName: {}", application, serviceName);
      consulDiscoveryInstanceList = getInstances(serviceName);
    return consulDiscoveryInstanceList;
    }
    
    public List<ConsulDiscoveryInstance> getInstances(@NotNull final String serviceName) {
    List<ConsulDiscoveryInstance> instances = new ArrayList<>();
    addInstancesToList(instances, serviceName);
    return instances;
    }
    
    private void addInstancesToList(List<ConsulDiscoveryInstance> instances, String serviceName) {
    List<ServiceHealth> healthServices = getHealthServices(serviceName);
    if (!CollectionUtils.isEmpty(healthServices)) {
      for (ServiceHealth serviceHealth : healthServices) {
        Service service = serviceHealth.getService();
        Gson gson = new GsonBuilder().disableHtmlEscaping().create();
        ConsulInstance consulInstance = gson.fromJson(service.getMeta().get("meta"), ConsulInstance.class);
        instances.add(new ConsulDiscoveryInstance(consulInstance));
      }
    }
    }
    
    private List<ServiceHealth> getHealthServices(String serviceName) {
    HealthClient healthClient = consulClient.healthClient();
    return healthClient.getHealthyServiceInstances(serviceName).getResponse();
    }
    
consul配置中心实现
  1. 新建config-consul模块
  2. 在pom中添加相关依赖,与consul有关的依赖如下
    <dependency>
      <groupId>org.kiwiproject</groupId>
      <artifactId>consul-client</artifactId>
      <version>1.4.2</version>
    </dependency>
    
  3. 实现配置中心功能
    1)创建ConsulConfigClient,示例代码:
    public ConsulConfigClient consulConfigClient(Environment environment) {
      ConsulConfigProperties consulConfigProperties = consulConfigProperties(environment);
      ConsulClient consulClient = consulClient(consulConfigProperties, consulRawClientBuilderSupplier());
      return new ConsulConfigClient(updateHandler, environment, consulConfigProperties, consulClient);
    }
    
    @Override
    public PropertySource<?> create(Environment environment) {
      try {
        consulConfigClient = consulConfigClient(environment);
        consulConfigClient.refreshConsulConfig();
      } catch (Exception e) {
        throw new IllegalStateException("Set up consul config failed.", e);
      }
      return new MapPropertySource(SOURCE_NAME, valueCache);
    }
    
  4. 在ConsulConfigClient中实现key-value的读取,示例代码如下:
    private Map<String, Object> getValues(String path) {
      Map<String, Object> values = new HashMap<>();
      KeyValueClient keyValueClient = consulClient.keyValueClient();
      String decodedValue = keyValueClient.getValueAsString(path).orElseThrow();
      if (StringUtils.isBlank(decodedValue)) {
        return values;
      }
      return getValues(path, decodedValue);
    }
    
    private @NotNull Map<String, Object> getValues(String path, String decodedValue) {
      Map<String, Object> values = new HashMap<>();
      if (path.endsWith(".yaml") || path.endsWith(".yml")) {
        YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean();
        yamlFactory.setResources(new ByteArrayResource(decodedValue.getBytes(StandardCharsets.UTF_8)));
        values.putAll(toMap(yamlFactory.getObject()));
      } else if (path.endsWith(".properties")) {
        Properties properties = new Properties();
        try {
          properties.load(new StringReader(decodedValue));
        } catch (IOException e) {
          LOGGER.error(e.getMessage(), e);
        }
        values.putAll(toMap(properties));
      } else {
        values.put(path, decodedValue);
      }
      return values;
    }
    
  5. 自动获取最新内容,示例代码:
    try (KVCache cache = KVCache.newCache(kvClient, path, consulConfig.getConsulWatchSeconds())) {
      cache.addListener(newValues -> {
        Optional<Value> newValue = newValues.values().stream()
            .filter(value -> value.getKey().equals(path))
            .findAny();
    
        newValue.ifPresent(value -> {
          Optional<String> decodedValue = newValue.get().getValueAsString();
          decodedValue.ifPresent(v -> new Thread(new GetDataRunnable("environmentData", getValues(path))).start());
        });
      });
      cache.start();
    }
    
功能测试
  1. 在demo模块下新建demo-consul模块,用户consul测试
  2. 编写完测试用例后,启动provider、gateway、consumer
  3. 启动test-client
  4. test-client运行完成后,观察控制台输出,没有输出测试相关错误的,表示测试通过
代码检查
  1. 代码检查要执行的命令
  2. 在本地执行除maven.yml文件的,有关maven命令和其它命令,需要安装插件或工具的自行参考有关工具的安装使用方法
  3. 执行maven.yml,由于在此过程中需要下载镜像,需要在能访问到有关镜像的机器上执行,同时要注意修改 test-client的pom.xml配置,使应用能够访问到对应的镜像里面的服务
提交代码
  • 功能测试和代码检查都通过后,就可以提交代码了,代码提交的消息参考github代码提交规范
提交PR
  1. 在github代码仓库页面发起 Pull Request
  2. 提交PR后,告知相关人员执行代码检查
修复代码检视中发现的错误
  1. 提交PR后,相关人员会对代码进行检视,并提出修改意见
  2. 根据修改意见修改代码,并重新提交代码
  3. 重复以上步骤,直至代码被合并
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。