前言

大家好,明天开始给大家分享 — Dubbo 专题之 Dubbo 本地调用。在后面的章节中咱们介绍了 Dubbo 异步调用,理解了什么是异步调用以及日常的应用场景和实现原理,同时咱们晓得 Dubbo 的异步调用可能切换咱们的申请和业务解决线程,这样充沛的利用的 NIO 的机制大大提供了线程的利用率。在这个章节中咱们会持续介绍 Dubbo 本地调用。首先咱们得理解什么是本地调用?与近程调用的区别以及有什么应用场景和实现原理。那就让咱们疾速开始吧!

1. Dubbo 本地调用简介

在后面的演示例子中咱们应用的都是近程调用,即通过网络通讯调用近程裸露的服务。本地调用就是在同一个 JVM 中进行服务调用不通过网络通讯进行近程调用,在 Dubbo 中本地调用的协定为 injvm://示意。与本地对象上办法调用不同的是,Dubbo 本地调用会通过 Filter 链,其中包含了服务生产端的 Filter 链以及服务提供端的 Filter 链。通过这样的机制,本地消费者和其余消费者都是对立看待,对立监控,服务对立进行治理。上面通过一个示例图演示本地调用和近程调用的区别:

从上图中能够看出 RPC 调用是通过网络近程调用服务,而咱们的本地调用是在同一个 JVM 过程中通过线程调用。这是两者最大的区别,本地调用是不须要到注册核心获取元信息,而近程调用时须要获取元数据的。

Tips:Dubbo 从 2.2.0 每个服务默认都会在本地裸露,无需进行任何配置即可进行本地援用,如果不心愿服务进行近程裸露,只须要在providerprotocol设置成 injvm 即可。

2. 多种应用形式

本地调用 Dubbo 提供多种配置形式:

  1. 应用 <dubbo:protocol/> 指定全局默认配置
<dubbo:protocol name="injvm" />
  1. 应用<dubbo:provider/>指定提供者配置
<dubbo:provider protocol="injvm" />
  1. 应用<dubbo:service/>标签指定某个服务配置
<dubbo:service protocol="injvm" />
  1. 通过应用scope="local"配置

同时咱们能够通过指定优先应用 injvm进行本地调用,配置形式如下:

  1. 全局指定
<dubbo:consumer injvm="true" /><!--指定所有消费者--><dubbo:provider injvm="true" /><!--指定所有服务提供者-->
  1. 指定服务
<dubbo:reference injvm="true" /><!--指定某个服务援用--><dubbo:service injvm="true" /><!--指定某个服务裸露-->

3. 应用场景

在后面探讨中咱们曾经晓得本地调用其实是不发动近程调用,而是在同一个中 JVM 中调用。咱们在日常工作中其实用得比拟少,其中有一种用法和前面将要介绍的Mock调用相似。就是当咱们须要调用近程的一个服务时,近程服务并没有开发实现,此时咱们就能够应用injvm协定在本地实现一个相似的服务,当调用此服务时调用咱们本地的实现服务。当近程服务开发实现时咱们切换到近程服务调用,这样就能够实现相似仿真的成果。

4. 示例演示

上面咱们以一个获取图书列表实例进行演示。我的项目构造如下:

这里咱们只有一个配置文件dubbo-xml.xml这是因为服务端和生产端都在同一个 JVM 中,其外围配置文件如下:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"       xmlns="http://www.springframework.org/schema/beans"       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">    <dubbo:application name="demo-provider"/>    <dubbo:protocol name="injvm"/>    <bean id="target" class="com.muke.dubbocourse.localinvoker.spring.BookFacadeImpl"/>    <!--裸露服务为Dubbo服务-->    <dubbo:service interface="com.muke.dubbocourse.common.api.BookFacade" ref="target" />    <!--援用本地服务-->    <dubbo:reference id="bookFacade" interface="com.muke.dubbocourse.common.api.BookFacade" scope="local"></dubbo:reference></beans>

下面的配置文件中咱们能够应用<dubbo:protocol name="injvm"/>形式裸露为本地服务应用scope="local"形式对本地裸露服务进行援用。

5. 实现原理

上面给出一张简化的调用流程图,其中最次要的就是依据咱们的配置比方:<dubbo:protocol name="injvm"/>scope="local"来判断是否裸露本地服务或近程服务。

接下来咱们通过代码的形式来进行简略的剖析:

当咱们须要裸露一个服务的时候最终会触发org.apache.dubbo.config.ServiceConfig#export办法调用,外围代码如下:

public synchronized void export() {             //...        //获取注册核心、检测配置本地存根和本地调用        checkAndUpdateSubConfigs();        //...        //判断是否提早保留        if (shouldDelay()) {            DELAY_EXPORT_EXECUTOR.schedule(this::doExport, getDelay(), TimeUnit.MILLISECONDS);        } else {            //服务保留            doExport();        }        //...    }

其中org.apache.dubbo.config.ServiceConfig#checkAndUpdateSubConfigs办法中有如下代码:

 private void checkAndUpdateSubConfigs() {        //..        // 判断协定是否配置为 injvm 例如:<dubbo:protocol name="injvm"/>        if (!isOnlyInJvm()) {            //获取注册核心配置            checkRegistry();        }               //...    }

此代码中isOnlyInJvm()办法判断协定是否配置为injvm,如果为injvm则不获取注册核心配置。紧接着开始调用上面

org.apache.dubbo.config.ServiceConfig#doExportUrlsFor1Protocol办法,其外围代码如下:

private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {        String name = protocolConfig.getName();              //判断是否配置protocol没有配置模式应用 dubbo 协定        if (StringUtils.isEmpty(name)) {            name = DUBBO;        }                //...                              //获取配置的 scope 例如:scope="local"        String scope = url.getParameter(SCOPE_KEY);        // scope 不等于 none         if (!SCOPE_NONE.equalsIgnoreCase(scope)) {            // scope 不等于 remote 裸露本地服务            if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {                exportLocal(url);            }             // scope 不等于 local 裸露近程服务            if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {                if (CollectionUtils.isNotEmpty(registryURLs)) {                    for (URL registryURL : registryURLs) {                        //判断如果是injvm协定不裸露近程服务                        if (LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {                            continue;                        }                                                                       //创立近程调用代理对象                        Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));                        DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);                        Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);                        exporters.add(exporter);                    }                } else {                                      //...                }                //...            }        }        this.urls.add(url);    }

下面的代码次要逻辑就是判断是否须要本地裸露和近程裸露,如果近程裸露则须要到注册核心注册服务元数据信息。

6. 小结

在本大节中咱们次要学习了 Dubbo 中的本地调用,同时咱们也介绍了常见的配置形式和一些应用场景。联合到咱们简化的流程图和源码的解说剖析咱们大抵可演绎为两大配置类:一类是应用injvm协定进行配置、一类是应用scope来配置。

本节课程的重点如下:

  1. 了解 Dubbo 中本地调用
  2. 理解常见应用形式
  3. 理解本地调用应用场景
  4. 理解本地调用实现原理

作者

集体从事金融行业,就任过易极付、思建科技、某网约车平台等重庆一流技术团队,目前就任于某银行负责对立领取零碎建设。本身对金融行业有强烈的喜好。同时也实际大数据、数据存储、自动化集成和部署、散布式微服务、响应式编程、人工智能等畛域。同时也热衷于技术分享创建公众号和博客站点对常识体系进行分享。关注公众号:青年IT男 获取最新技术文章推送!

博客地址: http://youngitman.tech

微信公众号: