资讯专栏INFORMATION COLUMN

dubbo源码解析(二十七)远程调用——injvm本地调用

sean / 2440人阅读

摘要:远程调用本地调用目标介绍本地调用的设计和实现,介绍的源码。前言是一个远程调用的框架,但是它没有理由不支持本地调用,本文就要讲解关于本地调用的实现。服务暴露者集合取消暴露调用父类的取消暴露方法从集合中移除二该类继承了类,是本地调用的实现。

远程调用——injvm本地调用
目标:介绍injvm本地调用的设计和实现,介绍dubbo-rpc-injvm的源码。
前言

dubbo是一个远程调用的框架,但是它没有理由不支持本地调用,本文就要讲解dubbo关于本地调用的实现。本地调用要比远程调用简单的多。

源码分析 (一)InjvmExporter

该类继承了AbstractExporter,是本地服务的暴露者封装,其中实现比较简单。只是实现了unexport方法,并且维护了一份保存暴露者的集合。

class InjvmExporter extends AbstractExporter {

    /**
     * 服务key
     */
    private final String key;

    /**
     * 暴露者集合
     */
    private final Map> exporterMap;

    InjvmExporter(Invoker invoker, String key, Map> exporterMap) {
        super(invoker);
        this.key = key;
        this.exporterMap = exporterMap;
        exporterMap.put(key, this);
    }

    /**
     * 取消暴露
     */
    @Override
    public void unexport() {
        // 调用父类的取消暴露方法
        super.unexport();
        // 从集合中移除
        exporterMap.remove(key);
    }

}
(二)InjvmInvoker

该类继承了AbstractInvoker类,是本地调用的invoker实现。

class InjvmInvoker extends AbstractInvoker {

    /**
     * 服务key
     */
    private final String key;

    /**
     * 暴露者集合
     */
    private final Map> exporterMap;

    InjvmInvoker(Class type, URL url, String key, Map> exporterMap) {
        super(type, url);
        this.key = key;
        this.exporterMap = exporterMap;
    }

    /**
     * 服务是否活跃
     * @return
     */
    @Override
    public boolean isAvailable() {
        InjvmExporter exporter = (InjvmExporter) exporterMap.get(key);
        if (exporter == null) {
            return false;
        } else {
            return super.isAvailable();
        }
    }

    /**
     * invoke方法
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Result doInvoke(Invocation invocation) throws Throwable {
        // 获得暴露者
        Exporter exporter = InjvmProtocol.getExporter(exporterMap, getUrl());
        // 如果为空,则抛出异常
        if (exporter == null) {
            throw new RpcException("Service [" + key + "] not found.");
        }
        // 设置远程地址为127.0.0.1
        RpcContext.getContext().setRemoteAddress(NetUtils.LOCALHOST, 0);
        // 调用下一个调用链
        return exporter.getInvoker().invoke(invocation);
    }
}

其中重写了isAvailable和doInvoke方法。

(三)InjvmProtocol

该类是本地调用的协议实现,其中实现了服务调用和服务暴露方法,并且封装了一个判断是否是本地调用的方法。

1.属性
/**
 * 本地调用  Protocol的实现类key
 */
public static final String NAME = Constants.LOCAL_PROTOCOL;

/**
 * 默认端口
 */
public static final int DEFAULT_PORT = 0;
/**
 * 单例
 */
private static InjvmProtocol INSTANCE;
2.getExporter
static Exporter getExporter(Map> map, URL key) {
    Exporter result = null;

    // 如果服务key不是*
    if (!key.getServiceKey().contains("*")) {
        // 直接从集合中取出
        result = map.get(key.getServiceKey());
    } else {
        // 如果 map不为空,则遍历暴露者,来找到对应的exporter
        if (map != null && !map.isEmpty()) {
            for (Exporter exporter : map.values()) {
                // 如果是服务key
                if (UrlUtils.isServiceKeyMatch(key, exporter.getInvoker().getUrl())) {
                    // 赋值
                    result = exporter;
                    break;
                }
            }
        }
    }

    // 如果没有找到exporter
    if (result == null) {
        // 则返回null
        return null;
    } else if (ProtocolUtils.isGeneric(
            result.getInvoker().getUrl().getParameter(Constants.GENERIC_KEY))) {
        // 如果是泛化调用,则返回null
        return null;
    } else {
        return result;
    }
}

该方法是获得相关的暴露者。

3.export
@Override
public  Exporter export(Invoker invoker) throws RpcException {
    // 创建InjvmExporter 并且返回
    return new InjvmExporter(invoker, invoker.getUrl().getServiceKey(), exporterMap);
}
4.refer
@Override
public  Invoker refer(Class serviceType, URL url) throws RpcException {
    // 创建InjvmInvoker 并且返回
    return new InjvmInvoker(serviceType, url, url.getServiceKey(), exporterMap);
}
5.isInjvmRefer
public boolean isInjvmRefer(URL url) {
    final boolean isJvmRefer;
    // 获得scope配置
    String scope = url.getParameter(Constants.SCOPE_KEY);
    // Since injvm protocol is configured explicitly, we don"t need to set any extra flag, use normal refer process.
    if (Constants.LOCAL_PROTOCOL.toString().equals(url.getProtocol())) {
        // 如果是injvm,则不是本地调用
        isJvmRefer = false;
    } else if (Constants.SCOPE_LOCAL.equals(scope) || (url.getParameter("injvm", false))) {
        // if it"s declared as local reference
        // "scope=local" is equivalent to "injvm=true", injvm will be deprecated in the future release
        // 如果它被声明为本地引用 scope = local"相当于"injvm = true",将在以后的版本中弃用injvm
        isJvmRefer = true;
    } else if (Constants.SCOPE_REMOTE.equals(scope)) {
        // it"s declared as remote reference
        // 如果被声明为远程调用
        isJvmRefer = false;
    } else if (url.getParameter(Constants.GENERIC_KEY, false)) {
        // generic invocation is not local reference
        // 泛化的调用不是本地调用
        isJvmRefer = false;
    } else if (getExporter(exporterMap, url) != null) {
        // by default, go through local reference if there"s the service exposed locally
        // 默认情况下,如果本地暴露服务,请通过本地引用
        isJvmRefer = true;
    } else {
        isJvmRefer = false;
    }
    return isJvmRefer;
}

该方法是判断是否为本地调用。

后记
该部分相关的源码解析地址:https://github.com/CrazyHZM/i...

该文章讲解了远程调用中关于injvm本地调用的部分,三种抽象的角色还是比较鲜明的,服务暴露相关的exporter、服务引用相关的invoker、以及协议相关的protocol,关键还是弄清楚再设计上的意图,以及他们分别代表的是什么。那么看这些不同的协议实现会很容易看懂。接下来我将开始对rpc模块关于memcached协议部分进行讲解。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/73232.html

相关文章

