You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@dubbo.apache.org by GitBox <gi...@apache.org> on 2018/07/10 06:35:30 UTC

[GitHub] diecui1202 closed pull request #33: add dubbo meetup shanghai blog

diecui1202 closed pull request #33: add dubbo meetup shanghai blog
URL: https://github.com/apache/incubator-dubbo-website/pull/33
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/blog/en-us/dubbo-meetup-shanghai-jun-23rd-2018.md b/blog/en-us/dubbo-meetup-shanghai-jun-23rd-2018.md
new file mode 100644
index 0000000..842a697
--- /dev/null
+++ b/blog/en-us/dubbo-meetup-shanghai-jun-23rd-2018.md
@@ -0,0 +1,10 @@
+Dubbo Shanghai meetup has been held successfully
+---
+
+The sencond Dubbo meetup has successfully been held in Shanghai, over 700 people submitted registration, and over 300 were present, more than 10,000 watched the live online. A great event again! 
+
+Please enjoy the slides of the topics:
+  * Jerrick Zhu: Dubbo Status and Roadmap (Chinese) [slides](https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/dubbo-status-and-roadmap.pdf)
+  * Mercy Ma: Dubbo Cloud Native Practices and Thoughts (Chinese) [slides](https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/dubbo-cloud-native-practices-and-thoughts.pdf)
+  * Ping Guo: Nacos Open Source Initiative (Chinese) [slides](https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/nacos-open-source-initiative.pdf)
+  * Zhiwei Pan: Dubbo Practices on Internet Finance Industries (Chinese) [slides](https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/dubbo-practices-on-internet-finance-industries.pdf) 
\ No newline at end of file
diff --git a/blog/zh-cn/dubbo-meetup-shanghai-jun-23rd-2018.md b/blog/zh-cn/dubbo-meetup-shanghai-jun-23rd-2018.md
new file mode 100644
index 0000000..9f58089
--- /dev/null
+++ b/blog/zh-cn/dubbo-meetup-shanghai-jun-23rd-2018.md
@@ -0,0 +1,10 @@
+第二届Dubbo开发者沙龙在上海成功举办
+---
+
+第二届Dubbo开发者沙龙在上海成功举办,超过700位开发者报名,现场参与人数300+,通过阿里云天池、云栖社区、大咖说引导线上直播观看次数10000+
+
+分享嘉宾及PPT:
+  * 朱勇: Dubbo开源现状与未来规划 (中文) [slides](https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/dubbo-status-and-roadmap.pdf)
+  * 小马哥: Dubbo Cloud Native 之路的实践与思考 (中文) [slides](https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/dubbo-cloud-native-practices-and-thoughts.pdf)
+  * 郭平: Nacos - 贡献Dubbo生态,阿里巴巴注册中心和配置中心开源计划 (中文) [slides](https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/nacos-open-source-initiative.pdf)
+  * 潘志伟: Dubbo在互金行业的应用场景 (中文) [slides](https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/dubbo-practices-on-internet-finance-industries.pdf) 
\ No newline at end of file
diff --git a/img/blog/dubbo-shanghai-meetup.jpeg b/img/blog/dubbo-shanghai-meetup.jpeg
new file mode 100644
index 0000000..0a08316
Binary files /dev/null and b/img/blog/dubbo-shanghai-meetup.jpeg differ
diff --git a/md_json/blog.json b/md_json/blog.json
index 268c088..8b22ebb 100644
--- a/md_json/blog.json
+++ b/md_json/blog.json
@@ -8,6 +8,10 @@
       "filename": "dubbo-basic-usage-dubbo-provider-configuration.md",
       "__html": "<h2>Dubbo基本用法-Dubbo Provider配置</h2>\n<h1>Dubbo基本用法</h1>\n<p>本章节主要讲述如何配置dubbo,按照配置方式上分,可以分为:XML配置,properties方式配置,注解方式配置,API调用方式配置。\n按照功能角度进行划分,可以分为Dubbo Provider和Dubbo Consumer。接下来章节中,分别对dubbo provider和Dubbo consumer进行讲解。</p>\n<h2>Dubbo Provider配置</h2>\n<h3>Provider 配置详解</h3>\n<p>配置Dubbo Provider有4种方式:XML配置,properties方式配置,API调用方式配置,注解方式配置。</p>\n<h4>XML配置</h4>\n<h6>最简单的配置的样例:</h6>\n<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;\n&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;\n    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;\n    xmlns:dubbo=&quot;http://dubbo.apache.org/schema/dubbo&quot;\n    xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd&quot;&gt;  \n    &lt;dubbo:application name=&quot;hello-world-app&quot; /&gt;  \n    &lt;dubbo:registry address=&quot;multicast://224.5.6.7:1234&quot; /&gt;  \n    &lt;dubbo:protocol name=&quot;dubbo&quot; port=&quot;20880&quot; /&gt;  \n    &lt;dubbo:service interface=&quot;com.alibaba.dubbo.demo.DemoService&quot; ref=&quot;demoServiceLocal&quot; /&gt;  \n    &lt;dubbo:reference id=&quot;demoServiceRemote&quot; interface=&quot;com.alibaba.dubbo.demo.DemoService&quot; /&gt;  \n&lt;/beans&gt;\n</code></pre>\n<p>上面样例中,注意下dubbo schema的写法:</p>\n<pre><code>&lt;beans xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;\n       xmlns:dubbo=&quot;http://code.alibabatech.com/schema/dubbo&quot;\n       xmlns=&quot;http://www.springframework.org/schema/beans&quot;\n       xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n       http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd&quot;&gt;\n</code></pre>\n<h6>支持的配置标签</h6>\n<table>\n<thead>\n<tr>\n<th>标签</th>\n<th>用途</th>\n<th style=\"text-align:left\">解释</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>&lt;dubbo:service/&gt;</td>\n<td>服务配置</td>\n<td style=\"text-align:left\">用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心</td>\n</tr>\n<tr>\n<td>&lt;dubbo:reference/&gt;</td>\n<td>引用配置</td>\n<td style=\"text-align:left\">用于创建一个远程服务代理,一个引用可以指向多个注册中心</td>\n</tr>\n<tr>\n<td>&lt;dubbo:protocol/&gt;</td>\n<td>协议配置</td>\n<td style=\"text-align:left\">用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受</td>\n</tr>\n<tr>\n<td>&lt;dubbo:application/&gt;</td>\n<td>应用配置</td>\n<td style=\"text-align:left\">用于配置当前应用信息,不管该应用是提供者还是消费者</td>\n</tr>\n<tr>\n<td>&lt;dubbo:module/&gt;</td>\n<td>模块配置</td>\n<td style=\"text-align:left\">用于配置当前模块信息,可选</td>\n</tr>\n<tr>\n<td>&lt;dubbo:registry/&gt;</td>\n<td>注册中心配置</td>\n<td style=\"text-align:left\">用于配置连接注册中心相关信息</td>\n</tr>\n<tr>\n<td>&lt;dubbo:monitor/&gt;</td>\n<td>监控中心配置</td>\n<td style=\"text-align:left\">用于配置连接监控中心相关信息,可选</td>\n</tr>\n<tr>\n<td>&lt;dubbo:provider/&gt;</td>\n<td>提供方配置</td>\n<td style=\"text-align:left\">当 ProtocolConfig 和 ServiceConfig 某属性没有配置时,采用此缺省值,可选</td>\n</tr>\n<tr>\n<td>&lt;dubbo:consumer/&gt;</td>\n<td>消费方配置</td>\n<td style=\"text-align:left\">当 ReferenceConfig 某属性没有配置时,采用此缺省值,可选</td>\n</tr>\n<tr>\n<td>&lt;dubbo:method/&gt;</td>\n<td>方法配置</td>\n<td style=\"text-align:left\">用于 ServiceConfig 和 ReferenceConfig 指定方法级的配置信息</td>\n</tr>\n<tr>\n<td>&lt;dubbo:argument/&gt;</td>\n<td>参数配置</td>\n<td style=\"text-align:left\">用于指定方法参数配置</td>\n</tr>\n</tbody>\n</table>\n<p><img src=\"https://cdn.yuque.com/lark/0/2018/png/15841/1527849348155-8423d401-9ea4-4dc6-8720-d9e3d90963b6.png\" alt=\"undefined\"></p>\n <center>配置之间关系图</center>\n<h6>配置项详解</h6>\n<ul>\n<li>\n<p>&lt;dubbo:application name=&quot;hello-world-app&quot; /&gt;<br>\n用于指定应用名,这里需要保证应用名唯一,这个应用名在后续的console admin中可以在列表中显示,方便管理。</p>\n</li>\n<li>\n<p>&lt;dubbo:registry address=&quot;multicast://224.5.6.7:1234&quot; /&gt;<br>\n注册中心配置,和服务发现的具体机制有关系。可以是zookeeper地质,也可以eureka地质。上面这个是广播地址,在本地服务调用的测试过程中非常方便。</p>\n</li>\n<li>\n<p>&lt;dubbo:protocol name=&quot;dubbo&quot; port=&quot;20880&quot; /&gt;<br>\n这里是传输的协议和默认端口,一般不需要更改。</p>\n</li>\n</ul>\n<blockquote>\n<p>接下来重点讲解下&lt;dubbo:service/&gt;的配置。</p>\n</blockquote>\n<ul>\n<li>&lt;dubbo:service/&gt;支持的主要属性列表:\n| 属性名 | 说明 |\n| -------- | ----- |\n| version | 版本号 |\n| scope | 服务可见性, 值为:local 或者 remote,默认为remote |\n| actives | 最大的激活的请求数 |\n| async | 方法调用是否异步,默认为false |\n| cache | 服务缓存,可选值:lru/threadlocal/jcache |\n| callbacks | callback实例的限制 |\n| generic | 泛化调用,可以绕过 |\n| class | Service的实现的类名 |\n| connections | 这个服务里的连接数 |\n| delay | 发布服务延迟的毫秒数 |\n| executes | 服务执行的请求上限 |\n| retries | 超时重试次数 |\n| timeout | 调用超时时间 |</li>\n</ul>\n<p>其他配置属性请参考xsd:<a href=\"http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">http://dubbo.apache.org/schema/dubbo/dubbo.xsd</a></p>\n<ul>\n<li>&lt;dubbo:method/&gt;作为&lt;dubbo:service/&gt;的子元素,它可以针对方法进行配置。比较常用的属性有:</li>\n</ul>\n<table>\n<thead>\n<tr>\n<th>属性名</th>\n<th>说明</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>executes</td>\n<td>服务执行的请求上限</td>\n</tr>\n<tr>\n<td>retries</td>\n<td>超时重试次数</td>\n</tr>\n<tr>\n<td>timeout</td>\n<td>调用超时时间</td>\n</tr>\n</tbody>\n</table>\n<p>其他属性,可以参考上面的xsd。</p>\n<h6>配置的覆盖关系</h6>\n<p><img src=\"https://cdn.yuque.com/lark/0/2018/png/15841/1527849374313-94a5ea24-0e72-4d83-871b-e0e95eab646a.png\" alt=\"undefined\"></p>\n<center>配置的覆盖关系图</center>\n<p>这里的覆盖关系包含了Provider和Consumer两端的配置,如果对consumer有疑问,可以参考后一章节的consumer章节之后再来理解。</p>\n<h4>dubbo.properties方式配置</h4>\n<blockquote>\n<p>如果公共配置很简单,没有多注册中心,多协议等情况,或者想多个 Spring 容器想共享配置,可以使用 dubbo.properties 作为缺省配置。</p>\n</blockquote>\n<p>Dubbo 将自动加载 classpath 根目录下的 dubbo.properties,可以通过JVM启动参数 -Ddubbo.properties.file=xxx.properties 改变缺省配置位置。</p>\n<h6>dubbo.properties配置样例</h6>\n<pre><code># 应用名\ndubbo.application.name=dubbodemo-provider\n# 注册中心地址\ndubbo.registry.address=zookeeper://localhost:2181\n# 广播的注册中心样例\n#dubbo.registry.address=multicast://224.5.6.7:1234\n# 调用协议地址\ndubbo.protocol.name=dubbo\ndubbo.protocol.port=28080\n</code></pre>\n<h6>映射规则</h6>\n<p>将 XML 配置的标签名,加属性名,用点分隔,多个属性拆成多行</p>\n<ul>\n<li>比如:dubbo.application.name=foo等价于&lt;dubbo:application name=&quot;foo&quot; /&gt;</li>\n<li>比如:dubbo.registry.address=10.20.153.10:9090等价于&lt;dubbo:registry address=&quot;10.20.153.10:9090&quot; /&gt;</li>\n</ul>\n<p>如果 XML 有多行同名标签配置,可用 id 号区分,如果没有 id 号将对所有同名标签生效</p>\n<ul>\n<li>比如:dubbo.protocol.rmi.port=1234等价于&lt;dubbo:protocol id=&quot;rmi&quot; name=&quot;rmi&quot; port=&quot;1099&quot; /&gt; 2</li>\n<li>比如:dubbo.registry.china.address=10.20.153.10:9090等价于&lt;dubbo:registry id=&quot;china&quot; address=&quot;10.20.153.10:9090&quot; /&gt;</li>\n</ul>\n<h6>覆盖策略</h6>\n<p><img src=\"https://cdn.yuque.com/lark/0/2018/png/15841/1527849393591-2c3de248-1b3d-47d3-bd10-8b415e9fcd39.png\" alt=\"undefined\"></p>\n<ul>\n<li>JVM 启动 -D 参数优先,这样可以使用户在部署和启动时进行参数重写,比如在启动时需改变协议的端口。</li>\n<li>XML 次之,如果在 XML 中有配置,则 dubbo.properties 中的相应配置项无效。</li>\n<li>Properties 最后,相当于缺省值,只有 XML 没有配置时,dubbo.properties 的相应配置项才会生效,通常用于共享公共配置,比如应用名。</li>\n</ul>\n<blockquote>\n<p>注意:</p>\n</blockquote>\n<ol>\n<li>如果 classpath 根目录下存在多个 dubbo.properties,比如多个 jar 包中有 dubbo.properties,Dubbo 会任意加载,并打印 Error 日志,后续可能改为抛异常。 ↩</li>\n<li>协议的 id 没配时,缺省使用协议名作为 id</li>\n</ol>\n<h4>annotation</h4>\n<h6>Service注解暴露服务</h6>\n<pre><code>import com.alibaba.dubbo.config.annotation.Service;\n\n@Service(timeout = 5000)\npublic class AnnotateServiceImpl implements AnnotateService { \n    // ...\n}\n</code></pre>\n<h6>javaconfig形式配置公共模块</h6>\n<pre><code>@Configuration\npublic class DubboConfiguration {\n\n    @Bean\n    public ApplicationConfig applicationConfig() {\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(&quot;provider-test&quot;);\n        return applicationConfig;\n    }\n\n    @Bean\n    public RegistryConfig registryConfig() {\n        RegistryConfig registryConfig = new RegistryConfig();\n        registryConfig.setAddress(&quot;zookeeper://127.0.0.1:2181&quot;);\n        registryConfig.setClient(&quot;curator&quot;);\n        return registryConfig;\n    }\n}\n</code></pre>\n<p>这种方式的配置和前面用xml配置的方式是一样的效果。</p>\n<h6>指定dubbo扫描路径</h6>\n<pre><code>@SpringBootApplication\n@DubboComponentScan(basePackages = &quot;com.alibaba.dubbo.test.service.impl&quot;)\npublic class ProviderTestApp {\n    // ...\n}\n</code></pre>\n<p>或者使用spring bean xml配置方式:</p>\n<pre><code>&lt;dubbo:annotation package=&quot;com.chanshuyi.service.impl&quot; /&gt;\n</code></pre>\n<h4>api直接触发</h4>\n<pre><code>import com.alibaba.dubbo.rpc.config.ApplicationConfig;\nimport com.alibaba.dubbo.rpc.config.RegistryConfig;\nimport com.alibaba.dubbo.rpc.config.ProviderConfig;\nimport com.alibaba.dubbo.rpc.config.ServiceConfig;\nimport com.xxx.XxxService;\nimport com.xxx.XxxServiceImpl;\n\n// 服务实现\nXxxService xxxService = new XxxServiceImpl();\n\n// 当前应用配置\nApplicationConfig application = new ApplicationConfig();\napplication.setName(&quot;xxx&quot;);\n\n// 连接注册中心配置\nRegistryConfig registry = new RegistryConfig();\nregistry.setAddress(&quot;10.20.130.230:9090&quot;);\nregistry.setUsername(&quot;aaa&quot;);\nregistry.setPassword(&quot;bbb&quot;);\n\n// 服务提供者协议配置\nProtocolConfig protocol = new ProtocolConfig();\nprotocol.setName(&quot;dubbo&quot;);\nprotocol.setPort(12345);\nprotocol.setThreads(200);\n\n// 注意:ServiceConfig为重对象,内部封装了与注册中心的连接,以及开启服务端口\n\n// 服务提供者暴露服务配置\nServiceConfig&lt;XxxService&gt; service = new ServiceConfig&lt;XxxService&gt;(); // 此实例很重,封装了与注册中心的连接,请自行缓存,否则可能造成内存和连接泄漏\nservice.setApplication(application);\nservice.setRegistry(registry); // 多个注册中心可以用setRegistries()\nservice.setProtocol(protocol); // 多个协议可以用setProtocols()\nservice.setInterface(XxxService.class);\nservice.setRef(xxxService);\nservice.setVersion(&quot;1.0.0&quot;);\n\n// 暴露及注册服务\nservice.export();\n</code></pre>\n<p>一般在spring应用中,不推荐使用这种方式。 具体的含义这里不做解释,可以通过github查看源码。</p>\n<h3>Provider 接口和实现</h3>\n<p>上面章节更多从配置角度出发,接下来通过一个完整的例子,来讲解下dubbo provider的完整使用。</p>\n<p>这个例子中只有一个服务UserReadService,有一个方法 getUserById。 需要将这个服务通过Dubbo暴露给远程的服务。具体的步骤如下:</p>\n<p>1.创建工程\n如果本来已经有工程,可以忽略。创建一个spring boot工程,可以通过 <a href=\"https://start.spring.io/\">https://start.spring.io/</a> 创建。\n2.定义接口\n定义接口:UserReadService</p>\n<pre><code>public interface UserReadService{\npublic User getUserById(Long userId);\n}\n</code></pre>\n<p>这个接口一般来说会放到独立的jar包里,作为client包。 其他应用要消费这个服务的时候,一般来说需要应用引用这个client包。(除了泛化调用)\n3.实现接口\n实现UserReadService, 当前实现部署在Provider的应用中。</p>\n<pre><code>public UserReadServiceImpl implements UserReadService{\n    public User getUserById(Long userId){\n        return xxx;\n    }\n}\n</code></pre>\n<p>4.Dubbo配置</p>\n<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;\n&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;\n    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;\n    xmlns:dubbo=&quot;http://dubbo.apache.org/schema/dubbo&quot;\n    xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd&quot;&gt;  \n    &lt;dubbo:application name=&quot;hello-world-app&quot; /&gt;  \n    &lt;dubbo:registry address=&quot;multicast://224.5.6.7:1234&quot; /&gt;  \n    &lt;dubbo:protocol name=&quot;dubbo&quot; port=&quot;20880&quot; /&gt;  \n    &lt;bean id=&quot;userReadService&quot; class=&quot;com.package.UserReadServiceImpl&quot;/&gt;\n    &lt;dubbo:service interface=&quot;com.package.UserReadService&quot; ref=&quot;userReadService&quot; /&gt;  \n&lt;/beans&gt;\n</code></pre>\n<p>Dubbo配置的其他方式可以参考上一章节的相关配置,或者使用集成dubbo spring boot starter方式。</p>\n"
     },
