网站首页 文章专栏 soul源码解析(三)
soul源码解析(三)

学习目标:

1. 继续结合divde插件,发起http请求soul网关,体验http代理

2. 梳理admin如何接受@SoulSpringMvcClient发来的请求,以及保存策略

3. 学习admin与网关之间的内存同步方式


1. admin端接受请求


1). SoulClientController

    在该controller中编写了多种方式的register,暴露url:/soul-client/springmvc-register ,通过SpringMvcRegisterDTO接受入参,返回 "success" 字符串

@Data
 public class SpringMvcRegisterDTO implements Serializable {
   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;
 }

2). 先判断参数中 registerMetaData 是否为true,是否注册元数据

    如果是:

        1>. 先根据参数中的 path 查库,判断是否存在

        2>. 存在的就忽略,不存在则保存入库

        3>. 并同时通过 ApplicationEventPublisher 发布 DataChangedEvent 事件 META_DATA CREATE 的通知

        4>. 通过定义的 DataChangedListener接口 的 onMetaDataChanged 监听该事件

        5>. 该接口有 4 中实现方式,AbstractDataChangedListener,NacosDataChangedListener,WebsocketDataChangedListener,ZookeeperDataChangedListener

 if (dto.isRegisterMetaData()) {
      MetaDataDO exist = metaDataMapper.findByPath(dto.getPath());
      if (Objects.isNull(exist)) {
          saveSpringMvcMetaData(dto);
      }
  }

3). 处理SpringMvc的选择器,根据path查询是否存在 Selector

     SelectorDO selectorDO = selectorService.findByName(contextPath);

4). 如果不存在,则创建一个,具体数据就是页面看到的那样,拼接ip,port,默认权重50,设置插件divide,并同步到内存

if (Objects.isNull(selectorDO)) {
     selectorId = registerSelector(contextPath, dto.getRpcType(), dto.getAppName(), uri);
 }
 
 private String registerSelector(final String contextPath, final String rpcType, final String appName, final String uri) {
   SelectorDTO selectorDTO = new SelectorDTO();
   selectorDTO.setName(contextPath);
   selectorDTO.setType(SelectorTypeEnum.CUSTOM_FLOW.getCode());
   selectorDTO.setMatchMode(MatchModeEnum.AND.getCode());
   selectorDTO.setEnabled(Boolean.TRUE);
   selectorDTO.setLoged(Boolean.TRUE);
   selectorDTO.setContinued(Boolean.TRUE);
   selectorDTO.setSort(1);
   if (RpcTypeEnum.DUBBO.getName().equals(rpcType)) {
       selectorDTO.setPluginId("6");
   } else if (RpcTypeEnum.SPRING_CLOUD.getName().equals(rpcType)) {
       selectorDTO.setPluginId("8");
       selectorDTO.setHandle(appName);
   } else {
       //is divide
       DivideUpstream divideUpstream = buildDivideUpstream(uri);
       String handler = GsonUtils.getInstance().toJson(Collections.singletonList(divideUpstream));
       selectorDTO.setHandle(handler);
       selectorDTO.setPluginId("5");
       upstreamCheckService.submit(selectorDTO.getName(), divideUpstream);
   }
   SelectorConditionDTO selectorConditionDTO = new SelectorConditionDTO();
   selectorConditionDTO.setParamType(ParamTypeEnum.URI.getName());
   selectorConditionDTO.setParamName("/");
   selectorConditionDTO.setOperator(OperatorEnum.MATCH.getAlias());
   selectorConditionDTO.setParamValue(contextPath + "/**");
   selectorDTO.setSelectorConditions(Collections.singletonList(selectorConditionDTO));
   return selectorService.register(selectorDTO);
}


5). 存在的话,且有新的 Selector 则在原来已存在的 Selector 基础上,增加新的,并更新到数据库


6). 提交过去检查,发送更新事件

    //更新数据库
    selectorMapper.updateSelective(selectorDO);
    //提交过去检查
    upstreamCheckService.submit(contextPath, addDivideUpstream);
    //发送更新事件
    // publish change event.
    eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.SELECTOR, DataEventTypeEnum.UPDATE,
            Collections.singletonList(selectorData)));

7). 处理规则,查询是否存在规则,不存在的话创建一个

 private void handlerSpringMvcRule(final String selectorId, final SpringMvcRegisterDTO dto) {
     RuleDO ruleDO = ruleMapper.findByName(dto.getRuleName());
     if (Objects.isNull(ruleDO)) {
         registerRule(selectorId, dto.getPath(), dto.getRpcType(), dto.getRuleName());
     }
 }

8). 同时通过 ruleService.register(ruleDTO); 保存到数据库,并发布规则更新事件

public String register(final RuleDTO ruleDTO) {
   RuleDO ruleDO = RuleDO.buildRuleDO(ruleDTO);
   List<RuleConditionDTO> ruleConditions = ruleDTO.getRuleConditions();
   if (StringUtils.isEmpty(ruleDTO.getId())) {
       ruleMapper.insertSelective(ruleDO);
       ruleConditions.forEach(ruleConditionDTO -> {
           ruleConditionDTO.setRuleId(ruleDO.getId());
           ruleConditionMapper.insertSelective(RuleConditionDO.buildRuleConditionDO(ruleConditionDTO));
       });
   }
   publishEvent(ruleDO, ruleConditions);
   return ruleDO.getId();
}


2. admin模块事件发布订阅,推送消息模式


1). ApplicationEventPublisher和监听ApplicationEvent事件

    1>. 自定义需要发布的事件类,需要继承ApplicationEvent类或PayloadApplicationEvent(该类也仅仅是对ApplicationEvent的一层封装)

           2>. 在soul中使用自定义 DataChangedEvent 继承ApplicationEvent类

           3>. 使用ApplicationEventPublisher来发布自定义事件(@Autowired注入即可)


3. 疑问未解决:

1).  onMetaDataChanged 事件的目的是什么?几种实现方式具体用的哪一个?


2). 下面这张图中,configServer代表什么,是在admin端,还是网关侧


3). 网关如何接受全量数据以及增量数据同步到内存的?


markdown-img-paste-20210115200628499.png

发现问题:


// publish AppAuthData's event该句注释应用在很多地方,应该是不对的




版权声明:本文由星尘阁原创出品,转载请注明出处!

本文链接:http://www.52xingchen.cn/detail/58




赞助本站,网站的发展离不开你们的支持!
来说两句吧
大侠留个名吧,或者可以使用QQ登录。
: 您已登陆!可以继续留言。
最新评论