1. 程式人生 > 其它 >【soul-admin】SpringCloud元資料註冊

【soul-admin】SpringCloud元資料註冊

技術標籤:微服務soulspringclod閘道器

在SoulClientController中提供瞭如下介面:

/**
* Register spring cloud string.
*
* @param springCloudRegisterDTO the spring cloud register dto
* @return the string
*/
@PostMapping("/springcloud-register")
public String registerSpringCloud(@RequestBody final SpringCloudRegisterDTO springCloudRegisterDTO) {
    return soulClientRegisterService.registerSpringCloud(springCloudRegisterDTO);
}

呼叫了下述方法

@Override
@Transactional
public synchronized String registerSpringCloud(final SpringCloudRegisterDTO dto) {
    MetaDataDO metaDataDO = metaDataMapper.findByPath(dto.getContext() + "/**");
    if (Objects.isNull(metaDataDO)) {
        saveSpringCloudMetaData(dto); // 元資料不存在,則儲存SpringClloud元資料到資料庫
    }
    String selectorId = handlerSpringCloudSelector(dto); // 處理其中選擇器資料
    handlerSpringCloudRule(selectorId, dto); // 處理規則資料
    return SoulResultMessage.SUCCESS;
}

元資料儲存

private void saveSpringCloudMetaData(final SpringCloudRegisterDTO dto) {
    Timestamp currentTime = new Timestamp(System.currentTimeMillis());
    MetaDataDO metaDataDO = MetaDataDO.builder()
        .appName(dto.getAppName())
        .path(dto.getContext() + "/**")
        .pathDesc(dto.getAppName() + "spring cloud meta data info")
        .serviceName(dto.getAppName())
        .methodName(dto.getContext())
        .rpcType(dto.getRpcType())
        .enabled(dto.isEnabled())
        .id(UUIDUtils.getInstance().generateShortUuid())
        .dateCreated(currentTime)
        .dateUpdated(currentTime)
        .build();
    metaDataMapper.insert(metaDataDO); // 入庫
    // publish AppAuthData's event
    eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.META_DATA, DataEventTypeEnum.CREATE, Collections.singletonList(MetaDataTransfer.INSTANCE.mapToData(metaDataDO)))); // 傳送元資料變更事件
}

選擇器資料更新

private String handlerSpringCloudSelector(final SpringCloudRegisterDTO dto) {
    String contextPath = dto.getContext();
    SelectorDO selectorDO = selectorService.findByName(contextPath);
    if (Objects.isNull(selectorDO)) {
        return registerSelector(contextPath, dto.getRpcType(), dto.getAppName(), ""); // 入庫變更
    } else {
        return selectorDO.getId();
    }
}

private String registerSelector(final String contextPath, final String rpcType, final String appName, final String uri) {
    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 {
        //is divide
        DivideUpstream divideUpstream = buildDivideUpstream(uri);
        String handler = GsonUtils.getInstance().toJson(Collections.singletonList(divideUpstream));
        selectorDTO.setHandle(handler);
        selectorDTO.setPluginId(getPluginId(PluginEnum.DIVIDE.getName()));
        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);
}

@Override
public String register(final SelectorDTO selectorDTO) {
    SelectorDO selectorDO = SelectorDO.buildSelectorDO(selectorDTO);
    List<SelectorConditionDTO> selectorConditionDTOs = selectorDTO.getSelectorConditions();
    if (StringUtils.isEmpty(selectorDTO.getId())) {
        selectorMapper.insertSelective(selectorDO);
        selectorConditionDTOs.forEach(selectorConditionDTO -> {
        selectorConditionDTO.setSelectorId(selectorDO.getId());
            selectorConditionMapper.insertSelective(SelectorConditionDO.buildSelectorConditionDO(selectorConditionDTO)); // 入庫
        });
    }
    publishEvent(selectorDO, selectorConditionDTOs); // 釋出事件
    return selectorDO.getId();
}

Rule資料註冊

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

private void registerRule(final String selectorId, final String path, final String rpcType, final String ruleName) {
    RuleHandle ruleHandle = RuleHandleFactory.ruleHandle(RpcTypeEnum.acquireByName(rpcType), path);
    RuleDTO ruleDTO = RuleDTO.builder()
        .selectorId(selectorId)
        .name(ruleName)
        .matchMode(MatchModeEnum.AND.getCode())
        .enabled(Boolean.TRUE)
        .loged(Boolean.TRUE)
        .sort(1)
        .handle(ruleHandle.toJson())
        .build();
    RuleConditionDTO ruleConditionDTO = RuleConditionDTO.builder()
        .paramType(ParamTypeEnum.URI.getName())
        .paramName("/")
        .paramValue(path)
        .build();
    if (path.indexOf("*") > 1) {
        ruleConditionDTO.setOperator(OperatorEnum.MATCH.getAlias());
    } else {
        ruleConditionDTO.setOperator(OperatorEnum.EQ.getAlias());
    }
    ruleDTO.setRuleConditions(Collections.singletonList(ruleConditionDTO));
    ruleService.register(ruleDTO);
}

@Override
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();
}

而在客戶端,【soul-bootstrap】需要向【soul-admin】註冊資料

對於普通的的請求,需要在 SpringCloudClientBeanPostProcessor 中使用 BeanPostProcessor 後置處理進行註冊請求

如果配置了full,則使用Spring事件機制,進行全域性註冊。

/**
* The type Soul spring cloud client configuration.
*
* @author xiaoyu
*/
@Configuration
public class SoulSpringCloudClientConfiguration {
    /**
    * Spring cloud client bean post processor spring cloud client bean post processor.
    *
    * @param soulSpringCloudConfig the soul spring cloud config
    * @param env the env
    * @return the spring cloud client bean post processor
    */
    @Bean
    public SpringCloudClientBeanPostProcessor springCloudClientBeanPostProcessor(final SoulSpringCloudConfig soulSpringCloudConfig, final Environment env) {
        return new SpringCloudClientBeanPostProcessor(soulSpringCloudConfig, env);
    }

