前面我们已经本地启动了SpringBoot服务,并将Controller的接口注册到了SoulAdmin,并通过网关调用成功转发到了我们的服务,这一节我们从http项目是如何注册到SoulAdmin,SoulAdmin又如何将注册信息同步到网关的整个流程来剖析下源代码
首先启动SoulAdmin。接下来在启动我们的SpringBoot项目
第二节,我们由于http注册问题,已经大体走完了,服务启动注册到SoulAdmin的流程,通过http请求到SoulAdmin的/soul-client/springmvc-register接口
接下来在SoulAdmin中定位到该接口
//org.dromara.soul.admin.controller.SoulClientController
/**
* Register spring mvc string.
*
* @param springMvcRegisterDTO the spring mvc register dto
* @return the string
*/
@PostMapping("/springmvc-register")
public String registerSpringMvc(@RequestBody final SpringMvcRegisterDTO springMvcRegisterDTO) {
return soulClientRegisterService.registerSpringMvc(springMvcRegisterDTO);
}
我们看下SpringMvcRegisterDTO类,这个是之前org.dromara.soul.client.springmvc.init.SpringMvcClientBeanPostProcessor#buildJsonParams构造的信息
@Data
public class SpringMvcRegisterDTO implements Serializable {
//我们SpringBoot项目配置的appName
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;
}
进入到service中
//org.dromara.soul.admin.service.impl.SoulClientRegisterServiceImpl
@Override
@Transactional
public String registerSpringMvc(final SpringMvcRegisterDTO dto) {
//是否注册元数据信息,这里http默认是false,元数据主要是为dubbo的泛化调用使用的,这里不是主要的关注重点
if (dto.isRegisterMetaData()) {
//根据path看元数据信息是否存在
MetaDataDO exist = metaDataMapper.findByPath(dto.getPath());
if (Objects.isNull(exist)) {
saveSpringMvcMetaData(dto);
}
}
//1
String selectorId = handlerSpringMvcSelector(dto);
handlerSpringMvcRule(selectorId, dto);
return SoulResultMessage.SUCCESS;
}
1.进入到org.dromara.soul.admin.service.impl.SoulClientRegisterServiceImpl#handlerSpringMvcSelector
private String handlerSpringMvcSelector(final SpringMvcRegisterDTO dto) {
//我们在SpringBoot项目中配置的contextPath
String contextPath = dto.getContext();
SelectorDO selectorDO = selectorService.findByName(contextPath);
String selectorId;
String uri = String.join(":", dto.getHost(), String.valueOf(dto.getPort()));
if (Objects.isNull(selectorDO)) {
//1.1 注册选择器
selectorId = registerSelector(contextPath, dto.getRpcType(), dto.getAppName(), uri);
} else {
selectorId = selectorDO.getId();
//update upstream
String handle = selectorDO.getHandle();
String handleAdd;
DivideUpstream addDivideUpstream = buildDivideUpstream(uri);
SelectorData selectorData = selectorService.buildByName(contextPath);
if (StringUtils.isBlank(handle)) {
handleAdd = GsonUtils.getInstance().toJson(Collections.singletonList(addDivideUpstream));
} else {
List exist = GsonUtils.getInstance().fromList(handle, DivideUpstream.class);
//如果已存在的规则和这次新增加的相等,则不需要更新
for (DivideUpstream upstream : exist) {
if (upstream.getUpstreamUrl().equals(addDivideUpstream.getUpstreamUrl())) {
return selectorId;
}
}
exist.add(addDivideUpstream);
handleAdd = GsonUtils.getInstance().toJson(exist);
}
selectorDO.setHandle(handleAdd);
selectorData.setHandle(handleAdd);
// update db
selectorMapper.updateSelective(selectorDO);
// submit upstreamCheck
upstreamCheckService.submit(contextPath, addDivideUpstream);
// publish change event.
eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.SELECTOR, DataEventTypeEnum.UPDATE,
Collections.singletonList(selectorData)));
}
return selectorId;
}
1.1 org.dromara.soul.admin.service.impl.SoulClientRegisterServiceImpl#registerSelector
private String registerSelector(final String contextPath, final String rpcType, final String appName, final String uri) {
//构造选择器默认类,无论我们在SpringBoot项目配置的full是true或者false,在选择器这里没有区别。都是CUSTOM_FLOW,区别是在规则那里
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 {
//我们这次是http服务注册,rpcType是http
//1.1.1 这里构造DivideUpstream代表http上游
DivideUpstream divideUpstream = buildDivideUpstream(uri);
String handler = GsonUtils.getInstance().toJson(Collections.singletonList(divideUpstream));
//DivideUpsteam的json字符串,对应选择器中的配置
selectorDTO.setHandle(handler);
//选择器对应的就是Divide控件
selectorDTO.setPluginId(getPluginId(PluginEnum.DIVIDE.getName()));
//这里是 上游检查服务,之后单独写一篇文章
upstreamCheckService.submit(selectorDTO.getName(), divideUpstream);
}
//选择器条件默认就是Match对应的contextPath+/**
SelectorConditionDTO selectorConditionDTO = new SelectorConditionDTO();
selectorConditionDTO.setParamType(ParamTypeEnum.URI.getName());
selectorConditionDTO.setParamName("/");
selectorConditionDTO.setOperator(OperatorEnum.MATCH.getAlias());
selectorConditionDTO.setParamValue(contextPath + "/**");
selectorDTO.setSelectorConditions(Collections.singletonList(selectorConditionDTO));
//1.1.2 注册
return selectorService.register(selectorDTO);
}
SelectorDto的handle是存储的就是DivideUpsteam的json字符串,对应选择器的Configuration
1.1.1 org.dromara.soul.admin.service.impl.SoulClientRegisterServiceImpl#buildDivideUpstream
//uri 是 前面传递过来的,String.join(":", dto.getHost(), String.valueOf(dto.getPort()));
//实际上就是代表咱们注册服务上游的http访问地址
private DivideUpstream buildDivideUpstream(final String uri) {
return DivideUpstream.builder()
.upstreamHost("localhost")
.protocol("http://")
.upstreamUrl(uri)
.weight(50)
.build();
}
1.1.2 org.dromara.soul.admin.service.impl.SelectorServiceImpl#register
@Override
public String register(final SelectorDTO selectorDTO) {
//这里就是简单的数据库操作
SelectorDO selectorDO = SelectorDO.buildSelectorDO(selectorDTO);
List selectorConditionDTOs = selectorDTO.getSelectorConditions();
if (StringUtils.isEmpty(selectorDTO.getId())) {
selectorMapper.insertSelective(selectorDO);
selectorConditionDTOs.forEach(selectorConditionDTO -> {
selectorConditionDTO.setSelectorId(selectorDO.getId());
selectorConditionMapper.insertSelective(SelectorConditionDO.buildSelectorConditionDO(selectorConditionDTO));
});
}
//1.1.2.1 这里发布事件
publishEvent(selectorDO, selectorConditionDTOs);
return selectorDO.getId();
}
1.1.2.1 org.dromara.soul.admin.service.impl.SelectorServiceImpl#publishEvent
private final ApplicationEventPublisher eventPublisher;
private void publishEvent(final SelectorDO selectorDO, final List selectorConditionDTOs) {
PluginDO pluginDO = pluginMapper.selectById(selectorDO.getPluginId());
List conditionDataList =
selectorConditionDTOs.stream().map(ConditionTransfer.INSTANCE::mapToSelectorDTO).collect(Collectors.toList());
// 发布数据变化事件,用到了Spring的EventBus机制,之后单独拿一章节讲一下EventBus
eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.SELECTOR, DataEventTypeEnum.UPDATE,
Collections.singletonList(SelectorDO.transFrom(selectorDO, pluginDO.getName(), conditionDataList))));
}
总结下来就是:
同步数据到数据库,并将数据的变化事件发送出去,具体发送后做的事情我们下篇文章在分析