【soul-admin】数据获取
【soul-admin】开放的dubbo注册接口
/**
* Register dubbo string.
*
* @param metaDataDTO the meta data dto
* @return the string
*/
@PostMapping("/dubbo-register")
public String registerRpc(@RequestBody final MetaDataDTO metaDataDTO) {
return soulClientRegisterService.registerDubbo(metaDataDTO);
}
调用了如下方法:
@Override
@Transactional
public String registerDubbo(final MetaDataDTO dto) {
MetaDataDO exist = metaDataMapper.findByPath(dto.getPath());
saveOrUpdateMetaData(exist, dto); // 保存元数据
String selectorId = handlerDubboSelector(dto); // 处理选择器数据
handlerDubboRule(selectorId, dto); // 处理规则数据
return SoulResultMessage.SUCCESS;
}
这个方法分为三步:
1. 保存更新元数据
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;
}
// publish MetaData's event
eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.META_DATA, eventType,
Collections.singletonList(MetaDataTransfer.INSTANCE.mapToData(metaDataDTO))));
}
2. 处理选择器数据
private String handlerDubboSelector(final MetaDataDTO metaDataDTO) {
return getString(metaDataDTO);
}
private String getString(final MetaDataDTO metaDataDTO) {
SelectorDO selectorDO = selectorService.findByName(metaDataDTO.getContextPath()); // 到数据库中获取选择器数据
String selectorId;
if (Objects.isNull(selectorDO)) {
// 注册选择器数据
selectorId = registerSelector(metaDataDTO.getContextPath(), metaDataDTO.getRpcType(), metaDataDTO.getAppName(), "");
} else {
selectorId = selectorDO.getId();
}
return selectorId;
}
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)) { // 设置Dubbo插件
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);
}
/**
* {@linkplain org.dromara.soul.admin.service.impl.SelectorServiceImpl#register}
**/
@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();
}
3. 处理规则数据
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());
}
}
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);
}
/**
* {@linkplain org.dromara.soul.admin.service.impl.RuleServiceImpl#register}
**/
@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();
}
客户端
客户端是通过Spring的事件机制(Spring容器初始化完成之后会在容器中发布ContextRefreshedEvent事件)对Spring管理的Bean进行扫描相对应的注解来注册服务的
@Configuration
public class SoulApacheDubboClientConfiguration {
/**
* Apache dubbo service bean post processor alibaba dubbo service bean post processor.
*
* @param dubboConfig the dubbo config
* @return the alibaba dubbo service bean post processor
*/
@Bean
public ApacheDubboServiceBeanPostProcessor apacheDubboServiceBeanPostProcessor(final DubboConfig dubboConfig) {
return new ApacheDubboServiceBeanPostProcessor(dubboConfig);
}
/**
* Dubbo config dubbo config.
*
* @return the dubbo config
*/
@Bean
@ConfigurationProperties(prefix = "soul.dubbo")
public DubboConfig dubboConfig() {
return new DubboConfig();
}
}
@Slf4j
public class ApacheDubboServiceBeanPostProcessor implements ApplicationListener<ContextRefreshedEvent> {
private DubboConfig dubboConfig;
private ExecutorService executorService;
private final String url;
public ApacheDubboServiceBeanPostProcessor(final DubboConfig dubboConfig) {
String contextPath = dubboConfig.getContextPath();
String adminUrl = dubboConfig.getAdminUrl();
if (StringUtils.isEmpty(contextPath)
|| StringUtils.isEmpty(adminUrl)) {
throw new RuntimeException("apache dubbo client must config the contextPath, adminUrl");
}
this.dubboConfig = dubboConfig;
url = dubboConfig.getAdminUrl() + "/soul-client/dubbo-register";
executorService = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
}
private void handler(final ServiceBean serviceBean) {
Class<?> clazz = serviceBean.getRef().getClass();
if (ClassUtils.isCglibProxyClass(clazz)) { // 获取Spring管理的类
String superClassName = clazz.getGenericSuperclass().getTypeName();
try {
clazz = Class.forName(superClassName);
} catch (ClassNotFoundException e) {
log.error(String.format("class not found: %s", superClassName));
return;
}
}
final Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(clazz); // 扫描方法,如果有SoulDubboClient注解,则注册到【soul-admin】中
for (Method method : methods) {
SoulDubboClient soulDubboClient = method.getAnnotation(SoulDubboClient.class);
if (Objects.nonNull(soulDubboClient)) {
RegisterUtils.doRegister(buildJsonParams(serviceBean, soulDubboClient, method), url, RpcTypeEnum.DUBBO);
}
}
}
@Override
public void onApplicationEvent(final ContextRefreshedEvent contextRefreshedEvent) { // Spring容器加载完毕后执行
if (Objects.nonNull(contextRefreshedEvent.getApplicationContext().getParent())) {
return;
}
Map<String, ServiceBean> serviceBean = contextRefreshedEvent.getApplicationContext().getBeansOfType(ServiceBean.class);
for (Map.Entry<String, ServiceBean> entry : serviceBean.entrySet()) { // 对 Spirng 容器中所有注解了ServiceBean的对象,注册到 【soul-admin】中
executorService.execute(() -> handler(entry.getValue()));
}
}
// 构造请求参数
private String buildJsonParams(final ServiceBean serviceBean, final SoulDubboClient soulDubboClient, final Method method) {
String appName = dubboConfig.getAppName();
if (StringUtils.isEmpty(appName)) {
appName = serviceBean.getApplication().getName();
}
String path = dubboConfig.getContextPath() + soulDubboClient.path();
String desc = soulDubboClient.desc();
String serviceName = serviceBean.getInterface();
String configRuleName = soulDubboClient.ruleName();
String ruleName = ("".equals(configRuleName)) ? path : configRuleName;
String methodName = method.getName();
Class<?>[] parameterTypesClazz = method.getParameterTypes();
String parameterTypes = Arrays.stream(parameterTypesClazz).map(Class::getName)
.collect(Collectors.joining(","));
MetaDataDTO metaDataDTO = MetaDataDTO.builder()
.appName(appName)
.serviceName(serviceName)
.methodName(methodName)
.contextPath(dubboConfig.getContextPath())
.path(path)
.ruleName(ruleName)
.pathDesc(desc)
.parameterTypes(parameterTypes)
.rpcExt(buildRpcExt(serviceBean))
.rpcType("dubbo")
.enabled(soulDubboClient.enabled())
.build();
return OkHttpTools.getInstance().getGson().toJson(metaDataDTO);
}
// RPC 额外信息构造 包括组/版本/负载均衡/重试次数/超时时间等
private String buildRpcExt(final ServiceBean serviceBean) {
MetaDataDTO.RpcExt build = MetaDataDTO.RpcExt.builder()
.group(StringUtils.isNotEmpty(serviceBean.getGroup()) ? serviceBean.getGroup() : "")
.version(StringUtils.isNotEmpty(serviceBean.getVersion()) ? serviceBean.getVersion() : "")
.loadbalance(StringUtils.isNotEmpty(serviceBean.getLoadbalance()) ? serviceBean.getLoadbalance() : Constants.DEFAULT_LOADBALANCE)
.retries(Objects.isNull(serviceBean.getRetries()) ? Constants.DEFAULT_RETRIES : serviceBean.getRetries())
.timeout(Objects.isNull(serviceBean.getTimeout()) ? Constants.DEFAULT_CONNECT_TIMEOUT : serviceBean.getTimeout())
.url("")
.build();
return OkHttpTools.getInstance().getGson().toJson(build);
}
}
以上就是Dubbo元数据上传流程