    /**
    * Context register listener context register listener.
    *
    * @param soulSpringCloudConfig the soul spring cloud config
    * @param env the env
    * @return the context register listener
    */
    @Bean
    public ContextRegisterListener contextRegisterListener(final SoulSpringCloudConfig soulSpringCloudConfig, final Environment env) {
        return new ContextRegisterListener(soulSpringCloudConfig, env);
    }

    /**
    * Soul spring cloud config soul spring cloud config.
    *
    * @return the soul spring cloud config
    */
    @Bean
    @ConfigurationProperties(prefix = "soul.springcloud")
    public SoulSpringCloudConfig soulSpringCloudConfig() {
        return new SoulSpringCloudConfig();

    }
}

@Slf4j

public class SpringCloudClientBeanPostProcessor implements BeanPostProcessor {
    private final ThreadPoolExecutor executorService;

    private final String url;

    private final SoulSpringCloudConfig config;

    private final Environment env;

    /**
    * Instantiates a new Soul client bean post processor.
    *
    * @param config the soul spring cloud config
    * @param env the env
    */
    public SpringCloudClientBeanPostProcessor(final SoulSpringCloudConfig config, final Environment env) {
        ValidateUtils.validate(config, env);
        this.config = config;
        this.env = env;
        this.url = config.getAdminUrl() + "/soul-client/springcloud-register";
        executorService = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
    }

    @Override
    public Object postProcessAfterInitialization(@NonNull final Object bean, @NonNull final String beanName) throws BeansException {
        if (config.isFull()) {
            return bean;
        }
        Controller controller = AnnotationUtils.findAnnotation(bean.getClass(), Controller.class);
        RestController restController = AnnotationUtils.findAnnotation(bean.getClass(), RestController.class);
        RequestMapping requestMapping = AnnotationUtils.findAnnotation(bean.getClass(), RequestMapping.class);
        if (controller != null || restController != null || requestMapping != null) {
            String prePath = "";
            SoulSpringCloudClient clazzAnnotation = AnnotationUtils.findAnnotation(bean.getClass(), SoulSpringCloudClient.class);
            if (Objects.nonNull(clazzAnnotation)) {
                if (clazzAnnotation.path().indexOf("*") > 1) {
                    String finalPrePath = prePath;
                    executorService.execute(() -> RegisterUtils.doRegister(buildJsonParams(clazzAnnotation, finalPrePath), url, RpcTypeEnum.SPRING_CLOUD));
                    return bean;
                }
                prePath = clazzAnnotation.path();
            }
            final Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(bean.getClass());
            for (Method method : methods) {
                SoulSpringCloudClient soulSpringCloudClient = AnnotationUtils.findAnnotation(method, SoulSpringCloudClient.class);
                if (Objects.nonNull(soulSpringCloudClient)) {
                    String finalPrePath = prePath;
                    executorService.execute(() -> RegisterUtils.doRegister(buildJsonParams(soulSpringCloudClient, finalPrePath), url, RpcTypeEnum.SPRING_CLOUD));
                }
            }
        }
        return bean;
    }

    private String buildJsonParams(final SoulSpringCloudClient soulSpringCloudClient, final String prePath) {
        String contextPath = config.getContextPath();
        String appName = env.getProperty("spring.application.name");
        String path = contextPath + prePath + soulSpringCloudClient.path();
        String desc = soulSpringCloudClient.desc();
        String configRuleName = soulSpringCloudClient.ruleName();
        String ruleName = ("".equals(configRuleName)) ? path : configRuleName;
        SpringCloudRegisterDTO registerDTO = SpringCloudRegisterDTO.builder()
            .context(contextPath)
            .appName(appName)
            .path(path)
            .pathDesc(desc)
            .rpcType(soulSpringCloudClient.rpcType())
            .enabled(soulSpringCloudClient.enabled())
            .ruleName(ruleName)
            .build();
        return OkHttpTools.getInstance().getGson().toJson(registerDTO);
    }
}

@Slf4j
public class ContextRegisterListener implements ApplicationListener<ContextRefreshedEvent> {
    private final AtomicBoolean registered = new AtomicBoolean(false);
    private final String url;
    private final SoulSpringCloudConfig config;
    private final Environment env;

    /**
    * Instantiates a new Context register listener.
    *
    * @param config the soul spring cloud config
    * @param env the env
    */
    public ContextRegisterListener(final SoulSpringCloudConfig config, final Environment env) {
        ValidateUtils.validate(config, env);
        this.config = config;
        this.env = env;
        this.url = config.getAdminUrl() + "/soul-client/springcloud-register";
    }

    @Override
    public void onApplicationEvent(final ContextRefreshedEvent contextRefreshedEvent) {
        if (!registered.compareAndSet(false, true)) {
            return;
        }
        if (config.isFull()) {
            RegisterUtils.doRegister(buildJsonParams(), url, RpcTypeEnum.SPRING_CLOUD);
        }
    }

    private String buildJsonParams() {
        String contextPath = config.getContextPath();
        String appName = env.getProperty("spring.application.name");
        String path = contextPath + "/**";
        SpringCloudRegisterDTO registerDTO = SpringCloudRegisterDTO.builder()
            .context(contextPath)
            .appName(appName)
            .path(path)
            .rpcType(RpcTypeEnum.SPRING_CLOUD.getName())
            .enabled(true)
            .ruleName(path)
            .build();
        return OkHttpTools.getInstance().getGson().toJson(registerDTO);
    }
}