美文网首页Java架构技术进阶码出未来老男孩的成长之路
Dubbo如何支持本地调用?InJvm方式解析

Dubbo如何支持本地调用?InJvm方式解析

作者: 老男孩_Misaya | 来源:发表于2020-02-12 18:29 被阅读0次

    推荐阅读:

    Dubbo是一个远程调用的框架,对于一个服务提供者,暴露了一个接口供外部消费者调用,
    那么对于提供者自己是否可以调用这个接口,需要什么特殊处理吗?

    这篇文章就分享下Dubbo关于本地调用的实现机制,以及如何开启和关闭本地调用。

    injvm支持本地调用

    使用 Dubbo 本地调用不需做特殊配置,按正常 Dubbo 服务暴露服务即可。
    任一服务在暴露远程服务的同时,也会同时以 injvm 的协议暴露本地服务。
    injvm 是一个伪协议,不会像其他协议那样对外开启端口,只用于本地调用的目的。

    InjvmProtocol源码学习

    injvm相关的代码实现在Dubbo-rpc-injvm模块中,主要是InjvmExporter、InjvmInvoker和InjvmProtocol。

    InjvmProtocol 继承 AbstractProtocol,

    public class InjvmProtocol extends AbstractProtocol implements Protocol {
    
        public static final String NAME = Constants.LOCAL_PROTOCOL;
    
        public static final int DEFAULT_PORT = 0;
        private static InjvmProtocol INSTANCE;
    
        public InjvmProtocol() {
            INSTANCE = this;
        }
    
        public static InjvmProtocol getInjvmProtocol() {
            if (INSTANCE == null) {
                ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(InjvmProtocol.NAME); // load
            }
            return INSTANCE;
        }
    
        @Override
        public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
            return new InjvmExporter<T>(invoker, invoker.getUrl().getServiceKey(), exporterMap);
        }
    
        @Override
        public <T> Invoker<T> refer(Class<T> serviceType, URL url) throws RpcException {
            return new InjvmInvoker<T>(serviceType, url, url.getServiceKey(), exporterMap);
        }
    }
    

    除了export和refer方法,InjvmProtocol提供了isInjvmRefer()方法,

    isInjvmRefer会读取配置文件,判断是否开启本地调用。

        public boolean isInjvmRefer(URL url) {
            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.SCOPE_LOCAL.equals(scope) || (url.getParameter(Constants.LOCAL_PROTOCOL, false))) {
                // if it's declared as local reference
                // 'scope=local' is equivalent to 'injvm=true', injvm will be deprecated in the future release
                return true;
            } else if (Constants.SCOPE_REMOTE.equals(scope)) {
                // it's declared as remote reference
                return false;
            } else if (url.getParameter(Constants.GENERIC_KEY, false)) {
                // generic invocation is not local reference
                return false;
            } else if (getExporter(exporterMap, url) != null) {
                // by default, go through local reference if there's the service exposed locally
                return true;
            } else {
                return false;
            }
        }
    
    

    本地调用同样经过Filter链

    与真正的本地方法调用不同的是,Dubbo 本地调用会经过 Filter 链,其中包括了 Consumer 端的 Filter 链以及 Provider 端的 Filter 链。

    通过这样的机制,本地消费者和其他消费者都是统一对待,统一监控,服务统一进行治理。

    如何开启本地调用

    默认情况下,本地调用是自动开启的,不需要做额外的配置。只有只有当需要关闭的时候,才需要通过 scope 的配置来显式的关闭。

    但是,特别需要指出的是,在下面的几种情况下,本地调用是无法使用的:

    第一,泛化调用的时候无法使用本地调用。

    第二,消费者明确指定 URL 发起直连调用。当然,如果消费者指定的是 injvm 的 URL,最终的调用也是走本地调用的,比如:

    <Dubbo:reference id="demoService" interface="org.apache.Dubbo.samples.local.api.DemoService" url="injvm://127.0.0.1/org.apache.Dubbo.samples.local.api.DemoService"/>
    

    如何关闭本地调用

    本地调用是可以显示关闭的,通过这种方式,服务提供者可以做到对远端服务消费者和本地消费者一视同仁。

    具体做法是通过 scope="remote" 来关闭 injvm 协议的暴露,这样,即使是本地调用者,也需要从注册中心上获取服务地址列表,然后才能发起调用,

    而这个时候的调用过程,与远端的服务消费者的过程是一致的。

    <bean id="target" class="org.apache.Dubbo.samples.local.impl.DemoServiceImpl"/>
    <!-- 服务提供者指定 scope="remote" -->
    <Dubbo:service interface="org.apache.Dubbo.samples.local.api.DemoService" ref="target" scope="remote"/>
    <Dubbo:reference id="demoService" interface="org.apache.Dubbo.samples.local.api.DemoService"/>
    

    相关文章

      网友评论

        本文标题:Dubbo如何支持本地调用?InJvm方式解析

        本文链接:https://www.haomeiwen.com/subject/nlpsxhtx.html