【高性能网关soul学习】4. soul-client 客户端信息上传

【高性能网关soul学习】4. soul-client 客户端信息上传

本文主要目标:
分析soul-client 中client 端如何注册相关信息到 soul-admin


1. dubbo服务

SoulAlibabaDubboClientConfiguration 配置类加载了两个bean DubboConfigAlibabaDubboServiceBeanPostProcessor/ApacheDubboServiceBeanPostProcessor

1.1 DubboConfig
@Data
public class DubboConfig {
		/** 为启动的soul-admin 项目的ip + 端口,注意要加 http:// */
    private String adminUrl;
		/** contextPath: 为该项目在soul网关的路由前缀,用于标识调用端标识当前项目 */
    private String contextPath;
    /** 应用名称 不配置的话,会默认取 dubbo配置中application 中的名称*/
    private String appName;
1.2 SoulDubboClient 和 处理器

dubbo服务的核心注解为 @SoulDubboClient, 该注解有两个 handler

  • alibaba-dubbo:AlibabaDubboServiceBeanPostProcessor
  • apache-dubbo:ApacheDubboServiceBeanPostProcessor

上述两个类代码极其相似,因此我们只针对一个做解析 AlibabaDubboServiceBeanPostProcessor 做解析

public class AlibabaDubboServiceBeanPostProcessor implements ApplicationListener<ContextRefreshedEvent> {
  
    @Override
    public void onApplicationEvent(final ContextRefreshedEvent contextRefreshedEvent) {
        if (Objects.nonNull(contextRefreshedEvent.getApplicationContext().getParent())) {
            return;
        }
        Map<String, ServiceBean> serviceBean = contextRefreshedEvent.getApplicationContext().getBeansOfType(ServiceBean.class);
      // 轮询所有的bean,放入线程池异步处理
        for (Map.Entry<String, ServiceBean> entry : serviceBean.entrySet()) {
            executorService.execute(() -> handler(entry.getValue()));
        }
    }
}

AlibabaDubboServiceBeanPostProcessor 实现了接口 ApplicationListener<ContextRefreshedEvent>, spring ioc 初始化完所有的bean之后,会发送事件 ContextRefreshedEvent , AlibabaDubboServiceBeanPostProcessor 接收上下文刷新事件之后就回去扫描所有的 dubbo ServiceBean,丢进线程池做异步处理

  • dubbo 每个暴露出去的服务都会生成一个的 ServiceBean
private void handler(final ServiceBean serviceBean) {
        Class<?> clazz = serviceBean.getRef().getClass();
        final Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(clazz);
        for (Method method : methods) {
            SoulDubboClient soulDubboClient = method.getAnnotation(SoulDubboClient.class);
            if (Objects.nonNull(soulDubboClient)) {
                RegisterUtils.doRegister(buildJsonParams(serviceBean, soulDubboClient, method), url, RpcTypeEnum.DUBBO);
            }
        }
    }
  • 可以看到 handler 的处理非常简单,获取到serviceBean中所引用的实际的类型;然后扫描类中每个方法,判断是否有包含注解 @SoulDubboClient 。对于包含的 method ,调用 RegisterUtils.doRegister 注册到 soul-admin 中

    • url:dubboConfig.getAdminUrl() + “/soul-client/dubbo-register”;

    • buildJsonParams(serviceBean, soulDubboClient, method) 最后拼装成如下的一个对象,然后进行序列化

      MetaDataDTO metaDataDTO = MetaDataDTO.builder()
                      .appName(appName) // 应用名
                      .serviceName(serviceName) // 暴露的服务名
                      .methodName(methodName) // 暴露的方法名
                      .contextPath(dubboConfig.getContextPath()) // 配置的soul上下文路径
                      .path(path) // 类似于当前服务在外部看来的路径
                      .ruleName(ruleName) // 规则名,没有配置则取path
                      .pathDesc(desc) // 描述
                      .parameterTypes(parameterTypes) // 参数名,多个参数 `,` 分割 
                      .rpcExt(buildRpcExt(serviceBean)) // 扩展字段,dubbo的分组、超时、版本号、重试次数等信息 
                      .rpcType("dubbo")
                      .enabled(soulDubboClient.enabled())
                      .build();
      
    • RegisterUtils.doRegister

      public static void doRegister(final String json, final String url, final RpcTypeEnum rpcTypeEnum) {
        // 删除异常处理代码之后,可以发现,本质就是http调用admin-url方法进行注册
              String result = OkHttpTools.getInstance().post(url, json);
          }
      
1.3 soul-admin端 的 dubbo-register

上面我们发现实际上调用的是soul-admin 中的 /soul-client/dubbo-register 接口,很容易就能发现实际上调用的是 SoulClientController中的 registerRpc方法

@RestController
@RequestMapping("/soul-client")
public class SoulClientController {
  
