blob: 7cde623cc06cbb332518396983ef043d8ab96821 [file] [log] [blame]
<!doctype html><html lang=zh-cn class=no-js><head><meta name=ROBOTS content="INDEX, FOLLOW"><link rel=canonical href=https://dubbo.apache.org/zh-cn/docsv2.7/dev/source/directory/><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name=generator content="Hugo 0.117.0"><link rel="shortcut icon" type=image/png href=/imgs/favicon.png><link rel=apple-touch-icon href=/favicons/apple-touch-icon-180x180.png sizes=180x180><link rel=manifest href=/manifest.webmanifest><title>服务目录 | Apache Dubbo</title><meta property="og:title" content="服务目录"><meta property="og:description" content="本文介绍了服务目录的原理和实现细节"><meta property="og:type" content="article"><meta property="og:url" content="https://dubbo.apache.org/zh-cn/docsv2.7/dev/source/directory/"><meta property="article:section" content="docsv2.7"><meta property="article:modified_time" content="2023-03-01T09:48:32+08:00"><meta itemprop=name content="服务目录"><meta itemprop=description content="本文介绍了服务目录的原理和实现细节"><meta itemprop=dateModified content="2023-03-01T09:48:32+08:00"><meta itemprop=wordCount content="1767"><meta itemprop=keywords content><meta name=twitter:card content="summary"><meta name=twitter:title content="服务目录"><meta name=twitter:description content="本文介绍了服务目录的原理和实现细节"><script async src="https://www.googletagmanager.com/gtag/js?id=G-1TFHM5YBH0"></script>
<script>var doNotTrack=!1;if(!doNotTrack){window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag("js",new Date),gtag("config","G-1TFHM5YBH0",{anonymize_ip:!1})}</script><link rel=preload href=/scss/main.min.fe7176cbe3102a33d3e8c0c9cec61eb52508abd24a2cc1ae23ccf535a481ffde.css as=style><link href=/scss/main.min.fe7176cbe3102a33d3e8c0c9cec61eb52508abd24a2cc1ae23ccf535a481ffde.css rel=stylesheet integrity><script src=/js/jquery-3.5.1.min.js integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin=anonymous></script>
<link rel=stylesheet href=https://cdn.jsdelivr.net/npm/@docsearch/css@3><meta name=theme-color content="#326ce5"><link rel=stylesheet href=/css/feature-states.css><meta name=description content="本文介绍了服务目录的原理和实现细节"><meta property="og:description" content="本文介绍了服务目录的原理和实现细节"><meta name=twitter:description content="本文介绍了服务目录的原理和实现细节"><meta property="og:url" content="https://dubbo.apache.org/zh-cn/docsv2.7/dev/source/directory/"><meta property="og:title" content="服务目录"><meta name=twitter:title content="服务目录"><meta name=twitter:image:alt content="Apache Dubbo"><meta property="og:type" content="article"><meta name=viewport content="width=device-width"><script async defer src=/js/github-buttons.js></script>
<link href=/css/community.css rel=stylesheet><link href=/css/contactus.css rel=stylesheet><link href=/css/language.css rel=stylesheet><script src=/js/script.js></script></head><body class="td-page td-documentation"><header><nav class="js-navbar-scroll navbar navbar-expand navbar-dark flex-column flex-md-row td-navbar" data-auto-burger=primary><a class=navbar-brand href=/zh-cn/><span class=navbar-logo></span><span class="text-uppercase font-weight-bold">Apache Dubbo</span></a><div class="td-navbar-nav-scroll ml-md-auto" id=main_navbar><ul class="navbar-nav mt-2 mt-lg-0"><li class="nav-item mr-4 mb-2 mb-lg-0"><a class=nav-link href=/zh-cn/overview/home/><span>文档</span></a></li><li class="nav-item mr-4 mb-2 mb-lg-0"><a class=nav-link href=/zh-cn/blog/><span>博客</span></a></li><li class="nav-item mr-4 mb-2 mb-lg-0"><a class=nav-link href=/zh-cn/download/><span>版本发布</span></a></li><li class="nav-item mr-4 mb-2 mb-lg-0"><a class=nav-link href=/zh-cn/contact/><span>联系社区</span></a></li><li class="nav-item mr-4 mb-2 mb-lg-0"><a class=nav-link href=https://start.dubbo.apache.org/bootstrap.html target=_blank><span>Initializer</span><i class='fas fa-external-link-alt'></i></a></li><li class="nav-item mr-4 mb-2 mb-lg-0"><a class=nav-link href=/zh-cn/github/><span>Github</span><i class='fa-brands fa-github'></i></a></li><li class="nav-item dropdown mr-4 d-none d-lg-block"><a class="nav-link dropdown-toggle" href=# id=navbarDropdown role=button data-toggle=dropdown aria-haspopup=true aria-expanded=false>版本列表</a><div class="dropdown-menu dropdown-menu-right" aria-labelledby=navbarDropdownMenuLink><a class=dropdown-item href=/releases>Release Information</a>
<a class=dropdown-item href=https://dubbo.apache.org/zh-cn/docsv2.7/dev/source/directory/>Java-3.3</a>
<a class=dropdown-item href=https://v3-2.dubbo.apache.org/zh-cn/docsv2.7/dev/source/directory/>Java-3.2</a>
<a class=dropdown-item href=https://dubbo.apache.org/zh-cn/docsv2.7/dev/source/directory/>Go-3.1</a>
<a class=dropdown-item href=https://dubbo.apache.org/zh-cn/docsv2.7/dev/source/directory/>Nodejs-0.1</a>
<a class=dropdown-item href=https://dubbo.apache.org/zh-cn/docsv2.7/dev/source/directory/>Web-0.1</a>
<a class=dropdown-item href=https://dubbo.apache.org/zh-cn/docsv2.7/dev/source/directory/>Rust-0.1</a></div></li><li class="nav-item dropdown d-lg-block"><a class="nav-link dropdown-toggle" href=# id=navbarDropdownMenuLink role=button data-toggle=dropdown aria-haspopup=true aria-expanded=false>中文</a><div class="dropdown-menu dropdown-menu-right" aria-labelledby=navbarDropdownMenuLink><a class=dropdown-item href=/en/>English</a></div></li><li class="nav-item dropdown d-lg-block"><div class="nav-item d-none d-lg-block"><div id=docsearch></div></div></li></ul></div></nav><div lang=zh-cn id=announcement style='background-color:#3371e3;color:#fff; "background-image: linear-gradient(to right, #073476, #002b76, #022274, #0b1772, #16066e);"'><aside><div class=announcement-main data-nosnippet><h4><img alt=ApacheCon-Asia src=/imgs/contacts/wechat-account.jpg style=float:right;width:10%;height:auto>
<a href=/zh-cn/blog/2023/08/25/coc-asia-2023-大会精彩回顾/>Dubbo 微服务专题论坛</a> 精彩回顾!</h4><p>Community Over Code 2023 暨 ApacheCon Asia 2023 大会在 8月18 - 8月20日在北京举办,让我们一起回顾一下可观测、Native、协议、Kubernetes部署、企业微服务实践等 8 个议题的精彩分享!</p></div></aside></div><section class="header-hero text-white pb-0 light-text"></section></header><div class="container-fluid td-outer"><div class=td-main><div class="row flex-md-nowrap"><div class="col-12 col-md-3 col-xl-2 td-sidebar d-print-none"><script>$(function(){$("#td-section-nav a").removeClass("active"),$("#td-section-nav #m-zh-cndocsv27devsourcedirectory").addClass("active"),$("#td-section-nav #m-zh-cndocsv27devsourcedirectory-li span").addClass("td-sidebar-nav-active-item"),$("#td-section-nav #m-zh-cndocsv27devsourcedirectory").parents("li").addClass("active-path"),$("#td-section-nav li.active-path").addClass("show"),$("#td-section-nav li.active-path").children("input").prop("checked",!0),$("#td-section-nav #m-zh-cndocsv27devsourcedirectory-li").siblings("li").addClass("show"),$("#td-section-nav #m-zh-cndocsv27devsourcedirectory-li").children("ul").children("li").addClass("show"),$("#td-sidebar-menu").toggleClass("d-none")})</script><div id=td-sidebar-menu class="td-sidebar__inner d-none"><div id=content-mobile><form class="td-sidebar__search d-flex align-items-center"><div id=docsearch></div><button class="btn btn-link td-sidebar__toggle d-md-none p-0 ml-3 fas fa-bars" type=button data-toggle=collapse data-target=#td-section-nav aria-controls=td-docs-nav aria-expanded=false aria-label="Toggle section navigation"></button></form></div><div id=content-desktop></div><nav class="collapse td-sidebar-nav foldable-nav" id=td-section-nav><ul class="td-sidebar-nav__section pr-md-3 ul-0"><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-zh-cndocsv27-li><ul class=ul-1><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-zh-cndocsv27user-li><input type=checkbox id=m-zh-cndocsv27user-check>
<label for=m-zh-cndocsv27user-check><a href=/zh-cn/docsv2.7/user/ class="align-left pl-0 td-sidebar-link td-sidebar-link__section" id=m-zh-cndocsv27user><span>用户文档</span></a></label><ul class="ul-2 foldable"><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-zh-cndocsv27userpreface-li><input type=checkbox id=m-zh-cndocsv27userpreface-check>
<label for=m-zh-cndocsv27userpreface-check><a href=/zh-cn/docsv2.7/user/preface/ class="align-left pl-0 td-sidebar-link td-sidebar-link__section" id=m-zh-cndocsv27userpreface><span>入门介绍</span></a></label><ul class="ul-3 foldable"><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userprefacebackground-li><input type=checkbox id=m-zh-cndocsv27userprefacebackground-check>
<label for=m-zh-cndocsv27userprefacebackground-check><a href=/zh-cn/docsv2.7/user/preface/background/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userprefacebackground><span>背景</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userprefacerequirements-li><input type=checkbox id=m-zh-cndocsv27userprefacerequirements-check>
<label for=m-zh-cndocsv27userprefacerequirements-check><a href=/zh-cn/docsv2.7/user/preface/requirements/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userprefacerequirements><span>需求</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userprefacearchitecture-li><input type=checkbox id=m-zh-cndocsv27userprefacearchitecture-check>
<label for=m-zh-cndocsv27userprefacearchitecture-check><a href=/zh-cn/docsv2.7/user/preface/architecture/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userprefacearchitecture><span>架构</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userprefaceusage-li><input type=checkbox id=m-zh-cndocsv27userprefaceusage-check>
<label for=m-zh-cndocsv27userprefaceusage-check><a href=/zh-cn/docsv2.7/user/preface/usage/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userprefaceusage><span>用法</span></a></label></li></ul></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userquick-start-li><input type=checkbox id=m-zh-cndocsv27userquick-start-check>
<label for=m-zh-cndocsv27userquick-start-check><a href=/zh-cn/docsv2.7/user/quick-start/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userquick-start><span>快速开始</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userdependencies-li><input type=checkbox id=m-zh-cndocsv27userdependencies-check>
<label for=m-zh-cndocsv27userdependencies-check><a href=/zh-cn/docsv2.7/user/dependencies/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userdependencies><span>基本依赖</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27usermaturity-li><input type=checkbox id=m-zh-cndocsv27usermaturity-check>
<label for=m-zh-cndocsv27usermaturity-check><a href=/zh-cn/docsv2.7/user/maturity/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27usermaturity><span>成熟度</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-zh-cndocsv27userconfiguration-li><input type=checkbox id=m-zh-cndocsv27userconfiguration-check>
<label for=m-zh-cndocsv27userconfiguration-check><a href=/zh-cn/docsv2.7/user/configuration/ class="align-left pl-0 td-sidebar-link td-sidebar-link__section" id=m-zh-cndocsv27userconfiguration><span>配置手册</span></a></label><ul class="ul-3 foldable"><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userconfigurationxml-li><input type=checkbox id=m-zh-cndocsv27userconfigurationxml-check>
<label for=m-zh-cndocsv27userconfigurationxml-check><a href=/zh-cn/docsv2.7/user/configuration/xml/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userconfigurationxml><span>XML 配置</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userconfigurationconfig-center-li><input type=checkbox id=m-zh-cndocsv27userconfigurationconfig-center-check>
<label for=m-zh-cndocsv27userconfigurationconfig-center-check><a href=/zh-cn/docsv2.7/user/configuration/config-center/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userconfigurationconfig-center><span>动态配置中心</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userconfigurationproperties-li><input type=checkbox id=m-zh-cndocsv27userconfigurationproperties-check>
<label for=m-zh-cndocsv27userconfigurationproperties-check><a href=/zh-cn/docsv2.7/user/configuration/properties/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userconfigurationproperties><span>属性配置</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userconfigurationenvironment-variables-li><input type=checkbox id=m-zh-cndocsv27userconfigurationenvironment-variables-check>
<label for=m-zh-cndocsv27userconfigurationenvironment-variables-check><a href=/zh-cn/docsv2.7/user/configuration/environment-variables/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userconfigurationenvironment-variables><span>自动加载环境变量</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userconfigurationapi-li><input type=checkbox id=m-zh-cndocsv27userconfigurationapi-check>
<label for=m-zh-cndocsv27userconfigurationapi-check><a href=/zh-cn/docsv2.7/user/configuration/api/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userconfigurationapi><span>API 配置</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userconfigurationannotation-li><input type=checkbox id=m-zh-cndocsv27userconfigurationannotation-check>
<label for=m-zh-cndocsv27userconfigurationannotation-check><a href=/zh-cn/docsv2.7/user/configuration/annotation/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userconfigurationannotation><span>注解配置</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userconfigurationconfiguration-load-process-li><input type=checkbox id=m-zh-cndocsv27userconfigurationconfiguration-load-process-check>
<label for=m-zh-cndocsv27userconfigurationconfiguration-load-process-check><a href=/zh-cn/docsv2.7/user/configuration/configuration-load-process/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userconfigurationconfiguration-load-process><span>配置加载流程</span></a></label></li></ul></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-zh-cndocsv27userexamples-li><input type=checkbox id=m-zh-cndocsv27userexamples-check>
<label for=m-zh-cndocsv27userexamples-check><a href=/zh-cn/docsv2.7/user/examples/ class="align-left pl-0 td-sidebar-link td-sidebar-link__section" id=m-zh-cndocsv27userexamples><span>用法示例</span></a></label><ul class="ul-3 foldable"><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplese9878de8af95e6aca1e695b0e9858de7bdae-li><input type=checkbox id=m-zh-cndocsv27userexamplese9878de8af95e6aca1e695b0e9858de7bdae-check>
<label for=m-zh-cndocsv27userexamplese9878de8af95e6aca1e695b0e9858de7bdae-check><a href=/zh-cn/docsv2.7/user/examples/%E9%87%8D%E8%AF%95%E6%AC%A1%E6%95%B0%E9%85%8D%E7%BD%AE/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplese9878de8af95e6aca1e695b0e9858de7bdae><span>服务重试</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplespreflight-check-li><input type=checkbox id=m-zh-cndocsv27userexamplespreflight-check-check>
<label for=m-zh-cndocsv27userexamplespreflight-check-check><a href=/zh-cn/docsv2.7/user/examples/preflight-check/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplespreflight-check><span>启动时检查</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesfault-tolerent-strategy-li><input type=checkbox id=m-zh-cndocsv27userexamplesfault-tolerent-strategy-check>
<label for=m-zh-cndocsv27userexamplesfault-tolerent-strategy-check><a href=/zh-cn/docsv2.7/user/examples/fault-tolerent-strategy/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesfault-tolerent-strategy><span>集群容错</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesloadbalance-li><input type=checkbox id=m-zh-cndocsv27userexamplesloadbalance-check>
<label for=m-zh-cndocsv27userexamplesloadbalance-check><a href=/zh-cn/docsv2.7/user/examples/loadbalance/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesloadbalance><span>负载均衡</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesthread-model-li><input type=checkbox id=m-zh-cndocsv27userexamplesthread-model-check>
<label for=m-zh-cndocsv27userexamplesthread-model-check><a href=/zh-cn/docsv2.7/user/examples/thread-model/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesthread-model><span>线程模型</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesexplicit-target-li><input type=checkbox id=m-zh-cndocsv27userexamplesexplicit-target-check>
<label for=m-zh-cndocsv27userexamplesexplicit-target-check><a href=/zh-cn/docsv2.7/user/examples/explicit-target/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesexplicit-target><span>直连提供者</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplessubscribe-only-li><input type=checkbox id=m-zh-cndocsv27userexamplessubscribe-only-check>
<label for=m-zh-cndocsv27userexamplessubscribe-only-check><a href=/zh-cn/docsv2.7/user/examples/subscribe-only/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplessubscribe-only><span>只订阅</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesmulti-protocols-li><input type=checkbox id=m-zh-cndocsv27userexamplesmulti-protocols-check>
<label for=m-zh-cndocsv27userexamplesmulti-protocols-check><a href=/zh-cn/docsv2.7/user/examples/multi-protocols/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesmulti-protocols><span>多协议</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesmulti-registry-li><input type=checkbox id=m-zh-cndocsv27userexamplesmulti-registry-check>
<label for=m-zh-cndocsv27userexamplesmulti-registry-check><a href=/zh-cn/docsv2.7/user/examples/multi-registry/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesmulti-registry><span>多注册中心</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesservice-group-li><input type=checkbox id=m-zh-cndocsv27userexamplesservice-group-check>
<label for=m-zh-cndocsv27userexamplesservice-group-check><a href=/zh-cn/docsv2.7/user/examples/service-group/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesservice-group><span>服务分组</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesstatic-service-li><input type=checkbox id=m-zh-cndocsv27userexamplesstatic-service-check>
<label for=m-zh-cndocsv27userexamplesstatic-service-check><a href=/zh-cn/docsv2.7/user/examples/static-service/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesstatic-service><span>静态服务</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesmulti-versions-li><input type=checkbox id=m-zh-cndocsv27userexamplesmulti-versions-check>
<label for=m-zh-cndocsv27userexamplesmulti-versions-check><a href=/zh-cn/docsv2.7/user/examples/multi-versions/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesmulti-versions><span>多版本</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesgroup-merger-li><input type=checkbox id=m-zh-cndocsv27userexamplesgroup-merger-check>
<label for=m-zh-cndocsv27userexamplesgroup-merger-check><a href=/zh-cn/docsv2.7/user/examples/group-merger/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesgroup-merger><span>分组聚合</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesparameter-validation-li><input type=checkbox id=m-zh-cndocsv27userexamplesparameter-validation-check>
<label for=m-zh-cndocsv27userexamplesparameter-validation-check><a href=/zh-cn/docsv2.7/user/examples/parameter-validation/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesparameter-validation><span>参数验证</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesgeneric-invoke-with-json-li><input type=checkbox id=m-zh-cndocsv27userexamplesgeneric-invoke-with-json-check>
<label for=m-zh-cndocsv27userexamplesgeneric-invoke-with-json-check><a href=/zh-cn/docsv2.7/user/examples/generic-invoke-with-json/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesgeneric-invoke-with-json><span>JSON泛化调用</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesmsgpack-serialization-li><input type=checkbox id=m-zh-cndocsv27userexamplesmsgpack-serialization-check>
<label for=m-zh-cndocsv27userexamplesmsgpack-serialization-check><a href=/zh-cn/docsv2.7/user/examples/msgpack-serialization/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesmsgpack-serialization><span>msgpack序列化</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesprovider-timeout-release-li><input type=checkbox id=m-zh-cndocsv27userexamplesprovider-timeout-release-check>
<label for=m-zh-cndocsv27userexamplesprovider-timeout-release-check><a href=/zh-cn/docsv2.7/user/examples/provider-timeout-release/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesprovider-timeout-release><span>provider超时打断</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesresult-cache-li><input type=checkbox id=m-zh-cndocsv27userexamplesresult-cache-check>
<label for=m-zh-cndocsv27userexamplesresult-cache-check><a href=/zh-cn/docsv2.7/user/examples/result-cache/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesresult-cache><span>结果缓存</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesbroadcast-resp-collect-li><input type=checkbox id=m-zh-cndocsv27userexamplesbroadcast-resp-collect-check>
<label for=m-zh-cndocsv27userexamplesbroadcast-resp-collect-check><a href=/zh-cn/docsv2.7/user/examples/broadcast-resp-collect/ title=收集Dubbo广播响应 class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesbroadcast-resp-collect><span>收集广播响应</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesinvoke-with-specified-ip-li><input type=checkbox id=m-zh-cndocsv27userexamplesinvoke-with-specified-ip-check>
<label for=m-zh-cndocsv27userexamplesinvoke-with-specified-ip-check><a href=/zh-cn/docsv2.7/user/examples/invoke-with-specified-ip/ title="指定Ip Port调用Provider" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesinvoke-with-specified-ip><span>指定IP</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesgeneric-reference-li><input type=checkbox id=m-zh-cndocsv27userexamplesgeneric-reference-check>
<label for=m-zh-cndocsv27userexamplesgeneric-reference-check><a href=/zh-cn/docsv2.7/user/examples/generic-reference/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesgeneric-reference><span>使用泛化调用</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesprotobuf-idl-li><input type=checkbox id=m-zh-cndocsv27userexamplesprotobuf-idl-check>
<label for=m-zh-cndocsv27userexamplesprotobuf-idl-check><a href=/zh-cn/docsv2.7/user/examples/protobuf-idl/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesprotobuf-idl><span>Protobuf</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplespb-generic-reference-li><input type=checkbox id=m-zh-cndocsv27userexamplespb-generic-reference-check>
<label for=m-zh-cndocsv27userexamplespb-generic-reference-check><a href=/zh-cn/docsv2.7/user/examples/pb-generic-reference/ title="GoogleProtobuf 对象泛化调用" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplespb-generic-reference><span>Protobuf 泛化调用</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesgeneric-service-li><input type=checkbox id=m-zh-cndocsv27userexamplesgeneric-service-check>
<label for=m-zh-cndocsv27userexamplesgeneric-service-check><a href=/zh-cn/docsv2.7/user/examples/generic-service/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesgeneric-service><span>实现泛化调用</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesecho-service-li><input type=checkbox id=m-zh-cndocsv27userexamplesecho-service-check>
<label for=m-zh-cndocsv27userexamplesecho-service-check><a href=/zh-cn/docsv2.7/user/examples/echo-service/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesecho-service><span>回声测试</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplescontext-li><input type=checkbox id=m-zh-cndocsv27userexamplescontext-check>
<label for=m-zh-cndocsv27userexamplescontext-check><a href=/zh-cn/docsv2.7/user/examples/context/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplescontext><span>上下文信息</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesattachment-li><input type=checkbox id=m-zh-cndocsv27userexamplesattachment-check>
<label for=m-zh-cndocsv27userexamplesattachment-check><a href=/zh-cn/docsv2.7/user/examples/attachment/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesattachment><span>隐式参数</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesasync-call-li><input type=checkbox id=m-zh-cndocsv27userexamplesasync-call-check>
<label for=m-zh-cndocsv27userexamplesasync-call-check><a href=/zh-cn/docsv2.7/user/examples/async-call/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesasync-call><span>异步调用</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesasync-execute-on-provider-li><input type=checkbox id=m-zh-cndocsv27userexamplesasync-execute-on-provider-check>
<label for=m-zh-cndocsv27userexamplesasync-execute-on-provider-check><a href=/zh-cn/docsv2.7/user/examples/async-execute-on-provider/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesasync-execute-on-provider><span>异步执行</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexampleslocal-call-li><input type=checkbox id=m-zh-cndocsv27userexampleslocal-call-check>
<label for=m-zh-cndocsv27userexampleslocal-call-check><a href=/zh-cn/docsv2.7/user/examples/local-call/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexampleslocal-call><span>本地调用</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplescallback-parameter-li><input type=checkbox id=m-zh-cndocsv27userexamplescallback-parameter-check>
<label for=m-zh-cndocsv27userexamplescallback-parameter-check><a href=/zh-cn/docsv2.7/user/examples/callback-parameter/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplescallback-parameter><span>参数回调</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesevents-notify-li><input type=checkbox id=m-zh-cndocsv27userexamplesevents-notify-check>
<label for=m-zh-cndocsv27userexamplesevents-notify-check><a href=/zh-cn/docsv2.7/user/examples/events-notify/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesevents-notify><span>事件通知</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexampleslocal-stub-li><input type=checkbox id=m-zh-cndocsv27userexampleslocal-stub-check>
<label for=m-zh-cndocsv27userexampleslocal-stub-check><a href=/zh-cn/docsv2.7/user/examples/local-stub/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexampleslocal-stub><span>本地存根</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexampleslocal-mock-li><input type=checkbox id=m-zh-cndocsv27userexampleslocal-mock-check>
<label for=m-zh-cndocsv27userexampleslocal-mock-check><a href=/zh-cn/docsv2.7/user/examples/local-mock/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexampleslocal-mock><span>本地伪装</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesdelay-publish-li><input type=checkbox id=m-zh-cndocsv27userexamplesdelay-publish-check>
<label for=m-zh-cndocsv27userexamplesdelay-publish-check><a href=/zh-cn/docsv2.7/user/examples/delay-publish/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesdelay-publish><span>延迟暴露</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesconcurrency-control-li><input type=checkbox id=m-zh-cndocsv27userexamplesconcurrency-control-check>
<label for=m-zh-cndocsv27userexamplesconcurrency-control-check><a href=/zh-cn/docsv2.7/user/examples/concurrency-control/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesconcurrency-control><span>并发控制</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesconfig-connections-li><input type=checkbox id=m-zh-cndocsv27userexamplesconfig-connections-check>
<label for=m-zh-cndocsv27userexamplesconfig-connections-check><a href=/zh-cn/docsv2.7/user/examples/config-connections/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesconfig-connections><span>连接控制</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexampleslazy-connect-li><input type=checkbox id=m-zh-cndocsv27userexampleslazy-connect-check>
<label for=m-zh-cndocsv27userexampleslazy-connect-check><a href=/zh-cn/docsv2.7/user/examples/lazy-connect/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexampleslazy-connect><span>延迟连接</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesstickiness-li><input type=checkbox id=m-zh-cndocsv27userexamplesstickiness-check>
<label for=m-zh-cndocsv27userexamplesstickiness-check><a href=/zh-cn/docsv2.7/user/examples/stickiness/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesstickiness><span>粘滞连接</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplestls-li><input type=checkbox id=m-zh-cndocsv27userexamplestls-check>
<label for=m-zh-cndocsv27userexamplestls-check><a href=/zh-cn/docsv2.7/user/examples/tls/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplestls><span>TLS</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplestoken-authorization-li><input type=checkbox id=m-zh-cndocsv27userexamplestoken-authorization-check>
<label for=m-zh-cndocsv27userexamplestoken-authorization-check><a href=/zh-cn/docsv2.7/user/examples/token-authorization/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplestoken-authorization><span>令牌验证</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesrouting-rule-li><input type=checkbox id=m-zh-cndocsv27userexamplesrouting-rule-check>
<label for=m-zh-cndocsv27userexamplesrouting-rule-check><a href=/zh-cn/docsv2.7/user/examples/routing-rule/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesrouting-rule><span>路由规则</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesrouting-rule-deprecated-li><input type=checkbox id=m-zh-cndocsv27userexamplesrouting-rule-deprecated-check>
<label for=m-zh-cndocsv27userexamplesrouting-rule-deprecated-check><a href=/zh-cn/docsv2.7/user/examples/routing-rule-deprecated/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesrouting-rule-deprecated><span>旧路由规则</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesconfig-rule-li><input type=checkbox id=m-zh-cndocsv27userexamplesconfig-rule-check>
<label for=m-zh-cndocsv27userexamplesconfig-rule-check><a href=/zh-cn/docsv2.7/user/examples/config-rule/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesconfig-rule><span>配置规则</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesservice-downgrade-li><input type=checkbox id=m-zh-cndocsv27userexamplesservice-downgrade-check>
<label for=m-zh-cndocsv27userexamplesservice-downgrade-check><a href=/zh-cn/docsv2.7/user/examples/service-downgrade/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesservice-downgrade><span>服务降级</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesconfig-rule-deprecated-li><input type=checkbox id=m-zh-cndocsv27userexamplesconfig-rule-deprecated-check>
<label for=m-zh-cndocsv27userexamplesconfig-rule-deprecated-check><a href=/zh-cn/docsv2.7/user/examples/config-rule-deprecated/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesconfig-rule-deprecated><span>旧配置规则</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesconsumer-threadpool-li><input type=checkbox id=m-zh-cndocsv27userexamplesconsumer-threadpool-check>
<label for=m-zh-cndocsv27userexamplesconsumer-threadpool-check><a href=/zh-cn/docsv2.7/user/examples/consumer-threadpool/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesconsumer-threadpool><span>消费端线程池模型</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesgraceful-shutdown-li><input type=checkbox id=m-zh-cndocsv27userexamplesgraceful-shutdown-check>
<label for=m-zh-cndocsv27userexamplesgraceful-shutdown-check><a href=/zh-cn/docsv2.7/user/examples/graceful-shutdown/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesgraceful-shutdown><span>优雅停机</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexampleshostname-binding-li><input type=checkbox id=m-zh-cndocsv27userexampleshostname-binding-check>
<label for=m-zh-cndocsv27userexampleshostname-binding-check><a href=/zh-cn/docsv2.7/user/examples/hostname-binding/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexampleshostname-binding><span>主机绑定</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userexamplesset-host-li><input type=checkbox id=m-zh-cndocsv27userexamplesset-host-check>
<label for=m-zh-cndocsv27userexamplesset-host-check><a href=/zh-cn/docsv2.7/user/examples/set-host/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userexamplesset-host><span>主机配置</span></a></label></li></ul></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-zh-cndocsv27userreferences-li><input type=checkbox id=m-zh-cndocsv27userreferences-check>
<label for=m-zh-cndocsv27userreferences-check><a href=/zh-cn/docsv2.7/user/references/ class="align-left pl-0 td-sidebar-link td-sidebar-link__section" id=m-zh-cndocsv27userreferences><span>参考手册</span></a></label><ul class="ul-3 foldable"><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-zh-cndocsv27userreferencesxml-li><input type=checkbox id=m-zh-cndocsv27userreferencesxml-check>
<label for=m-zh-cndocsv27userreferencesxml-check><a href=/zh-cn/docsv2.7/user/references/xml/ title="Schema 配置参考手册" class="align-left pl-0 td-sidebar-link td-sidebar-link__section" id=m-zh-cndocsv27userreferencesxml><span>XML 配置</span></a></label><ul class="ul-4 foldable"><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesxmldubbo-application-li><input type=checkbox id=m-zh-cndocsv27userreferencesxmldubbo-application-check>
<label for=m-zh-cndocsv27userreferencesxmldubbo-application-check><a href=/zh-cn/docsv2.7/user/references/xml/dubbo-application/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesxmldubbo-application><span>dubbo:application</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesxmldubbo-argument-li><input type=checkbox id=m-zh-cndocsv27userreferencesxmldubbo-argument-check>
<label for=m-zh-cndocsv27userreferencesxmldubbo-argument-check><a href=/zh-cn/docsv2.7/user/references/xml/dubbo-argument/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesxmldubbo-argument><span>dubbo:argument</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesxmldubbo-config-center-li><input type=checkbox id=m-zh-cndocsv27userreferencesxmldubbo-config-center-check>
<label for=m-zh-cndocsv27userreferencesxmldubbo-config-center-check><a href=/zh-cn/docsv2.7/user/references/xml/dubbo-config-center/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesxmldubbo-config-center><span>dubbo:config-center</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesxmldubbo-consumer-li><input type=checkbox id=m-zh-cndocsv27userreferencesxmldubbo-consumer-check>
<label for=m-zh-cndocsv27userreferencesxmldubbo-consumer-check><a href=/zh-cn/docsv2.7/user/references/xml/dubbo-consumer/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesxmldubbo-consumer><span>dubbo:consumer</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesxmldubbo-method-li><input type=checkbox id=m-zh-cndocsv27userreferencesxmldubbo-method-check>
<label for=m-zh-cndocsv27userreferencesxmldubbo-method-check><a href=/zh-cn/docsv2.7/user/references/xml/dubbo-method/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesxmldubbo-method><span>dubbo:method</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesxmldubbo-module-li><input type=checkbox id=m-zh-cndocsv27userreferencesxmldubbo-module-check>
<label for=m-zh-cndocsv27userreferencesxmldubbo-module-check><a href=/zh-cn/docsv2.7/user/references/xml/dubbo-module/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesxmldubbo-module><span>dubbo:module</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesxmldubbo-monitor-li><input type=checkbox id=m-zh-cndocsv27userreferencesxmldubbo-monitor-check>
<label for=m-zh-cndocsv27userreferencesxmldubbo-monitor-check><a href=/zh-cn/docsv2.7/user/references/xml/dubbo-monitor/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesxmldubbo-monitor><span>dubbo:monitor</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesxmldubbo-parameter-li><input type=checkbox id=m-zh-cndocsv27userreferencesxmldubbo-parameter-check>
<label for=m-zh-cndocsv27userreferencesxmldubbo-parameter-check><a href=/zh-cn/docsv2.7/user/references/xml/dubbo-parameter/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesxmldubbo-parameter><span>dubbo:parameter</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesxmldubbo-protocol-li><input type=checkbox id=m-zh-cndocsv27userreferencesxmldubbo-protocol-check>
<label for=m-zh-cndocsv27userreferencesxmldubbo-protocol-check><a href=/zh-cn/docsv2.7/user/references/xml/dubbo-protocol/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesxmldubbo-protocol><span>dubbo:protocol</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesxmldubbo-provider-li><input type=checkbox id=m-zh-cndocsv27userreferencesxmldubbo-provider-check>
<label for=m-zh-cndocsv27userreferencesxmldubbo-provider-check><a href=/zh-cn/docsv2.7/user/references/xml/dubbo-provider/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesxmldubbo-provider><span>dubbo:provider</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesxmldubbo-reference-li><input type=checkbox id=m-zh-cndocsv27userreferencesxmldubbo-reference-check>
<label for=m-zh-cndocsv27userreferencesxmldubbo-reference-check><a href=/zh-cn/docsv2.7/user/references/xml/dubbo-reference/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesxmldubbo-reference><span>dubbo:reference</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesxmldubbo-registry-li><input type=checkbox id=m-zh-cndocsv27userreferencesxmldubbo-registry-check>
<label for=m-zh-cndocsv27userreferencesxmldubbo-registry-check><a href=/zh-cn/docsv2.7/user/references/xml/dubbo-registry/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesxmldubbo-registry><span>dubbo:registry</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesxmldubbo-service-li><input type=checkbox id=m-zh-cndocsv27userreferencesxmldubbo-service-check>
<label for=m-zh-cndocsv27userreferencesxmldubbo-service-check><a href=/zh-cn/docsv2.7/user/references/xml/dubbo-service/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesxmldubbo-service><span>dubbo:service</span></a></label></li></ul></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-zh-cndocsv27userreferencesprotocol-li><input type=checkbox id=m-zh-cndocsv27userreferencesprotocol-check>
<label for=m-zh-cndocsv27userreferencesprotocol-check><a href=/zh-cn/docsv2.7/user/references/protocol/ class="align-left pl-0 td-sidebar-link td-sidebar-link__section" id=m-zh-cndocsv27userreferencesprotocol><span>协议参考手册</span></a></label><ul class="ul-4 foldable"><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesprotocoldubbo-li><input type=checkbox id=m-zh-cndocsv27userreferencesprotocoldubbo-check>
<label for=m-zh-cndocsv27userreferencesprotocoldubbo-check><a href=/zh-cn/docsv2.7/user/references/protocol/dubbo/ title="dubbo 协议" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesprotocoldubbo><span>dubbo://</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesprotocolrest-li><input type=checkbox id=m-zh-cndocsv27userreferencesprotocolrest-check>
<label for=m-zh-cndocsv27userreferencesprotocolrest-check><a href=/zh-cn/docsv2.7/user/references/protocol/rest/ title="rest 协议" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesprotocolrest><span>rest://</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesprotocolhttp-li><input type=checkbox id=m-zh-cndocsv27userreferencesprotocolhttp-check>
<label for=m-zh-cndocsv27userreferencesprotocolhttp-check><a href=/zh-cn/docsv2.7/user/references/protocol/http/ title="http 协议" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesprotocolhttp><span>http://</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesprotocolhessian-li><input type=checkbox id=m-zh-cndocsv27userreferencesprotocolhessian-check>
<label for=m-zh-cndocsv27userreferencesprotocolhessian-check><a href=/zh-cn/docsv2.7/user/references/protocol/hessian/ title="hessian 协议" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesprotocolhessian><span>hessian://</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesprotocolredis-li><input type=checkbox id=m-zh-cndocsv27userreferencesprotocolredis-check>
<label for=m-zh-cndocsv27userreferencesprotocolredis-check><a href=/zh-cn/docsv2.7/user/references/protocol/redis/ title="redis 协议" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesprotocolredis><span>redis://</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesprotocolthrift-li><input type=checkbox id=m-zh-cndocsv27userreferencesprotocolthrift-check>
<label for=m-zh-cndocsv27userreferencesprotocolthrift-check><a href=/zh-cn/docsv2.7/user/references/protocol/thrift/ title="thrift 协议" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesprotocolthrift><span>thrift://</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesprotocolgrpc-li><input type=checkbox id=m-zh-cndocsv27userreferencesprotocolgrpc-check>
<label for=m-zh-cndocsv27userreferencesprotocolgrpc-check><a href=/zh-cn/docsv2.7/user/references/protocol/grpc/ title="gRPC 协议" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesprotocolgrpc><span>grpc://</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesprotocolmemcached-li><input type=checkbox id=m-zh-cndocsv27userreferencesprotocolmemcached-check>
<label for=m-zh-cndocsv27userreferencesprotocolmemcached-check><a href=/zh-cn/docsv2.7/user/references/protocol/memcached/ title="memcached 协议" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesprotocolmemcached><span>memcached://</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesprotocolrmi-li><input type=checkbox id=m-zh-cndocsv27userreferencesprotocolrmi-check>
<label for=m-zh-cndocsv27userreferencesprotocolrmi-check><a href=/zh-cn/docsv2.7/user/references/protocol/rmi/ title="rmi 协议" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesprotocolrmi><span>rmi://</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesprotocolwebservice-li><input type=checkbox id=m-zh-cndocsv27userreferencesprotocolwebservice-check>
<label for=m-zh-cndocsv27userreferencesprotocolwebservice-check><a href=/zh-cn/docsv2.7/user/references/protocol/webservice/ title="webservice 协议" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesprotocolwebservice><span>webservice://</span></a></label></li></ul></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-zh-cndocsv27userreferencesregistry-li><input type=checkbox id=m-zh-cndocsv27userreferencesregistry-check>
<label for=m-zh-cndocsv27userreferencesregistry-check><a href=/zh-cn/docsv2.7/user/references/registry/ class="align-left pl-0 td-sidebar-link td-sidebar-link__section" id=m-zh-cndocsv27userreferencesregistry><span>注册中心参考手册</span></a></label><ul class="ul-4 foldable"><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesregistrynacos-li><input type=checkbox id=m-zh-cndocsv27userreferencesregistrynacos-check>
<label for=m-zh-cndocsv27userreferencesregistrynacos-check><a href=/zh-cn/docsv2.7/user/references/registry/nacos/ title="Nacos 注册中心" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesregistrynacos><span>Nacos</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesregistryzookeeper-li><input type=checkbox id=m-zh-cndocsv27userreferencesregistryzookeeper-check>
<label for=m-zh-cndocsv27userreferencesregistryzookeeper-check><a href=/zh-cn/docsv2.7/user/references/registry/zookeeper/ title="Zookeeper 注册中心" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesregistryzookeeper><span>Zookeeper</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesregistrymulticast-li><input type=checkbox id=m-zh-cndocsv27userreferencesregistrymulticast-check>
<label for=m-zh-cndocsv27userreferencesregistrymulticast-check><a href=/zh-cn/docsv2.7/user/references/registry/multicast/ title="Multicast 注册中心" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesregistrymulticast><span>Multicast</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesregistryredis-li><input type=checkbox id=m-zh-cndocsv27userreferencesregistryredis-check>
<label for=m-zh-cndocsv27userreferencesregistryredis-check><a href=/zh-cn/docsv2.7/user/references/registry/redis/ title="Redis 注册中心" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesregistryredis><span>Redis</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesregistrysimple-li><input type=checkbox id=m-zh-cndocsv27userreferencesregistrysimple-check>
<label for=m-zh-cndocsv27userreferencesregistrysimple-check><a href=/zh-cn/docsv2.7/user/references/registry/simple/ title="Simple 注册中心" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesregistrysimple><span>Simple</span></a></label></li></ul></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesmetadata-li><input type=checkbox id=m-zh-cndocsv27userreferencesmetadata-check>
<label for=m-zh-cndocsv27userreferencesmetadata-check><a href=/zh-cn/docsv2.7/user/references/metadata/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesmetadata><span>元数据参考手册</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesapi-li><input type=checkbox id=m-zh-cndocsv27userreferencesapi-check>
<label for=m-zh-cndocsv27userreferencesapi-check><a href=/zh-cn/docsv2.7/user/references/api/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesapi><span>API 参考手册</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesqos-li><input type=checkbox id=m-zh-cndocsv27userreferencesqos-check>
<label for=m-zh-cndocsv27userreferencesqos-check><a href=/zh-cn/docsv2.7/user/references/qos/ title=在线运维命令参考手册 class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesqos><span>QOS 手册</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencestelnet-li><input type=checkbox id=m-zh-cndocsv27userreferencestelnet-check>
<label for=m-zh-cndocsv27userreferencestelnet-check><a href=/zh-cn/docsv2.7/user/references/telnet/ title="Telnet 命令参考手册" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencestelnet><span>Telnet 手册</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userreferencesmaven-li><input type=checkbox id=m-zh-cndocsv27userreferencesmaven-check>
<label for=m-zh-cndocsv27userreferencesmaven-check><a href=/zh-cn/docsv2.7/user/references/maven/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userreferencesmaven><span>Maven 插件参考手册</span></a></label></li></ul></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-zh-cndocsv27userversions-li><input type=checkbox id=m-zh-cndocsv27userversions-check>
<label for=m-zh-cndocsv27userversions-check><a href=/zh-cn/docsv2.7/user/versions/ class="align-left pl-0 td-sidebar-link td-sidebar-link__section" id=m-zh-cndocsv27userversions><span>版本升级</span></a></label><ul class="ul-3 foldable"><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userversionsversion-270-li><input type=checkbox id=m-zh-cndocsv27userversionsversion-270-check>
<label for=m-zh-cndocsv27userversionsversion-270-check><a href=/zh-cn/docsv2.7/user/versions/version-270/ title=升级与可能的兼容性问题总结 class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userversionsversion-270><span>2.7.0</span></a></label></li></ul></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userbest-practice-li><input type=checkbox id=m-zh-cndocsv27userbest-practice-check>
<label for=m-zh-cndocsv27userbest-practice-check><a href=/zh-cn/docsv2.7/user/best-practice/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userbest-practice><span>服务化最佳实践</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userrecommend-li><input type=checkbox id=m-zh-cndocsv27userrecommend-check>
<label for=m-zh-cndocsv27userrecommend-check><a href=/zh-cn/docsv2.7/user/recommend/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userrecommend><span>推荐用法</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27usercapacity-plan-li><input type=checkbox id=m-zh-cndocsv27usercapacity-plan-check>
<label for=m-zh-cndocsv27usercapacity-plan-check><a href=/zh-cn/docsv2.7/user/capacity-plan/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27usercapacity-plan><span>容量规划</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userperf-test-li><input type=checkbox id=m-zh-cndocsv27userperf-test-check>
<label for=m-zh-cndocsv27userperf-test-check><a href=/zh-cn/docsv2.7/user/perf-test/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userperf-test><span>性能测试报告</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27usercoveragence-li><input type=checkbox id=m-zh-cndocsv27usercoveragence-check>
<label for=m-zh-cndocsv27usercoveragence-check><a href=/zh-cn/docsv2.7/user/coveragence/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27usercoveragence><span>测试覆盖率报告</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userbenchmark-tool-li><input type=checkbox id=m-zh-cndocsv27userbenchmark-tool-check>
<label for=m-zh-cndocsv27userbenchmark-tool-check><a href=/zh-cn/docsv2.7/user/benchmark-tool/ title=基准测试工具包 class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userbenchmark-tool><span>基准测试</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userrest-li><input type=checkbox id=m-zh-cndocsv27userrest-check>
<label for=m-zh-cndocsv27userrest-check><a href=/zh-cn/docsv2.7/user/rest/ title="开发 REST 应用" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userrest><span>REST 支持</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27usersimple-monitor-li><input type=checkbox id=m-zh-cndocsv27usersimple-monitor-check>
<label for=m-zh-cndocsv27usersimple-monitor-check><a href=/zh-cn/docsv2.7/user/simple-monitor/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27usersimple-monitor><span>简单监控</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userserialization-li><input type=checkbox id=m-zh-cndocsv27userserialization-check>
<label for=m-zh-cndocsv27userserialization-check><a href=/zh-cn/docsv2.7/user/serialization/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userserialization><span>Kryo 和 FST 序列化</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-zh-cndocsv27userlanguages-li><input type=checkbox id=m-zh-cndocsv27userlanguages-check>
<label for=m-zh-cndocsv27userlanguages-check><a href=/zh-cn/docsv2.7/user/languages/ class="align-left pl-0 td-sidebar-link td-sidebar-link__section" id=m-zh-cndocsv27userlanguages><span>其他语言支持</span></a></label><ul class="ul-3 foldable"><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-zh-cndocsv27userlanguageserlang-li><input type=checkbox id=m-zh-cndocsv27userlanguageserlang-check>
<label for=m-zh-cndocsv27userlanguageserlang-check><a href=/zh-cn/docsv2.7/user/languages/erlang/ class="align-left pl-0 td-sidebar-link td-sidebar-link__section" id=m-zh-cndocsv27userlanguageserlang><span>Erlang</span></a></label><ul class="ul-4 foldable"><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userlanguageserlangquick-start-li><input type=checkbox id=m-zh-cndocsv27userlanguageserlangquick-start-check>
<label for=m-zh-cndocsv27userlanguageserlangquick-start-check><a href=/zh-cn/docsv2.7/user/languages/erlang/quick-start/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userlanguageserlangquick-start><span>快速开始</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userlanguageserlangreference-li><input type=checkbox id=m-zh-cndocsv27userlanguageserlangreference-check>
<label for=m-zh-cndocsv27userlanguageserlangreference-check><a href=/zh-cn/docsv2.7/user/languages/erlang/reference/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userlanguageserlangreference><span>消费者配置</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userlanguageserlangservice-li><input type=checkbox id=m-zh-cndocsv27userlanguageserlangservice-check>
<label for=m-zh-cndocsv27userlanguageserlangservice-check><a href=/zh-cn/docsv2.7/user/languages/erlang/service/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userlanguageserlangservice><span>提供者配置</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27userlanguageserlangserialization-li><input type=checkbox id=m-zh-cndocsv27userlanguageserlangserialization-check>
<label for=m-zh-cndocsv27userlanguageserlangserialization-check><a href=/zh-cn/docsv2.7/user/languages/erlang/serialization/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27userlanguageserlangserialization><span>序列化配置项</span></a></label></li></ul></li></ul></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27usernew-features-in-a-glance-li><input type=checkbox id=m-zh-cndocsv27usernew-features-in-a-glance-check>
<label for=m-zh-cndocsv27usernew-features-in-a-glance-check><a href=/zh-cn/docsv2.7/user/new-features-in-a-glance/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27usernew-features-in-a-glance><span></span></a></label></li></ul></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-zh-cndocsv27dev-li><input type=checkbox id=m-zh-cndocsv27dev-check>
<label for=m-zh-cndocsv27dev-check><a href=/zh-cn/docsv2.7/dev/ class="align-left pl-0 td-sidebar-link td-sidebar-link__section" id=m-zh-cndocsv27dev><span>开发指南</span></a></label><ul class="ul-2 foldable"><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devbuild-li><input type=checkbox id=m-zh-cndocsv27devbuild-check>
<label for=m-zh-cndocsv27devbuild-check><a href=/zh-cn/docsv2.7/dev/build/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devbuild><span>源码构建</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devdesign-li><input type=checkbox id=m-zh-cndocsv27devdesign-check>
<label for=m-zh-cndocsv27devdesign-check><a href=/zh-cn/docsv2.7/dev/design/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devdesign><span>框架设计</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devspi-li><input type=checkbox id=m-zh-cndocsv27devspi-check>
<label for=m-zh-cndocsv27devspi-check><a href=/zh-cn/docsv2.7/dev/spi/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devspi><span>扩展点加载</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplementation-li><input type=checkbox id=m-zh-cndocsv27devimplementation-check>
<label for=m-zh-cndocsv27devimplementation-check><a href=/zh-cn/docsv2.7/dev/implementation/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplementation><span>实现细节</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-zh-cndocsv27devimpls-li><input type=checkbox id=m-zh-cndocsv27devimpls-check>
<label for=m-zh-cndocsv27devimpls-check><a href=/zh-cn/docsv2.7/dev/impls/ class="align-left pl-0 td-sidebar-link td-sidebar-link__section" id=m-zh-cndocsv27devimpls><span>SPI 扩展实现</span></a></label><ul class="ul-3 foldable"><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplsprotocol-li><input type=checkbox id=m-zh-cndocsv27devimplsprotocol-check>
<label for=m-zh-cndocsv27devimplsprotocol-check><a href=/zh-cn/docsv2.7/dev/impls/protocol/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplsprotocol><span>协议扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplsfilter-li><input type=checkbox id=m-zh-cndocsv27devimplsfilter-check>
<label for=m-zh-cndocsv27devimplsfilter-check><a href=/zh-cn/docsv2.7/dev/impls/filter/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplsfilter><span>调用拦截扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplsinvoker-listener-li><input type=checkbox id=m-zh-cndocsv27devimplsinvoker-listener-check>
<label for=m-zh-cndocsv27devimplsinvoker-listener-check><a href=/zh-cn/docsv2.7/dev/impls/invoker-listener/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplsinvoker-listener><span>引用监听扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplsexporter-listener-li><input type=checkbox id=m-zh-cndocsv27devimplsexporter-listener-check>
<label for=m-zh-cndocsv27devimplsexporter-listener-check><a href=/zh-cn/docsv2.7/dev/impls/exporter-listener/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplsexporter-listener><span>暴露监听扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplscluster-li><input type=checkbox id=m-zh-cndocsv27devimplscluster-check>
<label for=m-zh-cndocsv27devimplscluster-check><a href=/zh-cn/docsv2.7/dev/impls/cluster/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplscluster><span>集群扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplsrouter-li><input type=checkbox id=m-zh-cndocsv27devimplsrouter-check>
<label for=m-zh-cndocsv27devimplsrouter-check><a href=/zh-cn/docsv2.7/dev/impls/router/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplsrouter><span>路由扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplsload-balance-li><input type=checkbox id=m-zh-cndocsv27devimplsload-balance-check>
<label for=m-zh-cndocsv27devimplsload-balance-check><a href=/zh-cn/docsv2.7/dev/impls/load-balance/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplsload-balance><span>负载均衡扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplsmerger-li><input type=checkbox id=m-zh-cndocsv27devimplsmerger-check>
<label for=m-zh-cndocsv27devimplsmerger-check><a href=/zh-cn/docsv2.7/dev/impls/merger/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplsmerger><span>合并结果扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplsregistry-li><input type=checkbox id=m-zh-cndocsv27devimplsregistry-check>
<label for=m-zh-cndocsv27devimplsregistry-check><a href=/zh-cn/docsv2.7/dev/impls/registry/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplsregistry><span>注册中心扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplsmonitor-li><input type=checkbox id=m-zh-cndocsv27devimplsmonitor-check>
<label for=m-zh-cndocsv27devimplsmonitor-check><a href=/zh-cn/docsv2.7/dev/impls/monitor/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplsmonitor><span>监控中心扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplsextension-factory-li><input type=checkbox id=m-zh-cndocsv27devimplsextension-factory-check>
<label for=m-zh-cndocsv27devimplsextension-factory-check><a href=/zh-cn/docsv2.7/dev/impls/extension-factory/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplsextension-factory><span>扩展点加载扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplsproxy-factory-li><input type=checkbox id=m-zh-cndocsv27devimplsproxy-factory-check>
<label for=m-zh-cndocsv27devimplsproxy-factory-check><a href=/zh-cn/docsv2.7/dev/impls/proxy-factory/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplsproxy-factory><span>动态代理扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplscompiler-li><input type=checkbox id=m-zh-cndocsv27devimplscompiler-check>
<label for=m-zh-cndocsv27devimplscompiler-check><a href=/zh-cn/docsv2.7/dev/impls/compiler/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplscompiler><span>编译器扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplsconfig-center-li><input type=checkbox id=m-zh-cndocsv27devimplsconfig-center-check>
<label for=m-zh-cndocsv27devimplsconfig-center-check><a href=/zh-cn/docsv2.7/dev/impls/config-center/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplsconfig-center><span>配置中心扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplsdispatcher-li><input type=checkbox id=m-zh-cndocsv27devimplsdispatcher-check>
<label for=m-zh-cndocsv27devimplsdispatcher-check><a href=/zh-cn/docsv2.7/dev/impls/dispatcher/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplsdispatcher><span>消息派发扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplsthreadpool-li><input type=checkbox id=m-zh-cndocsv27devimplsthreadpool-check>
<label for=m-zh-cndocsv27devimplsthreadpool-check><a href=/zh-cn/docsv2.7/dev/impls/threadpool/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplsthreadpool><span>线程池扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplsserialize-li><input type=checkbox id=m-zh-cndocsv27devimplsserialize-check>
<label for=m-zh-cndocsv27devimplsserialize-check><a href=/zh-cn/docsv2.7/dev/impls/serialize/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplsserialize><span>序列化扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplsremoting-li><input type=checkbox id=m-zh-cndocsv27devimplsremoting-check>
<label for=m-zh-cndocsv27devimplsremoting-check><a href=/zh-cn/docsv2.7/dev/impls/remoting/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplsremoting><span>网络传输扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplsexchanger-li><input type=checkbox id=m-zh-cndocsv27devimplsexchanger-check>
<label for=m-zh-cndocsv27devimplsexchanger-check><a href=/zh-cn/docsv2.7/dev/impls/exchanger/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplsexchanger><span>信息交换扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplsnetworker-li><input type=checkbox id=m-zh-cndocsv27devimplsnetworker-check>
<label for=m-zh-cndocsv27devimplsnetworker-check><a href=/zh-cn/docsv2.7/dev/impls/networker/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplsnetworker><span>组网扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplstelnet-handler-li><input type=checkbox id=m-zh-cndocsv27devimplstelnet-handler-check>
<label for=m-zh-cndocsv27devimplstelnet-handler-check><a href=/zh-cn/docsv2.7/dev/impls/telnet-handler/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplstelnet-handler><span>Telnet 命令扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplsstatus-checker-li><input type=checkbox id=m-zh-cndocsv27devimplsstatus-checker-check>
<label for=m-zh-cndocsv27devimplsstatus-checker-check><a href=/zh-cn/docsv2.7/dev/impls/status-checker/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplsstatus-checker><span>状态检查扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplscontainer-li><input type=checkbox id=m-zh-cndocsv27devimplscontainer-check>
<label for=m-zh-cndocsv27devimplscontainer-check><a href=/zh-cn/docsv2.7/dev/impls/container/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplscontainer><span>容器扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplscache-li><input type=checkbox id=m-zh-cndocsv27devimplscache-check>
<label for=m-zh-cndocsv27devimplscache-check><a href=/zh-cn/docsv2.7/dev/impls/cache/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplscache><span>缓存扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplsvalidation-li><input type=checkbox id=m-zh-cndocsv27devimplsvalidation-check>
<label for=m-zh-cndocsv27devimplsvalidation-check><a href=/zh-cn/docsv2.7/dev/impls/validation/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplsvalidation><span>验证扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplslogger-adapter-li><input type=checkbox id=m-zh-cndocsv27devimplslogger-adapter-check>
<label for=m-zh-cndocsv27devimplslogger-adapter-check><a href=/zh-cn/docsv2.7/dev/impls/logger-adapter/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplslogger-adapter><span>日志适配扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devimplspage-li><input type=checkbox id=m-zh-cndocsv27devimplspage-check>
<label for=m-zh-cndocsv27devimplspage-check><a href=/zh-cn/docsv2.7/dev/impls/page/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devimplspage><span></span></a></label></li></ul></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-zh-cndocsv27devprincipals-li><input type=checkbox id=m-zh-cndocsv27devprincipals-check>
<label for=m-zh-cndocsv27devprincipals-check><a href=/zh-cn/docsv2.7/dev/principals/ class="align-left pl-0 td-sidebar-link td-sidebar-link__section" id=m-zh-cndocsv27devprincipals><span>设计原则</span></a></label><ul class="ul-3 foldable"><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devprincipalscode-detail-li><input type=checkbox id=m-zh-cndocsv27devprincipalscode-detail-check>
<label for=m-zh-cndocsv27devprincipalscode-detail-check><a href=/zh-cn/docsv2.7/dev/principals/code-detail/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devprincipalscode-detail><span>魔鬼在细节</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devprincipalsconfiguration-li><input type=checkbox id=m-zh-cndocsv27devprincipalsconfiguration-check>
<label for=m-zh-cndocsv27devprincipalsconfiguration-check><a href=/zh-cn/docsv2.7/dev/principals/configuration/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devprincipalsconfiguration><span>配置设计</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devprincipalsdummy-li><input type=checkbox id=m-zh-cndocsv27devprincipalsdummy-check>
<label for=m-zh-cndocsv27devprincipalsdummy-check><a href=/zh-cn/docsv2.7/dev/principals/dummy/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devprincipalsdummy><span>防痴呆设计</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devprincipalsexpansibility-li><input type=checkbox id=m-zh-cndocsv27devprincipalsexpansibility-check>
<label for=m-zh-cndocsv27devprincipalsexpansibility-check><a href=/zh-cn/docsv2.7/dev/principals/expansibility/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devprincipalsexpansibility><span>谈谈扩充式扩展与增量式扩展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devprincipalsextension-li><input type=checkbox id=m-zh-cndocsv27devprincipalsextension-check>
<label for=m-zh-cndocsv27devprincipalsextension-check><a href=/zh-cn/docsv2.7/dev/principals/extension/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devprincipalsextension><span>扩展点重构</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devprincipalsgeneral-knowledge-li><input type=checkbox id=m-zh-cndocsv27devprincipalsgeneral-knowledge-check>
<label for=m-zh-cndocsv27devprincipalsgeneral-knowledge-check><a href=/zh-cn/docsv2.7/dev/principals/general-knowledge/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devprincipalsgeneral-knowledge><span>一些设计上的基本常识</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devprincipalsrobustness-li><input type=checkbox id=m-zh-cndocsv27devprincipalsrobustness-check>
<label for=m-zh-cndocsv27devprincipalsrobustness-check><a href=/zh-cn/docsv2.7/dev/principals/robustness/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devprincipalsrobustness><span>设计实现的健壮性</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devprincipalsintroduction-li><input type=checkbox id=m-zh-cndocsv27devprincipalsintroduction-check>
<label for=m-zh-cndocsv27devprincipalsintroduction-check><a href=/zh-cn/docsv2.7/dev/principals/introduction/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devprincipalsintroduction><span></span></a></label></li></ul></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devcontract-li><input type=checkbox id=m-zh-cndocsv27devcontract-check>
<label for=m-zh-cndocsv27devcontract-check><a href=/zh-cn/docsv2.7/dev/contract/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devcontract><span>公共契约</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-zh-cndocsv27devsource-li><input type=checkbox id=m-zh-cndocsv27devsource-check>
<label for=m-zh-cndocsv27devsource-check><a href=/zh-cn/docsv2.7/dev/source/ title="Dubbo 源代码分析" class="align-left pl-0 td-sidebar-link td-sidebar-link__section" id=m-zh-cndocsv27devsource><span>源代码</span></a></label><ul class="ul-3 foldable"><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devsourcedubbo-spi-li><input type=checkbox id=m-zh-cndocsv27devsourcedubbo-spi-check>
<label for=m-zh-cndocsv27devsourcedubbo-spi-check><a href=/zh-cn/docsv2.7/dev/source/dubbo-spi/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devsourcedubbo-spi><span>Dubbo SPI</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devsourcerouter-li><input type=checkbox id=m-zh-cndocsv27devsourcerouter-check>
<label for=m-zh-cndocsv27devsourcerouter-check><a href=/zh-cn/docsv2.7/dev/source/router/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devsourcerouter><span>服务路由</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devsourceadaptive-extension-li><input type=checkbox id=m-zh-cndocsv27devsourceadaptive-extension-check>
<label for=m-zh-cndocsv27devsourceadaptive-extension-check><a href=/zh-cn/docsv2.7/dev/source/adaptive-extension/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devsourceadaptive-extension><span>SPI 自适应拓展</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devsourceexport-service-li><input type=checkbox id=m-zh-cndocsv27devsourceexport-service-check>
<label for=m-zh-cndocsv27devsourceexport-service-check><a href=/zh-cn/docsv2.7/dev/source/export-service/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devsourceexport-service><span>服务导出</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devsourcerefer-service-li><input type=checkbox id=m-zh-cndocsv27devsourcerefer-service-check>
<label for=m-zh-cndocsv27devsourcerefer-service-check><a href=/zh-cn/docsv2.7/dev/source/refer-service/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devsourcerefer-service><span>服务引用</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devsourceservice-invoking-process-li><input type=checkbox id=m-zh-cndocsv27devsourceservice-invoking-process-check>
<label for=m-zh-cndocsv27devsourceservice-invoking-process-check><a href=/zh-cn/docsv2.7/dev/source/service-invoking-process/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devsourceservice-invoking-process><span>服务调用过程</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devsourcedirectory-li><input type=checkbox id=m-zh-cndocsv27devsourcedirectory-check>
<label for=m-zh-cndocsv27devsourcedirectory-check><a href=/zh-cn/docsv2.7/dev/source/directory/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devsourcedirectory><span>服务目录</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devsourcecluster-li><input type=checkbox id=m-zh-cndocsv27devsourcecluster-check>
<label for=m-zh-cndocsv27devsourcecluster-check><a href=/zh-cn/docsv2.7/dev/source/cluster/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devsourcecluster><span>集群</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devsourceloadbalance-li><input type=checkbox id=m-zh-cndocsv27devsourceloadbalance-check>
<label for=m-zh-cndocsv27devsourceloadbalance-check><a href=/zh-cn/docsv2.7/dev/source/loadbalance/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devsourceloadbalance><span>负载均衡</span></a></label></li></ul></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devrelease-li><input type=checkbox id=m-zh-cndocsv27devrelease-check>
<label for=m-zh-cndocsv27devrelease-check><a href=/zh-cn/docsv2.7/dev/release/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devrelease><span>版本管理</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devchecklist-li><input type=checkbox id=m-zh-cndocsv27devchecklist-check>
<label for=m-zh-cndocsv27devchecklist-check><a href=/zh-cn/docsv2.7/dev/checklist/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devchecklist><span>检查列表</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devcoding-li><input type=checkbox id=m-zh-cndocsv27devcoding-check>
<label for=m-zh-cndocsv27devcoding-check><a href=/zh-cn/docsv2.7/dev/coding/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devcoding><span>编码约定</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devcode-smell-li><input type=checkbox id=m-zh-cndocsv27devcode-smell-check>
<label for=m-zh-cndocsv27devcode-smell-check><a href=/zh-cn/docsv2.7/dev/code-smell/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devcode-smell><span>坏味道</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27devtck-li><input type=checkbox id=m-zh-cndocsv27devtck-check>
<label for=m-zh-cndocsv27devtck-check><a href=/zh-cn/docsv2.7/dev/tck/ title=技术兼容性测试 class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27devtck><span>TCK</span></a></label></li></ul></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-zh-cndocsv27admin-li><input type=checkbox id=m-zh-cndocsv27admin-check>
<label for=m-zh-cndocsv27admin-check><a href=/zh-cn/docsv2.7/admin/ class="align-left pl-0 td-sidebar-link td-sidebar-link__section" id=m-zh-cndocsv27admin><span>运维指南</span></a></label><ul class="ul-2 foldable"><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-zh-cndocsv27adminops-li><input type=checkbox id=m-zh-cndocsv27adminops-check>
<label for=m-zh-cndocsv27adminops-check><a href=/zh-cn/docsv2.7/admin/ops/ class="align-left pl-0 td-sidebar-link td-sidebar-link__section" id=m-zh-cndocsv27adminops><span>Dubbo Admin 运维指南</span></a></label><ul class="ul-3 foldable"><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27adminopsfunctions-li><input type=checkbox id=m-zh-cndocsv27adminopsfunctions-check>
<label for=m-zh-cndocsv27adminopsfunctions-check><a href=/zh-cn/docsv2.7/admin/ops/functions/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27adminopsfunctions><span>管理控制台运维</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27adminopsintroduction-li><input type=checkbox id=m-zh-cndocsv27adminopsintroduction-check>
<label for=m-zh-cndocsv27adminopsintroduction-check><a href=/zh-cn/docsv2.7/admin/ops/introduction/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27adminopsintroduction><span>Dubbo 管理控制台介绍</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27adminopstest-li><input type=checkbox id=m-zh-cndocsv27adminopstest-check>
<label for=m-zh-cndocsv27adminopstest-check><a href=/zh-cn/docsv2.7/admin/ops/test/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27adminopstest><span>服务测试</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27adminopssearch-li><input type=checkbox id=m-zh-cndocsv27adminopssearch-check>
<label for=m-zh-cndocsv27adminopssearch-check><a href=/zh-cn/docsv2.7/admin/ops/search/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27adminopssearch><span>服务查询和详情展示</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27adminopsapidocs-li><input type=checkbox id=m-zh-cndocsv27adminopsapidocs-check>
<label for=m-zh-cndocsv27adminopsapidocs-check><a href=/zh-cn/docsv2.7/admin/ops/apidocs/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27adminopsapidocs><span>API文档&测试</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27adminopsgovernance-li><input type=checkbox id=m-zh-cndocsv27adminopsgovernance-check>
<label for=m-zh-cndocsv27adminopsgovernance-check><a href=/zh-cn/docsv2.7/admin/ops/governance/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27adminopsgovernance><span>服务治理和配置管理</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27adminopsskywalking-li><input type=checkbox id=m-zh-cndocsv27adminopsskywalking-check>
<label for=m-zh-cndocsv27adminopsskywalking-check><a href=/zh-cn/docsv2.7/admin/ops/skywalking/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27adminopsskywalking><span>使用 Apache Skywalking 做分布式跟踪</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27adminopspinpoint-li><input type=checkbox id=m-zh-cndocsv27adminopspinpoint-check>
<label for=m-zh-cndocsv27adminopspinpoint-check><a href=/zh-cn/docsv2.7/admin/ops/pinpoint/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27adminopspinpoint><span>使用 Pinpoint 做分布式跟踪</span></a></label></li></ul></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-zh-cndocsv27admininstall-li><input type=checkbox id=m-zh-cndocsv27admininstall-check>
<label for=m-zh-cndocsv27admininstall-check><a href=/zh-cn/docsv2.7/admin/install/ class="align-left pl-0 td-sidebar-link td-sidebar-link__section" id=m-zh-cndocsv27admininstall><span>安装手册</span></a></label><ul class="ul-3 foldable"><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27admininstalladmin-console-li><input type=checkbox id=m-zh-cndocsv27admininstalladmin-console-check>
<label for=m-zh-cndocsv27admininstalladmin-console-check><a href=/zh-cn/docsv2.7/admin/install/admin-console/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27admininstalladmin-console><span>管理控制台安装</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27admininstallprovider-demo-li><input type=checkbox id=m-zh-cndocsv27admininstallprovider-demo-check>
<label for=m-zh-cndocsv27admininstallprovider-demo-check><a href=/zh-cn/docsv2.7/admin/install/provider-demo/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27admininstallprovider-demo><span>示例提供者安装</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27admininstallconsumer-demo-li><input type=checkbox id=m-zh-cndocsv27admininstallconsumer-demo-check>
<label for=m-zh-cndocsv27admininstallconsumer-demo-check><a href=/zh-cn/docsv2.7/admin/install/consumer-demo/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27admininstallconsumer-demo><span>示例消费者安装</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27admininstallredis-li><input type=checkbox id=m-zh-cndocsv27admininstallredis-check>
<label for=m-zh-cndocsv27admininstallredis-check><a href=/zh-cn/docsv2.7/admin/install/redis/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27admininstallredis><span>Redis 注册中心安装</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27admininstallzookeeper-li><input type=checkbox id=m-zh-cndocsv27admininstallzookeeper-check>
<label for=m-zh-cndocsv27admininstallzookeeper-check><a href=/zh-cn/docsv2.7/admin/install/zookeeper/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27admininstallzookeeper><span>Zookeeper 注册中心安装</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-zh-cndocsv27admininstallmonitor-center-li><input type=checkbox id=m-zh-cndocsv27admininstallmonitor-center-check>
<label for=m-zh-cndocsv27admininstallmonitor-center-check><a href=/zh-cn/docsv2.7/admin/install/monitor-center/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-zh-cndocsv27admininstallmonitor-center><span>Simple 监控中心安装</span></a></label></li></ul></li></ul></li></ul></li></ul></nav></div></div><main class="col-12 col-md-9 col-xl-8 pl-md-5" role=main><nav aria-label=breadcrumb class=td-breadcrumbs><ol class=breadcrumb><li class=breadcrumb-item><a href=https://dubbo.apache.org/zh-cn/docsv2.7/>文档 2.x</a></li><li class=breadcrumb-item><a href=https://dubbo.apache.org/zh-cn/docsv2.7/dev/>开发指南</a></li><li class=breadcrumb-item><a href=https://dubbo.apache.org/zh-cn/docsv2.7/dev/source/>源代码</a></li><li class="breadcrumb-item active" aria-current=page><a href=https://dubbo.apache.org/zh-cn/docsv2.7/dev/source/directory/ aria-disabled=true class="btn-link disabled">服务目录</a></li></ol></nav><div class=td-content><h1>服务目录</h1><div class=lead>本文介绍了服务目录的原理和实现细节</div><header class=article-meta></header><h2 id=1-简介>1. 简介</h2><p>本篇文章,将开始分析 Dubbo 集群容错方面的源码。集群容错源码包含四个部分,分别是服务目录 Directory、服务路由 Router、集群 Cluster 和负载均衡 LoadBalance。这几个部分的源码逻辑相对比较独立,我们将会分四篇文章进行分析。本篇文章作为集群容错的开篇文章,将和大家一起分析服务目录相关的源码。在进行深入分析之前,我们先来了解一下服务目录是什么。服务目录中存储了一些和服务提供者有关的信息,通过服务目录,服务消费者可获取到服务提供者的信息,比如 ip、端口、服务协议等。通过这些信息,服务消费者就可通过 Netty 等客户端进行远程调用。在一个服务集群中,服务提供者数量并不是一成不变的,如果集群中新增了一台机器,相应地在服务目录中就要新增一条服务提供者记录。或者,如果服务提供者的配置修改了,服务目录中的记录也要做相应的更新。如果这样说,服务目录和注册中心的功能不就雷同了吗?确实如此,这里这么说是为了方便大家理解。实际上服务目录在获取注册中心的服务配置信息后,会为每条配置信息生成一个 Invoker 对象,并把这个 Invoker 对象存储起来,这个 Invoker 才是服务目录最终持有的对象。Invoker 有什么用呢?看名字就知道了,这是一个具有远程调用功能的对象。讲到这大家应该知道了什么是服务目录了,它可以看做是 Invoker 集合,且这个集合中的元素会随注册中心的变化而进行动态调整。</p><p>关于服务目录这里就先介绍这些,大家先有个大致印象。接下来我们通过继承体系图来了解一下服务目录的家族成员都有哪些。</p><h2 id=2-继承体系>2. 继承体系</h2><p>服务目录目前内置的实现有两个,分别为 StaticDirectory 和 RegistryDirectory,它们均是 AbstractDirectory 的子类。AbstractDirectory 实现了 Directory 接口,这个接口包含了一个重要的方法定义,即 list(Invocation),用于列举 Invoker。下面我们来看一下他们的继承体系图。</p><p><img src=/imgs/dev/directory-inherit-hierarchy.png alt=img></p><p>如上,Directory 继承自 Node 接口,Node 这个接口继承者比较多,像 Registry、Monitor、Invoker 等均继承了这个接口。这个接口包含了一个获取配置信息的方法 getUrl,实现该接口的类可以向外提供配置信息。另外,大家注意看 RegistryDirectory 实现了 NotifyListener 接口,当注册中心节点信息发生变化后,RegistryDirectory 可以通过此接口方法得到变更信息,并根据变更信息动态调整内部 Invoker 列表。</p><h2 id=3-源码分析>3. 源码分析</h2><p>本章将分析 AbstractDirectory 和它两个子类的源码。AbstractDirectory 封装了 Invoker 列举流程,具体的列举逻辑则由子类实现,这是典型的模板模式。所以,接下来我们先来看一下 AbstractDirectory 的源码。</p><div class=highlight><pre tabindex=0 style=color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=display:flex><span><span style=color:#268bd2>public</span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> <span style=color:#268bd2>list</span><span style=color:#719e07>(</span>Invocation invocation<span style=color:#719e07>)</span> <span style=color:#268bd2>throws</span> RpcException <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>destroyed<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>throw</span> <span style=color:#719e07>new</span> RpcException<span style=color:#719e07>(</span><span style=color:#2aa198>&#34;Directory already destroyed...&#34;</span><span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 调用 doList 方法列举 Invoker,doList 是模板方法,由子类实现
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> invokers <span style=color:#719e07>=</span> doList<span style=color:#719e07>(</span>invocation<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 获取路由 Router 列表
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> List<span style=color:#719e07>&lt;</span>Router<span style=color:#719e07>&gt;</span> localRouters <span style=color:#719e07>=</span> <span style=color:#719e07>this</span><span style=color:#719e07>.</span>routers<span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>localRouters <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>&amp;&amp;</span> <span style=color:#719e07>!</span>localRouters<span style=color:#719e07>.</span>isEmpty<span style=color:#719e07>())</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>for</span> <span style=color:#719e07>(</span>Router router <span style=color:#719e07>:</span> localRouters<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>try</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 获取 runtime 参数,并根据参数决定是否进行路由
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>router<span style=color:#719e07>.</span>getUrl<span style=color:#719e07>()</span> <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>||</span> router<span style=color:#719e07>.</span>getUrl<span style=color:#719e07>().</span>getParameter<span style=color:#719e07>(</span>Constants<span style=color:#719e07>.</span>RUNTIME_KEY<span style=color:#719e07>,</span> <span style=color:#cb4b16>false</span><span style=color:#719e07>))</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 进行服务路由
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> invokers <span style=color:#719e07>=</span> router<span style=color:#719e07>.</span>route<span style=color:#719e07>(</span>invokers<span style=color:#719e07>,</span> getConsumerUrl<span style=color:#719e07>(),</span> invocation<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span> <span style=color:#719e07>catch</span> <span style=color:#719e07>(</span>Throwable t<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> logger<span style=color:#719e07>.</span>error<span style=color:#719e07>(</span><span style=color:#2aa198>&#34;Failed to execute router: ...&#34;</span><span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>return</span> invokers<span style=color:#719e07>;</span>
</span></span><span style=display:flex><span><span style=color:#719e07>}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#586e75>// 模板方法,由子类实现
</span></span></span><span style=display:flex><span><span style=color:#586e75></span><span style=color:#268bd2>protected</span> <span style=color:#268bd2>abstract</span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> <span style=color:#268bd2>doList</span><span style=color:#719e07>(</span>Invocation invocation<span style=color:#719e07>)</span> <span style=color:#268bd2>throws</span> RpcException<span style=color:#719e07>;</span>
</span></span></code></pre></div><p>上面就是 AbstractDirectory 的 list 方法源码,这个方法封装了 Invoker 的列举过程。如下:</p><ol><li>调用 doList 获取 Invoker 列表</li><li>根据 Router 的 getUrl 返回值为空与否,以及 runtime 参数决定是否进行服务路由</li></ol><p>以上步骤中,doList 是模板方法,需由子类实现。Router 的 runtime 参数这里简单说明一下,这个参数决定了是否在每次调用服务时都执行路由规则。如果 runtime 为 true,那么每次调用服务前,都需要进行服务路由。这个对性能造成影响,配置时需要注意。</p><p>关于 AbstractDirectory 就分析这么多,下面开始分析子类的源码。</p><h3 id=31-staticdirectory>3.1 StaticDirectory</h3><p>StaticDirectory 即静态服务目录,顾名思义,它内部存放的 Invoker 是不会变动的。所以,理论上它和不可变 List 的功能很相似。下面我们来看一下这个类的实现。</p><div class=highlight><pre tabindex=0 style=color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=display:flex><span><span style=color:#268bd2>public</span> <span style=color:#268bd2>class</span> <span style=color:#268bd2>StaticDirectory</span><span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;</span> <span style=color:#268bd2>extends</span> AbstractDirectory<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// Invoker 列表
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#268bd2>private</span> <span style=color:#268bd2>final</span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> invokers<span style=color:#719e07>;</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 省略构造方法
</span></span></span><span style=display:flex><span><span style=color:#586e75></span>
</span></span><span style=display:flex><span> <span style=color:#268bd2>@Override</span>
</span></span><span style=display:flex><span> <span style=color:#268bd2>public</span> Class<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;</span> <span style=color:#268bd2>getInterface</span><span style=color:#719e07>()</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 获取接口类
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>return</span> invokers<span style=color:#719e07>.</span>get<span style=color:#719e07>(</span>0<span style=color:#719e07>).</span>getInterface<span style=color:#719e07>();</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 检测服务目录是否可用
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#268bd2>@Override</span>
</span></span><span style=display:flex><span> <span style=color:#268bd2>public</span> <span style=color:#dc322f>boolean</span> <span style=color:#268bd2>isAvailable</span><span style=color:#719e07>()</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>isDestroyed<span style=color:#719e07>())</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>return</span> <span style=color:#cb4b16>false</span><span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>for</span> <span style=color:#719e07>(</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;</span> invoker <span style=color:#719e07>:</span> invokers<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>invoker<span style=color:#719e07>.</span>isAvailable<span style=color:#719e07>())</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 只要有一个 Invoker 是可用的,就认为当前目录是可用的
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>return</span> <span style=color:#cb4b16>true</span><span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>return</span> <span style=color:#cb4b16>false</span><span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#268bd2>@Override</span>
</span></span><span style=display:flex><span> <span style=color:#268bd2>public</span> <span style=color:#dc322f>void</span> <span style=color:#268bd2>destroy</span><span style=color:#719e07>()</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>isDestroyed<span style=color:#719e07>())</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>return</span><span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 调用父类销毁逻辑
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#268bd2>super</span><span style=color:#719e07>.</span>destroy<span style=color:#719e07>();</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 遍历 Invoker 列表,并执行相应的销毁逻辑
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>for</span> <span style=color:#719e07>(</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;</span> invoker <span style=color:#719e07>:</span> invokers<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> invoker<span style=color:#719e07>.</span>destroy<span style=color:#719e07>();</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> invokers<span style=color:#719e07>.</span>clear<span style=color:#719e07>();</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#268bd2>@Override</span>
</span></span><span style=display:flex><span> <span style=color:#268bd2>protected</span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> <span style=color:#268bd2>doList</span><span style=color:#719e07>(</span>Invocation invocation<span style=color:#719e07>)</span> <span style=color:#268bd2>throws</span> RpcException <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 列举 Inovker,也就是直接返回 invokers 成员变量
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>return</span> invokers<span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span><span style=color:#719e07>}</span>
</span></span></code></pre></div><p>以上就是 StaticDirectory 的代码逻辑,很简单,就不多说了。下面来看看 RegistryDirectory,这个类的逻辑比较复杂。</p><h3 id=32-registrydirectory>3.2 RegistryDirectory</h3><p>RegistryDirectory 是一种动态服务目录,实现了 NotifyListener 接口。当注册中心服务配置发生变化后,RegistryDirectory 可收到与当前服务相关的变化。收到变更通知后,RegistryDirectory 可根据配置变更信息刷新 Invoker 列表。RegistryDirectory 中有几个比较重要的逻辑,第一是 Invoker 的列举逻辑,第二是接收服务配置变更的逻辑,第三是 Invoker 列表的刷新逻辑。接下来按顺序对这三块逻辑进行分析。</p><h4 id=321-列举-invoker>3.2.1 列举 Invoker</h4><p>Invoker 列举逻辑封装在 doList 方法中,相关代码如下:</p><div class=highlight><pre tabindex=0 style=color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=display:flex><span><span style=color:#268bd2>public</span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> <span style=color:#268bd2>doList</span><span style=color:#719e07>(</span>Invocation invocation<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>forbidden<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 服务提供者关闭或禁用了服务,此时抛出 No provider 异常
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>throw</span> <span style=color:#719e07>new</span> RpcException<span style=color:#719e07>(</span>RpcException<span style=color:#719e07>.</span>FORBIDDEN_EXCEPTION<span style=color:#719e07>,</span>
</span></span><span style=display:flex><span> <span style=color:#2aa198>&#34;No provider available from registry ...&#34;</span><span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> invokers <span style=color:#719e07>=</span> <span style=color:#cb4b16>null</span><span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 获取 Invoker 本地缓存
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> Map<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;&gt;</span> localMethodInvokerMap <span style=color:#719e07>=</span> <span style=color:#719e07>this</span><span style=color:#719e07>.</span>methodInvokerMap<span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>localMethodInvokerMap <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>&amp;&amp;</span> localMethodInvokerMap<span style=color:#719e07>.</span>size<span style=color:#719e07>()</span> <span style=color:#719e07>&gt;</span> 0<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 获取方法名和参数列表
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> String methodName <span style=color:#719e07>=</span> RpcUtils<span style=color:#719e07>.</span>getMethodName<span style=color:#719e07>(</span>invocation<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> Object<span style=color:#719e07>[]</span> args <span style=color:#719e07>=</span> RpcUtils<span style=color:#719e07>.</span>getArguments<span style=color:#719e07>(</span>invocation<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 检测参数列表的第一个参数是否为 String 或 enum 类型
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>args <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>&amp;&amp;</span> args<span style=color:#719e07>.</span>length <span style=color:#719e07>&gt;</span> 0 <span style=color:#719e07>&amp;&amp;</span> args<span style=color:#719e07>[</span>0<span style=color:#719e07>]</span> <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>&amp;&amp;</span> <span style=color:#719e07>(</span>args<span style=color:#719e07>[</span>0<span style=color:#719e07>]</span> <span style=color:#719e07>instanceof</span> String <span style=color:#719e07>||</span> args<span style=color:#719e07>[</span>0<span style=color:#719e07>].</span>getClass<span style=color:#719e07>().</span>isEnum<span style=color:#719e07>()))</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 通过 方法名 + 第一个参数名称 查询 Invoker 列表,具体的使用场景暂时没想到
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> invokers <span style=color:#719e07>=</span> localMethodInvokerMap<span style=color:#719e07>.</span>get<span style=color:#719e07>(</span>methodName <span style=color:#719e07>+</span> <span style=color:#2aa198>&#34;.&#34;</span> <span style=color:#719e07>+</span> args<span style=color:#719e07>[</span>0<span style=color:#719e07>]);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>invokers <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span><span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 通过方法名获取 Invoker 列表
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> invokers <span style=color:#719e07>=</span> localMethodInvokerMap<span style=color:#719e07>.</span>get<span style=color:#719e07>(</span>methodName<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>invokers <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span><span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 通过星号 * 获取 Invoker 列表
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> invokers <span style=color:#719e07>=</span> localMethodInvokerMap<span style=color:#719e07>.</span>get<span style=color:#719e07>(</span>Constants<span style=color:#719e07>.</span>ANY_VALUE<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 冗余逻辑,pull request #2861 移除了下面的 if 分支代码
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>invokers <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span><span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> Iterator<span style=color:#719e07>&lt;</span>List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;&gt;</span> iterator <span style=color:#719e07>=</span> localMethodInvokerMap<span style=color:#719e07>.</span>values<span style=color:#719e07>().</span>iterator<span style=color:#719e07>();</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>iterator<span style=color:#719e07>.</span>hasNext<span style=color:#719e07>())</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> invokers <span style=color:#719e07>=</span> iterator<span style=color:#719e07>.</span>next<span style=color:#719e07>();</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 返回 Invoker 列表
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>return</span> invokers <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>?</span> <span style=color:#719e07>new</span> ArrayList<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;(</span>0<span style=color:#719e07>)</span> <span style=color:#719e07>:</span> invokers<span style=color:#719e07>;</span>
</span></span><span style=display:flex><span><span style=color:#719e07>}</span>
</span></span></code></pre></div><p>以上代码进行多次尝试,以期从 localMethodInvokerMap 中获取到 Invoker 列表。一般情况下,普通的调用可通过方法名获取到对应的 Invoker 列表,泛化调用可通过 <code>*</code> 获取到 Invoker 列表。localMethodInvokerMap 源自 RegistryDirectory 类的成员变量 methodInvokerMap。doList 方法可以看做是对 methodInvokerMap 变量的读操作,至于对 methodInvokerMap 变量的写操作,下一节进行分析。</p><h4 id=322-接收服务变更通知>3.2.2 接收服务变更通知</h4><p>RegistryDirectory 是一个动态服务目录,会随注册中心配置的变化进行动态调整。因此 RegistryDirectory 实现了 NotifyListener 接口,通过这个接口获取注册中心变更通知。下面我们来看一下具体的逻辑。</p><div class=highlight><pre tabindex=0 style=color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=display:flex><span><span style=color:#268bd2>public</span> <span style=color:#268bd2>synchronized</span> <span style=color:#dc322f>void</span> <span style=color:#268bd2>notify</span><span style=color:#719e07>(</span>List<span style=color:#719e07>&lt;</span>URL<span style=color:#719e07>&gt;</span> urls<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 定义三个集合,分别用于存放服务提供者 url,路由 url,配置器 url
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> List<span style=color:#719e07>&lt;</span>URL<span style=color:#719e07>&gt;</span> invokerUrls <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> ArrayList<span style=color:#719e07>&lt;</span>URL<span style=color:#719e07>&gt;();</span>
</span></span><span style=display:flex><span> List<span style=color:#719e07>&lt;</span>URL<span style=color:#719e07>&gt;</span> routerUrls <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> ArrayList<span style=color:#719e07>&lt;</span>URL<span style=color:#719e07>&gt;();</span>
</span></span><span style=display:flex><span> List<span style=color:#719e07>&lt;</span>URL<span style=color:#719e07>&gt;</span> configuratorUrls <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> ArrayList<span style=color:#719e07>&lt;</span>URL<span style=color:#719e07>&gt;();</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>for</span> <span style=color:#719e07>(</span>URL url <span style=color:#719e07>:</span> urls<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> String protocol <span style=color:#719e07>=</span> url<span style=color:#719e07>.</span>getProtocol<span style=color:#719e07>();</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 获取 category 参数
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> String category <span style=color:#719e07>=</span> url<span style=color:#719e07>.</span>getParameter<span style=color:#719e07>(</span>Constants<span style=color:#719e07>.</span>CATEGORY_KEY<span style=color:#719e07>,</span> Constants<span style=color:#719e07>.</span>DEFAULT_CATEGORY<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 根据 category 参数将 url 分别放到不同的列表中
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>Constants<span style=color:#719e07>.</span>ROUTERS_CATEGORY<span style=color:#719e07>.</span>equals<span style=color:#719e07>(</span>category<span style=color:#719e07>)</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>||</span> Constants<span style=color:#719e07>.</span>ROUTE_PROTOCOL<span style=color:#719e07>.</span>equals<span style=color:#719e07>(</span>protocol<span style=color:#719e07>))</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 添加路由器 url
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> routerUrls<span style=color:#719e07>.</span>add<span style=color:#719e07>(</span>url<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span> <span style=color:#719e07>else</span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>Constants<span style=color:#719e07>.</span>CONFIGURATORS_CATEGORY<span style=color:#719e07>.</span>equals<span style=color:#719e07>(</span>category<span style=color:#719e07>)</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>||</span> Constants<span style=color:#719e07>.</span>OVERRIDE_PROTOCOL<span style=color:#719e07>.</span>equals<span style=color:#719e07>(</span>protocol<span style=color:#719e07>))</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 添加配置器 url
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> configuratorUrls<span style=color:#719e07>.</span>add<span style=color:#719e07>(</span>url<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span> <span style=color:#719e07>else</span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>Constants<span style=color:#719e07>.</span>PROVIDERS_CATEGORY<span style=color:#719e07>.</span>equals<span style=color:#719e07>(</span>category<span style=color:#719e07>))</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 添加服务提供者 url
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> invokerUrls<span style=color:#719e07>.</span>add<span style=color:#719e07>(</span>url<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span> <span style=color:#719e07>else</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 忽略不支持的 category
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> logger<span style=color:#719e07>.</span>warn<span style=color:#719e07>(</span><span style=color:#2aa198>&#34;Unsupported category ...&#34;</span><span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>configuratorUrls <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>&amp;&amp;</span> <span style=color:#719e07>!</span>configuratorUrls<span style=color:#719e07>.</span>isEmpty<span style=color:#719e07>())</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 将 url 转成 Configurator
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>this</span><span style=color:#719e07>.</span>configurators <span style=color:#719e07>=</span> toConfigurators<span style=color:#719e07>(</span>configuratorUrls<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>routerUrls <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>&amp;&amp;</span> <span style=color:#719e07>!</span>routerUrls<span style=color:#719e07>.</span>isEmpty<span style=color:#719e07>())</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 将 url 转成 Router
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> List<span style=color:#719e07>&lt;</span>Router<span style=color:#719e07>&gt;</span> routers <span style=color:#719e07>=</span> toRouters<span style=color:#719e07>(</span>routerUrls<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>routers <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span><span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> setRouters<span style=color:#719e07>(</span>routers<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> List<span style=color:#719e07>&lt;</span>Configurator<span style=color:#719e07>&gt;</span> localConfigurators <span style=color:#719e07>=</span> <span style=color:#719e07>this</span><span style=color:#719e07>.</span>configurators<span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>this</span><span style=color:#719e07>.</span>overrideDirectoryUrl <span style=color:#719e07>=</span> directoryUrl<span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>localConfigurators <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>&amp;&amp;</span> <span style=color:#719e07>!</span>localConfigurators<span style=color:#719e07>.</span>isEmpty<span style=color:#719e07>())</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>for</span> <span style=color:#719e07>(</span>Configurator configurator <span style=color:#719e07>:</span> localConfigurators<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 配置 overrideDirectoryUrl
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>this</span><span style=color:#719e07>.</span>overrideDirectoryUrl <span style=color:#719e07>=</span> configurator<span style=color:#719e07>.</span>configure<span style=color:#719e07>(</span>overrideDirectoryUrl<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 刷新 Invoker 列表
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> refreshInvoker<span style=color:#719e07>(</span>invokerUrls<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span><span style=color:#719e07>}</span>
</span></span></code></pre></div><p>如上,notify 方法首先是根据 url 的 category 参数对 url 进行分门别类存储,然后通过 toRouters 和 toConfigurators 将 url 列表转成 Router 和 Configurator 列表。最后调用 refreshInvoker 方法刷新 Invoker 列表。这里的 toRouters 和 toConfigurators 方法逻辑不复杂,大家自行分析。接下来,我们把重点放在 refreshInvoker 方法上。</p><h4 id=323-刷新-invoker-列表>3.2.3 刷新 Invoker 列表</h4><p>refreshInvoker 方法是保证 RegistryDirectory 随注册中心变化而变化的关键所在。这一块逻辑比较多,接下来一一进行分析。</p><div class=highlight><pre tabindex=0 style=color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=display:flex><span><span style=color:#268bd2>private</span> <span style=color:#dc322f>void</span> <span style=color:#268bd2>refreshInvoker</span><span style=color:#719e07>(</span>List<span style=color:#719e07>&lt;</span>URL<span style=color:#719e07>&gt;</span> invokerUrls<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// invokerUrls 仅有一个元素,且 url 协议头为 empty,此时表示禁用所有服务
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>invokerUrls <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>&amp;&amp;</span> invokerUrls<span style=color:#719e07>.</span>size<span style=color:#719e07>()</span> <span style=color:#719e07>==</span> 1 <span style=color:#719e07>&amp;&amp;</span> invokerUrls<span style=color:#719e07>.</span>get<span style=color:#719e07>(</span>0<span style=color:#719e07>)</span> <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>&amp;&amp;</span> Constants<span style=color:#719e07>.</span>EMPTY_PROTOCOL<span style=color:#719e07>.</span>equals<span style=color:#719e07>(</span>invokerUrls<span style=color:#719e07>.</span>get<span style=color:#719e07>(</span>0<span style=color:#719e07>).</span>getProtocol<span style=color:#719e07>()))</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 设置 forbidden 为 true
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>this</span><span style=color:#719e07>.</span>forbidden <span style=color:#719e07>=</span> <span style=color:#cb4b16>true</span><span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>this</span><span style=color:#719e07>.</span>methodInvokerMap <span style=color:#719e07>=</span> <span style=color:#cb4b16>null</span><span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 销毁所有 Invoker
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> destroyAllInvokers<span style=color:#719e07>();</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span> <span style=color:#719e07>else</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>this</span><span style=color:#719e07>.</span>forbidden <span style=color:#719e07>=</span> <span style=color:#cb4b16>false</span><span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> Map<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> oldUrlInvokerMap <span style=color:#719e07>=</span> <span style=color:#719e07>this</span><span style=color:#719e07>.</span>urlInvokerMap<span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>invokerUrls<span style=color:#719e07>.</span>isEmpty<span style=color:#719e07>()</span> <span style=color:#719e07>&amp;&amp;</span> <span style=color:#719e07>this</span><span style=color:#719e07>.</span>cachedInvokerUrls <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span><span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 添加缓存 url 到 invokerUrls 中
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> invokerUrls<span style=color:#719e07>.</span>addAll<span style=color:#719e07>(</span><span style=color:#719e07>this</span><span style=color:#719e07>.</span>cachedInvokerUrls<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span> <span style=color:#719e07>else</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>this</span><span style=color:#719e07>.</span>cachedInvokerUrls <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> HashSet<span style=color:#719e07>&lt;</span>URL<span style=color:#719e07>&gt;();</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 缓存 invokerUrls
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>this</span><span style=color:#719e07>.</span>cachedInvokerUrls<span style=color:#719e07>.</span>addAll<span style=color:#719e07>(</span>invokerUrls<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>invokerUrls<span style=color:#719e07>.</span>isEmpty<span style=color:#719e07>())</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>return</span><span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 将 url 转成 Invoker
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> Map<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> newUrlInvokerMap <span style=color:#719e07>=</span> toInvokers<span style=color:#719e07>(</span>invokerUrls<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 将 newUrlInvokerMap 转成方法名到 Invoker 列表的映射
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> Map<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;&gt;</span> newMethodInvokerMap <span style=color:#719e07>=</span> toMethodInvokers<span style=color:#719e07>(</span>newUrlInvokerMap<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 转换出错,直接打印异常,并返回
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>newUrlInvokerMap <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>||</span> newUrlInvokerMap<span style=color:#719e07>.</span>size<span style=color:#719e07>()</span> <span style=color:#719e07>==</span> 0<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> logger<span style=color:#719e07>.</span>error<span style=color:#719e07>(</span><span style=color:#719e07>new</span> IllegalStateException<span style=color:#719e07>(</span><span style=color:#2aa198>&#34;urls to invokers error ...&#34;</span><span style=color:#719e07>));</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>return</span><span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 合并多个组的 Invoker
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>this</span><span style=color:#719e07>.</span>methodInvokerMap <span style=color:#719e07>=</span> multiGroup <span style=color:#719e07>?</span> toMergeMethodInvokerMap<span style=color:#719e07>(</span>newMethodInvokerMap<span style=color:#719e07>)</span> <span style=color:#719e07>:</span> newMethodInvokerMap<span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>this</span><span style=color:#719e07>.</span>urlInvokerMap <span style=color:#719e07>=</span> newUrlInvokerMap<span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>try</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 销毁无用 Invoker
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> destroyUnusedInvokers<span style=color:#719e07>(</span>oldUrlInvokerMap<span style=color:#719e07>,</span> newUrlInvokerMap<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span> <span style=color:#719e07>catch</span> <span style=color:#719e07>(</span>Exception e<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> logger<span style=color:#719e07>.</span>warn<span style=color:#719e07>(</span><span style=color:#2aa198>&#34;destroyUnusedInvokers error. &#34;</span><span style=color:#719e07>,</span> e<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span><span style=color:#719e07>}</span>
</span></span></code></pre></div><p>refreshInvoker 方法首先会根据入参 invokerUrls 的数量和协议头判断是否禁用所有的服务,如果禁用,则将 forbidden 设为 true,并销毁所有的 Invoker。若不禁用,则将 url 转成 Invoker,得到 &lt;url, Invoker> 的映射关系。然后进一步进行转换,得到 &lt;methodName, Invoker 列表> 映射关系。之后进行多组 Invoker 合并操作,并将合并结果赋值给 methodInvokerMap。methodInvokerMap 变量在 doList 方法中会被用到,doList 会对该变量进行读操作,在这里是写操作。当新的 Invoker 列表生成后,还要一个重要的工作要做,就是销毁无用的 Invoker,避免服务消费者调用已下线的服务的服务。</p><p>接下来对 refreshInvoker 方法中涉及到的调用一一进行分析。按照顺序,先来分析 url 到 Invoker 的转换过程。</p><div class=highlight><pre tabindex=0 style=color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=display:flex><span><span style=color:#268bd2>private</span> Map<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> <span style=color:#268bd2>toInvokers</span><span style=color:#719e07>(</span>List<span style=color:#719e07>&lt;</span>URL<span style=color:#719e07>&gt;</span> urls<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> Map<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> newUrlInvokerMap <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> HashMap<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;();</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>urls <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>||</span> urls<span style=color:#719e07>.</span>isEmpty<span style=color:#719e07>())</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>return</span> newUrlInvokerMap<span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> Set<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>&gt;</span> keys <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> HashSet<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>&gt;();</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 获取服务消费端配置的协议
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> String queryProtocols <span style=color:#719e07>=</span> <span style=color:#719e07>this</span><span style=color:#719e07>.</span>queryMap<span style=color:#719e07>.</span>get<span style=color:#719e07>(</span>Constants<span style=color:#719e07>.</span>PROTOCOL_KEY<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>for</span> <span style=color:#719e07>(</span>URL providerUrl <span style=color:#719e07>:</span> urls<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>queryProtocols <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>&amp;&amp;</span> queryProtocols<span style=color:#719e07>.</span>length<span style=color:#719e07>()</span> <span style=color:#719e07>&gt;</span> 0<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#dc322f>boolean</span> accept <span style=color:#719e07>=</span> <span style=color:#cb4b16>false</span><span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> String<span style=color:#719e07>[]</span> acceptProtocols <span style=color:#719e07>=</span> queryProtocols<span style=color:#719e07>.</span>split<span style=color:#719e07>(</span><span style=color:#2aa198>&#34;,&#34;</span><span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 检测服务提供者协议是否被服务消费者所支持
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>for</span> <span style=color:#719e07>(</span>String acceptProtocol <span style=color:#719e07>:</span> acceptProtocols<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>providerUrl<span style=color:#719e07>.</span>getProtocol<span style=color:#719e07>().</span>equals<span style=color:#719e07>(</span>acceptProtocol<span style=color:#719e07>))</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> accept <span style=color:#719e07>=</span> <span style=color:#cb4b16>true</span><span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>break</span><span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(!</span>accept<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 若服务提供者协议头不被消费者所支持,则忽略当前 providerUrl
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>continue</span><span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 忽略 empty 协议
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>Constants<span style=color:#719e07>.</span>EMPTY_PROTOCOL<span style=color:#719e07>.</span>equals<span style=color:#719e07>(</span>providerUrl<span style=color:#719e07>.</span>getProtocol<span style=color:#719e07>()))</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>continue</span><span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 通过 SPI 检测服务端协议是否被消费端支持,不支持则抛出异常
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>if</span> <span style=color:#719e07>(!</span>ExtensionLoader<span style=color:#719e07>.</span>getExtensionLoader<span style=color:#719e07>(</span>Protocol<span style=color:#719e07>.</span>class<span style=color:#719e07>).</span>hasExtension<span style=color:#719e07>(</span>providerUrl<span style=color:#719e07>.</span>getProtocol<span style=color:#719e07>()))</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> logger<span style=color:#719e07>.</span>error<span style=color:#719e07>(</span><span style=color:#719e07>new</span> IllegalStateException<span style=color:#719e07>(</span><span style=color:#2aa198>&#34;Unsupported protocol...&#34;</span><span style=color:#719e07>));</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>continue</span><span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 合并 url
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> URL url <span style=color:#719e07>=</span> mergeUrl<span style=color:#719e07>(</span>providerUrl<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> String key <span style=color:#719e07>=</span> url<span style=color:#719e07>.</span>toFullString<span style=color:#719e07>();</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>keys<span style=color:#719e07>.</span>contains<span style=color:#719e07>(</span>key<span style=color:#719e07>))</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 忽略重复 url
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>continue</span><span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> keys<span style=color:#719e07>.</span>add<span style=color:#719e07>(</span>key<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 将本地 Invoker 缓存赋值给 localUrlInvokerMap
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> Map<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> localUrlInvokerMap <span style=color:#719e07>=</span> <span style=color:#719e07>this</span><span style=color:#719e07>.</span>urlInvokerMap<span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 获取与 url 对应的 Invoker
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;</span> invoker <span style=color:#719e07>=</span> localUrlInvokerMap <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>?</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>:</span> localUrlInvokerMap<span style=color:#719e07>.</span>get<span style=color:#719e07>(</span>key<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 缓存未命中
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>invoker <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span><span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>try</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#dc322f>boolean</span> enabled <span style=color:#719e07>=</span> <span style=color:#cb4b16>true</span><span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>url<span style=color:#719e07>.</span>hasParameter<span style=color:#719e07>(</span>Constants<span style=color:#719e07>.</span>DISABLED_KEY<span style=color:#719e07>))</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 获取 disable 配置,取反,然后赋值给 enable 变量
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> enabled <span style=color:#719e07>=</span> <span style=color:#719e07>!</span>url<span style=color:#719e07>.</span>getParameter<span style=color:#719e07>(</span>Constants<span style=color:#719e07>.</span>DISABLED_KEY<span style=color:#719e07>,</span> <span style=color:#cb4b16>false</span><span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span> <span style=color:#719e07>else</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 获取 enable 配置,并赋值给 enable 变量
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> enabled <span style=color:#719e07>=</span> url<span style=color:#719e07>.</span>getParameter<span style=color:#719e07>(</span>Constants<span style=color:#719e07>.</span>ENABLED_KEY<span style=color:#719e07>,</span> <span style=color:#cb4b16>true</span><span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>enabled<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 调用 refer 获取 Invoker
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> invoker <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> InvokerDelegate<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;(</span>protocol<span style=color:#719e07>.</span>refer<span style=color:#719e07>(</span>serviceType<span style=color:#719e07>,</span> url<span style=color:#719e07>),</span> url<span style=color:#719e07>,</span> providerUrl<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span> <span style=color:#719e07>catch</span> <span style=color:#719e07>(</span>Throwable t<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> logger<span style=color:#719e07>.</span>error<span style=color:#719e07>(</span><span style=color:#2aa198>&#34;Failed to refer invoker for interface...&#34;</span><span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>invoker <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span><span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 缓存 Invoker 实例
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> newUrlInvokerMap<span style=color:#719e07>.</span>put<span style=color:#719e07>(</span>key<span style=color:#719e07>,</span> invoker<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 缓存命中
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>}</span> <span style=color:#719e07>else</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 将 invoker 存储到 newUrlInvokerMap 中
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> newUrlInvokerMap<span style=color:#719e07>.</span>put<span style=color:#719e07>(</span>key<span style=color:#719e07>,</span> invoker<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> keys<span style=color:#719e07>.</span>clear<span style=color:#719e07>();</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>return</span> newUrlInvokerMap<span style=color:#719e07>;</span>
</span></span><span style=display:flex><span><span style=color:#719e07>}</span>
</span></span></code></pre></div><p>toInvokers 方法一开始会对服务提供者 url 进行检测,若服务消费端的配置不支持服务端的协议,或服务端 url 协议头为 empty 时,toInvokers 均会忽略服务提供方 url。必要的检测做完后,紧接着是合并 url,然后访问缓存,尝试获取与 url 对应的 invoker。如果缓存命中,直接将 Invoker 存入 newUrlInvokerMap 中即可。如果未命中,则需新建 Invoker。</p><p>toInvokers 方法返回的是 &lt;url, Invoker> 映射关系表,接下来还要对这个结果进行进一步处理,得到方法名到 Invoker 列表的映射关系。这个过程由 toMethodInvokers 方法完成,如下:</p><div class=highlight><pre tabindex=0 style=color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=display:flex><span><span style=color:#268bd2>private</span> Map<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;&gt;</span> <span style=color:#268bd2>toMethodInvokers</span><span style=color:#719e07>(</span>Map<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> invokersMap<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 方法名 -&gt; Invoker 列表
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> Map<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;&gt;</span> newMethodInvokerMap <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> HashMap<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;&gt;();</span>
</span></span><span style=display:flex><span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> invokersList <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> ArrayList<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;();</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>invokersMap <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>&amp;&amp;</span> invokersMap<span style=color:#719e07>.</span>size<span style=color:#719e07>()</span> <span style=color:#719e07>&gt;</span> 0<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>for</span> <span style=color:#719e07>(</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;</span> invoker <span style=color:#719e07>:</span> invokersMap<span style=color:#719e07>.</span>values<span style=color:#719e07>())</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 获取 methods 参数
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> String parameter <span style=color:#719e07>=</span> invoker<span style=color:#719e07>.</span>getUrl<span style=color:#719e07>().</span>getParameter<span style=color:#719e07>(</span>Constants<span style=color:#719e07>.</span>METHODS_KEY<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>parameter <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>&amp;&amp;</span> parameter<span style=color:#719e07>.</span>length<span style=color:#719e07>()</span> <span style=color:#719e07>&gt;</span> 0<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 切分 methods 参数值,得到方法名数组
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> String<span style=color:#719e07>[]</span> methods <span style=color:#719e07>=</span> Constants<span style=color:#719e07>.</span>COMMA_SPLIT_PATTERN<span style=color:#719e07>.</span>split<span style=color:#719e07>(</span>parameter<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>methods <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>&amp;&amp;</span> methods<span style=color:#719e07>.</span>length <span style=color:#719e07>&gt;</span> 0<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>for</span> <span style=color:#719e07>(</span>String method <span style=color:#719e07>:</span> methods<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 方法名不为 *
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>method <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>&amp;&amp;</span> method<span style=color:#719e07>.</span>length<span style=color:#719e07>()</span> <span style=color:#719e07>&gt;</span> 0
</span></span><span style=display:flex><span> <span style=color:#719e07>&amp;&amp;</span> <span style=color:#719e07>!</span>Constants<span style=color:#719e07>.</span>ANY_VALUE<span style=color:#719e07>.</span>equals<span style=color:#719e07>(</span>method<span style=color:#719e07>))</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 根据方法名获取 Invoker 列表
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> methodInvokers <span style=color:#719e07>=</span> newMethodInvokerMap<span style=color:#719e07>.</span>get<span style=color:#719e07>(</span>method<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>methodInvokers <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span><span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> methodInvokers <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> ArrayList<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;();</span>
</span></span><span style=display:flex><span> newMethodInvokerMap<span style=color:#719e07>.</span>put<span style=color:#719e07>(</span>method<span style=color:#719e07>,</span> methodInvokers<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 存储 Invoker 到列表中
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> methodInvokers<span style=color:#719e07>.</span>add<span style=color:#719e07>(</span>invoker<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> invokersList<span style=color:#719e07>.</span>add<span style=color:#719e07>(</span>invoker<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 进行服务级别路由,参考 pull request #749
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> newInvokersList <span style=color:#719e07>=</span> route<span style=color:#719e07>(</span>invokersList<span style=color:#719e07>,</span> <span style=color:#cb4b16>null</span><span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 存储 &lt;*, newInvokersList&gt; 映射关系
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> newMethodInvokerMap<span style=color:#719e07>.</span>put<span style=color:#719e07>(</span>Constants<span style=color:#719e07>.</span>ANY_VALUE<span style=color:#719e07>,</span> newInvokersList<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>serviceMethods <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>&amp;&amp;</span> serviceMethods<span style=color:#719e07>.</span>length <span style=color:#719e07>&gt;</span> 0<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>for</span> <span style=color:#719e07>(</span>String method <span style=color:#719e07>:</span> serviceMethods<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> methodInvokers <span style=color:#719e07>=</span> newMethodInvokerMap<span style=color:#719e07>.</span>get<span style=color:#719e07>(</span>method<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>methodInvokers <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>||</span> methodInvokers<span style=color:#719e07>.</span>isEmpty<span style=color:#719e07>())</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> methodInvokers <span style=color:#719e07>=</span> newInvokersList<span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 进行方法级别路由
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> newMethodInvokerMap<span style=color:#719e07>.</span>put<span style=color:#719e07>(</span>method<span style=color:#719e07>,</span> route<span style=color:#719e07>(</span>methodInvokers<span style=color:#719e07>,</span> method<span style=color:#719e07>));</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 排序,转成不可变列表
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>for</span> <span style=color:#719e07>(</span>String method <span style=color:#719e07>:</span> <span style=color:#719e07>new</span> HashSet<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>&gt;(</span>newMethodInvokerMap<span style=color:#719e07>.</span>keySet<span style=color:#719e07>()))</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> methodInvokers <span style=color:#719e07>=</span> newMethodInvokerMap<span style=color:#719e07>.</span>get<span style=color:#719e07>(</span>method<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> Collections<span style=color:#719e07>.</span>sort<span style=color:#719e07>(</span>methodInvokers<span style=color:#719e07>,</span> InvokerComparator<span style=color:#719e07>.</span>getComparator<span style=color:#719e07>());</span>
</span></span><span style=display:flex><span> newMethodInvokerMap<span style=color:#719e07>.</span>put<span style=color:#719e07>(</span>method<span style=color:#719e07>,</span> Collections<span style=color:#719e07>.</span>unmodifiableList<span style=color:#719e07>(</span>methodInvokers<span style=color:#719e07>));</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>return</span> Collections<span style=color:#719e07>.</span>unmodifiableMap<span style=color:#719e07>(</span>newMethodInvokerMap<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span><span style=color:#719e07>}</span>
</span></span></code></pre></div><p>上面方法主要做了三件事情, 第一是对入参进行遍历,然后从 Invoker 的 url 成员变量中获取 methods 参数,并切分成数组。随后以方法名为键,Invoker 列表为值,将映射关系存储到 newMethodInvokerMap 中。第二是分别基于类和方法对 Invoker 列表进行路由操作。第三是对 Invoker 列表进行排序,并转成不可变列表。关于 toMethodInvokers 方法就先分析到这,我们继续向下分析,这次要分析的多组服务的合并逻辑。</p><div class=highlight><pre tabindex=0 style=color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=display:flex><span><span style=color:#268bd2>private</span> Map<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;&gt;</span> <span style=color:#268bd2>toMergeMethodInvokerMap</span><span style=color:#719e07>(</span>Map<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;&gt;</span> methodMap<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> Map<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;&gt;</span> result <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> HashMap<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;&gt;();</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 遍历入参
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>for</span> <span style=color:#719e07>(</span>Map<span style=color:#719e07>.</span>Entry<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;&gt;</span> entry <span style=color:#719e07>:</span> methodMap<span style=color:#719e07>.</span>entrySet<span style=color:#719e07>())</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> String method <span style=color:#719e07>=</span> entry<span style=color:#719e07>.</span>getKey<span style=color:#719e07>();</span>
</span></span><span style=display:flex><span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> invokers <span style=color:#719e07>=</span> entry<span style=color:#719e07>.</span>getValue<span style=color:#719e07>();</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// group -&gt; Invoker 列表
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> Map<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;&gt;</span> groupMap <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> HashMap<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;&gt;();</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 遍历 Invoker 列表
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>for</span> <span style=color:#719e07>(</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;</span> invoker <span style=color:#719e07>:</span> invokers<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 获取分组配置
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> String group <span style=color:#719e07>=</span> invoker<span style=color:#719e07>.</span>getUrl<span style=color:#719e07>().</span>getParameter<span style=color:#719e07>(</span>Constants<span style=color:#719e07>.</span>GROUP_KEY<span style=color:#719e07>,</span> <span style=color:#2aa198>&#34;&#34;</span><span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> groupInvokers <span style=color:#719e07>=</span> groupMap<span style=color:#719e07>.</span>get<span style=color:#719e07>(</span>group<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>groupInvokers <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span><span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> groupInvokers <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> ArrayList<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;();</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 缓存 &lt;group, List&lt;Invoker&gt;&gt; 到 groupMap 中
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> groupMap<span style=color:#719e07>.</span>put<span style=color:#719e07>(</span>group<span style=color:#719e07>,</span> groupInvokers<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 存储 invoker 到 groupInvokers
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> groupInvokers<span style=color:#719e07>.</span>add<span style=color:#719e07>(</span>invoker<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>groupMap<span style=color:#719e07>.</span>size<span style=color:#719e07>()</span> <span style=color:#719e07>==</span> 1<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 如果 groupMap 中仅包含一组键值对,此时直接取出该键值对的值即可
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> result<span style=color:#719e07>.</span>put<span style=color:#719e07>(</span>method<span style=color:#719e07>,</span> groupMap<span style=color:#719e07>.</span>values<span style=color:#719e07>().</span>iterator<span style=color:#719e07>().</span>next<span style=color:#719e07>());</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// groupMap.size() &gt; 1 成立,表示 groupMap 中包含多组键值对,比如:
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#586e75>// {
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#586e75>// &#34;dubbo&#34;: [invoker1, invoker2, invoker3, ...],
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#586e75>// &#34;hello&#34;: [invoker4, invoker5, invoker6, ...]
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#586e75>// }
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>}</span> <span style=color:#719e07>else</span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>groupMap<span style=color:#719e07>.</span>size<span style=color:#719e07>()</span> <span style=color:#719e07>&gt;</span> 1<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> groupInvokers <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> ArrayList<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;();</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>for</span> <span style=color:#719e07>(</span>List<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> groupList <span style=color:#719e07>:</span> groupMap<span style=color:#719e07>.</span>values<span style=color:#719e07>())</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 通过集群类合并每个分组对应的 Invoker 列表
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> groupInvokers<span style=color:#719e07>.</span>add<span style=color:#719e07>(</span>cluster<span style=color:#719e07>.</span>join<span style=color:#719e07>(</span><span style=color:#719e07>new</span> StaticDirectory<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;(</span>groupList<span style=color:#719e07>)));</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 缓存结果
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> result<span style=color:#719e07>.</span>put<span style=color:#719e07>(</span>method<span style=color:#719e07>,</span> groupInvokers<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span> <span style=color:#719e07>else</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> result<span style=color:#719e07>.</span>put<span style=color:#719e07>(</span>method<span style=color:#719e07>,</span> invokers<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>return</span> result<span style=color:#719e07>;</span>
</span></span><span style=display:flex><span><span style=color:#719e07>}</span>
</span></span></code></pre></div><p>上面方法首先是生成 group 到 Invoker 列表的映射关系表,若关系表中的映射关系数量大于1,表示有多组服务。此时通过集群类合并每组 Invoker,并将合并结果存储到 groupInvokers 中。之后将方法名与 groupInvokers 存到到 result 中,并返回,整个逻辑结束。</p><p>接下来我们再来看一下 Invoker 列表刷新逻辑的最后一个动作 — 删除无用 Invoker。如下:</p><div class=highlight><pre tabindex=0 style=color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=display:flex><span><span style=color:#268bd2>private</span> <span style=color:#dc322f>void</span> <span style=color:#268bd2>destroyUnusedInvokers</span><span style=color:#719e07>(</span>Map<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> oldUrlInvokerMap<span style=color:#719e07>,</span> Map<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> newUrlInvokerMap<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>newUrlInvokerMap <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>||</span> newUrlInvokerMap<span style=color:#719e07>.</span>size<span style=color:#719e07>()</span> <span style=color:#719e07>==</span> 0<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> destroyAllInvokers<span style=color:#719e07>();</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>return</span><span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> List<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>&gt;</span> deleted <span style=color:#719e07>=</span> <span style=color:#cb4b16>null</span><span style=color:#719e07>;</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>oldUrlInvokerMap <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span><span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 获取新生成的 Invoker 列表
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> Collection<span style=color:#719e07>&lt;</span>Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> newInvokers <span style=color:#719e07>=</span> newUrlInvokerMap<span style=color:#719e07>.</span>values<span style=color:#719e07>();</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 遍历老的 &lt;url, Invoker&gt; 映射表
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>for</span> <span style=color:#719e07>(</span>Map<span style=color:#719e07>.</span>Entry<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>,</span> Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;&gt;</span> entry <span style=color:#719e07>:</span> oldUrlInvokerMap<span style=color:#719e07>.</span>entrySet<span style=color:#719e07>())</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 检测 newInvokers 中是否包含老的 Invoker
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>if</span> <span style=color:#719e07>(!</span>newInvokers<span style=color:#719e07>.</span>contains<span style=color:#719e07>(</span>entry<span style=color:#719e07>.</span>getValue<span style=color:#719e07>()))</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>deleted <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span><span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> deleted <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> ArrayList<span style=color:#719e07>&lt;</span>String<span style=color:#719e07>&gt;();</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 若不包含,则将老的 Invoker 对应的 url 存入 deleted 列表中
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> deleted<span style=color:#719e07>.</span>add<span style=color:#719e07>(</span>entry<span style=color:#719e07>.</span>getKey<span style=color:#719e07>());</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>deleted <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span><span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 遍历 deleted 集合,并到老的 &lt;url, Invoker&gt; 映射关系表查出 Invoker,销毁之
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> <span style=color:#719e07>for</span> <span style=color:#719e07>(</span>String url <span style=color:#719e07>:</span> deleted<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>url <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span><span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 从 oldUrlInvokerMap 中移除 url 对应的 Invoker
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;</span> invoker <span style=color:#719e07>=</span> oldUrlInvokerMap<span style=color:#719e07>.</span>remove<span style=color:#719e07>(</span>url<span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> <span style=color:#719e07>(</span>invoker <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span><span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>try</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 销毁 Invoker
</span></span></span><span style=display:flex><span><span style=color:#586e75></span> invoker<span style=color:#719e07>.</span>destroy<span style=color:#719e07>();</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span> <span style=color:#719e07>catch</span> <span style=color:#719e07>(</span>Exception e<span style=color:#719e07>)</span> <span style=color:#719e07>{</span>
</span></span><span style=display:flex><span> logger<span style=color:#719e07>.</span>warn<span style=color:#719e07>(</span><span style=color:#2aa198>&#34;destroy invoker...&#34;</span><span style=color:#719e07>);</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>}</span>
</span></span><span style=display:flex><span><span style=color:#719e07>}</span>
</span></span></code></pre></div><p>destroyUnusedInvokers 方法的主要逻辑是通过 newUrlInvokerMap 找出待删除 Invoker 对应的 url,并将 url 存入到 deleted 列表中。然后再遍历 deleted 列表,并从 oldUrlInvokerMap 中移除相应的 Invoker,销毁之。整个逻辑大致如此,不是很难理解。</p><p>到此关于 Invoker 列表的刷新逻辑就分析了,这里对整个过程进行简单总结。如下:</p><ol><li>检测入参是否仅包含一个 url,且 url 协议头为 empty</li><li>若第一步检测结果为 true,表示禁用所有服务,此时销毁所有的 Invoker</li><li>若第一步检测结果为 false,此时将入参转为 Invoker 列表</li><li>对上一步逻辑生成的结果进行进一步处理,得到方法名到 Invoker 的映射关系表</li><li>合并多组 Invoker</li><li>销毁无用 Invoker</li></ol><p>Invoker 的刷新逻辑还是比较复杂的,大家在看的过程中多写点 demo 进行调试,以加深理解。</p><h2 id=4-总结>4. 总结</h2><p>本篇文章对 Dubbo 服务目录进行了较为详细的分析,篇幅主要集中在 RegistryDirectory 的源码分析上。从代码量上可以看出,想让本地服务目录和注册中心保持一致还是需要做很多事情的,并不简单。服务目录是 Dubbo 集群容错的一部分,也是比较基础的部分,所以大家应尽量搞懂。</p><div id=pre-footer><h2>反馈</h2><p class=feedback--prompt>此页是否对您有帮助?</p><button class="btn btn-primary mb-4 feedback--yes"></button>
<button class="btn btn-primary mb-4 feedback--no"></button></div><script>const yes=document.querySelector(".feedback--yes"),no=document.querySelector(".feedback--no");document.querySelectorAll(".feedback--link").forEach(e=>{e.href=e.href+window.location.pathname});const sendFeedback=e=>{gtag||console.log("!gtag"),gtag("event","click",{event_category:"Helpful",event_label:window.location.pathname,value:e})},disableButtons=()=>{yes.disabled=!0,yes.classList.add("feedback--button__disabled"),no.disabled=!0,no.classList.add("feedback--button__disabled")};yes.addEventListener("click",()=>{sendFeedback(1),disableButtons(),document.querySelector(".feedback--response").classList.remove("feedback--response__hidden")}),no.addEventListener("click",()=>{sendFeedback(0),disableButtons(),document.querySelector(".feedback--response").classList.remove("feedback--response__hidden")})</script><br><div class="text-muted mt-5 pt-3 border-top">最后修改 March 1, 2023: <a href=https://github.com/apache/dubbo-website/commit/f2070b3fdd1b7b200db0f8f2a50fb09d7c398a64>Add /zh/ docs aliases (#2336) (f2070b3fdd)</a></div></div></main><div class="d-none d-xl-block col-xl-2 td-toc d-print-none"><div class="td-page-meta ml-2 pb-1 pt-2 mb-0"><a href=https://github.com/apache/dubbo-website/edit/master/content/zh-cn/docsv2.7/dev/source/directory.md target=_blank><i class="fa fa-edit fa-fw"></i> 编辑此页</a>
<a href="https://github.com/apache/dubbo-website/new/master/content/zh-cn/docsv2.7/dev/source/directory.md?filename=change-me.md&amp;value=---%0Atitle%3A+%22Long+Page+Title%22%0AlinkTitle%3A+%22Short+Nav+Title%22%0Aweight%3A+100%0Adescription%3A+%3E-%0A+++++Page+description+for+heading+and+indexes.%0A---%0A%0A%23%23+Heading%0A%0AEdit+this+template+to+create+your+new+page.%0A%0A%2A+Give+it+a+good+name%2C+ending+in+%60.md%60+-+e.g.+%60getting-started.md%60%0A%2A+Edit+the+%22front+matter%22+section+at+the+top+of+the+page+%28weight+controls+how+its+ordered+amongst+other+pages+in+the+same+directory%3B+lowest+number+first%29.%0A%2A+Add+a+good+commit+message+at+the+bottom+of+the+page+%28%3C80+characters%3B+use+the+extended+description+field+for+more+detail%29.%0A%2A+Create+a+new+branch+so+you+can+preview+your+new+file+and+request+a+review+via+Pull+Request.%0A" target=_blank><i class="fa fa-edit fa-fw"></i> 创建子页面</a>
<a href="https://github.com/apache/dubbo-website/issues/new?title=%e6%9c%8d%e5%8a%a1%e7%9b%ae%e5%bd%95" target=_blank><i class="fab fa-github fa-fw"></i> 登记问题</a>
<a href=https://github.com/apache/dubbo/issues/new target=_blank><i class="fas fa-tasks fa-fw"></i> 提交项目问题</a></div><nav id=TableOfContents><ul><li><a href=#1-简介>1. 简介</a></li><li><a href=#2-继承体系>2. 继承体系</a></li><li><a href=#3-源码分析>3. 源码分析</a><ul><li><a href=#31-staticdirectory>3.1 StaticDirectory</a></li><li><a href=#32-registrydirectory>3.2 RegistryDirectory</a></li></ul></li><li><a href=#4-总结>4. 总结</a></li></ul></nav></div></div></div></div><footer class="bg-dark py-5 row d-print-none footer-margin-0"><div class="container-fluid mx-sm-5"><div class=row><div class="col-6 col-sm-4 text-xs-center order-sm-2"><ul class="list-inline mb-0"><li class="list-inline-item mx-2 h3" data-toggle=tooltip data-placement=top title="Dubbo mailing list archive" aria-label="Dubbo mailing list archive"><a class=text-white target=_blank rel="noopener noreferrer" href=https://lists.apache.org/list.html?dev@dubbo.apache.org><i class="fa fa-envelope"></i></a></li></ul></div><div class="col-6 col-sm-4 text-right text-xs-center order-sm-3"><ul class="list-inline mb-0"><li class="list-inline-item mx-2 h3" data-toggle=tooltip data-placement=top title=GitHub aria-label=GitHub><a class=text-white target=_blank rel="noopener noreferrer" href=https://github.com/apache/dubbo><i class="fab fa-github"></i></a></li><li class="list-inline-item mx-2 h3" data-toggle=tooltip data-placement=top title="Subscribe to mailing list" aria-label="Subscribe to mailing list"><a class=text-white target=_blank rel="noopener noreferrer" href=mailto:dev-subscribe@dubbo.apache.org><i class="fa fa-envelope"></i></a></li></ul></div><div class="col-12 col-sm-4 text-center py-2 order-sm-2"><small class=text-white>&copy; 2023 The Apache Software Foundation. Apache and the Apache feather logo are trademarks of The Apache Software Foundation. 保留所有权利</small></div></div></div></footer><div class="row pt-2 pb-2 footer-margin-0"><div class="container-fluid mx-sm-5"><div class=text-center id=my-footer><img style=float:left alt=apache_logo src=/imgs/apache_logo.png><ul><li><a href=https://www.apache.org>Foundation</a></li><li><a href=https://www.apache.org/licenses/>License</a></li><li><a href=https://www.apache.org/security/>Security</a></li><li><a href=https://www.apache.org/events/current-event>Events</a></li><li><a href=https://www.apache.org/foundation/sponsorship.html>Sponsorship</a></li><li><a href=https://privacy.apache.org/policies/privacy-policy-public.html>Privacy</a></li><li><a href=https://www.apache.org/foundation/thanks.html>Thanks</a></li></ul></div></div></div><script src=/js/popper.min.js integrity=sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49 crossorigin=anonymous></script>
<script src=/js/bootstrap.min.js integrity=sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy crossorigin=anonymous></script>
<script src=/js/main.min.a4534a01940be8c082c4c0e6777b61df9884f202b61c9519352adb6d1039d5aa.js integrity="sha256-pFNKAZQL6MCCxMDmd3th35iE8gK2HJUZNSrbbRA51ao=" crossorigin=anonymous></script>
<script src=https://cdn.jsdelivr.net/npm/@docsearch/js@3></script>
<script>docsearch({appId:"L5F4T9F0I1",apiKey:"364ae307e1da9d02b2335675e9db1eb1",indexName:"apache_dubbo",container:"#docsearch",debug:!1}),docsearch({appId:"L5F4T9F0I1",apiKey:"364ae307e1da9d02b2335675e9db1eb1",indexName:"apache_dubbo",container:"#docsearch_zh_home",debug:!1})</script></body></html>