前面我們已經本地啟動了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<DivideUpstream> 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<SelectorConditionDTO> 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<SelectorConditionDTO> selectorConditionDTOs) {
PluginDO pluginDO = pluginMapper.selectById(selectorDO.getPluginId());
List<ConditionData> 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))));
}
總結下來就是:
同步數據到數據庫,并將數據的變化事件發送出去,具體發送后做的事情我們下篇文章在分析