+    {
+      "filename": "dubbo-meetup-shanghai-jun-23rd-2018.md",
+      "__html": "<h2>第二届Dubbo开发者沙龙在上海成功举办</h2>\n<p>第二届Dubbo开发者沙龙在上海成功举办,超过700位开发者报名,现场参与人数300+,通过阿里云天池、云栖社区、大咖说引导线上直播观看次数10000+</p>\n<p>分享嘉宾及PPT:</p>\n<ul>\n<li>朱勇: Dubbo开源现状与未来规划 (中文) <a href=\"https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/dubbo-status-and-roadmap.pdf\">slides</a></li>\n<li>小马哥: Dubbo Cloud Native 之路的实践与思考 (中文) <a href=\"https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/dubbo-cloud-native-practices-and-thoughts.pdf\">slides</a></li>\n<li>郭平: Nacos - 贡献Dubbo生态,阿里巴巴注册中心和配置中心开源计划 (中文) <a href=\"https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/nacos-open-source-initiative.pdf\">slides</a></li>\n<li>潘志伟: Dubbo在互金行业的应用场景 (中文) <a href=\"https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/dubbo-practices-on-internet-finance-industries.pdf\">slides</a></li>\n</ul>\n"
+    },
     {
       "filename": "introduction-to-dubbo-spi-2.md",
       "__html": "<h1>Dubbo可扩展机制源码解析</h1>\n<hr>\n<p>在<a href=\"#/blog/introduction-to-dubbo-spi.md\">Dubbo可扩展机制实战</a>中,我们了解了Dubbo扩展机制的一些概念,初探了Dubbo中LoadBalance的实现,并自己实现了一个LoadBalance。是不是觉得Dubbo的扩展机制很不错呀,接下来,我们就深入Dubbo的源码,一睹庐山真面目。</p>\n<h1>ExtensionLoader</h1>\n<p>ExtentionLoader是最核心的类,负责扩展点的加载和生命周期管理。我们就以这个类开始吧。\nExtension的方法比较多,比较常用的方法有:</p>\n<ul>\n<li><code>public static &lt;T&gt; ExtensionLoader&lt;T&gt; getExtensionLoader(Class&lt;T&gt; type)</code></li>\n<li><code>public T getExtension(String name)</code></li>\n<li><code>public T getAdaptiveExtension()</code></li>\n</ul>\n<p>比较常见的用法有:</p>\n<ul>\n<li><code>LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(loadbalanceName)</code></li>\n<li><code>RouterFactory routerFactory = ExtensionLoader.getExtensionLoader(RouterFactory.class).getAdaptiveExtension()</code></li>\n</ul>\n<p>说明:在接下来展示的源码中,我会将无关的代码(比如日志,异常捕获等)去掉,方便大家阅读和理解。</p>\n<ol>\n<li>getExtensionLoader方法\n这是一个静态工厂方法,入参是一个可扩展的接口,返回一个该接口的ExtensionLoader实体类。通过这个实体类,可以根据name获得具体的扩展,也可以获得一个自适应扩展。</li>\n</ol>\n<pre><code class=\"language-java\"><span class=\"hljs-keyword\">public</span> <span class=\"hljs-keyword\">static</span> &lt;T&gt; <span class=\"hljs-function\">ExtensionLoader&lt;T&gt; <span class=\"hljs-title\">getExtensionLoader</span><span class=\"hljs-params\">(Class&lt;T&gt; type)</span> </span>{\n        <span class=\"hljs-comment\">// 扩展点必须是接口</span>\n        <span class=\"hljs-keyword\">if</span> (!type.isInterface()) {\n            <span class=\"hljs-keyword\">throw</span> <span class=\"hljs-keyword\">new</span> IllegalArgumentException(<span class=\"hljs-string\">\"Extension type(\"</span> + type + <span class=\"hljs-string\">\") is not interface!\"</span>);\n        }\n        <span class=\"hljs-comment\">// 必须要有@SPI注解</span>\n        <span class=\"hljs-keyword\">if</span> (!withExtensionAnnotation(type)) {\n            <span class=\"hljs-keyword\">throw</span> <span class=\"hljs-keyword\">new</span> IllegalArgumentException(<span class=\"hljs-string\">\"Extension type without @SPI Annotation!\"</span>);\n        }\n        <span class=\"hljs-comment\">// 从缓存中根据接口获取对应的ExtensionLoader</span>\n        <span class=\"hljs-comment\">// 每个扩展只会被加载一次</span>\n        ExtensionLoader&lt;T&gt; loader = (ExtensionLoader&lt;T&gt;) EXTENSION_LOADERS.get(type);\n        <span class=\"hljs-keyword\">if</span> (loader == <span class=\"hljs-keyword\">null</span>) {\n            <span class=\"hljs-comment\">// 初始化扩展</span>\n            EXTENSION_LOADERS.putIfAbsent(type, <span class=\"hljs-keyword\">new</span> ExtensionLoader&lt;T&gt;(type));\n            loader = (ExtensionLoader&lt;T&gt;) EXTENSION_LOADERS.get(type);\n        }\n        <span class=\"hljs-keyword\">return</span> loader;\n    }\n    \n<span class=\"hljs-function\"><span class=\"hljs-keyword\">private</span> <span class=\"hljs-title\">ExtensionLoader</span><span class=\"hljs-params\">(Class&lt;?&gt; type)</span> </span>{\n        <span class=\"hljs-keyword\">this</span>.type = type;\n        objectFactory = (type == ExtensionFactory.class ? <span class=\"hljs-keyword\">null</span> : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());\n    }\n</code></pre>\n<ol start=\"2\">\n<li>getExtension方法</li>\n</ol>\n<pre><code class=\"language-java\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public</span> T <span class=\"hljs-title\">getExtension</span><span class=\"hljs-params\">(String name)</span> </span>{\n        Holder&lt;Object&gt; holder = cachedInstances.get(name);\n        <span class=\"hljs-keyword\">if</span> (holder == <span class=\"hljs-keyword\">null</span>) {\n            cachedInstances.putIfAbsent(name, <span class=\"hljs-keyword\">new</span> Holder&lt;Object&gt;());\n            holder = cachedInstances.get(name);\n        }\n        Object instance = holder.get();\n        <span class=\"hljs-comment\">// 从缓存中获取,如果不存在就创建</span>\n        <span class=\"hljs-keyword\">if</span> (instance == <span class=\"hljs-keyword\">null</span>) {\n            <span class=\"hljs-keyword\">synchronized</span> (holder) {\n                instance = holder.get();\n                <span class=\"hljs-keyword\">if</span> (instance == <span class=\"hljs-keyword\">null</span>) {\n                    instance = createExtension(name);\n                    holder.set(instance);\n                }\n            }\n        }\n        <span class=\"hljs-keyword\">return</span> (T) instance;\n    }\n</code></pre>\n<p>getExtention方法中做了一些判断和缓存,主要的逻辑在createExtension方法中。我们继续看createExtention方法。</p>\n<pre><code class=\"language-java\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">private</span> T <span class=\"hljs-title\">createExtension</span><span class=\"hljs-params\">(String name)</span> </span>{\n        <span class=\"hljs-comment\">// 根据扩展点名称得到扩展类,比如对于LoadBalance,根据random得到RandomLoadBalance类</span>\n        Class&lt;?&gt; clazz = getExtensionClasses().get(name);\n        \n        T instance = (T) EXTENSION_INSTANCES.get(clazz);\n        <span class=\"hljs-keyword\">if</span> (instance == <span class=\"hljs-keyword\">null</span>) {\n              <span class=\"hljs-comment\">// 使用反射调用nesInstance来创建扩展类的一个示例</span>\n            EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());\n            instance = (T) EXTENSION_INSTANCES.get(clazz);\n        }\n        <span class=\"hljs-comment\">// 对扩展类示例进行依赖注入</span>\n        injectExtension(instance);\n        <span class=\"hljs-comment\">// 如果有wrapper,添加wrapper</span>\n        Set&lt;Class&lt;?&gt;&gt; wrapperClasses = cachedWrapperClasses;\n        <span class=\"hljs-keyword\">if</span> (wrapperClasses != <span class=\"hljs-keyword\">null</span> &amp;&amp; !wrapperClasses.isEmpty()) {\n            <span class=\"hljs-keyword\">for</span> (Class&lt;?&gt; wrapperClass : wrapperClasses) {\n                instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));\n            }\n        }\n        <span class=\"hljs-keyword\">return</span> instance;\n}\n</code></pre>\n<p>createExtension方法做了以下事情:</p>\n<ol>\n<li>先根据name来得到对应的扩展类。从ClassPath下<code>META-INF</code>文件夹下读取扩展点配置文件。</li>\n<li>使用反射创建一个扩展类的实例</li>\n<li>对扩展类实例的属性进行依赖注入,即IoC。</li>\n<li>如果有wrapper,添加wrapper。即AoP。</li>\n</ol>\n<p>下面我们来重点看下这4个过程</p>\n<ol>\n<li>根据name获取对应的扩展类\n先看代码:</li>\n</ol>\n<pre><code class=\"language-java\"><span class=\"hljs-keyword\">private</span> Map&lt;String, Class&lt;?&gt;&gt; getExtensionClasses() {\n        Map&lt;String, Class&lt;?&gt;&gt; classes = cachedClasses.get();\n        <span class=\"hljs-keyword\">if</span> (classes == <span class=\"hljs-keyword\">null</span>) {\n            <span class=\"hljs-keyword\">synchronized</span> (cachedClasses) {\n                classes = cachedClasses.get();\n                <span class=\"hljs-keyword\">if</span> (classes == <span class=\"hljs-keyword\">null</span>) {\n                    classes = loadExtensionClasses();\n                    cachedClasses.set(classes);\n                }\n            }\n        }\n        <span class=\"hljs-keyword\">return</span> classes;\n    }\n\n    <span class=\"hljs-comment\">// synchronized in getExtensionClasses</span>\n    <span class=\"hljs-keyword\">private</span> Map&lt;String, Class&lt;?&gt;&gt; loadExtensionClasses() {\n        <span class=\"hljs-keyword\">final</span> SPI defaultAnnotation = type.getAnnotation(SPI.class);\n        <span class=\"hljs-keyword\">if</span> (defaultAnnotation != <span class=\"hljs-keyword\">null</span>) {\n            String value = defaultAnnotation.value();\n            <span class=\"hljs-keyword\">if</span> (value != <span class=\"hljs-keyword\">null</span> &amp;&amp; (value = value.trim()).length() &gt; <span class=\"hljs-number\">0</span>) {\n                String[] names = NAME_SEPARATOR.split(value);\n                <span class=\"hljs-keyword\">if</span> (names.length &gt; <span class=\"hljs-number\">1</span>) {\n                    <span class=\"hljs-keyword\">throw</span> <span class=\"hljs-keyword\">new</span> IllegalStateException(<span class=\"hljs-string\">\"more than 1 default extension name on extension \"</span> + type.getName());\n                }\n                <span class=\"hljs-keyword\">if</span> (names.length == <span class=\"hljs-number\">1</span>) cachedDefaultName = names[<span class=\"hljs-number\">0</span>];\n            }\n        }\n\n        Map&lt;String, Class&lt;?&gt;&gt; extensionClasses = <span class=\"hljs-keyword\">new</span> HashMap&lt;String, Class&lt;?&gt;&gt;();\n        loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);\n        loadFile(extensionClasses, DUBBO_DIRECTORY);\n        loadFile(extensionClasses, SERVICES_DIRECTORY);\n        <span class=\"hljs-keyword\">return</span> extensionClasses;\n    }\n</code></pre>\n<p>过程很简单,先从缓存中获取,如果没有,就从配置文件中加载。配置文件的路径就是之前提到的:</p>\n<ul>\n<li><code>META-INF/dubbo/internal</code></li>\n<li><code>META-INF/dubbo</code></li>\n<li><code>META-INF/services</code></li>\n</ul>\n<ol start=\"2\">\n<li>使用反射创建扩展实例\n这个过程很简单,使用<code>clazz.newInstance())</code>来完成。创建的扩展实例的属性都是空值。</li>\n<li>扩展实例自动装配\n在实际的场景中,类之间都是有依赖的。扩展实例中也会引用一些依赖,比如简单的Java类,另一个Dubbo的扩展或一个Spring Bean等。依赖的情况很复杂,Dubbo的处理也相对复杂些。我们稍后会有专门的章节对其进行说明,现在,我们只需要知道,Dubbo可以正确的注入扩展点中的普通依赖,Dubbo扩展依赖或Spring依赖等。</li>\n<li>扩展实例自动包装\n自动包装就是要实现类似于Spring的AOP功能。Dubbo利用它在内部实现一些通用的功能,比如日志,监控等。关于扩展实例自动包装的内容,也会在后面单独讲解。</li>\n</ol>\n<p>经过上面的4步,Dubbo就创建并初始化了一个扩展实例。这个实例的依赖被注入了,也根据需要被包装了。到此为止,这个扩展实例就可以被使用了。</p>\n<h1>Dubbo SPI高级用法之自动装配</h1>\n<p>自动装配的相关代码在injectExtension方法中:</p>\n<pre><code class=\"language-java\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">private</span> T <span class=\"hljs-title\">injectExtension</span><span class=\"hljs-params\">(T instance)</span> </span>{\n    <span class=\"hljs-keyword\">for</span> (Method method : instance.getClass().getMethods()) {\n        <span class=\"hljs-keyword\">if</span> (method.getName().startsWith(<span class=\"hljs-string\">\"set\"</span>)\n                &amp;&amp; method.getParameterTypes().length == <span class=\"hljs-number\">1</span>\n                &amp;&amp; Modifier.isPublic(method.getModifiers())) {\n            Class&lt;?&gt; pt = method.getParameterTypes()[<span class=\"hljs-number\">0</span>];\n          \n            String property = method.getName().length() &gt; <span class=\"hljs-number\">3</span> ? method.getName().substring(<span class=\"hljs-number\">3</span>, <span class=\"hljs-number\">4</span>).toLowerCase() + method.getName().substring(<span class=\"hljs-number\">4</span>) : <span class=\"hljs-string\">\"\"</span>;\n            Object object = objectFactory.getExtension(pt, property);\n            <span class=\"hljs-keyword\">if</span> (object != <span class=\"hljs-keyword\">null</span>) {\n                method.invoke(instance, object);\n            }\n        }\n    }\n    <span class=\"hljs-keyword\">return</span> instance;\n}\n</code></pre>\n<p>要实现对扩展实例的依赖的自动装配,首先需要知道有哪些依赖,这些依赖的类型是什么。Dubbo的方案是查找Java标准的setter方法。即方法名以set开始,只有一个参数。如果扩展类中有这样的set方法,Dubbo会对其进行依赖注入,类似于Spring的set方法注入。\n但是Dubbo中的依赖注入比Spring要复杂,因为Spring注入的都是Spring bean,都是由Spring容器来管理的。而Dubbo的依赖注入中,需要注入的可能是另一个Dubbo的扩展,也可能是一个Spring Bean,或是Google guice的组件,或其他任何一个框架中的组件。Dubbo需要能够从任何一个场景中加载扩展。在injectExtension方法中,是用<code>Object object = objectFactory.getExtension(pt, property)</code>来实现的。objectFactory是ExtensionFactory类型的,在创建ExtensionLoader时被初始化:</p>\n<pre><code class=\"language-java\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">private</span> <span class=\"hljs-title\">ExtensionLoader</span><span class=\"hljs-params\">(Class&lt;?&gt; type)</span> </span>{\n        <span class=\"hljs-keyword\">this</span>.type = type;\n        objectFactory = (type == ExtensionFactory.class ? <span class=\"hljs-keyword\">null</span> : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());\n    }\n</code></pre>\n<p>objectFacory本身也是一个扩展,通过<code>ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension())</code>来获取。</p>\n<p><img src=\"https://raw.githubusercontent.com/vangoleo/wiki/master/dubbo/dubbo-extensionfactory.png\" alt=\"Dubbo-ExtensionFactory | left\"></p>\n<p>ExtensionLoader有三个实现:</p>\n<ol>\n<li>SpiExtensionLoader:Dubbo自己的Spi去加载Extension</li>\n<li>SpringExtensionLoader:从Spring容器中去加载Extension</li>\n<li>AdaptiveExtensionLoader: 自适应的AdaptiveExtensionLoader</li>\n</ol>\n<p>这里要注意AdaptiveExtensionLoader,源码如下:</p>\n<pre><code class=\"language-java\"><span class=\"hljs-meta\">@Adaptive</span>\n<span class=\"hljs-keyword\">public</span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class</span> <span class=\"hljs-title\">AdaptiveExtensionFactory</span> <span class=\"hljs-keyword\">implements</span> <span class=\"hljs-title\">ExtensionFactory</span> </span>{\n\n    <span class=\"hljs-keyword\">private</span> <span class=\"hljs-keyword\">final</span> List&lt;ExtensionFactory&gt; factories;\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public</span> <span class=\"hljs-title\">AdaptiveExtensionFactory</span><span class=\"hljs-params\">()</span> </span>{\n        ExtensionLoader&lt;ExtensionFactory&gt; loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);\n        List&lt;ExtensionFactory&gt; list = <span class=\"hljs-keyword\">new</span> ArrayList&lt;ExtensionFactory&gt;();\n        <span class=\"hljs-keyword\">for</span> (String name : loader.getSupportedExtensions()) {\n            list.add(loader.getExtension(name));\n        }\n        factories = Collections.unmodifiableList(list);\n    }\n\n    <span class=\"hljs-keyword\">public</span> &lt;T&gt; <span class=\"hljs-function\">T <span class=\"hljs-title\">getExtension</span><span class=\"hljs-params\">(Class&lt;T&gt; type, String name)</span> </span>{\n        <span class=\"hljs-keyword\">for</span> (ExtensionFactory factory : factories) {\n            T extension = factory.getExtension(type, name);\n            <span class=\"hljs-keyword\">if</span> (extension != <span class=\"hljs-keyword\">null</span>) {\n                <span class=\"hljs-keyword\">return</span> extension;\n            }\n        }\n        <span class=\"hljs-keyword\">return</span> <span class=\"hljs-keyword\">null</span>;\n    }\n}\n</code></pre>\n<p>AdaptiveExtensionLoader类有@Adaptive注解。前面提到了,Dubbo会为每一个扩展创建一个自适应实例。如果扩展类上有@Adaptive,会使用该类作为自适应类。如果没有,Dubbo会为我们创建一个。所以<code>ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension())</code>会返回一个AdaptiveExtensionLoader实例,作为自适应扩展实例。\nAdaptiveExtentionLoader会遍历所有的ExtensionFactory实现,尝试着去加载扩展。如果找到了,返回。如果没有,在下一个ExtensionFactory中继续找。Dubbo内置了两个ExtensionFactory,分别从Dubbo自身的扩展机制和Spring容器中去寻找。由于ExtensionFactory本身也是一个扩展点,我们可以实现自己的ExtensionFactory,让Dubbo的自动装配支持我们自定义的组件。比如,我们在项目中使用了Google的guice这个IoC容器。我们可以实现自己的GuiceExtensionFactory,让Dubbo支持从guice容器中加载扩展。</p>\n<h1>Dubbo SPI高级用法之AoP</h1>\n<p>在用Spring的时候,我们经常会用到AOP功能。在目标类的方法前后插入其他逻辑。比如通常使用Spring AOP来实现日志,监控和鉴权等功能。\nDubbo的扩展机制,是否也支持类似的功能呢?答案是yes。在Dubbo中,有一种特殊的类,被称为Wrapper类。通过装饰者模式,使用包装类包装原始的扩展点实例。在原始扩展点实现前后插入其他逻辑,实现AOP功能。</p>\n<h3>什么是Wrapper类</h3>\n<p>那什么样类的才是Dubbo扩展机制中的Wrapper类呢?Wrapper类是一个有复制构造函数的类,也是典型的装饰者模式。下面就是一个Wrapper类:</p>\n<pre><code class=\"language-java\"><span class=\"hljs-class\"><span class=\"hljs-keyword\">class</span> <span class=\"hljs-title\">A</span></span>{\n    <span class=\"hljs-keyword\">private</span> A a;\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public</span> <span class=\"hljs-title\">A</span><span class=\"hljs-params\">(A a)</span></span>{\n        <span class=\"hljs-keyword\">this</span>.a = a;\n    }\n}\n</code></pre>\n<p>类A有一个构造函数<code>public A(A a)</code>,构造函数的参数是A本身。这样的类就可以成为Dubbo扩展机制中的一个Wrapper类。Dubbo中这样的Wrapper类有ProtocolFilterWrapper, ProtocolListenerWrapper等, 大家可以查看源码加深理解。</p>\n<h3>怎么配置Wrapper类</h3>\n<p>在Dubbo中Wrapper类也是一个扩展点,和其他的扩展点一样,也是在<code>META-INF</code>文件夹中配置的。比如前面举例的ProtocolFilterWrapper和ProtocolListenerWrapper就是在路径<code>dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol</code>中配置的:</p>\n<pre><code class=\"language-text\">filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper\nlistener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper\nmock=com.alibaba.dubbo.rpc.support.MockProtocol\n</code></pre>\n<p>在Dubbo加载扩展配置文件时,有一段如下的代码:</p>\n<pre><code class=\"language-java\"><span class=\"hljs-keyword\">try</span> {  \n  clazz.getConstructor(type);    \n  Set&lt;Class&lt;?&gt;&gt; wrappers = cachedWrapperClasses;\n  <span class=\"hljs-keyword\">if</span> (wrappers == <span class=\"hljs-keyword\">null</span>) {\n    cachedWrapperClasses = <span class=\"hljs-keyword\">new</span> ConcurrentHashSet&lt;Class&lt;?&gt;&gt;();\n    wrappers = cachedWrapperClasses;\n  }\n  wrappers.add(clazz);\n} <span class=\"hljs-keyword\">catch</span> (NoSuchMethodException e) {}\n</code></pre>\n<p>这段代码的意思是,如果扩展类有复制构造函数,就把该类存起来,供以后使用。有复制构造函数的类就是Wrapper类。通过<code>clazz.getConstructor(type)</code>来获取参数是扩展点接口的构造函数。注意构造函数的参数类型是扩展点接口,而不是扩展类。\n以Protocol为例。配置文件<code>dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol</code>中定义了<code>filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper</code>。\nProtocolFilterWrapper代码如下:</p>\n<pre><code class=\"language-java\"><span class=\"hljs-keyword\">public</span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class</span> <span class=\"hljs-title\">ProtocolFilterWrapper</span> <span class=\"hljs-keyword\">implements</span> <span class=\"hljs-title\">Protocol</span> </span>{\n\n    <span class=\"hljs-keyword\">private</span> <span class=\"hljs-keyword\">final</span> Protocol protocol;\n\n    <span class=\"hljs-comment\">// 有一个参数是Protocol的复制构造函数</span>\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public</span> <span class=\"hljs-title\">ProtocolFilterWrapper</span><span class=\"hljs-params\">(Protocol protocol)</span> </span>{\n        <span class=\"hljs-keyword\">if</span> (protocol == <span class=\"hljs-keyword\">null</span>) {\n            <span class=\"hljs-keyword\">throw</span> <span class=\"hljs-keyword\">new</span> IllegalArgumentException(<span class=\"hljs-string\">\"protocol == null\"</span>);\n        }\n        <span class=\"hljs-keyword\">this</span>.protocol = protocol;\n    }\n</code></pre>\n<p>ProtocolFilterWrapper有一个构造函数<code>public ProtocolFilterWrapper(Protocol protocol)</code>,参数是扩展点Protocol,所以它是一个Dubbo扩展机制中的Wrapper类。ExtensionLoader会把它缓存起来,供以后创建Extension实例的时候,使用这些包装类依次包装原始扩展点。</p>\n<h1>扩展点自适应</h1>\n<p>前面讲到过,Dubbo需要在运行时根据方法参数来决定该使用哪个扩展,所以有了扩展点自适应实例。其实是一个扩展点的代理,将扩展的选择从Dubbo启动时,延迟到RPC调用时。Dubbo中每一个扩展点都有一个自适应类,如果没有显式提供,Dubbo会自动为我们创建一个,默认使用Javaassist。\n先来看下创建自适应扩展类的代码:</p>\n<pre><code class=\"language-java\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public</span> T <span class=\"hljs-title\">getAdaptiveExtension</span><span class=\"hljs-params\">()</span> </span>{\n    Object instance = cachedAdaptiveInstance.get();\n    <span class=\"hljs-keyword\">if</span> (instance == <span class=\"hljs-keyword\">null</span>) {\n            <span class=\"hljs-keyword\">synchronized</span> (cachedAdaptiveInstance) {\n                instance = cachedAdaptiveInstance.get();\n                <span class=\"hljs-keyword\">if</span> (instance == <span class=\"hljs-keyword\">null</span>) {\n                      instance = createAdaptiveExtension();\n                      cachedAdaptiveInstance.set(instance); \n                }\n            }        \n    }\n\n    <span class=\"hljs-keyword\">return</span> (T) instance;\n}\n</code></pre>\n<p>继续看createAdaptiveExtension方法</p>\n<pre><code class=\"language-java\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">private</span> T <span class=\"hljs-title\">createAdaptiveExtension</span><span class=\"hljs-params\">()</span> </span>{        \n    <span class=\"hljs-keyword\">return</span> injectExtension((T) getAdaptiveExtensionClass().newInstance());\n}\n</code></pre>\n<p>继续看getAdaptiveExtensionClass方法</p>\n<pre><code class=\"language-java\"><span class=\"hljs-keyword\">private</span> Class&lt;?&gt; getAdaptiveExtensionClass() {\n        getExtensionClasses();\n        <span class=\"hljs-keyword\">if</span> (cachedAdaptiveClass != <span class=\"hljs-keyword\">null</span>) {\n            <span class=\"hljs-keyword\">return</span> cachedAdaptiveClass;\n        }\n        <span class=\"hljs-keyword\">return</span> cachedAdaptiveClass = createAdaptiveExtensionClass();\n    }\n</code></pre>\n<p>继续看createAdaptiveExtensionClass方法,绕了一大圈,终于来到了具体的实现了。看这个createAdaptiveExtensionClass方法,它首先会生成自适应类的Java源码,然后再将源码编译成Java的字节码,加载到JVM中。</p>\n<pre><code class=\"language-java\"><span class=\"hljs-keyword\">private</span> Class&lt;?&gt; createAdaptiveExtensionClass() {\n        String code = createAdaptiveExtensionClassCode();\n        ClassLoader classLoader = findClassLoader();\n        com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();\n        <span class=\"hljs-keyword\">return</span> compiler.compile(code, classLoader);\n    }\n</code></pre>\n<p>Compiler的代码,默认实现是javassist。</p>\n<pre><code class=\"language-java\"><span class=\"hljs-meta\">@SPI</span>(<span class=\"hljs-string\">\"javassist\"</span>)\n<span class=\"hljs-keyword\">public</span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">interface</span> <span class=\"hljs-title\">Compiler</span> </span>{\n    Class&lt;?&gt; compile(String code, ClassLoader classLoader);\n}\n</code></pre>\n<p>createAdaptiveExtensionClassCode()方法中使用一个StringBuilder来构建自适应类的Java源码。方法实现比较长,这里就不贴代码了。这种生成字节码的方式也挺有意思的,先生成Java源代码,然后编译,加载到jvm中。通过这种方式,可以更好的控制生成的Java类。而且这样也不用care各个字节码生成框架的api等。因为xxx.java文件是Java通用的,也是我们最熟悉的。只是代码的可读性不强,需要一点一点构建xx.java的内容。\n下面是使用createAdaptiveExtensionClassCode方法为Protocol创建的自适应类的Java代码范例:</p>\n<pre><code class=\"language-java\"><span class=\"hljs-keyword\">package</span> com.alibaba.dubbo.rpc;\n\n<span class=\"hljs-keyword\">import</span> com.alibaba.dubbo.common.extension.ExtensionLoader;\n\n<span class=\"hljs-keyword\">public</span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class</span> <span class=\"hljs-title\">Protocol</span>$<span class=\"hljs-title\">Adpative</span> <span class=\"hljs-keyword\">implements</span> <span class=\"hljs-title\">com</span>.<span class=\"hljs-title\">alibaba</span>.<span class=\"hljs-title\">dubbo</span>.<span class=\"hljs-title\">rpc</span>.<span class=\"hljs-title\">Protocol</span> </span>{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public</span> <span class=\"hljs-keyword\">void</span> <span class=\"hljs-title\">destroy</span><span class=\"hljs-params\">()</span> </span>{\n        <span class=\"hljs-keyword\">throw</span> <span class=\"hljs-keyword\">new</span> UnsupportedOperationException(<span class=\"hljs-string\">\"method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!\"</span>);\n    }\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public</span> <span class=\"hljs-keyword\">int</span> <span class=\"hljs-title\">getDefaultPort</span><span class=\"hljs-params\">()</span> </span>{\n        <span class=\"hljs-keyword\">throw</span> <span class=\"hljs-keyword\">new</span> UnsupportedOperationException(<span class=\"hljs-string\">\"method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!\"</span>);\n    }\n\n    <span class=\"hljs-keyword\">public</span> com.alibaba.dubbo.rpc.<span class=\"hljs-function\">Exporter <span class=\"hljs-title\">export</span><span class=\"hljs-params\">(com.alibaba.dubbo.rpc.Invoker arg0)</span> <span class=\"hljs-keyword\">throws</span> com.alibaba.dubbo.rpc.RpcException </span>{\n        <span class=\"hljs-keyword\">if</span> (arg0 == <span class=\"hljs-keyword\">null</span>) <span class=\"hljs-keyword\">throw</span> <span class=\"hljs-keyword\">new</span> IllegalArgumentException(<span class=\"hljs-string\">\"com.alibaba.dubbo.rpc.Invoker argument == null\"</span>);\n        <span class=\"hljs-keyword\">if</span> (arg0.getUrl() == <span class=\"hljs-keyword\">null</span>)\n            <span class=\"hljs-keyword\">throw</span> <span class=\"hljs-keyword\">new</span> IllegalArgumentException(<span class=\"hljs-string\">\"com.alibaba.dubbo.rpc.Invoker argument getUrl() == null\"</span>);\n        com.alibaba.dubbo.common.URL url = arg0.getUrl();\n        String extName = (url.getProtocol() == <span class=\"hljs-keyword\">null</span> ? <span class=\"hljs-string\">\"dubbo\"</span> : url.getProtocol());\n        <span class=\"hljs-keyword\">if</span> (extName == <span class=\"hljs-keyword\">null</span>)\n            <span class=\"hljs-keyword\">throw</span> <span class=\"hljs-keyword\">new</span> IllegalStateException(<span class=\"hljs-string\">\"Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(\"</span> + url.toString() + <span class=\"hljs-string\">\") use keys([protocol])\"</span>);\n        com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);\n        <span class=\"hljs-keyword\">return</span> extension.export(arg0);\n    }\n\n    <span class=\"hljs-keyword\">public</span> com.alibaba.dubbo.rpc.<span class=\"hljs-function\">Invoker <span class=\"hljs-title\">refer</span><span class=\"hljs-params\">(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1)</span> <span class=\"hljs-keyword\">throws</span> com.alibaba.dubbo.rpc.RpcException </span>{\n        <span class=\"hljs-keyword\">if</span> (arg1 == <span class=\"hljs-keyword\">null</span>) <span class=\"hljs-keyword\">throw</span> <span class=\"hljs-keyword\">new</span> IllegalArgumentException(<span class=\"hljs-string\">\"url == null\"</span>);\n        com.alibaba.dubbo.common.URL url = arg1;\n        String extName = (url.getProtocol() == <span class=\"hljs-keyword\">null</span> ? <span class=\"hljs-string\">\"dubbo\"</span> : url.getProtocol());\n        <span class=\"hljs-keyword\">if</span> (extName == <span class=\"hljs-keyword\">null</span>)\n            <span class=\"hljs-keyword\">throw</span> <span class=\"hljs-keyword\">new</span> IllegalStateException(<span class=\"hljs-string\">\"Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(\"</span> + url.toString() + <span class=\"hljs-string\">\") use keys([protocol])\"</span>);\n        com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);\n        <span class=\"hljs-keyword\">return</span> extension.refer(arg0, arg1);\n    }\n}\n</code></pre>\n<p>大致的逻辑和开始说的一样,通过url解析出参数,解析的逻辑由@Adaptive的value参数控制,然后再根据得到的扩展点名获取扩展点实现,然后进行调用。如果大家想知道具体的构建.java代码的逻辑,可以看<code>createAdaptiveExtensionClassCode</code>的完整实现。\n在生成的Protocol$Adpative中,发现getDefaultPort和destroy方法都是直接抛出异常的,这是为什么呢?来看看Protocol的源码</p>\n<pre><code class=\"language-java\"><span class=\"hljs-meta\">@SPI</span>(<span class=\"hljs-string\">\"dubbo\"</span>)\n<span class=\"hljs-keyword\">public</span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">interface</span> <span class=\"hljs-title\">Protocol</span> </span>{\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">int</span> <span class=\"hljs-title\">getDefaultPort</span><span class=\"hljs-params\">()</span></span>;\n\n    <span class=\"hljs-meta\">@Adaptive</span>\n    &lt;T&gt; <span class=\"hljs-function\">Exporter&lt;T&gt; <span class=\"hljs-title\">export</span><span class=\"hljs-params\">(Invoker&lt;T&gt; invoker)</span> <span class=\"hljs-keyword\">throws</span> RpcException</span>;\n\n    <span class=\"hljs-meta\">@Adaptive</span>\n    &lt;T&gt; <span class=\"hljs-function\">Invoker&lt;T&gt; <span class=\"hljs-title\">refer</span><span class=\"hljs-params\">(Class&lt;T&gt; type, URL url)</span> <span class=\"hljs-keyword\">throws</span> RpcException</span>;\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">void</span> <span class=\"hljs-title\">destroy</span><span class=\"hljs-params\">()</span></span>;\n</code></pre>\n<p>可以看到Protocol接口中有4个方法,但只有export和refer两个方法使用了@Adaptive注解。Dubbo自动生成的自适应实例,只有@Adaptive修饰的方法才有具体的实现。所以,Protocol$Adpative类中,也只有export和refer这两个方法有具体的实现,其余方法都是抛出异常。</p>\n"
@@ -34,6 +38,10 @@
       "filename": "dubbo-meetup-beijing-may-12th-2018.md",
       "__html": "<h2>The first Dubbo meetup has been held in Beijing</h2>\n<p>The first Dubbo meetup has successfully been held in Beijing, over 400+ people were present. What a great event!</p>\n<p>Please enjoy the slides of the topics:</p>\n<ul>\n<li>Ian Luo: Dubbo's present and future (Chinese) <a href=\"https://github.com/dubbo/awesome-dubbo/raw/master/slides/meetup/201805%40Beijing/dubbo-present-and-future.pdf\">slides</a></li>\n<li>Jun Liu: Introduction to the 4th Aliware Performance Challenge (Chinese) <a href=\"https://github.com/dubbo/awesome-dubbo/raw/master/slides/meetup/201805%40Beijing/introduction-to-4th-aliware-performance-challenge.pdf\">slides</a></li>\n<li>Zhixuan Chen: Quickly building Microservice with Dubbo and Spring-boot (Chinese) <a href=\"https://github.com/dubbo/awesome-dubbo/raw/master/slides/meetup/201805%40Beijing/quickly-building-microservice-with-dubbo-and-springboot.pdf\">slides</a></li>\n<li>Xin Wang: Dubbo and Weidian's Practice on Microservice Architecture (Chinese) <a href=\"https://github.com/dubbo/awesome-dubbo/raw/master/slides/meetup/201805%40Beijing/dubbo-and-weidian's-practice-on-microservice-architecture.pdf\">slides</a></li>\n</ul>\n"
     },