  • dubbo源码解析(四十八)异步化改造

    摘要:大揭秘异步化改造目标从源码的角度分析的新特性中对于异步化的改造原理。看源码解析四十六消费端发送请求过程讲到的十四的,在以前的逻辑会直接在方法中根据配置区分同步异步单向调用。改为关于可以参考源码解析十远程通信层的六。 2.7大揭秘——异步化改造 目标:从源码的角度分析2.7的新特性中对于异步化的改造原理。 前言 dubbo中提供了很多类型的协议,关于协议的系列可以查看下面的文章: du...

    lijinke666 评论0 收藏0
  • dubbo源码解析(四十四)服务暴露过程

    摘要:服务暴露过程目标从源码的角度分析服务暴露过程。导出服务,包含暴露服务到本地,和暴露服务到远程两个过程。其中服务暴露的第八步已经没有了。将泛化调用版本号或者等信息加入获得服务暴露地址和端口号,利用内数据组装成。 dubbo服务暴露过程 目标:从源码的角度分析服务暴露过程。 前言 本来这一篇一个写异步化改造的内容,但是最近我一直在想,某一部分的优化改造该怎么去撰写才能更加的让读者理解。我觉...

    light 评论0 收藏0
  • dubbo源码解析二十六)远程调用——http协议

    摘要:前言基于表单的远程调用协议,采用的实现,关于协议就不用多说了吧。后记该部分相关的源码解析地址该文章讲解了远程调用中关于协议的部分,内容比较简单,可以参考着官方文档了解一下。 远程调用——http协议 目标:介绍远程调用中跟http协议相关的设计和实现,介绍dubbo-rpc-http的源码。 前言 基于HTTP表单的远程调用协议,采用 Spring 的HttpInvoker实现,关于h...

    xiyang 评论0 收藏0
  • dubbo源码解析(四十七)服务端处理请求过程

    摘要:而存在的意义就是保证请求或响应对象可在线程池中被解码,解码完成后,就会分发到的。 2.7大揭秘——服务端处理请求过程 目标:从源码的角度分析服务端接收到请求后的一系列操作,最终把客户端需要的值返回。 前言 上一篇讲到了消费端发送请求的过程,该篇就要将服务端处理请求的过程。也就是当服务端收到请求数据包后的一系列处理以及如何返回最终结果。我们也知道消费端在发送请求的时候已经做了编码,所以我...

    yzzz 评论0 收藏0
  • dubbo源码解析(四十六)消费端发送请求过程

    摘要:可以参考源码解析二十四远程调用协议的八。十六的该类也是用了适配器模式,该类主要的作用就是增加了心跳功能,可以参考源码解析十远程通信层的四。二十的可以参考源码解析十七远程通信的一。 2.7大揭秘——消费端发送请求过程 目标:从源码的角度分析一个服务方法调用经历怎么样的磨难以后到达服务端。 前言 前一篇文章讲到的是引用服务的过程,引用服务无非就是创建出一个代理。供消费者调用服务的相关方法。...

    fish 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<