继续上篇
从之前的3篇文章中,我们可以知道,我们的dubbo
服务启动,会将服务注册到网关soul-admin
,并生成对应的服务元数据;而我们的网关soul-bootstrap
则会同步服务元数据,将其放置到一个应用配置ApplicationConfigCache
保持的缓存中进行存储。那soul-bootstrap
什么时候会去使用这部分的数据呢?这个就是我们今天要分析的问题。
分析
- 查找
ApplicationConfigCache
被使用的地方,我们查看其方法,大致可以得出get
方法引用地方则就是其使用的地方
- 接着查看
ApplicationConfigCache.get
被调用的地方
- 从而可以找到关键类
org.dromara.soul.plugin.alibaba.dubbo.proxy.AlibabaDubboProxyService
- 继续查看
AlibabaDubboProxyService.genericInvoker
被引用的地方,可以定位到org.dromara.soul.plugin.alibaba.dubbo.AlibabaDubboPlugin
- 好,跟踪到这里基本上就能衔接起来了。大致如下:
- 从前端的请求,经过插件链,链上有
dubbo
插件; - 先判断
dubbo
插件是否开启,再判断dubbo
插件中是否有匹配的选择器selector
,再判断选择器中的规则rule
是否匹配; - 当上述条件都成立时,才会进入
dubbo
插件AlibabaDubboPlugin
本身的执行逻辑onExecute
方法; - 进入
onExecute
方法后,调用AlibabaDubboProxyService
的genericInvoker
方法完成服务的调用
- 从前端的请求,经过插件链,链上有
protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
String body = exchange.getAttribute(Constants.DUBBO_PARAMS);
SoulContext soulContext = exchange.getAttribute(Constants.CONTEXT);
assert soulContext != null;
MetaData metaData = exchange.getAttribute(Constants.META_DATA);
// 校验:metaData是否有效,方法名&服务名不为空
if (!checkMetaData(metaData)) {
assert metaData != null;
log.error(" path is :{}, meta data have error.... {}", soulContext.getPath(), metaData.toString());
exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
Object error = SoulResultWrap.error(SoulResultEnum.META_DATA_ERROR.getCode(), SoulResultEnum.META_DATA_ERROR.getMsg(), null);
return WebFluxResultUtils.result(exchange, error);
}
// 校验:参数类型不为空,则必须要有请求body,不能为空
if (StringUtils.isNoneBlank(metaData.getParameterTypes()) && StringUtils.isBlank(body)) {
exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
Object error = SoulResultWrap.error(SoulResultEnum.DUBBO_HAVE_BODY_PARAM.getCode(), SoulResultEnum.DUBBO_HAVE_BODY_PARAM.getMsg(), null);
return WebFluxResultUtils.result(exchange, error);
}
// 完成dubbo服务调用
Object result = alibabaDubboProxyService.genericInvoker(body, metaData);
// 处理返回结果
if (Objects.nonNull(result)) {
exchange.getAttributes().put(Constants.DUBBO_RPC_RESULT, result);
} else {
exchange.getAttributes().put(Constants.DUBBO_RPC_RESULT, Constants.DUBBO_RPC_RESULT_EMPTY);
}
exchange.getAttributes().put(Constants.CLIENT_RESPONSE_RESULT_TYPE, ResultEnum.SUCCESS.getName());
// 继续下一个插件链路
return chain.execute(exchange);
}
- 该方法的主要逻辑就是:先根据请求路径
path
从ApplicationConfigCache
中查找是否存在服务引用配置ReferenceConfig
,获取配置中的引用服务,组装请求参数,完成调用,返回调用结果。
public Object genericInvoker(final String body, final MetaData metaData) throws SoulException {
// 找服务引用配置
ReferenceConfig<GenericService> reference = ApplicationConfigCache.getInstance().get(metaData.getPath());
// 为空则初始化一个服务引用配置
if (Objects.isNull(reference) || StringUtils.isEmpty(reference.getInterface())) {
ApplicationConfigCache.getInstance().invalidate(metaData.getPath());
reference = ApplicationConfigCache.getInstance().initRef(metaData);
}
// 获取服务引用配置中的服务
GenericService genericService = reference.get();
try {
// 处理dubbo服务的请求参数;为请求参数对;key为参数名数组,value为参数值数组
Pair<String[], Object[]> pair;
if (ParamCheckUtils.dubboBodyIsEmpty(body)) {
pair = new ImmutablePair<>(new String[]{}, new Object[]{});
} else {
pair = dubboParamResolveService.buildParameter(body, metaData.getParameterTypes());
}
// 完成dubbo服务调用
return genericService.$invoke(metaData.getMethodName(), pair.getLeft(), pair.getRight());
} catch (GenericException e) {
log.error("dubbo invoker have exception", e);
throw new SoulException(e.getExceptionMessage());
}
}
end
至此,终于将dubbo协议转换过程分析完成,主要为如下几块
dubbo
服务配置注册到网关soul-admin
- 网关
soul-admin
同步dubbo服务配置数据到网关soul-bootstrap
dubbo
插件如何完成dubbo
服务调用