七、soul源码学习-http服务注册数据同步机制源码解析

前面我们已经本地启动了SpringBoot服务,并将Controller的接口注册到了SoulAdmin,并通过网关调用成功转发到了我们的服务,这一节我们从http项目是如何注册到SoulAdmin,SoulAdmin又如何将注册信息同步到网关的整个流程来剖析下源代码

首先启动SoulAdmin。接下来在启动我们的SpringBoot项目

第二节,我们由于http注册问题,已经大体走完了,服务启动注册到SoulAdmin的流程,通过http请求到SoulAdmin的/soul-client/springmvc-register接口

接下来在SoulAdmin中定位到该接口

//org.dromara.soul.admin.controller.SoulClientController
/**
* Register spring mvc string.
*
* @param springMvcRegisterDTO the spring mvc register dto
* @return the string
*/
@PostMapping("/springmvc-register")
public String registerSpringMvc(@RequestBody final SpringMvcRegisterDTO springMvcRegisterDTO) {
  return soulClientRegisterService.registerSpringMvc(springMvcRegisterDTO);
}

我们看下SpringMvcRegisterDTO类,这个是之前org.dromara.soul.client.springmvc.init.SpringMvcClientBeanPostProcessor#buildJsonParams构造的信息

@Data
public class SpringMvcRegisterDTO implements Serializable {
  //我们SpringBoot项目配置的appName
  private String appName;
 //
  private String context;

  private String path;

  private String pathDesc;

  private String rpcType;

  private String host;

  private Integer port;

  private String ruleName;

  private boolean enabled;

  private boolean registerMetaData;
}

进入到service中

//org.dromara.soul.admin.service.impl.SoulClientRegisterServiceImpl
@Override
@Transactional
public String registerSpringMvc(final SpringMvcRegisterDTO dto) {
  //是否注册元数据信息,这里http默认是false,元数据主要是为dubbo的泛化调用使用的,这里不是主要的关注重点
  if (dto.isRegisterMetaData()) {
    //根据path看元数据信息是否存在
    MetaDataDO exist = metaDataMapper.findByPath(dto.getPath());
    if (Objects.isNull(exist)) {
      saveSpringMvcMetaData(dto);
    }
  }
  //1
  String selectorId = handlerSpringMvcSelector(dto);
  handlerSpringMvcRule(selectorId, dto);
  return SoulResultMessage.SUCCESS;
}

1.进入到org.dromara.soul.admin.service.impl.SoulClientRegisterServiceImpl#handlerSpringMvcSelector

private String handlerSpringMvcSelector(final SpringMvcRegisterDTO dto) {
  //我们在SpringBoot项目中配置的contextPath
  String contextPath = dto.getContext();
  SelectorDO selectorDO = selectorService.findByName(contextPath);
  String selectorId;
  String uri = String.join(":", dto.getHost(), String.valueOf(dto.getPort()));
  if (Objects.isNull(selectorDO)) {
    //1.1 注册选择器
    selectorId = registerSelector(contextPath, dto.getRpcType(), dto.getAppName(), uri);
  } else {
    selectorId = selectorDO.getId();
    //update upstream
    String handle = selectorDO.getHandle();
    String handleAdd;
    DivideUpstream addDivideUpstream = buildDivideUpstream(uri);
    SelectorData selectorData = selectorService.buildByName(contextPath);
    if (StringUtils.isBlank(handle)) {
      handleAdd = GsonUtils.getInstance().toJson(Collections.singletonList(addDivideUpstream));
    } else {
      List exist = GsonUtils.getInstance().fromList(handle, DivideUpstream.class);
      //如果已存在的规则和这次新增加的相等,则不需要更新
      for (DivideUpstream upstream : exist) {
        if (upstream.getUpstreamUrl().equals(addDivideUpstream.getUpstreamUrl())) {
          return selectorId;
        }
      }
      exist.add(addDivideUpstream);
      handleAdd = GsonUtils.getInstance().toJson(exist);
    }
    selectorDO.setHandle(handleAdd);
    selectorData.setHandle(handleAdd);
    // update db
    selectorMapper.updateSelective(selectorDO);
    // submit upstreamCheck
    upstreamCheckService.submit(contextPath, addDivideUpstream);
    // publish change event.
    eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.SELECTOR, DataEventTypeEnum.UPDATE,
                                                     Collections.singletonList(selectorData)));
  }
  return selectorId;
}

1.1 org.dromara.soul.admin.service.impl.SoulClientRegisterServiceImpl#registerSelector

