Apache ShenYu 网关 dubbo、sofa插件底层原理分析

说明

  • 本文将分析 Apache ShenYu 网关 alibaba dubbo、apache dubbo、sofa插件底层原理分析
  • dubbo、sofa项目如何配置 shenyu,以及 shenyu 网关如何开启对应插件的支持不在此讲述,可参考本站文章 Apache ShenYu 官方examples体验

shenyu 网关 alibaba dubbo 插件底层原理解析

插件概述

shenyu 网关 alibaba dubbo 插件使得网关支持 alibaba dubbo的服务,也就是说 客户端发送的http请求,最终可以请求到alibaba dubbo rpc的服务。

源码分析

shenyu 网关 alibaba dubbo 插件的底层原理是:将客户端请求进网关的http请求,根据uri匹配插件,验证选择器、规则,然后交给 AlibabaDubboPlugin,它再交由AlibabaDubboProxyService去请求 alibaba dubbo服务,AlibabaDubboProxyService做的事情就是将http的请求转换为 alibaba dubbo协议的请求。

public class AlibabaDubboPlugin extends AbstractShenyuPlugin {

    @Override
    protected Mono<Void> doExecute(final ServerWebExchange exchange, final ShenyuPluginChain chain, final SelectorData selector, final RuleData rule) {
        ……
        //AlibabaDubboProxyService里会转换为 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);
    }
}

public class AlibabaDubboProxyService {
    ……
    public Object genericInvoker(final String body, final MetaData metaData) throws ShenyuException {
       //在缓存里获取 alibaba dubbo config的信息 
        ReferenceConfig<GenericService> reference = ApplicationConfigCache.getInstance().get(metaData.getPath());
        ……
        //根据 alibaba dubbo config获取alibaba dubbo rpc服务
        GenericService genericService = reference.get();
        try {
            Pair<String[], Object[]> pair;
            //封装参数
            if (ParamCheckUtils.dubboBodyIsEmpty(body)) {
                pair = new ImmutablePair<>(new String[]{}, new Object[]{});
            } else {
                pair = dubboParamResolveService.buildParameter(body, metaData.getParameterTypes());
            }
            //通过 dubbo rpc请求上游目标服务
            return genericService.$invoke(metaData.getMethodName(), pair.getLeft(), pair.getRight());
        }
        ……
}

shenyul 网关 apache dubbo 插件底层原理解析

插件概述

shenyu 网关 apache dubbo 插件使得网关支持 apache dubbo的服务,也就是说 客户端发送的http请求,最终可以请求apache dubbo rpc的服务。

源码分析

shenyu 网关 alibaba dubbo 插件的的执行流程和 alibaba dubbo 基本一致,有差别的地方在于协议转换,针对 apache dubbo协议做了针对处理。通过http请求 apache dubbo服务的底层原理就是,在网关这边创建 alibaba dubbo rpc,再由它去请求具体的 alibaba dubbo rpc服务,然后返回结果。 做协议转换并发送请求的类是ApacheDubboProxyService,它的核心源码如下:

public class ApacheDubboProxyService {
    ……
    public Mono<Object> genericInvoker(final String body, final MetaData metaData, final ServerWebExchange exchange) throws ShenyuException {
        // 增加 dubbo tag的路由信息
        String dubboTagRouteFromHttpHeaders = exchange.getRequest().getHeaders().getFirst(Constants.DUBBO_TAG_ROUTE);
        ……
        RpcContext.getContext().setAttachment(CommonConstants.TAG_KEY, dubboTagRouteFromHttpHeaders);

        //从缓存中获取 apache dubbo 配置类
        ReferenceConfig<GenericService> reference = ApplicationConfigCache.getInstance().get(metaData.getPath());
        ……
        //根据 apache dubbo 配置类获取 apache dubbo rpc 服务类
        GenericService genericService = reference.get();

        //装配参数
        Pair<String[], Object[]> pair;
        if (ParamCheckUtils.dubboBodyIsEmpty(body)) {
            pair = new ImmutablePair<>(new String[]{}, new Object[]{});
        } else {
            pair = dubboParamResolveService.buildParameter(body, metaData.getParameterTypes());
        }
        //通过ache dubbo rpc协议请求上游对应服务
        CompletableFuture<Object> future = genericService.$invokeAsync(metaData.getMethodName(), pair.getLeft(), pair.getRight());
       ……
    }
}

shenyu 网关 sofa 插件底层原理解析

插件概述

shenyul 网关 sofa插件使得我们网关能够支持目标端为 sofa的服务,我们可以通过http去请求到 sofa的服务。

源码分析

sofa插件的主要赋能的是将 http协议请求转换为 sofa rpc协议,然后去请求 sofa rpc的上游服务,并返回结果。从而实现通过 http 去请求到 sofa 的服务。它的底层原理也就是协议的转换,简单来说就是将http协议请求的参数封装到 sofa rpc 服务的请求参数,最后执行。它的源码类为SofaProxyService,核心代码如下:

public class SofaProxyService {
    public Mono<Object> genericInvoker(final String body, final MetaData metaData, final ServerWebExchange exchange) throws ShenyuException {
        //从服务缓存中获取 sofa rpc 的配置信息
        ConsumerConfig<GenericService> reference = ApplicationConfigCache.getInstance().get(metaData.getPath());
        ……
        //根据 配置信息获取 sofa rpc 服务
        GenericService genericService = reference.refer();

        //封装sofa rpc 服务请求参数
        Pair<String[], Object[]> pair;
        if (null == body || "".equals(body) || "{}".equals(body) || "null".equals(body)) {
            pair = new ImmutablePair<>(new String[]{}, new Object[]{});
        } else {
            pair = sofaParamResolveService.buildParameter(body, metaData.getParameterTypes());
        }
        //异步结果封装
        CompletableFuture<Object> future = new CompletableFuture<>();
        //设置 sofa rpc 的响应回调
        RpcInvokeContext.getContext().setResponseCallback(new SofaResponseCallback<Object>() {
            @Override
            public void onAppResponse(final Object o, final String s, final RequestBase requestBase) {
                future.complete(o);
            }
            ……

        });
        //执行 sofa rpc请求
        genericService.$invoke(metaData.getMethodName(), pair.getLeft(), pair.getRight());
        //将线程串行化,sofa rpc 服务请求有结果后再执行,将请求结果返回
        return Mono.fromFuture(future.thenApply(ret -> {
            if (Objects.isNull(ret)) {
                ret = Constants.SOFA_RPC_RESULT_EMPTY;
            }
            exchange.getAttributes().put(Constants.SOFA_RPC_RESULT, ret);
            ……
            return ret;
        })).onErrorMap(ShenyuException::new);
    }
}

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注