    @PostMapping("/dubbo-register")
    public String registerRpc(@RequestBody final MetaDataDTO metaDataDTO) {
        return soulClientRegisterService.registerDubbo(metaDataDTO);
    }
}
@Service("soulClientRegisterService")
public class SoulClientRegisterServiceImpl implements SoulClientRegisterService {

    private final MetaDataMapper metaDataMapper;

    private final ApplicationEventPublisher eventPublisher;

    private final SelectorService selectorService;

    private final RuleService ruleService;

    private final RuleMapper ruleMapper;

    private final UpstreamCheckService upstreamCheckService;

    private final SelectorMapper selectorMapper;

    private final PluginMapper pluginMapper;
  
    @Override
    @Transactional
    public String registerDubbo(final MetaDataDTO dto) {
      	// 取数据库查询元数据是否已存在
        MetaDataDO exist = metaDataMapper.findByPath(dto.getPath());
      	// 新建或者更新元数据信息
        saveOrUpdateMetaData(exist, dto);
      	// 下面selector和rule都只会注册一次,如果已经存在,则不会重复注册
      	// 注册seletor信息,从元数据中获取到selectorId (根据 dto.contextPath 进行搜索, 没有则进行注册)
        String selectorId = handlerDubboSelector(dto);
      	// 注册seletor下属的rule信息
        handlerDubboRule(selectorId, dto);
        return SoulResultMessage.SUCCESS;
    }
  
  
    private void saveOrUpdateMetaData(final MetaDataDO exist, final MetaDataDTO metaDataDTO) {
        DataEventTypeEnum eventType;
        MetaDataDO metaDataDO = MetaDataTransfer.INSTANCE.mapToEntity(metaDataDTO);
      	// 对于已存在的进行更新,不存在的进行创建
        if (Objects.isNull(exist)) {
            Timestamp currentTime = new Timestamp(System.currentTimeMillis());
            metaDataDO.setId(UUIDUtils.getInstance().generateShortUuid());
            metaDataDO.setDateCreated(currentTime);
            metaDataDO.setDateUpdated(currentTime);
            metaDataMapper.insert(metaDataDO);
            eventType = DataEventTypeEnum.CREATE;
        } else {
            metaDataDO.setId(exist.getId());
            metaDataMapper.update(metaDataDO);
            eventType = DataEventTypeEnum.UPDATE;
        }
        // 发送一个元数据变更事件
        eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.META_DATA, eventType,
                Collections.singletonList(MetaDataTransfer.INSTANCE.mapToData(metaDataDTO))));
    }
  
  	// 如果不存在,则进行注册(会保存在数据库,并发送一个 ConfigGroupEnum.RULE 的 DataChangedEvent)
    private void handlerDubboRule(final String selectorId, final MetaDataDTO metaDataDTO) {
        RuleDO existRule = ruleMapper.findByName(metaDataDTO.getPath());
        if (Objects.isNull(existRule)) {
            registerRule(selectorId, metaDataDTO.getPath(), metaDataDTO.getRpcType(), metaDataDTO.getRuleName());
        }
    }
}
  • 数据变更事件的核心分发器 DataChangedEventDispatcher,对所有监听到的事件进行分发处理,这里暂时略过,后续再详细分析
public class DataChangedEventDispatcher implements ApplicationListener<DataChangedEvent>, InitializingBean {
    @Override
    @SuppressWarnings("unchecked")
    public void onApplicationEvent(final DataChangedEvent event) {
        for (DataChangedListener listener : listeners) {
            switch (event.getGroupKey()) {
                case APP_AUTH:
                    listener.onAppAuthChanged((List<AppAuthData>) event.getSource(), event.getEventType());
                    break;
                case PLUGIN:
                    listener.onPluginChanged((List<PluginData>) event.getSource(), event.getEventType());
                    break;
                case RULE:
                    listener.onRuleChanged((List<RuleData>) event.getSource(), event.getEventType());
                    break;
                case SELECTOR:
                    listener.onSelectorChanged((List<SelectorData>) event.getSource(), event.getEventType());
                    break;
                case META_DATA:
                    listener.onMetaDataChanged((List<MetaData>) event.getSource(), event.getEventType());
                    break;
                default:
                    throw new IllegalStateException("Unexpected value: " + event.getGroupKey());
            }
        }
    }
}

2. 其他服务的注册

其他服务的注册逻辑大致相似,唯一的区别是有些通过 实现BeanPostProcessor,在每个 bean 初始化完毕之后直接触发元数据的注册。

配置类注解处理类
SpringCloudSoulSpringCloudConfigSoulSpringCloudClientSpringMvcClientBeanPostProcessor
SpringMVCSoulSpringMvcClientSoulSpringMvcConfigSpringMvcClientBeanPostProcessor
SofaSofaConfigSoulSofaClientSofaServiceBeanPostProcessor
TarsTarsConfigSoulTarsClient / SoulTarsServiceTarsServiceBeanPostProcessor
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值