+    {
+      "filename": "dubbo-meetup-shanghai-jun-23rd-2018.md",
+      "__html": "<h2>Dubbo Shanghai meetup has been held successfully</h2>\n<p>The sencond Dubbo meetup has successfully been held in Shanghai, over 700 people submitted registration, and over 300 were present, more than 10,000 watched the live online. A great event again!</p>\n<p>Please enjoy the slides of the topics:</p>\n<ul>\n<li>Jerrick Zhu: Dubbo Status and Roadmap (Chinese) <a href=\"https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/dubbo-status-and-roadmap.pdf\">slides</a></li>\n<li>Mercy Ma: Dubbo Cloud Native Practices and Thoughts (Chinese) <a href=\"https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/dubbo-cloud-native-practices-and-thoughts.pdf\">slides</a></li>\n<li>Ping Guo: Nacos Open Source Initiative (Chinese) <a href=\"https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/nacos-open-source-initiative.pdf\">slides</a></li>\n<li>Zhiwei Pan: Dubbo Practices on Internet Finance Industries (Chinese) <a href=\"https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/dubbo-practices-on-internet-finance-industries.pdf\">slides</a></li>\n</ul>\n"
+    },
     {
       "filename": "gsoc-2018.md",
       "__html": "<h2>The GSoC(Google Summer of Code) 2018 projects has been announced</h2>\n<p>The GSoC(Google Summer of Code) 2018 projects has been announced, Raghu Reddy's project &quot;Extending Serialization protocols support for Apache Dubbo&quot; has been <a href=\"https://summerofcode.withgoogle.com/projects/#4747840161579008\">accepted</a>! Congratulations!</p>\n"
diff --git a/site_config/community.jsx b/site_config/community.jsx
index 0b77156..b066ebd 100644
--- a/site_config/community.jsx
+++ b/site_config/community.jsx
@@ -6,6 +6,13 @@ export default {
     events: {
       title: 'Events & News',
       list: [
+        {
+          img: './img/blog/dubbo-shanghai-meetup.jpeg',
+          title: 'Dubbo Shanghai meetup has been held successfully',
+          content: 'The Dubbo meetup has successfully been held in Shanghai, over 700 people submitted registration, and over 300 were present, more than 10,000 watched the live online.',
+          dateStr: 'June 23rd,2018',
+          link: '/blog/dubbo-meetup-shanghai-jun-23rd-2018.md',
+        },
         {
           img: './img/blog/dubbo-beijing-meetup.png',
           title: 'The first Dubbo meetup has successfully been held in Beijing',
@@ -364,6 +371,13 @@ export default {
     events: {
       title: '事件 & 新闻',
       list: [
+        {
+          img: './img/blog/dubbo-shanghai-meetup.jpeg',
+          title: '第二届Dubbo开发者沙龙在上海成功举办',
+          content: '第二届Dubbo开发者沙龙在上海成功举办,超过700位开发者报名,现场参与人数300+,通过阿里云天池、云栖社区、大咖说引导线上直播观看次数10000+',
+          dateStr: 'Jun 23rd,2018',
+          link: '/blog/dubbo-meetup-shanghai-jun-23rd-2018.md',
+        },
         {
           img: './img/blog/dubbo-beijing-meetup.png',
           title: '首届Dubbo开发者沙龙在北京成功举办',


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org