blob: 33afffea12fc19977d0d2868eb9c8fb382087b8b [file] [log] [blame]
<!doctype html><html lang=zh-cn class=no-js><head><meta name=ROBOTS content="INDEX, FOLLOW"><link rel=canonical href=https://cn.dubbo.apache.org/zh-cn/docsv2.7/dev/source/adaptive-extension/><script>var _hmt=_hmt||[];(function(){var e,t=document.createElement("script");t.src="https://hm.baidu.com/hm.js?3b78f49ba47181e4d998a66b689446e9",e=document.getElementsByTagName("script")[0],e.parentNode.insertBefore(t,e)})()</script><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta http-equiv=Content-Security-Policy content="frame-src *"><meta name=generator content="Hugo 0.122.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>SPI 自适应拓展 | Apache Dubbo</title><meta property="og:title" content="SPI 自适应拓展">
<meta property="og:description" content="本文介绍了自适应拓展的原理和实现细节"><meta property="og:type" content="article"><meta property="og:url" content="https://cn.dubbo.apache.org/zh-cn/docsv2.7/dev/source/adaptive-extension/"><meta property="article:section" content="docsv2.7"><meta property="article:modified_time" content="2023-03-01T09:48:32+08:00"><meta itemprop=name content="SPI 自适应拓展"><meta itemprop=description content="本文介绍了自适应拓展的原理和实现细节"><meta itemprop=dateModified content="2023-03-01T09:48:32+08:00"><meta itemprop=wordCount content="2234"><meta itemprop=keywords content><meta name=twitter:card content="summary"><meta name=twitter:title content="SPI 自适应拓展"><meta name=twitter:description content="本文介绍了自适应拓展的原理和实现细节"><script async src="https://www.googletagmanager.com/gtag/js?id=G-NM6FFMT51J"></script><script>var doNotTrack=!1;if(!doNotTrack){window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag("js",new Date),gtag("config","G-NM6FFMT51J",{anonymize_ip:!1})}</script><link rel=preload href=/scss/main.min.f77e221bcdbe0cadb996060fe82063c747b60c229a1f8bbf0ee529adbadd84fa.css as=style><link href=/scss/main.min.f77e221bcdbe0cadb996060fe82063c747b60c229a1f8bbf0ee529adbadd84fa.css rel=stylesheet integrity><script src=/js/jquery-3.5.1.min.js integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin=anonymous></script><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://cn.dubbo.apache.org/zh-cn/docsv2.7/dev/source/adaptive-extension/"><meta property="og:title" content="SPI 自适应拓展"><meta name=twitter:title content="SPI 自适应拓展"><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 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></li></ul></div></nav><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-cndocsv27devsourceadaptive-extension").addClass("active"),$("#td-section-nav #m-zh-cndocsv27devsourceadaptive-extension-li span").addClass("td-sidebar-nav-active-item"),$("#td-section-nav #m-zh-cndocsv27devsourceadaptive-extension").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-cndocsv27devsourceadaptive-extension-li").siblings("li").addClass("show"),$("#td-section-nav #m-zh-cndocsv27devsourceadaptive-extension-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"><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://cn.dubbo.apache.org/zh-cn/docsv2.7/>文档 2.x</a></li><li class=breadcrumb-item><a href=https://cn.dubbo.apache.org/zh-cn/docsv2.7/dev/>开发指南</a></li><li class=breadcrumb-item><a href=https://cn.dubbo.apache.org/zh-cn/docsv2.7/dev/source/>源代码</a></li><li class="breadcrumb-item active" aria-current=page><a href=https://cn.dubbo.apache.org/zh-cn/docsv2.7/dev/source/adaptive-extension/ aria-disabled=true class="btn-link disabled">SPI 自适应拓展</a></li></ol></nav><div class=td-content><h1>SPI 自适应拓展</h1><div class=lead>本文介绍了自适应拓展的原理和实现细节</div><header class=article-meta></header><h2 id=1原理>1.原理</h2><p>在 Dubbo 中,很多拓展都是通过 SPI 机制进行加载的,比如 Protocol、Cluster、LoadBalance 等。有时,有些拓展并不想在框架启动阶段被加载,而是希望在拓展方法被调用时,根据运行时参数进行加载。这听起来有些矛盾。拓展未被加载,那么拓展方法就无法被调用(静态方法除外)。拓展方法未被调用,拓展就无法被加载。对于这个矛盾的问题,Dubbo 通过自适应拓展机制很好的解决了。自适应拓展机制的实现逻辑比较复杂,首先 Dubbo 会为拓展接口生成具有代理功能的代码。然后通过 javassist 或 jdk 编译这段代码,得到 Class 类。最后再通过反射创建代理类,整个过程比较复杂。为了让大家对自适应拓展有一个感性的认识,下面我们通过一个示例进行演示。这是一个与汽车相关的例子,我们有一个车轮制造厂接口 WheelMaker:</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>interface</span> <span style=color:#268bd2>WheelMaker</span> {
</span></span><span style=display:flex><span> Wheel <span style=color:#268bd2>makeWheel</span>(URL url);
</span></span><span style=display:flex><span>}
</span></span></code></pre></div><p>WheelMaker 接口的自适应实现类如下:</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>AdaptiveWheelMaker</span> <span style=color:#268bd2>implements</span> WheelMaker {
</span></span><span style=display:flex><span> <span style=color:#268bd2>public</span> Wheel <span style=color:#268bd2>makeWheel</span>(URL url) {
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (url <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span>) {
</span></span><span style=display:flex><span> <span style=color:#719e07>throw</span> <span style=color:#719e07>new</span> IllegalArgumentException(<span style=color:#2aa198>&#34;url == null&#34;</span>);
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 1.从 URL 中获取 WheelMaker 名称</span>
</span></span><span style=display:flex><span> String wheelMakerName <span style=color:#719e07>=</span> url.getParameter(<span style=color:#2aa198>&#34;Wheel.maker&#34;</span>);
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (wheelMakerName <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span>) {
</span></span><span style=display:flex><span> <span style=color:#719e07>throw</span> <span style=color:#719e07>new</span> IllegalArgumentException(<span style=color:#2aa198>&#34;wheelMakerName == null&#34;</span>);
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 2.通过 SPI 加载具体的 WheelMaker</span>
</span></span><span style=display:flex><span> WheelMaker wheelMaker <span style=color:#719e07>=</span> ExtensionLoader
</span></span><span style=display:flex><span> .getExtensionLoader(WheelMaker.class).getExtension(wheelMakerName);
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 3.调用目标方法</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>return</span> wheelMaker.makeWheel(url);
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span>}
</span></span></code></pre></div><p>AdaptiveWheelMaker 是一个代理类,与传统的代理逻辑不同,AdaptiveWheelMaker 所代理的对象是在 makeWheel 方法中通过 SPI 加载得到的。makeWheel 方法主要做了三件事情:</p><ol><li>从 URL 中获取 WheelMaker 名称</li><li>通过 SPI 加载具体的 WheelMaker 实现类</li><li>调用目标方法</li></ol><p>接下来,我们来看看汽车制造厂 CarMaker 接口与其实现类。</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>interface</span> <span style=color:#268bd2>CarMaker</span> {
</span></span><span style=display:flex><span> Car <span style=color:#268bd2>makeCar</span>(URL url);
</span></span><span style=display:flex><span>}
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#268bd2>public</span> <span style=color:#268bd2>class</span> <span style=color:#268bd2>RaceCarMaker</span> <span style=color:#268bd2>implements</span> CarMaker {
</span></span><span style=display:flex><span> WheelMaker wheelMaker;
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 通过 setter 注入 AdaptiveWheelMaker</span>
</span></span><span style=display:flex><span> <span style=color:#268bd2>public</span> <span style=color:#268bd2>setWheelMaker</span>(WheelMaker wheelMaker) {
</span></span><span style=display:flex><span> <span style=color:#719e07>this</span>.wheelMaker <span style=color:#719e07>=</span> wheelMaker;
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#268bd2>public</span> Car <span style=color:#268bd2>makeCar</span>(URL url) {
</span></span><span style=display:flex><span> Wheel wheel <span style=color:#719e07>=</span> wheelMaker.makeWheel(url);
</span></span><span style=display:flex><span> <span style=color:#719e07>return</span> <span style=color:#719e07>new</span> RaceCar(wheel, ...);
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span>}
</span></span></code></pre></div><p>RaceCarMaker 持有一个 WheelMaker 类型的成员变量,在程序启动时,我们可以将 AdaptiveWheelMaker 通过 setter 方法注入到 RaceCarMaker 中。在运行时,假设有这样一个 url 参数传入:</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-fallback data-lang=fallback><span style=display:flex><span>dubbo://192.168.0.101:20880/XxxService?wheel.maker=MichelinWheelMaker
</span></span></code></pre></div><p>RaceCarMaker 的 makeCar 方法将上面的 url 作为参数传给 AdaptiveWheelMaker 的 makeWheel 方法,makeWheel 方法从 url 中提取 wheel.maker 参数,得到 MichelinWheelMaker。之后再通过 SPI 加载配置名为 MichelinWheelMaker 的实现类,得到具体的 WheelMaker 实例。</p><p>上面的示例展示了自适应拓展类的核心实现 &mdash;- 在拓展接口的方法被调用时,通过 SPI 加载具体的拓展实现类,并调用拓展对象的同名方法。接下来,我们深入到源码中,探索自适应拓展类生成的过程。</p><h2 id=2源码分析>2.源码分析</h2><p>在对自适应拓展生成过程进行深入分析之前,我们先来看一下与自适应拓展息息相关的一个注解,即 Adaptive 注解。该注解的定义如下:</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>@Documented</span>
</span></span><span style=display:flex><span><span style=color:#268bd2>@Retention</span>(RetentionPolicy.RUNTIME)
</span></span><span style=display:flex><span><span style=color:#268bd2>@Target</span>({ElementType.TYPE, ElementType.METHOD})
</span></span><span style=display:flex><span><span style=color:#268bd2>public</span> <span style=color:#268bd2>@interface</span> Adaptive {
</span></span><span style=display:flex><span> String<span style=color:#719e07>[]</span> <span style=color:#268bd2>value</span>() <span style=color:#719e07>default</span> {};
</span></span><span style=display:flex><span>}
</span></span></code></pre></div><p>从上面的代码中可知,Adaptive 可注解在类或方法上。当 Adaptive 注解在类上时,Dubbo 不会为该类生成代理类。注解在方法(接口方法)上时,Dubbo 则会为该方法生成代理逻辑。Adaptive 注解在类上的情况很少,在 Dubbo 中,仅有两个类被 Adaptive 注解了,分别是 AdaptiveCompiler 和 AdaptiveExtensionFactory。此种情况,表示拓展的加载逻辑由人工编码完成。更多时候,Adaptive 是注解在接口方法上的,表示拓展的加载逻辑需由框架自动生成。Adaptive 注解的地方不同,相应的处理逻辑也是不同的。注解在类上时,处理逻辑比较简单,本文就不分析了。注解在接口方法上时,处理逻辑较为复杂,本章将会重点分析此块逻辑。</p><h3 id=21-获取自适应拓展>2.1 获取自适应拓展</h3><p>getAdaptiveExtension 方法是获取自适应拓展的入口方法,因此下面我们从这个方法进行分析。相关代码如下:</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> T <span style=color:#268bd2>getAdaptiveExtension</span>() {
</span></span><span style=display:flex><span> <span style=color:#586e75>// 从缓存中获取自适应拓展</span>
</span></span><span style=display:flex><span> Object instance <span style=color:#719e07>=</span> cachedAdaptiveInstance.get();
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (instance <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span>) { <span style=color:#586e75>// 缓存未命中</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (createAdaptiveInstanceError <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span>) {
</span></span><span style=display:flex><span> <span style=color:#268bd2>synchronized</span> (cachedAdaptiveInstance) {
</span></span><span style=display:flex><span> instance <span style=color:#719e07>=</span> cachedAdaptiveInstance.get();
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (instance <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span>) {
</span></span><span style=display:flex><span> <span style=color:#719e07>try</span> {
</span></span><span style=display:flex><span> <span style=color:#586e75>// 创建自适应拓展</span>
</span></span><span style=display:flex><span> instance <span style=color:#719e07>=</span> createAdaptiveExtension();
</span></span><span style=display:flex><span> <span style=color:#586e75>// 设置自适应拓展到缓存中</span>
</span></span><span style=display:flex><span> cachedAdaptiveInstance.set(instance);
</span></span><span style=display:flex><span> } <span style=color:#719e07>catch</span> (Throwable t) {
</span></span><span style=display:flex><span> createAdaptiveInstanceError <span style=color:#719e07>=</span> t;
</span></span><span style=display:flex><span> <span style=color:#719e07>throw</span> <span style=color:#719e07>new</span> IllegalStateException(<span style=color:#2aa198>&#34;fail to create adaptive instance: ...&#34;</span>);
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> } <span style=color:#719e07>else</span> {
</span></span><span style=display:flex><span> <span style=color:#719e07>throw</span> <span style=color:#719e07>new</span> IllegalStateException(<span style=color:#2aa198>&#34;fail to create adaptive instance: ...&#34;</span>);
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#719e07>return</span> (T) instance;
</span></span><span style=display:flex><span>}
</span></span></code></pre></div><p>getAdaptiveExtension 方法首先会检查缓存,缓存未命中,则调用 createAdaptiveExtension 方法创建自适应拓展。下面,我们看一下 createAdaptiveExtension 方法的代码。</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> T <span style=color:#268bd2>createAdaptiveExtension</span>() {
</span></span><span style=display:flex><span> <span style=color:#719e07>try</span> {
</span></span><span style=display:flex><span> <span style=color:#586e75>// 获取自适应拓展类,并通过反射实例化</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>return</span> injectExtension((T) getAdaptiveExtensionClass().newInstance());
</span></span><span style=display:flex><span> } <span style=color:#719e07>catch</span> (Exception e) {
</span></span><span style=display:flex><span> <span style=color:#719e07>throw</span> <span style=color:#719e07>new</span> IllegalStateException(<span style=color:#2aa198>&#34;Can not create adaptive extension ...&#34;</span>);
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span>}
</span></span></code></pre></div><p>createAdaptiveExtension 方法的代码比较少,但却包含了三个逻辑,分别如下:</p><ol><li>调用 getAdaptiveExtensionClass 方法获取自适应拓展 Class 对象</li><li>通过反射进行实例化</li><li>调用 injectExtension 方法向拓展实例中注入依赖</li></ol><p>前两个逻辑比较好理解,第三个逻辑用于向自适应拓展对象中注入依赖。这个逻辑看似多余,但有存在的必要,这里简单说明一下。前面说过,Dubbo 中有两种类型的自适应拓展,一种是手工编码的,一种是自动生成的。手工编码的自适应拓展中可能存在着一些依赖,而自动生成的 Adaptive 拓展则不会依赖其他类。这里调用 injectExtension 方法的目的是为手工编码的自适应拓展注入依赖,这一点需要大家注意一下。关于 injectExtension 方法,前文已经分析过了,这里不再赘述。接下来,分析 getAdaptiveExtensionClass 方法的逻辑。</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> Class<span style=color:#719e07>&lt;?&gt;</span> getAdaptiveExtensionClass() {
</span></span><span style=display:flex><span> <span style=color:#586e75>// 通过 SPI 获取所有的拓展类</span>
</span></span><span style=display:flex><span> getExtensionClasses();
</span></span><span style=display:flex><span> <span style=color:#586e75>// 检查缓存,若缓存不为空,则直接返回缓存</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (cachedAdaptiveClass <span style=color:#719e07>!=</span> <span style=color:#cb4b16>null</span>) {
</span></span><span style=display:flex><span> <span style=color:#719e07>return</span> cachedAdaptiveClass;
</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:#719e07>return</span> cachedAdaptiveClass <span style=color:#719e07>=</span> createAdaptiveExtensionClass();
</span></span><span style=display:flex><span>}
</span></span></code></pre></div><p>getAdaptiveExtensionClass 方法同样包含了三个逻辑,如下:</p><ol><li>调用 getExtensionClasses 获取所有的拓展类</li><li>检查缓存,若缓存不为空,则返回缓存</li><li>若缓存为空,则调用 createAdaptiveExtensionClass 创建自适应拓展类</li></ol><p>这三个逻辑看起来平淡无奇,似乎没有多讲的必要。但是这些平淡无奇的代码中隐藏了着一些细节,需要说明一下。首先从第一个逻辑说起,getExtensionClasses 这个方法用于获取某个接口的所有实现类。比如该方法可以获取 Protocol 接口的 DubboProtocol、HttpProtocol、InjvmProtocol 等实现类。在获取实现类的过程中,如果某个实现类被 Adaptive 注解修饰了,那么该类就会被赋值给 cachedAdaptiveClass 变量。此时,上面步骤中的第二步条件成立(缓存不为空),直接返回 cachedAdaptiveClass 即可。如果所有的实现类均未被 Adaptive 注解修饰,那么执行第三步逻辑,创建自适应拓展类。相关代码如下:</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> Class<span style=color:#719e07>&lt;?&gt;</span> createAdaptiveExtensionClass() {
</span></span><span style=display:flex><span> <span style=color:#586e75>// 构建自适应拓展代码</span>
</span></span><span style=display:flex><span> String code <span style=color:#719e07>=</span> createAdaptiveExtensionClassCode();
</span></span><span style=display:flex><span> ClassLoader classLoader <span style=color:#719e07>=</span> findClassLoader();
</span></span><span style=display:flex><span> <span style=color:#586e75>// 获取编译器实现类</span>
</span></span><span style=display:flex><span> com.alibaba.dubbo.common.compiler.Compiler compiler <span style=color:#719e07>=</span> ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
</span></span><span style=display:flex><span> <span style=color:#586e75>// 编译代码,生成 Class</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>return</span> compiler.compile(code, classLoader);
</span></span><span style=display:flex><span>}
</span></span></code></pre></div><p>createAdaptiveExtensionClass 方法用于生成自适应拓展类,该方法首先会生成自适应拓展类的源码,然后通过 Compiler 实例(Dubbo 默认使用 javassist 作为编译器)编译源码,得到代理类 Class 实例。接下来,我们把重点放在代理类代码生成的逻辑上,其他逻辑大家自行分析。</p><h3 id=22-自适应拓展类代码生成>2.2 自适应拓展类代码生成</h3><p>createAdaptiveExtensionClassCode 方法代码略多,约有两百行代码。因此本节将会对该方法的代码进行拆分分析,以帮助大家更好的理解代码逻辑。</p><h4 id=221-adaptive-注解检测>2.2.1 Adaptive 注解检测</h4><p>在生成代理类源码之前,createAdaptiveExtensionClassCode 方法首先会通过反射检测接口方法是否包含 Adaptive 注解。对于要生成自适应拓展的接口,Dubbo 要求该接口至少有一个方法被 Adaptive 注解修饰。若不满足此条件,就会抛出运行时异常。相关代码如下:</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:#586e75>// 通过反射获取所有的方法</span>
</span></span><span style=display:flex><span>Method<span style=color:#719e07>[]</span> methods <span style=color:#719e07>=</span> type.getMethods();
</span></span><span style=display:flex><span><span style=color:#dc322f>boolean</span> hasAdaptiveAnnotation <span style=color:#719e07>=</span> <span style=color:#cb4b16>false</span>;
</span></span><span style=display:flex><span><span style=color:#586e75>// 遍历方法列表</span>
</span></span><span style=display:flex><span><span style=color:#719e07>for</span> (Method m : methods) {
</span></span><span style=display:flex><span> <span style=color:#586e75>// 检测方法上是否有 Adaptive 注解</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (m.isAnnotationPresent(Adaptive.class)) {
</span></span><span style=display:flex><span> hasAdaptiveAnnotation <span style=color:#719e07>=</span> <span style=color:#cb4b16>true</span>;
</span></span><span style=display:flex><span> <span style=color:#719e07>break</span>;
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><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>hasAdaptiveAnnotation)
</span></span><span style=display:flex><span> <span style=color:#586e75>// 若所有的方法上均无 Adaptive 注解,则抛出异常</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>throw</span> <span style=color:#719e07>new</span> IllegalStateException(<span style=color:#2aa198>&#34;No adaptive method on extension ...&#34;</span>);
</span></span></code></pre></div><h4 id=222-生成类>2.2.2 生成类</h4><p>通过 Adaptive 注解检测后,即可开始生成代码。代码生成的顺序与 Java 文件内容顺序一致,首先会生成 package 语句,然后生成 import 语句,紧接着生成类名等代码。整个逻辑如下:</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:#586e75>// 生成 package 代码:package + type 所在包</span>
</span></span><span style=display:flex><span>codeBuilder.append(<span style=color:#2aa198>&#34;package &#34;</span>).append(type.getPackage().getName()).append(<span style=color:#2aa198>&#34;;&#34;</span>);
</span></span><span style=display:flex><span><span style=color:#586e75>// 生成 import 代码:import + ExtensionLoader 全限定名</span>
</span></span><span style=display:flex><span>codeBuilder.append(<span style=color:#2aa198>&#34;\nimport &#34;</span>).append(ExtensionLoader.class.getName()).append(<span style=color:#2aa198>&#34;;&#34;</span>);
</span></span><span style=display:flex><span><span style=color:#586e75>// 生成类代码:public class + type简单名称 + $Adaptive + implements + type全限定名 + {</span>
</span></span><span style=display:flex><span>codeBuilder.append(<span style=color:#2aa198>&#34;\npublic class &#34;</span>)
</span></span><span style=display:flex><span> .append(type.getSimpleName())
</span></span><span style=display:flex><span> .append(<span style=color:#2aa198>&#34;$Adaptive&#34;</span>)
</span></span><span style=display:flex><span> .append(<span style=color:#2aa198>&#34; implements &#34;</span>)
</span></span><span style=display:flex><span> .append(type.getCanonicalName())
</span></span><span style=display:flex><span> .append(<span style=color:#2aa198>&#34; {&#34;</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></span><span style=display:flex><span>codeBuilder.append(<span style=color:#2aa198>&#34;\n}&#34;</span>);
</span></span></code></pre></div><p>这里使用 ${&mldr;} 占位符代表其他代码的生成逻辑,该部分逻辑将在随后进行分析。上面代码不是很难理解,下面直接通过一个例子展示该段代码所生成的内容。以 Dubbo 的 Protocol 接口为例,生成的代码如下:</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:#719e07>package</span> com.alibaba.dubbo.rpc;
</span></span><span style=display:flex><span><span style=color:#719e07>import</span> com.alibaba.dubbo.common.extension.ExtensionLoader;
</span></span><span style=display:flex><span><span style=color:#268bd2>public</span> <span style=color:#268bd2>class</span> <span style=color:#268bd2>Protocol$Adaptive</span> <span style=color:#268bd2>implements</span> com.alibaba.dubbo.rpc.Protocol {
</span></span><span style=display:flex><span> <span style=color:#586e75>// 省略方法代码</span>
</span></span><span style=display:flex><span>}
</span></span></code></pre></div><h4 id=223-生成方法>2.2.3 生成方法</h4><p>一个方法可以被 Adaptive 注解修饰,也可以不被修饰。这里将未被 Adaptive 注解修饰的方法称为“无 Adaptive 注解方法”,下面我们先来看看此种方法的代码生成逻辑是怎样的。</p><h5 id=2231-无-adaptive-注解方法代码生成逻辑>2.2.3.1 无 Adaptive 注解方法代码生成逻辑</h5><p>对于接口方法,我们可以按照需求标注 Adaptive 注解。以 Protocol 接口为例,该接口的 destroy 和 getDefaultPort 未标注 Adaptive 注解,其他方法均标注了 Adaptive 注解。Dubbo 不会为没有标注 Adaptive 注解的方法生成代理逻辑,对于该种类型的方法,仅会生成一句抛出异常的代码。生成逻辑如下:</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:#719e07>for</span> (Method method : methods) {
</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></span><span style=display:flex><span> Adaptive adaptiveAnnotation <span style=color:#719e07>=</span> method.getAnnotation(Adaptive.class);
</span></span><span style=display:flex><span> StringBuilder code <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> StringBuilder(512);
</span></span><span style=display:flex><span> <span style=color:#586e75>// 如果方法上无 Adaptive 注解,则生成 throw new UnsupportedOperationException(...) 代码</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (adaptiveAnnotation <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span>) {
</span></span><span style=display:flex><span> <span style=color:#586e75>// 生成的代码格式如下:</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// throw new UnsupportedOperationException(</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// &#34;method &#34; + 方法签名 + of interface + 全限定接口名 + is not adaptive method!”)</span>
</span></span><span style=display:flex><span> code.append(<span style=color:#2aa198>&#34;throw new UnsupportedOperationException(\&#34;method &#34;</span>)
</span></span><span style=display:flex><span> .append(method.toString()).append(<span style=color:#2aa198>&#34; of interface &#34;</span>)
</span></span><span style=display:flex><span> .append(type.getName()).append(<span style=color:#2aa198>&#34; is not adaptive method!\&#34;);&#34;</span>);
</span></span><span style=display:flex><span> } <span style=color:#719e07>else</span> {
</span></span><span style=display:flex><span> <span style=color:#586e75>// 省略无关逻辑</span>
</span></span><span style=display:flex><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></span></code></pre></div><p>以 Protocol 接口的 destroy 方法为例,上面代码生成的内容如下:</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:#719e07>throw</span> <span style=color:#719e07>new</span> UnsupportedOperationException(
</span></span><span style=display:flex><span> <span style=color:#2aa198>&#34;method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!&#34;</span>);
</span></span></code></pre></div><h5 id=2232-获取-url-数据>2.2.3.2 获取 URL 数据</h5><p>前面说过方法代理逻辑会从 URL 中提取目标拓展的名称,因此代码生成逻辑的一个重要的任务是从方法的参数列表或者其他参数中获取 URL 数据。举例说明一下,我们要为 Protocol 接口的 refer 和 export 方法生成代理逻辑。在运行时,通过反射得到的方法定义大致如下:</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>Invoker <span style=color:#268bd2>refer</span>(Class<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;</span> arg0, URL arg1) <span style=color:#268bd2>throws</span> RpcException;
</span></span><span style=display:flex><span>Exporter <span style=color:#268bd2>export</span>(Invoker<span style=color:#719e07>&lt;</span>T<span style=color:#719e07>&gt;</span> arg0) <span style=color:#268bd2>throws</span> RpcException;
</span></span></code></pre></div><p>对于 refer 方法,通过遍历 refer 的参数列表即可获取 URL 数据,这个还比较简单。对于 export 方法,获取 URL 数据则要麻烦一些。export 参数列表中没有 URL 参数,因此需要从 Invoker 参数中获取 URL 数据。获取方式是调用 Invoker 中可返回 URL 的 getter 方法,比如 getUrl。如果 Invoker 中无相关 getter 方法,此时则会抛出异常。整个逻辑如下:</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:#719e07>for</span> (Method method : methods) {
</span></span><span style=display:flex><span> Class<span style=color:#719e07>&lt;?&gt;</span> rt <span style=color:#719e07>=</span> method.getReturnType();
</span></span><span style=display:flex><span> Class<span style=color:#719e07>&lt;?&gt;[]</span> pts <span style=color:#719e07>=</span> method.getParameterTypes();
</span></span><span style=display:flex><span> Class<span style=color:#719e07>&lt;?&gt;[]</span> ets <span style=color:#719e07>=</span> method.getExceptionTypes();
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> Adaptive adaptiveAnnotation <span style=color:#719e07>=</span> method.getAnnotation(Adaptive.class);
</span></span><span style=display:flex><span> StringBuilder code <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> StringBuilder(512);
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (adaptiveAnnotation <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span>) {
</span></span><span style=display:flex><span> <span style=color:#586e75>// ${无 Adaptive 注解方法代码生成逻辑}</span>
</span></span><span style=display:flex><span> } <span style=color:#719e07>else</span> {
</span></span><span style=display:flex><span> <span style=color:#dc322f>int</span> urlTypeIndex <span style=color:#719e07>=</span> <span style=color:#719e07>-</span>1;
</span></span><span style=display:flex><span> <span style=color:#586e75>// 遍历参数列表,确定 URL 参数位置</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>for</span> (<span style=color:#dc322f>int</span> i <span style=color:#719e07>=</span> 0; i <span style=color:#719e07>&lt;</span> pts.length; <span style=color:#719e07>++</span>i) {
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (pts<span style=color:#719e07>[</span>i<span style=color:#719e07>]</span>.equals(URL.class)) {
</span></span><span style=display:flex><span> urlTypeIndex <span style=color:#719e07>=</span> i;
</span></span><span style=display:flex><span> <span style=color:#719e07>break</span>;
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// urlTypeIndex != -1,表示参数列表中存在 URL 参数</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (urlTypeIndex <span style=color:#719e07>!=</span> <span style=color:#719e07>-</span>1) {
</span></span><span style=display:flex><span> <span style=color:#586e75>// 为 URL 类型参数生成判空代码,格式如下:</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// if (arg + urlTypeIndex == null) </span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// throw new IllegalArgumentException(&#34;url == null&#34;);</span>
</span></span><span style=display:flex><span> String s <span style=color:#719e07>=</span> String.format(<span style=color:#2aa198>&#34;\nif (arg%d == null) throw new IllegalArgumentException(\&#34;url == null\&#34;);&#34;</span>,
</span></span><span style=display:flex><span> urlTypeIndex);
</span></span><span style=display:flex><span> code.append(s);
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 为 URL 类型参数生成赋值代码,形如 URL url = arg1</span>
</span></span><span style=display:flex><span> s <span style=color:#719e07>=</span> String.format(<span style=color:#2aa198>&#34;\n%s url = arg%d;&#34;</span>, URL.class.getName(), urlTypeIndex);
</span></span><span style=display:flex><span> code.append(s);
</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:#719e07>else</span> {
</span></span><span style=display:flex><span> String attribMethod <span style=color:#719e07>=</span> <span style=color:#cb4b16>null</span>;
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> LBL_PTS:
</span></span><span style=display:flex><span> <span style=color:#586e75>// 遍历方法的参数类型列表</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>for</span> (<span style=color:#dc322f>int</span> i <span style=color:#719e07>=</span> 0; i <span style=color:#719e07>&lt;</span> pts.length; <span style=color:#719e07>++</span>i) {
</span></span><span style=display:flex><span> <span style=color:#586e75>// 获取某一类型参数的全部方法</span>
</span></span><span style=display:flex><span> Method<span style=color:#719e07>[]</span> ms <span style=color:#719e07>=</span> pts<span style=color:#719e07>[</span>i<span style=color:#719e07>]</span>.getMethods();
</span></span><span style=display:flex><span> <span style=color:#586e75>// 遍历方法列表,寻找可返回 URL 的 getter 方法</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>for</span> (Method m : ms) {
</span></span><span style=display:flex><span> String name <span style=color:#719e07>=</span> m.getName();
</span></span><span style=display:flex><span> <span style=color:#586e75>// 1. 方法名以 get 开头,或方法名大于3个字符</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 2. 方法的访问权限为 public</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 3. 非静态方法</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 4. 方法参数数量为0</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 5. 方法返回值类型为 URL</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> ((name.startsWith(<span style=color:#2aa198>&#34;get&#34;</span>) <span style=color:#719e07>||</span> name.length() <span style=color:#719e07>&gt;</span> 3)
</span></span><span style=display:flex><span> <span style=color:#719e07>&amp;&amp;</span> Modifier.isPublic(m.getModifiers())
</span></span><span style=display:flex><span> <span style=color:#719e07>&amp;&amp;</span> <span style=color:#719e07>!</span>Modifier.isStatic(m.getModifiers())
</span></span><span style=display:flex><span> <span style=color:#719e07>&amp;&amp;</span> m.getParameterTypes().length <span style=color:#719e07>==</span> 0
</span></span><span style=display:flex><span> <span style=color:#719e07>&amp;&amp;</span> m.getReturnType() <span style=color:#719e07>==</span> URL.class) {
</span></span><span style=display:flex><span> urlTypeIndex <span style=color:#719e07>=</span> i;
</span></span><span style=display:flex><span> attribMethod <span style=color:#719e07>=</span> name;
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 结束 for (int i = 0; i &lt; pts.length; ++i) 循环</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>break</span> LBL_PTS;
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (attribMethod <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span>) {
</span></span><span style=display:flex><span> <span style=color:#586e75>// 如果所有参数中均不包含可返回 URL 的 getter 方法,则抛出异常</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>throw</span> <span style=color:#719e07>new</span> IllegalStateException(<span style=color:#2aa198>&#34;fail to create adaptive class for interface ...&#34;</span>);
</span></span><span style=display:flex><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>// if (arg + urlTypeIndex == null) </span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// throw new IllegalArgumentException(&#34;参数全限定名 + argument == null&#34;);</span>
</span></span><span style=display:flex><span> String s <span style=color:#719e07>=</span> String.format(<span style=color:#2aa198>&#34;\nif (arg%d == null) throw new IllegalArgumentException(\&#34;%s argument == null\&#34;);&#34;</span>,
</span></span><span style=display:flex><span> urlTypeIndex, pts<span style=color:#719e07>[</span>urlTypeIndex<span style=color:#719e07>]</span>.getName());
</span></span><span style=display:flex><span> code.append(s);
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 为 getter 方法返回的 URL 生成判空代码,格式如下:</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// if (argN.getter方法名() == null) </span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// throw new IllegalArgumentException(参数全限定名 + argument getUrl() == null);</span>
</span></span><span style=display:flex><span> s <span style=color:#719e07>=</span> String.format(<span style=color:#2aa198>&#34;\nif (arg%d.%s() == null) throw new IllegalArgumentException(\&#34;%s argument %s() == null\&#34;);&#34;</span>,
</span></span><span style=display:flex><span> urlTypeIndex, attribMethod, pts<span style=color:#719e07>[</span>urlTypeIndex<span style=color:#719e07>]</span>.getName(), attribMethod);
</span></span><span style=display:flex><span> code.append(s);
</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>// URL全限定名 url = argN.getter方法名(),比如 </span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// com.alibaba.dubbo.common.URL url = invoker.getUrl();</span>
</span></span><span style=display:flex><span> s <span style=color:#719e07>=</span> String.format(<span style=color:#2aa198>&#34;%s url = arg%d.%s();&#34;</span>, URL.class.getName(), urlTypeIndex, attribMethod);
</span></span><span style=display:flex><span> code.append(s);
</span></span><span style=display:flex><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></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></span></code></pre></div><p>上面代码有点多,需要耐心看一下。这段代码主要目的是为了获取 URL 数据,并为之生成判空和赋值代码。以 Protocol 的 refer 和 export 方法为例,上面的代码为它们生成如下内容(代码已格式化):</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>refer:
</span></span><span style=display:flex><span><span style=color:#719e07>if</span> (arg1 <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span>)
</span></span><span style=display:flex><span> <span style=color:#719e07>throw</span> <span style=color:#719e07>new</span> IllegalArgumentException(<span style=color:#2aa198>&#34;url == null&#34;</span>);
</span></span><span style=display:flex><span>com.alibaba.dubbo.common.URL url <span style=color:#719e07>=</span> arg1;
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>export:
</span></span><span style=display:flex><span><span style=color:#719e07>if</span> (arg0 <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span>)
</span></span><span style=display:flex><span> <span style=color:#719e07>throw</span> <span style=color:#719e07>new</span> IllegalArgumentException(<span style=color:#2aa198>&#34;com.alibaba.dubbo.rpc.Invoker argument == null&#34;</span>);
</span></span><span style=display:flex><span><span style=color:#719e07>if</span> (arg0.getUrl() <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span>)
</span></span><span style=display:flex><span> <span style=color:#719e07>throw</span> <span style=color:#719e07>new</span> IllegalArgumentException(<span style=color:#2aa198>&#34;com.alibaba.dubbo.rpc.Invoker argument getUrl() == null&#34;</span>);
</span></span><span style=display:flex><span>com.alibaba.dubbo.common.URL url <span style=color:#719e07>=</span> arg0.getUrl();
</span></span></code></pre></div><h5 id=2233-获取-adaptive-注解值>2.2.3.3 获取 Adaptive 注解值</h5><p>Adaptive 注解值 value 类型为 String[],可填写多个值,默认情况下为空数组。若 value 为非空数组,直接获取数组内容即可。若 value 为空数组,则需进行额外处理。处理过程是将类名转换为字符数组,然后遍历字符数组,并将字符放入 StringBuilder 中。若字符为大写字母,则向 StringBuilder 中添加点号,随后将字符变为小写存入 StringBuilder 中。比如 LoadBalance 经过处理后,得到 load.balance。</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:#719e07>for</span> (Method method : methods) {
</span></span><span style=display:flex><span> Class<span style=color:#719e07>&lt;?&gt;</span> rt <span style=color:#719e07>=</span> method.getReturnType();
</span></span><span style=display:flex><span> Class<span style=color:#719e07>&lt;?&gt;[]</span> pts <span style=color:#719e07>=</span> method.getParameterTypes();
</span></span><span style=display:flex><span> Class<span style=color:#719e07>&lt;?&gt;[]</span> ets <span style=color:#719e07>=</span> method.getExceptionTypes();
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> Adaptive adaptiveAnnotation <span style=color:#719e07>=</span> method.getAnnotation(Adaptive.class);
</span></span><span style=display:flex><span> StringBuilder code <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> StringBuilder(512);
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (adaptiveAnnotation <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span>) {
</span></span><span style=display:flex><span> <span style=color:#586e75>// ${无 Adaptive 注解方法代码生成逻辑}</span>
</span></span><span style=display:flex><span> } <span style=color:#719e07>else</span> {
</span></span><span style=display:flex><span> <span style=color:#586e75>// ${获取 URL 数据}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> String<span style=color:#719e07>[]</span> value <span style=color:#719e07>=</span> adaptiveAnnotation.value();
</span></span><span style=display:flex><span> <span style=color:#586e75>// value 为空数组</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (value.length <span style=color:#719e07>==</span> 0) {
</span></span><span style=display:flex><span> <span style=color:#586e75>// 获取类名,并将类名转换为字符数组</span>
</span></span><span style=display:flex><span> <span style=color:#dc322f>char</span><span style=color:#719e07>[]</span> charArray <span style=color:#719e07>=</span> type.getSimpleName().toCharArray();
</span></span><span style=display:flex><span> StringBuilder sb <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> StringBuilder(128);
</span></span><span style=display:flex><span> <span style=color:#586e75>// 遍历字节数组</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>for</span> (<span style=color:#dc322f>int</span> i <span style=color:#719e07>=</span> 0; i <span style=color:#719e07>&lt;</span> charArray.length; i<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:#719e07>if</span> (Character.isUpperCase(charArray<span style=color:#719e07>[</span>i<span style=color:#719e07>]</span>)) {
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (i <span style=color:#719e07>!=</span> 0) {
</span></span><span style=display:flex><span> <span style=color:#586e75>// 向 sb 中添加点号</span>
</span></span><span style=display:flex><span> sb.append(<span style=color:#2aa198>&#34;.&#34;</span>);
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> <span style=color:#586e75>// 将字符变为小写,并添加到 sb 中</span>
</span></span><span style=display:flex><span> sb.append(Character.toLowerCase(charArray<span style=color:#719e07>[</span>i<span style=color:#719e07>]</span>));
</span></span><span style=display:flex><span> } <span style=color:#719e07>else</span> {
</span></span><span style=display:flex><span> <span style=color:#586e75>// 添加字符到 sb 中</span>
</span></span><span style=display:flex><span> sb.append(charArray<span style=color:#719e07>[</span>i<span style=color:#719e07>]</span>);
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> value <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> String<span style=color:#719e07>[]</span>{sb.toString()};
</span></span><span style=display:flex><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></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></span></code></pre></div><h5 id=2234-检测-invocation-参数>2.2.3.4 检测 Invocation 参数</h5><p>此段逻辑是检测方法列表中是否存在 Invocation 类型的参数,若存在,则为其生成判空代码和其他一些代码。相应的逻辑如下:</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:#719e07>for</span> (Method method : methods) {
</span></span><span style=display:flex><span> Class<span style=color:#719e07>&lt;?&gt;</span> rt <span style=color:#719e07>=</span> method.getReturnType();
</span></span><span style=display:flex><span> Class<span style=color:#719e07>&lt;?&gt;[]</span> pts <span style=color:#719e07>=</span> method.getParameterTypes(); <span style=color:#586e75>// 获取参数类型列表</span>
</span></span><span style=display:flex><span> Class<span style=color:#719e07>&lt;?&gt;[]</span> ets <span style=color:#719e07>=</span> method.getExceptionTypes();
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> Adaptive adaptiveAnnotation <span style=color:#719e07>=</span> method.getAnnotation(Adaptive.class);
</span></span><span style=display:flex><span> StringBuilder code <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> StringBuilder(512);
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (adaptiveAnnotation <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span>) {
</span></span><span style=display:flex><span> <span style=color:#586e75>// ${无 Adaptive 注解方法代码生成逻辑}</span>
</span></span><span style=display:flex><span> } <span style=color:#719e07>else</span> {
</span></span><span style=display:flex><span> <span style=color:#586e75>// ${获取 URL 数据}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// ${获取 Adaptive 注解值}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#dc322f>boolean</span> hasInvocation <span style=color:#719e07>=</span> <span style=color:#cb4b16>false</span>;
</span></span><span style=display:flex><span> <span style=color:#586e75>// 遍历参数类型列表</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>for</span> (<span style=color:#dc322f>int</span> i <span style=color:#719e07>=</span> 0; i <span style=color:#719e07>&lt;</span> pts.length; <span style=color:#719e07>++</span>i) {
</span></span><span style=display:flex><span> <span style=color:#586e75>// 判断当前参数名称是否等于 com.alibaba.dubbo.rpc.Invocation</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (pts<span style=color:#719e07>[</span>i<span style=color:#719e07>]</span>.getName().equals(<span style=color:#2aa198>&#34;com.alibaba.dubbo.rpc.Invocation&#34;</span>)) {
</span></span><span style=display:flex><span> <span style=color:#586e75>// 为 Invocation 类型参数生成判空代码</span>
</span></span><span style=display:flex><span> String s <span style=color:#719e07>=</span> String.format(<span style=color:#2aa198>&#34;\nif (arg%d == null) throw new IllegalArgumentException(\&#34;invocation == null\&#34;);&#34;</span>, i);
</span></span><span style=display:flex><span> code.append(s);
</span></span><span style=display:flex><span> <span style=color:#586e75>// 生成 getMethodName 方法调用代码,格式为:</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// String methodName = argN.getMethodName();</span>
</span></span><span style=display:flex><span> s <span style=color:#719e07>=</span> String.format(<span style=color:#2aa198>&#34;\nString methodName = arg%d.getMethodName();&#34;</span>, i);
</span></span><span style=display:flex><span> code.append(s);
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 设置 hasInvocation 为 true</span>
</span></span><span style=display:flex><span> hasInvocation <span style=color:#719e07>=</span> <span style=color:#cb4b16>true</span>;
</span></span><span style=display:flex><span> <span style=color:#719e07>break</span>;
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><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></span></code></pre></div><h5 id=2235-生成拓展名获取逻辑>2.2.3.5 生成拓展名获取逻辑</h5><p>本段逻辑用于根据 SPI 和 Adaptive 注解值生成“获取拓展名逻辑”,同时生成逻辑也受 Invocation 类型参数影响,综合因素导致本段逻辑相对复杂。本段逻辑可能会生成但不限于下面的代码:</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>String extName <span style=color:#719e07>=</span> (url.getProtocol() <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span> <span style=color:#719e07>?</span> <span style=color:#2aa198>&#34;dubbo&#34;</span> : url.getProtocol());
</span></span></code></pre></div><p></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>String extName <span style=color:#719e07>=</span> url.getMethodParameter(methodName, <span style=color:#2aa198>&#34;loadbalance&#34;</span>, <span style=color:#2aa198>&#34;random&#34;</span>);
</span></span></code></pre></div><p>亦或是</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>String extName <span style=color:#719e07>=</span> url.getParameter(<span style=color:#2aa198>&#34;client&#34;</span>, url.getParameter(<span style=color:#2aa198>&#34;transporter&#34;</span>, <span style=color:#2aa198>&#34;netty&#34;</span>));
</span></span></code></pre></div><p>本段逻辑复杂之处在于条件分支比较多,大家在阅读源码时需要知道每个条件分支的意义是什么,否则不太容易看懂相关代码。下面开始分析本段逻辑。</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:#719e07>for</span> (Method method : methods) {
</span></span><span style=display:flex><span> Class<span style=color:#719e07>&lt;?&gt;</span> rt <span style=color:#719e07>=</span> method.getReturnType();
</span></span><span style=display:flex><span> Class<span style=color:#719e07>&lt;?&gt;[]</span> pts <span style=color:#719e07>=</span> method.getParameterTypes();
</span></span><span style=display:flex><span> Class<span style=color:#719e07>&lt;?&gt;[]</span> ets <span style=color:#719e07>=</span> method.getExceptionTypes();
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> Adaptive adaptiveAnnotation <span style=color:#719e07>=</span> method.getAnnotation(Adaptive.class);
</span></span><span style=display:flex><span> StringBuilder code <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> StringBuilder(512);
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (adaptiveAnnotation <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span>) {
</span></span><span style=display:flex><span> <span style=color:#586e75>// $无 Adaptive 注解方法代码生成逻辑}</span>
</span></span><span style=display:flex><span> } <span style=color:#719e07>else</span> {
</span></span><span style=display:flex><span> <span style=color:#586e75>// ${获取 URL 数据}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// ${获取 Adaptive 注解值}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// ${检测 Invocation 参数}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 设置默认拓展名,cachedDefaultName 源于 SPI 注解值,默认情况下,</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// SPI 注解值为空串,此时 cachedDefaultName = null</span>
</span></span><span style=display:flex><span> String defaultExtName <span style=color:#719e07>=</span> cachedDefaultName;
</span></span><span style=display:flex><span> String getNameCode <span style=color:#719e07>=</span> <span style=color:#cb4b16>null</span>;
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 遍历 value,这里的 value 是 Adaptive 的注解值,2.2.3.3 节分析过 value 变量的获取过程。</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 此处循环目的是生成从 URL 中获取拓展名的代码,生成的代码会赋值给 getNameCode 变量。注意这</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 个循环的遍历顺序是由后向前遍历的。</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>for</span> (<span style=color:#dc322f>int</span> i <span style=color:#719e07>=</span> value.length <span style=color:#719e07>-</span> 1; i <span style=color:#719e07>&gt;=</span> 0; <span style=color:#719e07>--</span>i) {
</span></span><span style=display:flex><span> <span style=color:#586e75>// 当 i 为最后一个元素的坐标时</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (i <span style=color:#719e07>==</span> value.length <span style=color:#719e07>-</span> 1) {
</span></span><span style=display:flex><span> <span style=color:#586e75>// 默认拓展名非空</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (<span style=color:#cb4b16>null</span> <span style=color:#719e07>!=</span> defaultExtName) {
</span></span><span style=display:flex><span> <span style=color:#586e75>// protocol 是 url 的一部分,可通过 getProtocol 方法获取,其他的则是从</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// URL 参数中获取。因为获取方式不同,所以这里要判断 value[i] 是否为 protocol</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (<span style=color:#719e07>!</span><span style=color:#2aa198>&#34;protocol&#34;</span>.equals(value<span style=color:#719e07>[</span>i<span style=color:#719e07>]</span>))
</span></span><span style=display:flex><span> <span style=color:#586e75>// hasInvocation 用于标识方法参数列表中是否有 Invocation 类型参数</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (hasInvocation)
</span></span><span style=display:flex><span> <span style=color:#586e75>// 生成的代码功能等价于下面的代码:</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// url.getMethodParameter(methodName, value[i], defaultExtName)</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 以 LoadBalance 接口的 select 方法为例,最终生成的代码如下:</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// url.getMethodParameter(methodName, &#34;loadbalance&#34;, &#34;random&#34;)</span>
</span></span><span style=display:flex><span> getNameCode <span style=color:#719e07>=</span> String.format(<span style=color:#2aa198>&#34;url.getMethodParameter(methodName, \&#34;%s\&#34;, \&#34;%s\&#34;)&#34;</span>, value<span style=color:#719e07>[</span>i<span style=color:#719e07>]</span>, defaultExtName);
</span></span><span style=display:flex><span> <span style=color:#719e07>else</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 生成的代码功能等价于下面的代码:</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// url.getParameter(value[i], defaultExtName)</span>
</span></span><span style=display:flex><span> getNameCode <span style=color:#719e07>=</span> String.format(<span style=color:#2aa198>&#34;url.getParameter(\&#34;%s\&#34;, \&#34;%s\&#34;)&#34;</span>, value<span style=color:#719e07>[</span>i<span style=color:#719e07>]</span>, defaultExtName);
</span></span><span style=display:flex><span> <span style=color:#719e07>else</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 生成的代码功能等价于下面的代码:</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// ( url.getProtocol() == null ? defaultExtName : url.getProtocol() )</span>
</span></span><span style=display:flex><span> getNameCode <span style=color:#719e07>=</span> String.format(<span style=color:#2aa198>&#34;( url.getProtocol() == null ? \&#34;%s\&#34; : url.getProtocol() )&#34;</span>, defaultExtName);
</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:#719e07>else</span> {
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (<span style=color:#719e07>!</span><span style=color:#2aa198>&#34;protocol&#34;</span>.equals(value<span style=color:#719e07>[</span>i<span style=color:#719e07>]</span>))
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (hasInvocation)
</span></span><span style=display:flex><span> <span style=color:#586e75>// 生成代码格式同上</span>
</span></span><span style=display:flex><span> getNameCode <span style=color:#719e07>=</span> String.format(<span style=color:#2aa198>&#34;url.getMethodParameter(methodName, \&#34;%s\&#34;, \&#34;%s\&#34;)&#34;</span>, value<span style=color:#719e07>[</span>i<span style=color:#719e07>]</span>, defaultExtName);
</span></span><span style=display:flex><span> <span style=color:#719e07>else</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 生成的代码功能等价于下面的代码:</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// url.getParameter(value[i])</span>
</span></span><span style=display:flex><span> getNameCode <span style=color:#719e07>=</span> String.format(<span style=color:#2aa198>&#34;url.getParameter(\&#34;%s\&#34;)&#34;</span>, value<span style=color:#719e07>[</span>i<span style=color:#719e07>]</span>);
</span></span><span style=display:flex><span> <span style=color:#719e07>else</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 生成从 url 中获取协议的代码,比如 &#34;dubbo&#34;</span>
</span></span><span style=display:flex><span> getNameCode <span style=color:#719e07>=</span> <span style=color:#2aa198>&#34;url.getProtocol()&#34;</span>;
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> } <span style=color:#719e07>else</span> {
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (<span style=color:#719e07>!</span><span style=color:#2aa198>&#34;protocol&#34;</span>.equals(value<span style=color:#719e07>[</span>i<span style=color:#719e07>]</span>))
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (hasInvocation)
</span></span><span style=display:flex><span> <span style=color:#586e75>// 生成代码格式同上</span>
</span></span><span style=display:flex><span> getNameCode <span style=color:#719e07>=</span> String.format(<span style=color:#2aa198>&#34;url.getMethodParameter(methodName, \&#34;%s\&#34;, \&#34;%s\&#34;)&#34;</span>, value<span style=color:#719e07>[</span>i<span style=color:#719e07>]</span>, defaultExtName);
</span></span><span style=display:flex><span> <span style=color:#719e07>else</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 生成的代码功能等价于下面的代码:</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// url.getParameter(value[i], getNameCode)</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 以 Transporter 接口的 connect 方法为例,最终生成的代码如下:</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// url.getParameter(&#34;client&#34;, url.getParameter(&#34;transporter&#34;, &#34;netty&#34;))</span>
</span></span><span style=display:flex><span> getNameCode <span style=color:#719e07>=</span> String.format(<span style=color:#2aa198>&#34;url.getParameter(\&#34;%s\&#34;, %s)&#34;</span>, value<span style=color:#719e07>[</span>i<span style=color:#719e07>]</span>, getNameCode);
</span></span><span style=display:flex><span> <span style=color:#719e07>else</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 生成的代码功能等价于下面的代码:</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// url.getProtocol() == null ? getNameCode : url.getProtocol()</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 以 Protocol 接口的 connect 方法为例,最终生成的代码如下:</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// url.getProtocol() == null ? &#34;dubbo&#34; : url.getProtocol()</span>
</span></span><span style=display:flex><span> getNameCode <span style=color:#719e07>=</span> String.format(<span style=color:#2aa198>&#34;url.getProtocol() == null ? (%s) : url.getProtocol()&#34;</span>, getNameCode);
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> <span style=color:#586e75>// 生成 extName 赋值代码</span>
</span></span><span style=display:flex><span> code.append(<span style=color:#2aa198>&#34;\nString extName = &#34;</span>).append(getNameCode).append(<span style=color:#2aa198>&#34;;&#34;</span>);
</span></span><span style=display:flex><span> <span style=color:#586e75>// 生成 extName 判空代码</span>
</span></span><span style=display:flex><span> String s <span style=color:#719e07>=</span> String.format(<span style=color:#2aa198>&#34;\nif(extName == null) &#34;</span> <span style=color:#719e07>+</span>
</span></span><span style=display:flex><span> <span style=color:#2aa198>&#34;throw new IllegalStateException(\&#34;Fail to get extension(%s) name from url(\&#34; + url.toString() + \&#34;) use keys(%s)\&#34;);&#34;</span>,
</span></span><span style=display:flex><span> type.getName(), Arrays.toString(value));
</span></span><span style=display:flex><span> code.append(s);
</span></span><span style=display:flex><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></span></code></pre></div><p>上面代码比较复杂,不是很好理解。对于这段代码,建议大家写点测试用例,对 Protocol、LoadBalance 以及 Transporter 等接口的自适应拓展类代码生成过程进行调试。这里我以 Transporter 接口的自适应拓展类代码生成过程举例说明。首先看一下 Transporter 接口的定义,如下:</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>@SPI</span>(<span style=color:#2aa198>&#34;netty&#34;</span>)
</span></span><span style=display:flex><span><span style=color:#268bd2>public</span> <span style=color:#268bd2>interface</span> <span style=color:#268bd2>Transporter</span> {
</span></span><span style=display:flex><span> <span style=color:#586e75>// @Adaptive({server, transporter})</span>
</span></span><span style=display:flex><span> <span style=color:#268bd2>@Adaptive</span>({Constants.SERVER_KEY, Constants.TRANSPORTER_KEY})
</span></span><span style=display:flex><span> Server <span style=color:#268bd2>bind</span>(URL url, ChannelHandler handler) <span style=color:#268bd2>throws</span> RemotingException;
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// @Adaptive({client, transporter})</span>
</span></span><span style=display:flex><span> <span style=color:#268bd2>@Adaptive</span>({Constants.CLIENT_KEY, Constants.TRANSPORTER_KEY})
</span></span><span style=display:flex><span> Client <span style=color:#268bd2>connect</span>(URL url, ChannelHandler handler) <span style=color:#268bd2>throws</span> RemotingException;
</span></span><span style=display:flex><span>}
</span></span></code></pre></div><p>下面对 connect 方法代理逻辑生成的过程进行分析,此时生成代理逻辑所用到的变量如下:</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>String defaultExtName <span style=color:#719e07>=</span> <span style=color:#2aa198>&#34;netty&#34;</span>;
</span></span><span style=display:flex><span><span style=color:#dc322f>boolean</span> hasInvocation <span style=color:#719e07>=</span> <span style=color:#cb4b16>false</span>;
</span></span><span style=display:flex><span>String getNameCode <span style=color:#719e07>=</span> <span style=color:#cb4b16>null</span>;
</span></span><span style=display:flex><span>String<span style=color:#719e07>[]</span> value <span style=color:#719e07>=</span> <span style=color:#719e07>[</span><span style=color:#2aa198>&#34;client&#34;</span>, <span style=color:#2aa198>&#34;transporter&#34;</span><span style=color:#719e07>]</span>;
</span></span></code></pre></div><p>下面对 value 数组进行遍历,此时 i = 1, value[i] = &ldquo;transporter&rdquo;,生成的代码如下:</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>getNameCode <span style=color:#719e07>=</span> url.getParameter(<span style=color:#2aa198>&#34;transporter&#34;</span>, <span style=color:#2aa198>&#34;netty&#34;</span>);
</span></span></code></pre></div><p>接下来,for 循环继续执行,此时 i = 0, value[i] = &ldquo;client&rdquo;,生成的代码如下:</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>getNameCode <span style=color:#719e07>=</span> url.getParameter(<span style=color:#2aa198>&#34;client&#34;</span>, url.getParameter(<span style=color:#2aa198>&#34;transporter&#34;</span>, <span style=color:#2aa198>&#34;netty&#34;</span>));
</span></span></code></pre></div><p>for 循环结束运行,现在为 extName 变量生成赋值和判空代码,如下:</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>String extName <span style=color:#719e07>=</span> url.getParameter(<span style=color:#2aa198>&#34;client&#34;</span>, url.getParameter(<span style=color:#2aa198>&#34;transporter&#34;</span>, <span style=color:#2aa198>&#34;netty&#34;</span>));
</span></span><span style=display:flex><span><span style=color:#719e07>if</span> (extName <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span>) {
</span></span><span style=display:flex><span> <span style=color:#719e07>throw</span> <span style=color:#719e07>new</span> IllegalStateException(
</span></span><span style=display:flex><span> <span style=color:#2aa198>&#34;Fail to get extension(com.alibaba.dubbo.remoting.Transporter) name from url(&#34;</span> <span style=color:#719e07>+</span> url.toString()
</span></span><span style=display:flex><span> <span style=color:#719e07>+</span> <span style=color:#2aa198>&#34;) use keys([client, transporter])&#34;</span>);
</span></span><span style=display:flex><span>}
</span></span></code></pre></div><h5 id=2236-生成拓展加载与目标方法调用逻辑>2.2.3.6 生成拓展加载与目标方法调用逻辑</h5><p>本段代码逻辑用于根据拓展名加载拓展实例,并调用拓展实例的目标方法。相关逻辑如下:</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:#719e07>for</span> (Method method : methods) {
</span></span><span style=display:flex><span> Class<span style=color:#719e07>&lt;?&gt;</span> rt <span style=color:#719e07>=</span> method.getReturnType();
</span></span><span style=display:flex><span> Class<span style=color:#719e07>&lt;?&gt;[]</span> pts <span style=color:#719e07>=</span> method.getParameterTypes();
</span></span><span style=display:flex><span> Class<span style=color:#719e07>&lt;?&gt;[]</span> ets <span style=color:#719e07>=</span> method.getExceptionTypes();
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> Adaptive adaptiveAnnotation <span style=color:#719e07>=</span> method.getAnnotation(Adaptive.class);
</span></span><span style=display:flex><span> StringBuilder code <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> StringBuilder(512);
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (adaptiveAnnotation <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span>) {
</span></span><span style=display:flex><span> <span style=color:#586e75>// $无 Adaptive 注解方法代码生成逻辑}</span>
</span></span><span style=display:flex><span> } <span style=color:#719e07>else</span> {
</span></span><span style=display:flex><span> <span style=color:#586e75>// ${获取 URL 数据}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// ${获取 Adaptive 注解值}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// ${检测 Invocation 参数}</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></span><span style=display:flex><span> <span style=color:#586e75>// 生成拓展获取代码,格式如下:</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// type全限定名 extension = (type全限定名)ExtensionLoader全限定名</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// .getExtensionLoader(type全限定名.class).getExtension(extName);</span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// Tips: 格式化字符串中的 %&lt;s 表示使用前一个转换符所描述的参数,即 type 全限定名</span>
</span></span><span style=display:flex><span> s <span style=color:#719e07>=</span> String.format(<span style=color:#2aa198>&#34;\n%s extension = (%&lt;s)%s.getExtensionLoader(%s.class).getExtension(extName);&#34;</span>,
</span></span><span style=display:flex><span> type.getName(), ExtensionLoader.class.getSimpleName(), type.getName());
</span></span><span style=display:flex><span> code.append(s);
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// 如果方法返回值类型非 void,则生成 return 语句。</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (<span style=color:#719e07>!</span>rt.equals(<span style=color:#dc322f>void</span>.class)) {
</span></span><span style=display:flex><span> code.append(<span style=color:#2aa198>&#34;\nreturn &#34;</span>);
</span></span><span style=display:flex><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>// extension.方法名(arg0, arg2, ..., argN);</span>
</span></span><span style=display:flex><span> s <span style=color:#719e07>=</span> String.format(<span style=color:#2aa198>&#34;extension.%s(&#34;</span>, method.getName());
</span></span><span style=display:flex><span> code.append(s);
</span></span><span style=display:flex><span> <span style=color:#719e07>for</span> (<span style=color:#dc322f>int</span> i <span style=color:#719e07>=</span> 0; i <span style=color:#719e07>&lt;</span> pts.length; i<span style=color:#719e07>++</span>) {
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (i <span style=color:#719e07>!=</span> 0)
</span></span><span style=display:flex><span> code.append(<span style=color:#2aa198>&#34;, &#34;</span>);
</span></span><span style=display:flex><span> code.append(<span style=color:#2aa198>&#34;arg&#34;</span>).append(i);
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> code.append(<span style=color:#2aa198>&#34;);&#34;</span>);
</span></span><span style=display:flex><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></span></code></pre></div><p>以 Protocol 接口举例说明,上面代码生成的内容如下:</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>com.alibaba.dubbo.rpc.Protocol extension <span style=color:#719e07>=</span> (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader
</span></span><span style=display:flex><span> .getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
</span></span><span style=display:flex><span><span style=color:#719e07>return</span> extension.refer(arg0, arg1);
</span></span></code></pre></div><h5 id=2237-生成完整的方法>2.2.3.7 生成完整的方法</h5><p>本节进行代码生成的收尾工作,主要用于生成方法定义的代码。相关逻辑如下:</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:#719e07>for</span> (Method method : methods) {
</span></span><span style=display:flex><span> Class<span style=color:#719e07>&lt;?&gt;</span> rt <span style=color:#719e07>=</span> method.getReturnType();
</span></span><span style=display:flex><span> Class<span style=color:#719e07>&lt;?&gt;[]</span> pts <span style=color:#719e07>=</span> method.getParameterTypes();
</span></span><span style=display:flex><span> Class<span style=color:#719e07>&lt;?&gt;[]</span> ets <span style=color:#719e07>=</span> method.getExceptionTypes();
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> Adaptive adaptiveAnnotation <span style=color:#719e07>=</span> method.getAnnotation(Adaptive.class);
</span></span><span style=display:flex><span> StringBuilder code <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> StringBuilder(512);
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (adaptiveAnnotation <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span>) {
</span></span><span style=display:flex><span> <span style=color:#586e75>// $无 Adaptive 注解方法代码生成逻辑}</span>
</span></span><span style=display:flex><span> } <span style=color:#719e07>else</span> {
</span></span><span style=display:flex><span> <span style=color:#586e75>// ${获取 URL 数据}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// ${获取 Adaptive 注解值}</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#586e75>// ${检测 Invocation 参数}</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></span><span style=display:flex><span> <span style=color:#586e75>// ${生成拓展加载与目标方法调用逻辑}</span>
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span>}
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#586e75>// public + 返回值全限定名 + 方法名 + (</span>
</span></span><span style=display:flex><span>codeBuilder.append(<span style=color:#2aa198>&#34;\npublic &#34;</span>)
</span></span><span style=display:flex><span> .append(rt.getCanonicalName())
</span></span><span style=display:flex><span> .append(<span style=color:#2aa198>&#34; &#34;</span>)
</span></span><span style=display:flex><span> .append(method.getName())
</span></span><span style=display:flex><span> .append(<span style=color:#2aa198>&#34;(&#34;</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:#719e07>for</span> (<span style=color:#dc322f>int</span> i <span style=color:#719e07>=</span> 0; i <span style=color:#719e07>&lt;</span> pts.length; i<span style=color:#719e07>++</span>) {
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (i <span style=color:#719e07>&gt;</span> 0) {
</span></span><span style=display:flex><span> codeBuilder.append(<span style=color:#2aa198>&#34;, &#34;</span>);
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> codeBuilder.append(pts<span style=color:#719e07>[</span>i<span style=color:#719e07>]</span>.getCanonicalName());
</span></span><span style=display:flex><span> codeBuilder.append(<span style=color:#2aa198>&#34; &#34;</span>);
</span></span><span style=display:flex><span> codeBuilder.append(<span style=color:#2aa198>&#34;arg&#34;</span>).append(i);
</span></span><span style=display:flex><span>}
</span></span><span style=display:flex><span>codeBuilder.append(<span style=color:#2aa198>&#34;)&#34;</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:#719e07>if</span> (ets.length <span style=color:#719e07>&gt;</span> 0) {
</span></span><span style=display:flex><span> codeBuilder.append(<span style=color:#2aa198>&#34; throws &#34;</span>);
</span></span><span style=display:flex><span> <span style=color:#719e07>for</span> (<span style=color:#dc322f>int</span> i <span style=color:#719e07>=</span> 0; i <span style=color:#719e07>&lt;</span> ets.length; i<span style=color:#719e07>++</span>) {
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (i <span style=color:#719e07>&gt;</span> 0) {
</span></span><span style=display:flex><span> codeBuilder.append(<span style=color:#2aa198>&#34;, &#34;</span>);
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> codeBuilder.append(ets<span style=color:#719e07>[</span>i<span style=color:#719e07>]</span>.getCanonicalName());
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span>}
</span></span><span style=display:flex><span>codeBuilder.append(<span style=color:#2aa198>&#34; {&#34;</span>);
</span></span><span style=display:flex><span>codeBuilder.append(code.toString());
</span></span><span style=display:flex><span>codeBuilder.append(<span style=color:#2aa198>&#34;\n}&#34;</span>);
</span></span></code></pre></div><p>以 Protocol 的 refer 方法为例,上面代码生成的内容如下:</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> com.alibaba.dubbo.rpc.Invoker <span style=color:#268bd2>refer</span>(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) {
</span></span><span style=display:flex><span> <span style=color:#586e75>// 方法体</span>
</span></span><span style=display:flex><span>}
</span></span></code></pre></div><h2 id=3总结>3.总结</h2><p>到此,关于自适应拓展的原理,实现就分析完了。总的来说自适应拓展整个逻辑还是很复杂的,并不是很容易弄懂。因此,大家在阅读该部分源码时,耐心一些。同时多进行调试,也可以通过生成好的代码思考代码的生成逻辑。好了,本篇文章就分析到这里。</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) (f2070b3fdd1)</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/adaptive-extension.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/adaptive-extension.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=SPI%20%e8%87%aa%e9%80%82%e5%ba%94%e6%8b%93%e5%b1%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><ul><li><a href=#21-获取自适应拓展>2.1 获取自适应拓展</a></li><li><a href=#22-自适应拓展类代码生成>2.2 自适应拓展类代码生成</a></li></ul></li><li><a href=#3总结>3.总结</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; 2024 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 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://dubbo.apache.org/en/overview/notices/>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.b075178d232d3b0039b3cb6af2fc2e9d90071820167a60f4eea3a79169975ee8.js integrity="sha256-sHUXjSMtOwA5s8tq8vwunZAHGCAWemD07qOnkWmXXug=" crossorigin=anonymous></script><script async src=https://widget.kapa.ai/kapa-widget.bundle.js data-website-id=d763c4f2-f871-400b-aeca-d986c4af73c2 data-project-name="Apache Dubbo" data-project-color=#E8442E data-button-text="Ask AI" data-search-mode-enabled=true data-modal-open-on-command-k=true data-modal-disclaimer="The AI supports multiple languages, but it may not be accessible in China due to recaptcha, a proxy is required." data-project-logo=https://pbs.twimg.com/profile_images/1011849068283191302/FJbH5vbF_400x400.jpg data-modal-example-questions="What is Apache Dubbo?,How to run Apache Dubbo?" data-button-position-top data-button-position-right=20px data-button-position-bottom=200px data-button-position-left></script><script>(function(e,t,n,s){e[s]=e[s]||[];var a=t.getElementsByTagName(n)[0],i=t.createElement(n);i.async=!0,i.id="beacon-aplus",i.setAttribute("exparams","userid=&aplus&sidx=aplusSidex&ckx=aplusCkx"),i.src="//g.alicdn.com/alilog/mlog/aplus_v2.js",i.crossorigin="anonymous",a.parentNode.insertBefore(i,a)})(window,document,"script","aplus_queue"),function(e){var t=e.createElement("script");t.type="text/javascript",t.async=!0,t.src="//g.alicdn.com/aes/??tracker/3.3.4/index.js,tracker-plugin-pv/3.0.5/index.js,tracker-plugin-event/3.0.0/index.js,tracker-plugin-autolog/3.0.3/index.js,tracker-plugin-survey/3.0.3/index.js,tracker-plugin-jserror/3.0.3/index.js,tracker-plugin-resourceError/3.0.3/index.js",t.onload=function(){window.AES_CONFIG=window.AES_CONFIG||{env:"prod"},window.aes=new AES({pid:"zN245h",user_type:6}),window.AESPluginAutologConfig={exposure:"auto"},window.AEMPluginInstances=[aes.use(AESPluginPV,window.AESPluginPVConfig||{enableHistory:!0}),aes.use(AESPluginEvent,window.AESPluginEventConfig||{}),aes.use(AESPluginSurvey,window.AESPluginEventConfig||{}),aes.use(AESPluginAutolog,window.AESPluginAutologConfig||{}),aes.use(AESPluginJSError,window.AESPluginJSError||{}),aes.use(AESPluginResourceError,window.AESPluginResourceError||{})]},setTimeout(function(){e.getElementsByTagName("body")[0].appendChild(t)},800)}(document)</script></body></html>