private String registerSelector(final String contextPath, final String rpcType, final String appName, final String uri) {
  //构造选择器默认类,无论我们在SpringBoot项目配置的full是true或者false,在选择器这里没有区别。都是CUSTOM_FLOW,区别是在规则那里
  SelectorDTO selectorDTO = SelectorDTO.builder()
    .name(contextPath)
    .type(SelectorTypeEnum.CUSTOM_FLOW.getCode())
    .matchMode(MatchModeEnum.AND.getCode())
    .enabled(Boolean.TRUE)
    .loged(Boolean.TRUE)
    .continued(Boolean.TRUE)
    .sort(1)
    .build();
  if (RpcTypeEnum.DUBBO.getName().equals(rpcType)) {
    selectorDTO.setPluginId(getPluginId(PluginEnum.DUBBO.getName()));
  } else if (RpcTypeEnum.SPRING_CLOUD.getName().equals(rpcType)) {
    selectorDTO.setPluginId(getPluginId(PluginEnum.SPRING_CLOUD.getName()));
    selectorDTO.setHandle(GsonUtils.getInstance().toJson(buildSpringCloudSelectorHandle(appName)));
  } else if (RpcTypeEnum.SOFA.getName().equals(rpcType)) {
    selectorDTO.setPluginId(getPluginId(PluginEnum.SOFA.getName()));
    selectorDTO.setHandle(appName);
  } else if (RpcTypeEnum.TARS.getName().equals(rpcType)) {
    selectorDTO.setPluginId(getPluginId(PluginEnum.TARS.getName()));
    selectorDTO.setHandle(appName);
  } else {
    //我们这次是http服务注册,rpcType是http
    //1.1.1 这里构造DivideUpstream代表http上游
    DivideUpstream divideUpstream = buildDivideUpstream(uri);
    String handler = GsonUtils.getInstance().toJson(Collections.singletonList(divideUpstream));
    //DivideUpsteam的json字符串,对应选择器中的配置
    selectorDTO.setHandle(handler);
    //选择器对应的就是Divide控件
    selectorDTO.setPluginId(getPluginId(PluginEnum.DIVIDE.getName()));
    //这里是 上游检查服务,之后单独写一篇文章
    upstreamCheckService.submit(selectorDTO.getName(), divideUpstream);
  }
  //选择器条件默认就是Match对应的contextPath+/**
  SelectorConditionDTO selectorConditionDTO = new SelectorConditionDTO();
  selectorConditionDTO.setParamType(ParamTypeEnum.URI.getName());
  selectorConditionDTO.setParamName("/");
  selectorConditionDTO.setOperator(OperatorEnum.MATCH.getAlias());
  selectorConditionDTO.setParamValue(contextPath + "/**");
  selectorDTO.setSelectorConditions(Collections.singletonList(selectorConditionDTO));
  //1.1.2 注册
  return selectorService.register(selectorDTO);
}

SelectorDto的handle是存储的就是DivideUpsteam的json字符串,对应选择器的Configuration

image.png

1.1.1 org.dromara.soul.admin.service.impl.SoulClientRegisterServiceImpl#buildDivideUpstream

//uri 是 前面传递过来的,String.join(":", dto.getHost(), String.valueOf(dto.getPort()));
//实际上就是代表咱们注册服务上游的http访问地址
private DivideUpstream buildDivideUpstream(final String uri) {
  return DivideUpstream.builder()
    .upstreamHost("localhost")
    .protocol("http://")
    .upstreamUrl(uri)
    .weight(50)
    .build();
}

1.1.2 org.dromara.soul.admin.service.impl.SelectorServiceImpl#register

@Override
public String register(final SelectorDTO selectorDTO) {
  //这里就是简单的数据库操作
  SelectorDO selectorDO = SelectorDO.buildSelectorDO(selectorDTO);
  List selectorConditionDTOs = selectorDTO.getSelectorConditions();
  if (StringUtils.isEmpty(selectorDTO.getId())) {
    selectorMapper.insertSelective(selectorDO);
    selectorConditionDTOs.forEach(selectorConditionDTO -> {
      selectorConditionDTO.setSelectorId(selectorDO.getId());
     selectorConditionMapper.insertSelective(SelectorConditionDO.buildSelectorConditionDO(selectorConditionDTO));
    });
  }
  //1.1.2.1 这里发布事件
  publishEvent(selectorDO, selectorConditionDTOs);
  return selectorDO.getId();
}

1.1.2.1 org.dromara.soul.admin.service.impl.SelectorServiceImpl#publishEvent

private final ApplicationEventPublisher eventPublisher;

private void publishEvent(final SelectorDO selectorDO, final List selectorConditionDTOs) {
  PluginDO pluginDO = pluginMapper.selectById(selectorDO.getPluginId());
  List conditionDataList =
    selectorConditionDTOs.stream().map(ConditionTransfer.INSTANCE::mapToSelectorDTO).collect(Collectors.toList());
  // 发布数据变化事件,用到了Spring的EventBus机制,之后单独拿一章节讲一下EventBus
  eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.SELECTOR, DataEventTypeEnum.UPDATE,
                                                   Collections.singletonList(SelectorDO.transFrom(selectorDO, pluginDO.getName(), conditionDataList))));
}

总结下来就是:

同步数据到数据库,并将数据的变化事件发送出去,具体发送后做的事情我们下篇文章在分析

你可能感兴趣的:(七、soul源码学习-http服务注册数据同步机制源码解析)