【soul-admin】SpringCloud元資料註冊
阿新 • • 發佈:2021-01-30
技術標籤:微服務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);
}
}