This is an automated email from the ASF dual-hosted git repository.

wangxin pushed a commit to branch asf-site
in repository https://gitbox.apache.org/repos/asf/incubator-dubbo-website.git


The following commit(s) were added to refs/heads/asf-site by this push:
     new 55ff61b  genrate htmls
55ff61b is described below

commit 55ff61beba90e893b40055eadb00f063687ba7ac
Author: Xin Wang <xin.victorw...@gmail.com>
AuthorDate: Mon Mar 4 18:24:57 2019 +0800

    genrate htmls
---
 build/blog.js                                    |   2 +-
 en-us/blog/introduction-to-dubbo-spi-2.html      |  85 +++++++--------
 en-us/blog/introduction-to-dubbo-spi-2.json      |   2 +-
 en-us/docs/developers/developers_dev.html        |  13 +--
 en-us/docs/developers/developers_dev.json        |   2 +-
 md_json/blog.json                                |  32 ++++++
 zh-cn/blog/dubbo-admin.html                      |   2 +-
 zh-cn/blog/dubbo-admin.json                      |   2 +-
 zh-cn/blog/dubbo-echo-test.html                  | 111 +++++++++++++++++++
 zh-cn/blog/dubbo-echo-test.json                  |   6 ++
 zh-cn/blog/dubbo-gracefully-shutdown.html        | 130 +++++++++++++++++++++++
 zh-cn/blog/dubbo-gracefully-shutdown.json        |  10 ++
 zh-cn/blog/dubboAsync_client.html                | 102 ++++++++++++++++++
 zh-cn/blog/dubboAsync_client.json                |  10 ++
 zh-cn/blog/dubboAsync_server.html                | 103 ++++++++++++++++++
 zh-cn/blog/dubboAsync_server.json                |  10 ++
 zh-cn/blog/index.html                            |   2 +-
 zh-cn/blog/introduction-to-dubbo-spi-2.html      |  86 +++++++--------
 zh-cn/blog/introduction-to-dubbo-spi-2.json      |   2 +-
 zh-cn/docs/dev/principals/configuration.html     |  17 ++-
 zh-cn/docs/dev/principals/configuration.json     |   2 +-
 zh-cn/docs/developers/developers_dev.html        |  13 +--
 zh-cn/docs/developers/developers_dev.json        |   2 +-
 zh-cn/docs/source_code_guide/export-service.html |   2 +-
 zh-cn/docs/source_code_guide/export-service.json |   2 +-
 zh-cn/docs/source_code_guide/refer-service.html  |   8 +-
 zh-cn/docs/source_code_guide/refer-service.json  |   2 +-
 27 files changed, 645 insertions(+), 115 deletions(-)

diff --git a/build/blog.js b/build/blog.js
index b8388d7..e3be865 100644
--- a/build/blog.js
+++ b/build/blog.js
@@ -3,4 +3,4 @@
   Licensed under the MIT License (MIT), see
   http://jedwatson.github.io/classnames
 */
-!function(){"use strict";function n(){for(var 
e=[],t=0;t<arguments.length;t++){var r=arguments[t];if(r){var o=typeof 
r;if("string"===o||"number"===o)e.push(r);else 
if(Array.isArray(r)&&r.length){var a=n.apply(null,r);a&&e.push(a)}else 
if("object"===o)for(var u in r)i.call(r,u)&&r[u]&&e.push(u)}}return e.join(" 
")}var i={}.hasOwnProperty;void 
0!==e&&e.exports?(n.default=n,e.exports=n):(r=[],void 0!==(o=function(){return 
n}.apply(t,r))&&(e.exports=o))}()},function(e,t,n){"use strict";funct [...]
\ No newline at end of file
+!function(){"use strict";function n(){for(var 
e=[],t=0;t<arguments.length;t++){var r=arguments[t];if(r){var o=typeof 
r;if("string"===o||"number"===o)e.push(r);else 
if(Array.isArray(r)&&r.length){var a=n.apply(null,r);a&&e.push(a)}else 
if("object"===o)for(var u in r)i.call(r,u)&&r[u]&&e.push(u)}}return e.join(" 
")}var i={}.hasOwnProperty;void 
0!==e&&e.exports?(n.default=n,e.exports=n):(r=[],void 0!==(o=function(){return 
n}.apply(t,r))&&(e.exports=o))}()},function(e,t,n){"use strict";funct [...]
\ No newline at end of file
diff --git a/en-us/blog/introduction-to-dubbo-spi-2.html 
b/en-us/blog/introduction-to-dubbo-spi-2.html
index b50dd6f..6b8da10 100644
--- a/en-us/blog/introduction-to-dubbo-spi-2.html
+++ b/en-us/blog/introduction-to-dubbo-spi-2.html
@@ -13,10 +13,9 @@
 </head>
 <body>
        <div id="root"><div class="blog-detail-page" data-reactroot=""><header 
class="header-container header-container-normal"><div class="header-body"><a 
href="/en-us/index.html"><img class="logo" 
src="/img/dubbo_colorful.png"/></a><div class="search search-normal"><span 
class="icon-search"></span></div><span class="language-switch 
language-switch-normal">中</span><div class="header-menu"><img 
class="header-menu-toggle" src="/img/menu_gray.png"/><ul><li class="menu-item 
menu-item-normal"><a hr [...]
-<hr>
 <p>In the <a href="./introduction-to-dubbo-spi.md">actual implementation of 
the Dubbo extensibility mechanism</a>, we learned some concepts of the Dubbo 
extension mechanism, explored the implementation of LoadBalance in Dubbo, and 
implemented a LoadBalance on our own. Do you think Dubbo's extension mechanism 
is great? Next, we will go deep into the source code of Dubbo and see what it 
is.</p>
 <h2>ExtensionLoader</h2>
-<p><code>ExtentionLoader</code> is the core class, which is responsible for 
the loading and lifecycle management of extension points. Let's start with this 
class. There are many methods of Extension, and the common methods include:</p>
+<p><code>ExtensionLoader</code> is the core class, which is responsible for 
the loading and lifecycle management of extension points. Let's start with this 
class. There are many methods of Extension, and the common methods include:</p>
 <ul>
 <li><code>public static &lt;T&gt; ExtensionLoader&lt;T&gt; 
getExtensionLoader(Class&lt;T&gt; type)</code></li>
 <li><code>public T getExtension(String name)</code></li>
@@ -50,12 +49,12 @@ This is a static factory method that enters an extensible 
interface and returns
             loader = (ExtensionLoader&lt;T&gt;) EXTENSION_LOADERS.get(type);
         }
         <span class="hljs-keyword">return</span> loader;
-    }
+}
     
 <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>{
         <span class="hljs-keyword">this</span>.type = type;
         objectFactory = (type == ExtensionFactory.class ? <span 
class="hljs-keyword">null</span> : 
ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
-    }
+}
 </code></pre>
 <ol start="2">
 <li>getExtension</li>
@@ -78,9 +77,9 @@ This is a static factory method that enters an extensible 
interface and returns
             }
         }
         <span class="hljs-keyword">return</span> (T) instance;
-    }
+}
 </code></pre>
-<p>Some judgments and caching have been made in the getExtention method, and 
the main logic is in the createExtension method. Let's move on to the 
createExtention method.</p>
+<p>Some judgments and caching have been made in the getExtension method, and 
the main logic is in the createExtension method. Let's move on to the 
createExtension method.</p>
 <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>{
         <span class="hljs-comment">// Get the extension class according to the 
name of extension point. For example,  for LoadBalance, get the 
RandomLoadBalance class according to random</span>
         Class&lt;?&gt; clazz = getExtensionClasses().get(name);
@@ -108,7 +107,7 @@ This is a static factory method that enters an extensible 
interface and returns
 <li>First, get the corresponding extension class according to name. Read the 
extension point configuration file from the <code>META-INF</code> folder under 
ClassPath.</li>
 <li>Use reflection to create an instance of an extended class.</li>
 <li>make dependency injection for the attributes of the extended class 
instance. That is, IoC.</li>
-<li>If there is a wrapper, add the wrapper. That is, AoP.</li>
+<li>If there is a wrapper, add the wrapper. That is, AOP.</li>
 </ol>
 <p>Let's focus on these four processes.</p>
 <ol>
@@ -128,8 +127,8 @@ This is a static factory method that enters an extensible 
interface and returns
         <span class="hljs-keyword">return</span> classes;
     }
 
-    <span class="hljs-comment">// synchronized in getExtensionClasses</span>
-    <span class="hljs-keyword">private</span> Map&lt;String, 
Class&lt;?&gt;&gt; loadExtensionClasses() {
+<span class="hljs-comment">// synchronized in getExtensionClasses</span>
+<span class="hljs-keyword">private</span> Map&lt;String, Class&lt;?&gt;&gt; 
loadExtensionClasses() {
         <span class="hljs-keyword">final</span> SPI defaultAnnotation = 
type.getAnnotation(SPI.class);
         <span class="hljs-keyword">if</span> (defaultAnnotation != <span 
class="hljs-keyword">null</span>) {
             String value = defaultAnnotation.value();
@@ -147,7 +146,7 @@ This is a static factory method that enters an extensible 
interface and returns
         loadFile(extensionClasses, DUBBO_DIRECTORY);
         loadFile(extensionClasses, SERVICES_DIRECTORY);
         <span class="hljs-keyword">return</span> extensionClasses;
-    }
+}
 </code></pre>
 <p>This process is very simple. Get the extension class from the cache first, 
and if it does not exist, load it from the configuration file. The path of the 
configuration file has been mentioned before:</p>
 <ul>
@@ -184,15 +183,15 @@ This is a static factory method that enters an extensible 
interface and returns
 <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>{
         <span class="hljs-keyword">this</span>.type = type;
         objectFactory = (type == ExtensionFactory.class ? <span 
class="hljs-keyword">null</span> : 
ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
-    }
+}
 </code></pre>
 <p>ObjectFacore is also an extension, obtained through 
<code>ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()</code>.</p>
 <p><img 
src="https://raw.githubusercontent.com/vangoleo/wiki/master/dubbo/dubbo-extensionfactory.png";
 alt="Dubbo-ExtensionFactory | left"></p>
-<p>ExtensionLoader includes three implementations:</p>
+<p>ExtensionFactory includes three implementations:</p>
 <ol>
-<li>SpiExtensionLoader: use Dubbo's Spi to load Extension.</li>
-<li>SpringExtensionLoader: load Extension from the Spring container.</li>
-<li>AdaptiveExtensionLoader: adaptive AdaptiveExtensionLoader</li>
+<li>SpiExtensionFactory: use Dubbo's Spi to load Extension.</li>
+<li>SpringExtensionFactory: load Extension from the Spring container.</li>
+<li>AdaptiveExtensionFactory: adaptive AdaptiveExtensionLoader</li>
 </ol>
 <p>Pay attention to the AdaptiveExtensionLoader here, the source code is as 
follows:</p>
 <pre><code class="language-java"><span class="hljs-meta">@Adaptive</span>
@@ -221,8 +220,8 @@ This is a static factory method that enters an extensible 
interface and returns
 }
 </code></pre>
 <p>The AdaptiveExtensionLoader class has @Adaptive annotations. As mentioned 
earlier, Dubbo creates an adaptive instance for each extension. If the 
extension class has @Adaptive annotations, it will use it as an adaptive class. 
If not, Dubbo will create one for us. So 
<code>ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension())</code>
 will return an AdaptiveExtensionLoader instance as an adaptive extension 
instance.
-The AdaptiveExtentionLoader will iterate through all the ExtensionFactory 
implementations and try to load the extensions. If found, return. If not, 
continue to find it in the next ExtensionFactory. Dubbo has two 
ExtensionFactory built in, which are searched from Dubbo's own extension 
mechanism and Spring container. Since ExtensionFactory itself is also an 
extension point, we can implement our own ExtensionFactory to enable automatic 
assembly of Dubbo to support our custom components. For [...]
-<h2>AoP of Dubbo SPI advanced usage</h2>
+The AdaptiveExtensionLoader will iterate through all the ExtensionFactory 
implementations and try to load the extensions. If found, return. If not, 
continue to find it in the next ExtensionFactory. Dubbo has two 
ExtensionFactory built in, which are searched from Dubbo's own extension 
mechanism and Spring container. Since ExtensionFactory itself is also an 
extension point, we can implement our own ExtensionFactory to enable automatic 
assembly of Dubbo to support our custom components. For [...]
+<h2>AOP of Dubbo SPI advanced usage</h2>
 <p>We often use AOP functionality when using Spring. Insert other logic before 
and after the method of the target class. For example, Spring AOP is usually 
used to implement logging, monitoring, and authentication, and so on.
 Does Dubbo's extension mechanism also support similar features? The answer is 
yes. In Dubbo, there is a special class called the Wrapper class. It uses the 
wrapper class to wrap the original extension point instance through the 
decorator pattern, and then inserts additional logic before and after the 
original extension point implementation to implement AOP functionality.</p>
 <h3>What is the Wrapper class</h3>
@@ -236,10 +235,10 @@ Does Dubbo's extension mechanism also support similar 
features? The answer is ye
 </code></pre>
 <p>Class A has a constructor <code>public A(A a)</code>, and the argument to 
the constructor is A itself. Such a class can be a Wrapper class in the Dubbo 
extension mechanism. Such Wrapper classes in Dubbo include 
ProtocolFilterWrapper, ProtocolListenerWrapper, and so on. You can check the 
source code to deepen your understanding.</p>
 <h3>How to configure the Wrapper class</h3>
-<p>The Wipper class in Dubbo is also an extension point. Like other extension 
points, it is also configured in the <code>META-INF</code> folder. For example, 
the ProtocolFilterWrapper and ProtocolListenerWrapper in the previous example 
are configured in the path 
<code>dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol</code>:</p>
-<pre><code 
class="language-text">filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
-listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
-mock=com.alibaba.dubbo.rpc.support.MockProtocol
+<p>The Wrapper class in Dubbo is also an extension point. Like other extension 
points, it is also configured in the <code>META-INF</code> folder. For example, 
the ProtocolFilterWrapper and ProtocolListenerWrapper in the previous example 
are configured in the path 
<code>dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol</code>:</p>
+<pre><code 
class="language-text">filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper
+listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper
+mock=org.apache.dubbo.rpc.support.MockProtocol
 </code></pre>
 <p>When Dubbo loads the extension configuration file, there is a piece of code 
as follows:</p>
 <pre><code class="language-java"><span class="hljs-keyword">try</span> {  
@@ -253,7 +252,7 @@ mock=com.alibaba.dubbo.rpc.support.MockProtocol
 } <span class="hljs-keyword">catch</span> (NoSuchMethodException e) {}
 </code></pre>
 <p>The meaning of this code is that if the extension class has a copy 
constructor, it will be saved for later use. The class that has the copy 
constructor is the Wrapper class. The parameter obtained by 
<code>clazz.getConstructor(type)</code> is the constructor of the extension 
point interface. Note that the parameter type of the constructor is an 
extension point interface, not an extension class.
-Take Protocol as an example. The configuration file 
<code>dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol
 defines filter=com.alibaba.dubbo.rpc.protocol. ProtocolFilterWrapper</code>.
+Take Protocol as an example. The configuration file 
<code>dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol
 defines filter=org.apache.dubbo.rpc.protocol. ProtocolFilterWrapper</code>.
 The code of ProtocolFilterWrapper is as follows:</p>
 <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>{
 
@@ -266,6 +265,7 @@ The code of ProtocolFilterWrapper is as follows:</p>
         }
         <span class="hljs-keyword">this</span>.protocol = protocol;
     }
+}
 </code></pre>
 <p>ProtocolFilterWrapper has a constructor <code>public 
ProtocolFilterWrapper(Protocol protocol)</code>, and the parameter is the 
extension point Protocol. So it is a Wrapper class in the Dubbo extension 
mechanism. The ExtensionLoader will cache it. When creating Extension instances 
later, the ExtensionLoader use these wrapper classes to wrap the original 
Extension point in turn.</p>
 <h2>Extension point adaptive</h2>
@@ -298,15 +298,15 @@ Let's first look at the code to create an adaptive 
extension class:</p>
             <span class="hljs-keyword">return</span> cachedAdaptiveClass;
         }
         <span class="hljs-keyword">return</span> cachedAdaptiveClass = 
createAdaptiveExtensionClass();
-    }
+}
 </code></pre>
 <p>Continue to read the createAdaptiveExtensionClass method. After a long 
journey, we finally come to a concrete realization. Look at this 
createAdaptiveExtensionClass method, which first generates the Java source code 
for the adaptive class, and then compile the source code into Java bytecode and 
load it into the JVM.</p>
 <pre><code class="language-java"><span class="hljs-keyword">private</span> 
Class&lt;?&gt; createAdaptiveExtensionClass() {
         String code = createAdaptiveExtensionClassCode();
         ClassLoader classLoader = findClassLoader();
-        com.alibaba.dubbo.common.compiler.Compiler compiler = 
ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
+        org.apache.dubbo.common.compiler.Compiler compiler = 
ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
         <span class="hljs-keyword">return</span> compiler.compile(code, 
classLoader);
-    }
+}
 </code></pre>
 <p>The default implementation of Compiler's code is javassist.</p>
 <pre><code class="language-java"><span class="hljs-meta">@SPI</span>(<span 
class="hljs-string">"javassist"</span>)
@@ -316,44 +316,44 @@ Let's first look at the code to create an adaptive 
extension class:</p>
 </code></pre>
 <p>The createAdaptiveExtensionClassCode () method uses a StringBuilder to 
build Java source code for the adaptive class. The method implementation is 
relatively long, and the code is not posted here. The approach to bytecode 
generation is also interesting, first generating Java source code, then 
compiling it and loading it into the jvm. In this way, the generated Java class 
can be better controlled. And it doesn't have to care about the API of the 
bytecode generation framework. Because t [...]
 Below are the Java code example for Protocol adaptive class created by 
createAdaptiveExtensionClassCode method:</p>
-<pre><code class="language-java"><span class="hljs-keyword">package</span> 
com.alibaba.dubbo.rpc;
+<pre><code class="language-java"><span class="hljs-keyword">package</span> 
org.apache.dubbo.rpc;
 
-<span class="hljs-keyword">import</span> 
com.alibaba.dubbo.common.extension.ExtensionLoader;
+<span class="hljs-keyword">import</span> 
org.apache.dubbo.common.extension.ExtensionLoader;
 
-<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>{
+<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">Adaptive</span> 
<span class="hljs-keyword">implements</span> <span 
class="hljs-title">org</span>.<span class="hljs-title">apache</span>.<span 
class="hljs-title">dubbo</span>.<span class="hljs-title">rpc</span>.<span 
class="hljs-title">Protocol</span> </span>{
     <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>{
-        <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>);
+        <span class="hljs-keyword">throw</span> <span 
class="hljs-keyword">new</span> UnsupportedOperationException(<span 
class="hljs-string">"method public abstract void 
org.apache.dubbo.rpc.Protocol.destroy() of interface 
org.apache.dubbo.rpc.Protocol is not adaptive method!"</span>);
     }
 
     <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>{
-        <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>);
+        <span class="hljs-keyword">throw</span> <span 
class="hljs-keyword">new</span> UnsupportedOperationException(<span 
class="hljs-string">"method public abstract int 
org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface 
org.apache.dubbo.rpc.Protocol is not adaptive method!"</span>);
     }
 
-    <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>{
-        <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>);
+    <span class="hljs-keyword">public</span> org.apache.dubbo.rpc.<span 
class="hljs-function">Exporter <span class="hljs-title">export</span><span 
class="hljs-params">(org.apache.dubbo.rpc.Invoker arg0)</span> <span 
class="hljs-keyword">throws</span> org.apache.dubbo.rpc.RpcException </span>{
+        <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">"org.apache.dubbo.rpc.Invoker argument == null"</span>);
         <span class="hljs-keyword">if</span> (arg0.getUrl() == <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 getUrl() == 
null"</span>);
-        com.alibaba.dubbo.common.URL url = arg0.getUrl();
+            <span class="hljs-keyword">throw</span> <span 
class="hljs-keyword">new</span> IllegalArgumentException(<span 
class="hljs-string">"org.apache.dubbo.rpc.Invoker argument getUrl() == 
null"</span>);
+        org.apache.dubbo.common.URL url = arg0.getUrl();
         String extName = (url.getProtocol() == <span 
class="hljs-keyword">null</span> ? <span class="hljs-string">"dubbo"</span> : 
url.getProtocol());
         <span class="hljs-keyword">if</span> (extName == <span 
class="hljs-keyword">null</span>)
-            <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>);
-        com.alibaba.dubbo.rpc.Protocol extension = 
(com.alibaba.dubbo.rpc.Protocol) 
ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
+            <span class="hljs-keyword">throw</span> <span 
class="hljs-keyword">new</span> IllegalStateException(<span 
class="hljs-string">"Fail to get extension(org.apache.dubbo.rpc.Protocol) name 
from url("</span> + url.toString() + <span class="hljs-string">") use 
keys([protocol])"</span>);
+        org.apache.dubbo.rpc.Protocol extension = 
(org.apache.dubbo.rpc.Protocol) 
ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
         <span class="hljs-keyword">return</span> extension.export(arg0);
     }
 
-    <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>{
+    <span class="hljs-keyword">public</span> org.apache.dubbo.rpc.<span 
class="hljs-function">Invoker <span class="hljs-title">refer</span><span 
class="hljs-params">(java.lang.Class arg0, org.apache.dubbo.common.URL 
arg1)</span> <span class="hljs-keyword">throws</span> 
org.apache.dubbo.rpc.RpcException </span>{
         <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>);
-        com.alibaba.dubbo.common.URL url = arg1;
+        org.apache.dubbo.common.URL url = arg1;
         String extName = (url.getProtocol() == <span 
class="hljs-keyword">null</span> ? <span class="hljs-string">"dubbo"</span> : 
url.getProtocol());
         <span class="hljs-keyword">if</span> (extName == <span 
class="hljs-keyword">null</span>)
-            <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>);
-        com.alibaba.dubbo.rpc.Protocol extension = 
(com.alibaba.dubbo.rpc.Protocol) 
ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
+            <span class="hljs-keyword">throw</span> <span 
class="hljs-keyword">new</span> IllegalStateException(<span 
class="hljs-string">"Fail to get extension(org.apache.dubbo.rpc.Protocol) name 
from url("</span> + url.toString() + <span class="hljs-string">") use 
keys([protocol])"</span>);
+        org.apache.dubbo.rpc.Protocol extension = 
(org.apache.dubbo.rpc.Protocol) 
ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
         <span class="hljs-keyword">return</span> extension.refer(arg0, arg1);
     }
 }
 </code></pre>
 <p>The general logic is the same as at the beginning. The parameters are 
parsed through the url, and the parsed logic is controlled by the value 
parameter of @adaptive, and then the extension points implementation are 
obtained according to the name of the extension point. And then finally make 
the call. If you want to know the specific construction logic of .Java code, 
you can see the complete implementation of 
<code>createAdaptiveExtensionClassCode</code>.
-In the generated Protocol$Adpative, both the getDefaultPort and destroy 
methods are found to throw the exception directly. Why? Take a look at the 
source code of Protocol:</p>
+In the generated Protocol$Adaptive, both the getDefaultPort and destroy 
methods are found to throw the exception directly. Why? Take a look at the 
source code of Protocol:</p>
 <pre><code class="language-java"><span class="hljs-meta">@SPI</span>(<span 
class="hljs-string">"dubbo"</span>)
 <span class="hljs-keyword">public</span> <span class="hljs-class"><span 
class="hljs-keyword">interface</span> <span class="hljs-title">Protocol</span> 
</span>{
 
@@ -366,8 +366,9 @@ In the generated Protocol$Adpative, both the getDefaultPort 
and destroy methods
     &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>;
 
     <span class="hljs-function"><span class="hljs-keyword">void</span> <span 
class="hljs-title">destroy</span><span class="hljs-params">()</span></span>;
+}
 </code></pre>
-<p>As you can see, there are four methods in the Protocol interface, but only 
the methods of export and refer use the @adaptive annotation. Dubbo 
automatically generates adaptive instances, and only the methods modified by 
@Adaptive has a specific implementation. Therefore, in the Protocol$Adpative 
class, only the export and refer methods have specific implementations, and the 
rest of the methods throw exceptions.</p>
+<p>As you can see, there are four methods in the Protocol interface, but only 
the methods of export and refer use the @Adaptive annotation. Dubbo 
automatically generates adaptive instances, and only the methods modified by 
@Adaptive has a specific implementation. Therefore, in the Protocol$Adaptive 
class, only the export and refer methods have specific implementations, and the 
rest of the methods throw exceptions.</p>
 </section><footer class="footer-container"><div class="footer-body"><img 
src="/img/dubbo_gray.png"/><img class="apache" src="/img/apache_logo.png"/><div 
class="cols-container"><div class="col col-12"><h3>Disclaimer</h3><p>Apache 
Dubbo is an effort undergoing incubation at The Apache Software Foundation 
(ASF), sponsored by the Incubator. Incubation is required of all newly accepted 
projects until a further review indicates that the infrastructure, 
communications, and decision making proce [...]
        <script 
src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js";></script>
        <script 
src="https://f.alicdn.com/react/15.4.1/react-dom.min.js";></script>
diff --git a/en-us/blog/introduction-to-dubbo-spi-2.json 
b/en-us/blog/introduction-to-dubbo-spi-2.json
index b6b38ae..188bef6 100644
--- a/en-us/blog/introduction-to-dubbo-spi-2.json
+++ b/en-us/blog/introduction-to-dubbo-spi-2.json
@@ -1,6 +1,6 @@
 {
   "filename": "introduction-to-dubbo-spi-2.md",
-  "__html": "<h1>Dubbo extensible mechanism source code 
analysis</h1>\n<hr>\n<p>In the <a 
href=\"./introduction-to-dubbo-spi.md\">actual implementation of the Dubbo 
extensibility mechanism</a>, we learned some concepts of the Dubbo extension 
mechanism, explored the implementation of LoadBalance in Dubbo, and implemented 
a LoadBalance on our own. Do you think Dubbo's extension mechanism is great? 
Next, we will go deep into the source code of Dubbo and see what it 
is.</p>\n<h2>ExtensionLoa [...]
+  "__html": "<h1>Dubbo extensible mechanism source code analysis</h1>\n<p>In 
the <a href=\"./introduction-to-dubbo-spi.md\">actual implementation of the 
Dubbo extensibility mechanism</a>, we learned some concepts of the Dubbo 
extension mechanism, explored the implementation of LoadBalance in Dubbo, and 
implemented a LoadBalance on our own. Do you think Dubbo's extension mechanism 
is great? Next, we will go deep into the source code of Dubbo and see what it 
is.</p>\n<h2>ExtensionLoader</h [...]
   "link": "/en-us/blog/introduction-to-dubbo-spi-2.html",
   "meta": {
     "title": "Dubbo extensible mechanism source code analysis",
diff --git a/en-us/docs/developers/developers_dev.html 
b/en-us/docs/developers/developers_dev.html
index 0503cce..227e4ed 100644
--- a/en-us/docs/developers/developers_dev.html
+++ b/en-us/docs/developers/developers_dev.html
@@ -236,6 +236,13 @@
 <td>Committer</td>
 <td>+8</td>
 </tr>
+<tr>
+<td>biyuhao</td>
+<td>Yuhao Bi</td>
+<td>Asiainfo-sec</td>
+<td>Committer</td>
+<td>+8</td>
+</tr>
 </tbody>
 </table>
 <h3>Contributors</h3>
@@ -262,12 +269,6 @@
 <td>+8</td>
 </tr>
 <tr>
-<td>biyuhao</td>
-<td><a href="https://github.com/biyuhao";>https://github.com/biyuhao</a></td>
-<td>Asiainfo-sec</td>
-<td>+8</td>
-</tr>
-<tr>
 <td>huyuechy</td>
 <td><a href="https://github.com/huyuechy";>https://github.com/huyuechy</a></td>
 <td></td>
diff --git a/en-us/docs/developers/developers_dev.json 
b/en-us/docs/developers/developers_dev.json
index 015b2e5..b2423c6 100644
--- a/en-us/docs/developers/developers_dev.json
+++ b/en-us/docs/developers/developers_dev.json
@@ -1,6 +1,6 @@
 {
   "filename": "developers_dev.md",
-  "__html": "<h2>Developers</h2>\n<p>This page shows Dubbo developers. Please 
file PR to add or change 
items.</p>\n<h3>Committers</h3>\n<table>\n<thead>\n<tr>\n<th>Apache 
ID</th>\n<th>Name</th>\n<th>Organization</th>\n<th>Role</th>\n<th>TimeZone</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>jmclean</td>\n<td>Justin
 
Mclean</td>\n<td>Apache</td>\n<td>Mentor</td>\n<td>+11</td>\n</tr>\n<tr>\n<td>markt</td>\n<td>Mark
 
Thomas</td>\n<td>Apache</td>\n<td>Mentor</td>\n<td>+0</td>\n</tr>\n<tr>\n<td>wav
 [...]
+  "__html": "<h2>Developers</h2>\n<p>This page shows Dubbo developers. Please 
file PR to add or change 
items.</p>\n<h3>Committers</h3>\n<table>\n<thead>\n<tr>\n<th>Apache 
ID</th>\n<th>Name</th>\n<th>Organization</th>\n<th>Role</th>\n<th>TimeZone</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>jmclean</td>\n<td>Justin
 
Mclean</td>\n<td>Apache</td>\n<td>Mentor</td>\n<td>+11</td>\n</tr>\n<tr>\n<td>markt</td>\n<td>Mark
 
Thomas</td>\n<td>Apache</td>\n<td>Mentor</td>\n<td>+0</td>\n</tr>\n<tr>\n<td>wav
 [...]
   "link": "/en-us/docs/developers/developers_dev.html",
   "meta": {}
 }
\ No newline at end of file
diff --git a/md_json/blog.json b/md_json/blog.json
index 4037dd0..d53ffd4 100644
--- a/md_json/blog.json
+++ b/md_json/blog.json
@@ -326,6 +326,11 @@
       }
     },
     {
+      "filename": "dubbo-echo-test.md",
+      "link": "/zh-cn/blog/dubbo-echo-test.html",
+      "meta": {}
+    },
+    {
       "filename": "dubbo-externalized-configuration.md",
       "link": "/zh-cn/blog/dubbo-externalized-configuration.html",
       "meta": {}
@@ -349,6 +354,15 @@
       }
     },
     {
+      "filename": "dubbo-gracefully-shutdown.md",
+      "link": "/zh-cn/blog/dubbo-gracefully-shutdown.html",
+      "meta": {
+        "title": "Dubbo 优雅停机",
+        "keywords": "Dubbo, Gracefully Shutdown, Safely Shutdown",
+        "description": "介绍Dubbo优雅停机的原理和使用方式"
+      }
+    },
+    {
       "filename": "dubbo-heartbeat-design.md",
       "link": "/zh-cn/blog/dubbo-heartbeat-design.html",
       "meta": {
@@ -503,6 +517,24 @@
       }
     },
     {
+      "filename": "dubboAsync_client.md",
+      "link": "/zh-cn/blog/dubboAsync_client.html",
+      "meta": {
+        "title": "Dubbo客户端异步接口的实现背景和实践",
+        "keywords": "Dubbo, 异步, Reactive",
+        "description": "Dubbo客户端异步接口的实现背景和实践"
+      }
+    },
+    {
+      "filename": "dubboAsync_server.md",
+      "link": "/zh-cn/blog/dubboAsync_server.html",
+      "meta": {
+        "title": "Dubbo客户端异步接口的实现背景和实践",
+        "keywords": "Dubbo, 异步, Reactive",
+        "description": "Dubbo服务端异步接口的实现背景和实践"
+      }
+    },
+    {
       "filename": "first-dubbo-filter.md",
       "link": "/zh-cn/blog/first-dubbo-filter.html",
       "meta": {}
diff --git a/zh-cn/blog/dubbo-admin.html b/zh-cn/blog/dubbo-admin.html
index 91a26fc..fa0eb30 100644
--- a/zh-cn/blog/dubbo-admin.html
+++ b/zh-cn/blog/dubbo-admin.html
@@ -28,7 +28,7 @@ github: https://github.com/apache/incubator-dubbo-ops
 <p>由于在Dubbo2.7中,配置中心和注册中心做了分离,并且增加了元数据中心,因此Dubbo 
Admin的配置方式也做了更新,<code>application.properties</code>中的配置如下:</p>
 <pre><code class="language-properties"><span 
class="hljs-meta">admin.registry.address</span>=<span 
class="hljs-string">zookeeper://127.0.0.1:2181</span>
 <span class="hljs-meta">admin.config-center</span>=<span 
class="hljs-string">zookeeper://127.0.0.1:2181</span>
-<span class="hljs-meta">admin.metadata.address</span>=<span 
class="hljs-string">zookeeper://127.0.0.1:2181</span>
+<span class="hljs-meta">admin.metadata-report.address</span>=<span 
class="hljs-string">zookeeper://127.0.0.1:2181</span>
 </code></pre>
 <p>也可以和Dubbo2.7一样,在配置中心指定元数据和注册中心的地址,以zookeeper为例,配置的路径和内容如下:</p>
 <pre><code class="language-properties"><span class="hljs-comment"># 
/dubbo/config/dubbo/dubbo.properties</span>
diff --git a/zh-cn/blog/dubbo-admin.json b/zh-cn/blog/dubbo-admin.json
index 8918d0a..215f85c 100644
--- a/zh-cn/blog/dubbo-admin.json
+++ b/zh-cn/blog/dubbo-admin.json
@@ -1,6 +1,6 @@
 {
   "filename": "dubbo-admin.md",
-  "__html": "<h1>新版Dubbo 
Admin介绍</h1>\n<pre><code>Demo地址:http://47.91.207.147/#/service  \ngithub: 
https://github.com/apache/incubator-dubbo-ops\n</code></pre>\n<p>Dubbo 
Admin之前的版本过于老旧,也长期疏于维护,因此在去年年中的时候,对该项目进行了一次重构,项目结构上的变化如下:</p>\n<ul>\n<li>将后端框架从webx替换成spring
 
boot</li>\n<li>前端采用Vue和Vuetify.js作为开发框架</li>\n<li>移除velocity模板</li>\n<li>集成swagger,提供api管理功能</li>\n</ul>\n<p>当前版本的Dubbo
 
Admin包含了之前版本中的绝大部分功能,包括服务治理,服务查询等,同时支持了Dubbo2.7中服务治理的新特性。</p>\n<h2>配置规范</h2>\n<p>由于在Dubbo2.7中,配置中心和注册中心做了分离,并
 [...]
+  "__html": "<h1>新版Dubbo 
Admin介绍</h1>\n<pre><code>Demo地址:http://47.91.207.147/#/service  \ngithub: 
https://github.com/apache/incubator-dubbo-ops\n</code></pre>\n<p>Dubbo 
Admin之前的版本过于老旧,也长期疏于维护,因此在去年年中的时候,对该项目进行了一次重构,项目结构上的变化如下:</p>\n<ul>\n<li>将后端框架从webx替换成spring
 
boot</li>\n<li>前端采用Vue和Vuetify.js作为开发框架</li>\n<li>移除velocity模板</li>\n<li>集成swagger,提供api管理功能</li>\n</ul>\n<p>当前版本的Dubbo
 
Admin包含了之前版本中的绝大部分功能,包括服务治理,服务查询等,同时支持了Dubbo2.7中服务治理的新特性。</p>\n<h2>配置规范</h2>\n<p>由于在Dubbo2.7中,配置中心和注册中心做了分离,并
 [...]
   "link": "/zh-cn/blog/dubbo-admin.html",
   "meta": {}
 }
\ No newline at end of file
diff --git a/zh-cn/blog/dubbo-echo-test.html b/zh-cn/blog/dubbo-echo-test.html
new file mode 100644
index 0000000..1bc769c
--- /dev/null
+++ b/zh-cn/blog/dubbo-echo-test.html
@@ -0,0 +1,111 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+       <meta charset="UTF-8">
+       <meta name="viewport" content="width=device-width, initial-scale=1.0, 
maximum-scale=1.0, user-scalable=no">
+       <meta name="keywords" content="dubbo-echo-test" />
+       <meta name="description" content="dubbo-echo-test" />
+       <!-- 网页标签标题 -->
+       <title>dubbo-echo-test</title>
+       <link rel="shortcut icon" href="/img/dubbo.ico"/>
+       <link rel="stylesheet" href="/build/blogDetail.css" />
+</head>
+<body>
+       <div id="root"><div class="blog-detail-page" data-reactroot=""><header 
class="header-container header-container-normal"><div class="header-body"><a 
href="/zh-cn/index.html"><img class="logo" 
src="/img/dubbo_colorful.png"/></a><div class="search search-normal"><span 
class="icon-search"></span></div><span class="language-switch 
language-switch-normal">En</span><div class="header-menu"><img 
class="header-menu-toggle" src="/img/menu_gray.png"/><ul><li class="menu-item 
menu-item-normal"><a h [...]
+<p>回声测试用于检测服务是否可用。客户端通过 EchoService 来使用回声测试。EchoService 申明如下:</p>
+<pre><code class="language-Java"><span class="hljs-keyword">public</span> 
<span class="hljs-class"><span class="hljs-keyword">interface</span> <span 
class="hljs-title">EchoService</span> </span>{
+
+    <span class="hljs-comment">/**
+     * echo test.
+     *
+     * <span class="hljs-doctag">@param</span> message message.
+     * <span class="hljs-doctag">@return</span> message.
+     */</span>
+    Object $echo(Object message);
+
+}
+</code></pre>
+<p>用户通过 $echo 方法发起的请求,会按照正常请求的流程执行,能够测试整个调用是否通畅,监控系统可以使用回声测试来检测服务可用性。</p>
+<h2>使用范例</h2>
+<p>所有服务引用自动实现 EchoService 接口,用户只需将服务引用强制转型为 EchoService,即可使用。配置和代码范例如下所示。
+Spring 配置:</p>
+<pre><code>&lt;dubbo:reference id=&quot;demoService&quot; 
interface=&quot;org.apache.dubbo.samples.echo.DemoService&quot; /&gt;
+</code></pre>
+<p>代码:</p>
+<pre><code class="language-Java"><span class="hljs-comment">// 远程服务引用</span>
+DemoService demoService= ctx.getBean(<span 
class="hljs-string">"demoService"</span>);
+<span class="hljs-comment">// 强制转型为EchoService</span>
+EchoService echoService = (EchoService) demoService;
+<span class="hljs-comment">// 回声测试可用性</span>
+String status = echoService.$echo(<span class="hljs-string">"OK"</span>);
+<span class="hljs-keyword">assert</span>(status.equals(<span 
class="hljs-string">"OK"</span>));
+</code></pre>
+<h2>实现原理</h2>
+<p>我们在配置服务引用时,并没有配置 EchoService 这个接口,为什么可以直接把服务引用转型为 EchoService 呢?
+用户拿到的服务引用其实是一个 Proxy,Dubbo 在生成 Proxy 的时候,已经默认将 EchoService 这个接口加入到 Proxy 
的接口列表中,所以用户拿到的 Proxy 都已经实现了 EchoService。生成代理相关代码如下:</p>
+<pre><code class="language-Java"> <span class="hljs-keyword">public</span> 
&lt;T&gt; <span class="hljs-function">T <span 
class="hljs-title">getProxy</span><span class="hljs-params">(Invoker&lt;T&gt; 
invoker, <span class="hljs-keyword">boolean</span> generic)</span> <span 
class="hljs-keyword">throws</span> RpcException </span>{
+        Class&lt;?&gt;[] interfaces = <span class="hljs-keyword">null</span>;
+        String config = invoker.getUrl().getParameter(Constants.INTERFACES);
+        <span class="hljs-keyword">if</span> (config != <span 
class="hljs-keyword">null</span> &amp;&amp; config.length() &gt; <span 
class="hljs-number">0</span>) {
+            String[] types = Constants.COMMA_SPLIT_PATTERN.split(config);
+            <span class="hljs-keyword">if</span> (types != <span 
class="hljs-keyword">null</span> &amp;&amp; types.length &gt; <span 
class="hljs-number">0</span>) {
+                interfaces = <span class="hljs-keyword">new</span> 
Class&lt;?&gt;[types.length + <span class="hljs-number">2</span>];
+                interfaces[<span class="hljs-number">0</span>] = 
invoker.getInterface();
+                interfaces[<span class="hljs-number">1</span>] = 
EchoService.class;
+                <span class="hljs-keyword">for</span> (<span 
class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; 
types.length; i++) {
+                    <span class="hljs-comment">// TODO can we load 
successfully for a different classloader?.</span>
+                    interfaces[i + <span class="hljs-number">2</span>] = 
ReflectUtils.forName(types[i]);
+                }
+            }
+        }
+        <span class="hljs-keyword">if</span> (interfaces == <span 
class="hljs-keyword">null</span>) {
+            interfaces = <span class="hljs-keyword">new</span> 
Class&lt;?&gt;[]{invoker.getInterface(), EchoService.class};
+        }
+
+        <span class="hljs-keyword">if</span> 
(!GenericService.class.isAssignableFrom(invoker.getInterface()) &amp;&amp; 
generic) {
+            <span class="hljs-keyword">int</span> len = interfaces.length;
+            Class&lt;?&gt;[] temp = interfaces;
+            interfaces = <span class="hljs-keyword">new</span> 
Class&lt;?&gt;[len + <span class="hljs-number">1</span>];
+            System.arraycopy(temp, <span class="hljs-number">0</span>, 
interfaces, <span class="hljs-number">0</span>, len);
+            interfaces[len] = 
com.alibaba.dubbo.rpc.service.GenericService.class;
+        }
+
+        <span class="hljs-keyword">return</span> getProxy(invoker, interfaces);
+    }
+</code></pre>
+<p>通过这种方式,任何服务引用都可以被转型成 EchoService 来使用。
+上面解释了客户端的实现,另外一边,用户在服务端也并没有实现 EchoService,那么客户端 EchoService 
发出的调用在服务端是如何处理的呢?框架使用 Filter 机制来处理 EchoService 请求。Filter 实现代码如下:</p>
+<pre><code class="language-Java"><span 
class="hljs-meta">@Activate</span>(group = Constants.PROVIDER, order = -<span 
class="hljs-number">110000</span>)
+<span class="hljs-keyword">public</span> <span class="hljs-class"><span 
class="hljs-keyword">class</span> <span class="hljs-title">EchoFilter</span> 
<span class="hljs-keyword">implements</span> <span 
class="hljs-title">Filter</span> </span>{
+
+    <span class="hljs-meta">@Override</span>
+    <span class="hljs-function"><span class="hljs-keyword">public</span> 
Result <span class="hljs-title">invoke</span><span 
class="hljs-params">(Invoker&lt;?&gt; invoker, Invocation inv)</span> <span 
class="hljs-keyword">throws</span> RpcException </span>{
+        <span class="hljs-keyword">if</span> 
(inv.getMethodName().equals(Constants.$ECHO) &amp;&amp; inv.getArguments() != 
<span class="hljs-keyword">null</span> &amp;&amp; inv.getArguments().length == 
<span class="hljs-number">1</span>) {
+            <span class="hljs-keyword">return</span> <span 
class="hljs-keyword">new</span> RpcResult(inv.getArguments()[<span 
class="hljs-number">0</span>]);
+        }
+        <span class="hljs-keyword">return</span> invoker.invoke(inv);
+    }
+
+}
+</code></pre>
+<p>请求经过 EchoFilter.invoke 方法时,如果判定为 $echo 调用,则直接返回请求参数,否则继续执行 Filter 
链。EchoFilter 默认加入到每一个服务提供者的 Filter 链里 EchoFilter.invoke 方法时,如果判定为 $echo 
调用,则直接返回请求参数,否则继续执行 Filter 链。EchoFilter 默认加入到每一个服务提供者的 Filter 
链里。这样每一个服务提供者自动具备了响应 EchoService 的能力。</p>
+<p>通过上述分析,我们了解了框架是如何通过动态代理和 Filter 机制,使得用户可以透明地使用 EchoService 功能。</p>
+</section><footer class="footer-container"><div class="footer-body"><img 
src="/img/dubbo_gray.png"/><img class="apache" src="/img/apache_logo.png"/><div 
class="cols-container"><div class="col col-12"><h3>Disclaimer</h3><p>Apache 
Dubbo is an effort undergoing incubation at The Apache Software Foundation 
(ASF), sponsored by the Incubator. Incubation is required of all newly accepted 
projects until a further review indicates that the infrastructure, 
communications, and decision making proce [...]
+       <script 
src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js";></script>
+       <script 
src="https://f.alicdn.com/react/15.4.1/react-dom.min.js";></script>
+       <script>
+               window.rootPath = '';
+  </script>
+  <script src="/build/blogDetail.js"></script>
+  <!-- Global site tag (gtag.js) - Google Analytics -->
+       <script async 
src="https://www.googletagmanager.com/gtag/js?id=UA-112489517-1";></script>
+       <script>
+               window.dataLayer = window.dataLayer || [];
+               function gtag(){dataLayer.push(arguments);}
+               gtag('js', new Date());
+
+               gtag('config', 'UA-112489517-1');
+       </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zh-cn/blog/dubbo-echo-test.json b/zh-cn/blog/dubbo-echo-test.json
new file mode 100644
index 0000000..0dc2f88
--- /dev/null
+++ b/zh-cn/blog/dubbo-echo-test.json
@@ -0,0 +1,6 @@
+{
+  "filename": "dubbo-echo-test.md",
+  "__html": "<h1>回声测试</h1>\n<p>回声测试用于检测服务是否可用。客户端通过 EchoService 
来使用回声测试。EchoService 申明如下:</p>\n<pre><code class=\"language-Java\"><span 
class=\"hljs-keyword\">public</span> <span class=\"hljs-class\"><span 
class=\"hljs-keyword\">interface</span> <span 
class=\"hljs-title\">EchoService</span> </span>{\n\n    <span 
class=\"hljs-comment\">/**\n     * echo test.\n     *\n     * <span 
class=\"hljs-doctag\">@param</span> message message.\n     * <span 
class=\"hljs-doctag\">@return</span> messag [...]
+  "link": "/zh-cn/blog/dubbo-echo-test.html",
+  "meta": {}
+}
\ No newline at end of file
diff --git a/zh-cn/blog/dubbo-gracefully-shutdown.html 
b/zh-cn/blog/dubbo-gracefully-shutdown.html
new file mode 100644
index 0000000..5a93c67
--- /dev/null
+++ b/zh-cn/blog/dubbo-gracefully-shutdown.html
@@ -0,0 +1,130 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+       <meta charset="UTF-8">
+       <meta name="viewport" content="width=device-width, initial-scale=1.0, 
maximum-scale=1.0, user-scalable=no">
+       <meta name="keywords" content="Dubbo, Gracefully Shutdown, Safely 
Shutdown" />
+       <meta name="description" content="介绍Dubbo优雅停机的原理和使用方式" />
+       <!-- 网页标签标题 -->
+       <title>Dubbo 优雅停机</title>
+       <link rel="shortcut icon" href="/img/dubbo.ico"/>
+       <link rel="stylesheet" href="/build/blogDetail.css" />
+</head>
+<body>
+       <div id="root"><div class="blog-detail-page" data-reactroot=""><header 
class="header-container header-container-normal"><div class="header-body"><a 
href="/zh-cn/index.html"><img class="logo" 
src="/img/dubbo_colorful.png"/></a><div class="search search-normal"><span 
class="icon-search"></span></div><span class="language-switch 
language-switch-normal">En</span><div class="header-menu"><img 
class="header-menu-toggle" src="/img/menu_gray.png"/><ul><li class="menu-item 
menu-item-normal"><a h [...]
+<h2>背景</h2>
+<p>对于任何一个线上应用,如何在服务更新部署过程中保证客户端无感知是开发者必须要解决的问题,即从应用停止到重启恢复服务这个阶段不能影响正常的业务请求。理想条件下,在没有请求的时候再进行更新是最安全可靠的,然而互联网应用必须要保证可用性,因此在技术层面上优化应用更新流程来保证服务在更新时无损是必要的。</p>
+<p>传统的解决方式是通过将应用更新流程划分为手工摘流量、停应用、更新重启三个步骤,由人工操作实现客户端无对更新感知。这种方式简单而有效,但是限制较多:不仅需要使用借助网关的支持来摘流量,还需要在停应用前人工判断来保证在途请求已经处理完毕。这种需要人工介入的方式运维复杂度较高,只能适用规模较小的应用,无法在大规模系统上使用。</p>
+<p>因此,如果在容器/框架级别提供某种自动化机制,来自动进行摘流量并确保处理完以到达的请求,不仅能保证业务不受更新影响,还可以极大地提升更新应用时的运维效率。</p>
+<p>这个机制也就是优雅停机,目前Tomcat/Undertow/Dubbo等容器/框架都有提供相关实现。下面给出正式一些的定义:优雅停机是指在停止应用时,执行的一系列保证应用正常关闭的操作。这些操作往往包括等待已有请求执行完成、关闭线程、关闭连接和释放资源等,优雅停机可以避免非正常关闭程序可能造成数据异常或丢失,应用异常等问题。优雅停机本质上是JVM即将关闭前执行的一些额外的处理代码。</p>
+<h2>适用场景</h2>
+<ul>
+<li>JVM主动关闭(<code>System.exit(int)</code>;</li>
+<li>JVM由于资源问题退出(<code>OOM</code>);</li>
+<li>应用程序接受到<code>SIGTERM</code>或<code>SIGINT</code>信号。</li>
+</ul>
+<h2>配置方式</h2>
+<h3>服务的优雅停机</h3>
+<p>在Dubbo中,优雅停机是默认开启的,停机等待时间为10000毫秒。可以通过配置<code>dubbo.service.shutdown.wait</code>来修改等待时间。</p>
+<p>例如将等待时间设置为20秒可通过增加以下配置实现:</p>
+<pre><code class="language-shell">dubbo.service.shutdown.wait=20000
+</code></pre>
+<h3>容器的优雅停机</h3>
+<p>当使用<code>org.apache.dubbo.container.Main</code>这种容器方式来使用 Dubbo 
时,也可以通过配置<code>dubbo.shutdown.hook</code>为<code>true</code>来开启优雅停机。</p>
+<h3>通过QOS优雅上下线</h3>
+<p>基于<code>ShutdownHook</code>方式的优雅停机无法确保所有关闭流程一定执行完,所以 Dubbo 
推出了多段关闭的方式来保证服务完全无损。</p>
+<p>多段关闭即将停止应用分为多个步骤,通过运维自动化脚本或手工操作的方式来保证脚本每一阶段都能执行完毕。</p>
+<p>在关闭应用前,首先通过 QOS 
的<code>offline</code>指令下线所有服务,然后等待一定时间确保已经到达请求全部处理完毕,由于服务已经在注册中心下线,当前应用不会有新的请求。这时再执行真正的关闭(<code>SIGTERM</code>
 或<code>SIGINT</code>)流程,就能保证服务无损。</p>
+<p>QOS可通过 telnet 或 HTTP 方式使用,具体方式请见<a 
href="http://dubbo.apache.org/zh-cn/docs/user/references/qos.html";>Dubbo-QOS命令使用说明</a>。</p>
+<h2>流程</h2>
+<p>Provider在接收到停机指令后</p>
+<ul>
+<li>从注册中心上注销所有服务;</li>
+<li>从配置中心取消监听动态配置;</li>
+<li>向所有连接的客户端发送只读事件,停止接收新请求;</li>
+<li>等待一段时间以处理已到达的请求,然后关闭请求处理线程池;</li>
+<li>断开所有客户端连接。</li>
+</ul>
+<p>Consumer在接收到停机指令后</p>
+<ul>
+<li>拒绝新到请求,直接返回调用异常;</li>
+<li>等待当前已发送请求执行完毕,如果响应超时则强制关闭连接。</li>
+</ul>
+<p>当使用容器方式运行 Dubbo 时,在容器准备退出前,可进行一系列的资源释放和清理工。</p>
+<p>例如使用 SpringContainer时,Dubbo 
的ShutdownHook线程会执行<code>ApplicationContext</code>的<code>stop</code>和<code>close</code>方法,保证
 Bean的生命周期完整。</p>
+<h2>实现原理</h2>
+<ol>
+<li>
+<p>在加载类<code>org.apache.dubbo.config.AbstractConfig</code>时,通过<code>org.apache.dubbo.config.DubboShutdownHook</code>向JVM注册
 ShutdownHook。</p>
+<pre><code class="language-java"><span class="hljs-comment">/**
+ * Register the ShutdownHook
+ */</span>
+<span class="hljs-function"><span class="hljs-keyword">public</span> <span 
class="hljs-keyword">void</span> <span class="hljs-title">register</span><span 
class="hljs-params">()</span> </span>{
+    <span class="hljs-keyword">if</span> (!registered.get() &amp;&amp; 
registered.compareAndSet(<span class="hljs-keyword">false</span>, <span 
class="hljs-keyword">true</span>)) {
+        Runtime.getRuntime().addShutdownHook(getDubboShutdownHook());
+    }
+}
+</code></pre>
+</li>
+<li>
+<p>每个ShutdownHook都是一个单独的线程,由JVM在退出时触发执行<code>org.apache.dubbo.config.DubboShutdownHook</code>。</p>
+<pre><code class="language-java"><span class="hljs-comment">/**
+ * Destroy all the resources, including registries and protocols.
+ */</span>
+<span class="hljs-function"><span class="hljs-keyword">public</span> <span 
class="hljs-keyword">void</span> <span class="hljs-title">doDestroy</span><span 
class="hljs-params">()</span> </span>{
+    <span class="hljs-keyword">if</span> (!destroyed.compareAndSet(<span 
class="hljs-keyword">false</span>, <span class="hljs-keyword">true</span>)) {
+        <span class="hljs-keyword">return</span>;
+    }
+    <span class="hljs-comment">// destroy all the registries</span>
+    AbstractRegistryFactory.destroyAll();
+    <span class="hljs-comment">// destroy all the protocols</span>
+    destroyProtocols();
+}
+</code></pre>
+</li>
+<li>
+<p>首先关闭所有注册中心,这一步包括:</p>
+<ul>
+<li>从注册中心注销所有已经发布的服务;</li>
+<li>取消订阅当前应用所有依赖的服务;</li>
+<li>断开与注册中心的连接。</li>
+</ul>
+</li>
+<li>
+<p>执行所有<code>Protocol</code>的<code>destroy()</code>,主要包括:</p>
+<ul>
+<li>销毁所有<code>Invoker</code>和<code>Exporter</code>;</li>
+<li>关闭Server,向所有已连接Client发送当前Server只读事件;</li>
+<li>关闭独享/共享Client,断开连接,取消超时和重试任务;</li>
+<li>释放所有相关资源。</li>
+</ul>
+</li>
+<li>
+<p>执行完毕,关闭JVM。</p>
+</li>
+</ol>
+<h2>注意事项</h2>
+<ul>
+<li>使用<code>SIGKILL</code>关闭应用不会执行优雅停机;</li>
+<li>优雅停机不保证会等待所有已发送/到达请求结束;</li>
+<li>配置的优雅停机等待时间<code>timeout</code>不是所有步骤等待时间的总和,而是每一个<code>destroy</code>执行的最大时间。例如配置等待时间为5秒,则关闭Server、关闭Client等步骤会分别等待5秒。</li>
+</ul>
+</section><footer class="footer-container"><div class="footer-body"><img 
src="/img/dubbo_gray.png"/><img class="apache" src="/img/apache_logo.png"/><div 
class="cols-container"><div class="col col-12"><h3>Disclaimer</h3><p>Apache 
Dubbo is an effort undergoing incubation at The Apache Software Foundation 
(ASF), sponsored by the Incubator. Incubation is required of all newly accepted 
projects until a further review indicates that the infrastructure, 
communications, and decision making proce [...]
+       <script 
src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js";></script>
+       <script 
src="https://f.alicdn.com/react/15.4.1/react-dom.min.js";></script>
+       <script>
+               window.rootPath = '';
+  </script>
+  <script src="/build/blogDetail.js"></script>
+  <!-- Global site tag (gtag.js) - Google Analytics -->
+       <script async 
src="https://www.googletagmanager.com/gtag/js?id=UA-112489517-1";></script>
+       <script>
+               window.dataLayer = window.dataLayer || [];
+               function gtag(){dataLayer.push(arguments);}
+               gtag('js', new Date());
+
+               gtag('config', 'UA-112489517-1');
+       </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zh-cn/blog/dubbo-gracefully-shutdown.json 
b/zh-cn/blog/dubbo-gracefully-shutdown.json
new file mode 100644
index 0000000..d026b9e
--- /dev/null
+++ b/zh-cn/blog/dubbo-gracefully-shutdown.json
@@ -0,0 +1,10 @@
+{
+  "filename": "dubbo-gracefully-shutdown.md",
+  "__html": "<h1>Dubbo 
优雅停机</h1>\n<h2>背景</h2>\n<p>对于任何一个线上应用,如何在服务更新部署过程中保证客户端无感知是开发者必须要解决的问题,即从应用停止到重启恢复服务这个阶段不能影响正常的业务请求。理想条件下,在没有请求的时候再进行更新是最安全可靠的,然而互联网应用必须要保证可用性,因此在技术层面上优化应用更新流程来保证服务在更新时无损是必要的。</p>\n<p>传统的解决方式是通过将应用更新流程划分为手工摘流量、停应用、更新重启三个步骤,由人工操作实现客户端无对更新感知。这种方式简单而有效,但是限制较多:不仅需要使用借助网关的支持来摘流量,还需要在停应用前人工判断来保证在途请求已经处理完毕。这种需要人工介入的方式运维复杂度较高,只能适用规模较小的应用,无法在大规模系统上使用。</
 
p>\n<p>因此,如果在容器/框架级别提供某种自动化机制,来自动进行摘流量并确保处理完以到达的请求,不仅能保证业务不受更新影响,还可以极大地提升更新应用时的运维效率。</p>\n<p>这个机制也就是优雅停机,目前Tomcat/Undertow/
 [...]
+  "link": "/zh-cn/blog/dubbo-gracefully-shutdown.html",
+  "meta": {
+    "title": "Dubbo 优雅停机",
+    "keywords": "Dubbo, Gracefully Shutdown, Safely Shutdown",
+    "description": "介绍Dubbo优雅停机的原理和使用方式"
+  }
+}
\ No newline at end of file
diff --git a/zh-cn/blog/dubboAsync_client.html 
b/zh-cn/blog/dubboAsync_client.html
new file mode 100644
index 0000000..8fb6525
--- /dev/null
+++ b/zh-cn/blog/dubboAsync_client.html
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+       <meta charset="UTF-8">
+       <meta name="viewport" content="width=device-width, initial-scale=1.0, 
maximum-scale=1.0, user-scalable=no">
+       <meta name="keywords" content="Dubbo, 异步, Reactive" />
+       <meta name="description" content="Dubbo客户端异步接口的实现背景和实践" />
+       <!-- 网页标签标题 -->
+       <title>Dubbo客户端异步接口的实现背景和实践</title>
+       <link rel="shortcut icon" href="/img/dubbo.ico"/>
+       <link rel="stylesheet" href="/build/blogDetail.css" />
+</head>
+<body>
+       <div id="root"><div class="blog-detail-page" data-reactroot=""><header 
class="header-container header-container-normal"><div class="header-body"><a 
href="/zh-cn/index.html"><img class="logo" 
src="/img/dubbo_colorful.png"/></a><div class="search search-normal"><span 
class="icon-search"></span></div><span class="language-switch 
language-switch-normal">En</span><div class="header-menu"><img 
class="header-menu-toggle" src="/img/menu_gray.png"/><ul><li class="menu-item 
menu-item-normal"><a h [...]
+<h2>铺垫</h2>
+<p><img src="../../img/blog/dubboasyn_client/1.png" alt="image | left"></p>
+<p>先简单介绍下一次完整的Dubbo调用所经历的线程阶段。几个信息这里罗列下</p>
+<ol>
+<li>
+<p>Biz~代表业务线程,即便是业务逻辑处理所处的线程,Biz~线程池可能是业务自己创建维护,大多数的可能是系统框架自身管理的(比如web型的业务系统跑在Tomcat容器下,Biz~线程就是Tomcat维护);IO~代表网络数据处理线程,是IO框架(比如Netty,Grizzly)创建维护,Dubbo
 
Remoting所默认Netty实现是NioEventloopLoopGroup;另外按照Channel与IO线程的绑定关系,也可以直接把IO~看成一个可接受事件消息的Channel。像Biz和IO这样的异步处理阶段在JDK8中有个很精确地抽象描述,叫CompletionStage。</p>
+</li>
+<li>
+<p>大家知道,线程与线程之间做数据通信的方式是共享变量,Biz和IO两个stage之间的数据通信是Queue,具体到Dubbo实现,在客户端一侧的实现(即上图中用1所标注的步骤)中Biz是通过向EventLoop的LinkedBlockingQueue放置一个Task,而EventLoop有对应的Thread会不停的迭代Queue来执行Task中所包含的信息,具体代码可以看SingleThreadEventExecutor(顺便提下,Netty中默认是用无上限的LinkedBlockingQueue,在Biz的速率高于网络速率情况下,似乎好像有Memory
 Leak的风险)。</p>
+</li>
+<li>
+<p>如上图所示,标准的一次RPC调用经过了图中所示的1,2,3,4的四次消息(事件)传递,分别是客户端业务线程到IO线程的请求发出,服务端IO线程到业务逻辑线程的__请求接受,__服务端处理完成后由业务逻辑线程到IO线程的响应写出,客户端收到结果后从IO线程到业务逻辑的响应处理。除了1与4之间一般需要维护响应和请求的映射对应关系,四次的事件处理都是完全独立的,所以一次RPC调用天然是异步的,而同步是基于异步而来。</p>
+</li>
+</ol>
+<h2>客户端异步</h2>
+<h3>实现背景</h3>
+<p>在Java语言(其他语言不清楚)下一次本地接口的调用可以透明地通过代理机制转为远程RPC的调用,大多数业务方也比较喜欢这种与本地接口类似的编程方式做远程服务集成,所以虽然RPC内部天然是异步的,但使用Dubbo的用户使用最广泛的还是同步,而异步反而成为小众的使用场景。同步的优点是编程模型更加符合业务方的“传统”习惯,代价是在图中的1代表的请求发出事件后需要阻塞当前的Biz~线程,一直等到4代表的响应处理后才能唤醒。在这个短则微妙级别,长则秒级的1,2,3,4处理过程中都要阻塞Biz~线程,就会消耗线程资源,增加系统资源的开销。</p>
+<p>所以,客户端异步的出发点是节省线程资源开销,代价是需要了解下异步的使用方式:)。在同步方式下API接口的返回类型是代表着某个业务类,而当异步情况下,响应返回与请求发出是完全独立的两个事件,需要API接口的返回类型变为上述中说的CompletionStage才是最贴合的,这是Dubbo在异步上支持的必然异步。回到最近的Dubbo发布版,是不改变接口的情况下,需要在服务创建时注册一个回调接口来处理响应返回事件。</p>
+<p>下面以示例来说。</p>
+<h3>示例</h3>
+<p>事件通知的示例代码请参考:<a 
href="https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-notify";>https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-notify</a></p>
+<p>事件通知允许 Consumer 端在调用之前、调用正常返回之后或调用出现异常时,触发 
<code>oninvoke</code>、<code>onreturn</code>、<code>onthrow</code> 三个事件。</p>
+<p>可以通过在配置 Consumer 时,指定事件需要通知的方法,如:</p>
+<pre><code class="language-xml"><span class="hljs-tag">&lt;<span 
class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span 
class="hljs-string">"demoCallback"</span> <span 
class="hljs-attr">class</span>=<span 
class="hljs-string">"com.alibaba.dubbo.samples.notify.impl.NotifyImpl"</span> 
/&gt;</span>
+
+<span class="hljs-tag">&lt;<span class="hljs-name">dubbo:reference</span> 
<span class="hljs-attr">id</span>=<span 
class="hljs-string">"demoService"</span> <span 
class="hljs-attr">check</span>=<span class="hljs-string">"false"</span> <span 
class="hljs-attr">interface</span>=<span 
class="hljs-string">"com.alibaba.dubbo.samples.notify.api.DemoService"</span> 
<span class="hljs-attr">version</span>=<span class="hljs-string">"1.0.0"</span> 
<span class="hljs-attr">group</span>=<span class="hljs [...]
+    <span class="hljs-tag">&lt;<span class="hljs-name">dubbo:method</span> 
<span class="hljs-attr">name</span>=<span class="hljs-string">"sayHello"</span> 
<span class="hljs-attr">onreturn</span>=<span 
class="hljs-string">"demoCallback.onreturn"</span> <span 
class="hljs-attr">onthrow</span>=<span 
class="hljs-string">"demoCallback.onthrow"</span>/&gt;</span>
+<span class="hljs-tag">&lt;/<span 
class="hljs-name">dubbo:reference</span>&gt;</span>
+</code></pre>
+<p>其中,NotifyImpl 的代码如下:</p>
+<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">NotifyImpl</span> <span 
class="hljs-keyword">implements</span> <span 
class="hljs-title">Notify</span></span>{
+
+    <span class="hljs-keyword">public</span> Map&lt;Integer, String&gt; ret = 
<span class="hljs-keyword">new</span> HashMap&lt;Integer, String&gt;();
+    
+    <span class="hljs-function"><span class="hljs-keyword">public</span> <span 
class="hljs-keyword">void</span> <span class="hljs-title">onreturn</span><span 
class="hljs-params">(String name, <span class="hljs-keyword">int</span> 
id)</span> </span>{
+        ret.put(id, name);
+        System.out.println(<span class="hljs-string">"onreturn: "</span> + 
name);
+    }
+
+    <span class="hljs-function"><span class="hljs-keyword">public</span> <span 
class="hljs-keyword">void</span> <span class="hljs-title">onthrow</span><span 
class="hljs-params">(Throwable ex, String name, <span 
class="hljs-keyword">int</span> id)</span> </span>{
+        System.out.println(<span class="hljs-string">"onthrow: "</span> + 
name);
+    }
+}
+</code></pre>
+<p>这里要强调一点,自定义 Notify 接口中的三个方法的参数规则如下:</p>
+<ul>
+<li><code>oninvoke</code> 方法参数与调用方法的参数相同;</li>
+<li><code>onreturn</code>方法第一个参数为调用方法的返回值,其余为调用方法的参数;</li>
+<li><code>onthrow</code>方法第一个参数为调用异常,其余为调用方法的参数。</li>
+</ul>
+<p>上述配置中,<code>sayHello</code>方法为同步调用,因此事件通知方法的执行也是同步执行。可以配置 
<code>async=true</code>让方法调用为异步,这时事件通知的方法也是异步执行的。特别强调一下,<code>oninvoke</code>方法不管是否异步调用,都是同步执行的。</p>
+<h3>实践建议</h3>
+<ul>
+<li>
+<div data-type="alignment" data-value="justify" style="text-align:justify">
+<div 
data-type="p">RPC调用后的逻辑非强依赖结果:异步回调是在客户端<strong>非强依赖服务端的结果</strong>情况下,是适用客户端的异步调用。</div>
+</div>
+</li>
+<li>
+<div data-type="alignment" data-value="justify" style="text-align:justify">
+<div 
data-type="p">rx场景:自从了解到reactive的编程模型后,认为只要编程思维能够拥抱reactive,并且业务模型的状态机设计能做适当的调整,任何场景下都比较适用异步来解决,从而得到更好的终端响应体验。
 对于Dubbo来说,当下的异步接口模型是需要像reactive的模型接口做改进,才能使得用户更自然地适用异步接口。</div>
+</div>
+</li>
+</ul>
+<h3>小结</h3>
+<ul>
+<li>客户端异步的出发点就是请求发出和响应处理本身为两个不同的独立事件,响应如何被处理和在哪个线程中处理等都是不需要和请求发出事件的业务逻辑线程做耦合绑定。</li>
+<li>响应事件回调的处理逻辑在哪个线程中做处理是需要根据情况来选择。建议,如果回调逻辑比较简单,建议直接在IO线程中;如果包含了远程访问或者DB访问等IO型的__同步__操作,建议在独立的线程池做处理。</li>
+</ul>
+</section><footer class="footer-container"><div class="footer-body"><img 
src="/img/dubbo_gray.png"/><img class="apache" src="/img/apache_logo.png"/><div 
class="cols-container"><div class="col col-12"><h3>Disclaimer</h3><p>Apache 
Dubbo is an effort undergoing incubation at The Apache Software Foundation 
(ASF), sponsored by the Incubator. Incubation is required of all newly accepted 
projects until a further review indicates that the infrastructure, 
communications, and decision making proce [...]
+       <script 
src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js";></script>
+       <script 
src="https://f.alicdn.com/react/15.4.1/react-dom.min.js";></script>
+       <script>
+               window.rootPath = '';
+  </script>
+  <script src="/build/blogDetail.js"></script>
+  <!-- Global site tag (gtag.js) - Google Analytics -->
+       <script async 
src="https://www.googletagmanager.com/gtag/js?id=UA-112489517-1";></script>
+       <script>
+               window.dataLayer = window.dataLayer || [];
+               function gtag(){dataLayer.push(arguments);}
+               gtag('js', new Date());
+
+               gtag('config', 'UA-112489517-1');
+       </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zh-cn/blog/dubboAsync_client.json 
b/zh-cn/blog/dubboAsync_client.json
new file mode 100644
index 0000000..d4159f3
--- /dev/null
+++ b/zh-cn/blog/dubboAsync_client.json
@@ -0,0 +1,10 @@
+{
+  "filename": "dubboAsync_client.md",
+  "__html": "<h1>Dubbo客户端异步接口的实现背景和实践</h1>\n<h2>铺垫</h2>\n<p><img 
src=\"../../img/blog/dubboasyn_client/1.png\" alt=\"image | 
left\"></p>\n<p>先简单介绍下一次完整的Dubbo调用所经历的线程阶段。几个信息这里罗列下</p>\n<ol>\n<li>\n<p>Biz~代表业务线程,即便是业务逻辑处理所处的线程,Biz~线程池可能是业务自己创建维护,大多数的可能是系统框架自身管理的(比如web型的业务系统跑在Tomcat容器下,Biz~线程就是Tomcat维护);IO~代表网络数据处理线程,是IO框架(比如Netty,Grizzly)创建维护,Dubbo
 
Remoting所默认Netty实现是NioEventloopLoopGroup;另外按照Channel与IO线程的绑定关系,也可以直接把IO~看成一个可接受事件消息的Channel。像Biz和IO这样的异步处理阶段在JDK8中有个很精确地抽象描述,叫CompletionStage。</
 [...]
+  "link": "/zh-cn/blog/dubboAsync_client.html",
+  "meta": {
+    "title": "Dubbo客户端异步接口的实现背景和实践",
+    "keywords": "Dubbo, 异步, Reactive",
+    "description": "Dubbo客户端异步接口的实现背景和实践"
+  }
+}
\ No newline at end of file
diff --git a/zh-cn/blog/dubboAsync_server.html 
b/zh-cn/blog/dubboAsync_server.html
new file mode 100644
index 0000000..86f39df
--- /dev/null
+++ b/zh-cn/blog/dubboAsync_server.html
@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+       <meta charset="UTF-8">
+       <meta name="viewport" content="width=device-width, initial-scale=1.0, 
maximum-scale=1.0, user-scalable=no">
+       <meta name="keywords" content="Dubbo, 异步, Reactive" />
+       <meta name="description" content="Dubbo服务端异步接口的实现背景和实践" />
+       <!-- 网页标签标题 -->
+       <title>Dubbo客户端异步接口的实现背景和实践</title>
+       <link rel="shortcut icon" href="/img/dubbo.ico"/>
+       <link rel="stylesheet" href="/build/blogDetail.css" />
+</head>
+<body>
+       <div id="root"><div class="blog-detail-page" data-reactroot=""><header 
class="header-container header-container-normal"><div class="header-body"><a 
href="/zh-cn/index.html"><img class="logo" 
src="/img/dubbo_colorful.png"/></a><div class="search search-normal"><span 
class="icon-search"></span></div><span class="language-switch 
language-switch-normal">En</span><div class="header-menu"><img 
class="header-menu-toggle" src="/img/menu_gray.png"/><ul><li class="menu-item 
menu-item-normal"><a h [...]
+<h2>铺垫</h2>
+<p>建议先对Dubbo的处理过程中涉及的线程阶段先做个了解,具体可参考<a 
href="http://dubbo.apache.org/zh-cn/blog/dubboAsync_client.html";>Dubbo客户端异步接口的实现背景和使用场景</a>。</p>
+<h2>实现背景</h2>
+<p>有必要比较详细点的介绍下服务端的线程策略来加深用户在选择服务端异步的判断依据,同时有必要引出协程这一在服务端异步中常常会用到的“秘密武器”。</p>
+<h3>服务端的线程策略</h3>
+<p>Dubbo是支持多种NIO框架来做Remoting的协议实现,无论是Netty,Mina或者Grizzly,实现都大同小异,都是基于事件驱动的方式来做网络通道建立,数据流读取的,其中Grizzly对于线程策略介绍的为例,通常支持以下四种。Dubbo作为一个RPC框架,默认选择的是第一种策略,原因在于业务服务是CPU密集型还是IO阻塞性,是无法断定的,第一种策略是最保险的策略。当然,对于这几种策略有了了解后,再结合业务场景做针对性的选择是最完美的。</p>
+<ol>
+<li><strong>Worker-thread
+策略</strong></li>
+</ol>
+<p>最常用最普适的策略,其中IO线程将NIO事件处理委托给工作线程。</p>
+<p><img src="../../img/blog/dubboasyn_server/1.png" 
alt="workerthread-strategy.png | center | 371x244"></p>
+<p>此策略具有很高的伸缩性。我们可以根据需要更改IO和worker线程池的大小,并且不存在在特定NIO事件处理期间可能发生的某些问题将影响在同一IO线程上注册的其他通道的风险。
+缺点是有线程上下文切换的代价。</p>
+<ol start="2">
+<li><strong>Same-thread策略</strong></li>
+</ol>
+<p>可能是最有效的策略。与第一种不同,同一线程处理当前线程中的NIO事件,避免了昂贵的线程上下文切换。</p>
+<p><img src="../../img/blog/dubboasyn_server/2.png" 
alt="samethread-strategy.png | center | 389x264"></p>
+<p>考虑到这个策略可以调整IO线程池大小,是具备可伸缩性;缺点也很明显,它要求业务处理中一定不要有阻塞处理,因为它可能会阻止在同一个IO线程上发生的其他NIO事件的处理。</p>
+<ol start="3">
+<li>dynamic__策略__</li>
+</ol>
+<p>如前所述,前两种策略具有明显的优点和缺点。但是,如果策略可以尝试在运行时根据当前条件(负载,收集的统计信息等)巧妙地交换它们,何如?</p>
+<p><img src="../../img/blog/dubboasyn_server/3.png" alt="dynamic-strategy.png 
| center | 361x387"></p>
+<p>这种策略可能会带来很多好处,能更好地控制资源,前提是不要使条件评估逻辑过载,防止评估判断的复杂性会使这种策略效率低下。
+多说一句,希望大家对这个策略多留意一下,它可能是Dubbo服务端异步方式的最佳搭配。我也多扯个淡,这几天关注了些adaptive 
XX或者predictive 
XX,这里看到dynamic真是亲切,Dubbo作为产品级生产级的微服务解决方案,是必须既要adaptive,又要predictive,还要dynamic,哈哈。</p>
+<ol start="4">
+<li>__Leader-follower __
+策略</li>
+</ol>
+<p><img src="../../img/blog/dubboasyn_server/4.png" 
alt="leaderfollower-strategy.png | center | 443x286"></p>
+<p>此策略类似于第一种,但它不是将NIO事件处理传递给worker线程,而是通过将控制传递给Selector给工作线程,并将实际NIO事件处理当前IO线程中。这种策略其实是把worker和IO线程阶段做了混淆,个人不建议。</p>
+<h3>协程与线程</h3>
+<p>在CPU资源的管理上,OS和JVM的最小调度单位都是线程,业务应用通过扩展实现的协程包是可以具备独立的运行单位,事实上也是基于线程来做的,核心应该是遇到IO阻塞,或者锁等待时,保存上下文,然后切换到另一个协程。至于说的协程开销低,能更高效的使用CPU,这些考虑到协程库的用户态实现和上下文设计是支持的,但也建议大家结合实际业务场景做性能测试。</p>
+<p><strong>在默认的Dubbo线程策略中,是有worker线程池来执行业务逻辑,但也常常会发生ThreadPool 
Full的问题,为了尽快释放worker线程,在业务服务的实现中会另起线程。代价是再次增加线程上下文切换,同时需要考虑链路级别的数据传送(比如tracing信息)和流控的出口控制等等。当然,如果Dubbo能够切换到Same-thread策略,再配合协程库的支持,服务端异步是一种值得推荐的使用方式。</strong></p>
+<h2>示例</h2>
+<p>通过示例来体验下Dubbo服务端异步接口。Demo代码请访问github之<a 
href="https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-notify";>https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-notify</a>。</p>
+<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">AsyncServiceImpl</span> <span 
class="hljs-keyword">implements</span> <span 
class="hljs-title">AsyncService</span> </span>{
+
+    <span class="hljs-meta">@Override</span>
+    <span class="hljs-function"><span class="hljs-keyword">public</span> 
String <span class="hljs-title">sayHello</span><span 
class="hljs-params">(String name)</span> </span>{
+        System.out.println(<span class="hljs-string">"Main sayHello() method 
start."</span>);
+        <span class="hljs-keyword">final</span> AsyncContext asyncContext = 
RpcContext.startAsync();
+        <span class="hljs-keyword">new</span> Thread(() -&gt; {
+            asyncContext.signalContextSwitch();
+            System.out.println(<span class="hljs-string">"Attachment from 
consumer: "</span> + RpcContext.getContext().getAttachment(<span 
class="hljs-string">"consumer-key1"</span>));
+            System.out.println(<span class="hljs-string">"    -- Async 
start."</span>);
+            <span class="hljs-keyword">try</span> {
+                Thread.sleep(<span class="hljs-number">500</span>);
+            } <span class="hljs-keyword">catch</span> (InterruptedException e) 
{
+                e.printStackTrace();
+            }
+            asyncContext.write(<span class="hljs-string">"Hello "</span> + 
name + <span class="hljs-string">", response from provider."</span>);
+            System.out.println(<span class="hljs-string">"    -- Async 
end."</span>);
+        }).start();
+        System.out.println(<span class="hljs-string">"Main sayHello() method 
end."</span>);
+        <span class="hljs-keyword">return</span> <span 
class="hljs-string">"hello, "</span> + name;
+    }
+
+</code></pre>
+<h2>实践建议</h2>
+<ul>
+<li>不用迷信服务端异步</li>
+<li>不要迷信服务端异步</li>
+<li>服务端异步在Event-Driven或者Reactive面前基本是伪命题.<span data-type="color" 
style="color:rgb(36, 41, 46)"><span data-type="background" 
style="background-color:rgb(255, 255, 
255)">补充下原因:服务端异步初衷是说Dubbo的服务端业务线程数(默认是200个)不够,但其实在event-driven模式下, 
200个肯定不需要那么多,只需要cpu核数那样就可以,只要业务实现是非阻塞的纯异步方式的非阻塞的业务逻辑处理,用再多的线程数就是浪费资源。</span></span></li>
+<li>要用服务端异步,建议服务端的线程策略采用same thread模式+协程包</li>
+</ul>
+<h2>小结</h2>
+<p>Dubbo在支持业务应用时,会碰到千奇百怪的需求场景,服务端异步为用户提供了一种解决ThreadPool Full的方案。当发生ThreadPool 
Full的情况下,如果当前系统瓶颈是CPU,不建议用这种方案;如果系统Load不高,调高worker的线程数目,或者采用服务端异步,都是可以考虑的。</p>
+</section><footer class="footer-container"><div class="footer-body"><img 
src="/img/dubbo_gray.png"/><img class="apache" src="/img/apache_logo.png"/><div 
class="cols-container"><div class="col col-12"><h3>Disclaimer</h3><p>Apache 
Dubbo is an effort undergoing incubation at The Apache Software Foundation 
(ASF), sponsored by the Incubator. Incubation is required of all newly accepted 
projects until a further review indicates that the infrastructure, 
communications, and decision making proce [...]
+       <script 
src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js";></script>
+       <script 
src="https://f.alicdn.com/react/15.4.1/react-dom.min.js";></script>
+       <script>
+               window.rootPath = '';
+  </script>
+  <script src="/build/blogDetail.js"></script>
+  <!-- Global site tag (gtag.js) - Google Analytics -->
+       <script async 
src="https://www.googletagmanager.com/gtag/js?id=UA-112489517-1";></script>
+       <script>
+               window.dataLayer = window.dataLayer || [];
+               function gtag(){dataLayer.push(arguments);}
+               gtag('js', new Date());
+
+               gtag('config', 'UA-112489517-1');
+       </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zh-cn/blog/dubboAsync_server.json 
b/zh-cn/blog/dubboAsync_server.json
new file mode 100644
index 0000000..989ea0c
--- /dev/null
+++ b/zh-cn/blog/dubboAsync_server.json
@@ -0,0 +1,10 @@
+{
+  "filename": "dubboAsync_server.md",
+  "__html": 
"<h1>Dubbo服务端异步接口的实现背景和实践</h1>\n<h2>铺垫</h2>\n<p>建议先对Dubbo的处理过程中涉及的线程阶段先做个了解,具体可参考<a
 
href=\"http://dubbo.apache.org/zh-cn/blog/dubboAsync_client.html\";>Dubbo客户端异步接口的实现背景和使用场景</a>。</p>\n<h2>实现背景</h2>\n<p>有必要比较详细点的介绍下服务端的线程策略来加深用户在选择服务端异步的判断依据,同时有必要引出协程这一在服务端异步中常常会用到的“秘密武器”。</p>\n<h3>服务端的线程策略</h3>\n<p>Dubbo是支持多种NIO框架来做Remoting的协议实现,无论是Netty,Mina或者Grizzly,实现都大同小异,都是基于事件驱动的方式来做网络通道建立,数据流读取的,其中Grizzly对于线程策略介绍的为例,通常支持以下四种。Dubbo作为一个RPC框架,默认选择的是第一种策略,原因在于业务服务是CPU密集型还是IO阻�
 ��性,是无法断定的,第一种策 [...]
+  "link": "/zh-cn/blog/dubboAsync_server.html",
+  "meta": {
+    "title": "Dubbo客户端异步接口的实现背景和实践",
+    "keywords": "Dubbo, 异步, Reactive",
+    "description": "Dubbo服务端异步接口的实现背景和实践"
+  }
+}
\ No newline at end of file
diff --git a/zh-cn/blog/index.html b/zh-cn/blog/index.html
index f542e0a..c66b9df 100644
--- a/zh-cn/blog/index.html
+++ b/zh-cn/blog/index.html
@@ -12,7 +12,7 @@
        <link rel="stylesheet" href="/build/blog.css" />
 </head>
 <body>
-       <div id="root"><div class="blog-list-page" data-reactroot=""><header 
class="header-container header-container-normal"><div class="header-body"><a 
href="/zh-cn/index.html"><img class="logo" 
src="/img/dubbo_colorful.png"/></a><div class="search search-normal"><span 
class="icon-search"></span></div><span class="language-switch 
language-switch-normal">En</span><div class="header-menu"><img 
class="header-menu-toggle" src="/img/menu_gray.png"/><ul><li class="menu-item 
menu-item-normal"><a hre [...]
+       <div id="root"><div class="blog-list-page" data-reactroot=""><header 
class="header-container header-container-normal"><div class="header-body"><a 
href="/zh-cn/index.html"><img class="logo" 
src="/img/dubbo_colorful.png"/></a><div class="search search-normal"><span 
class="icon-search"></span></div><span class="language-switch 
language-switch-normal">En</span><div class="header-menu"><img 
class="header-menu-toggle" src="/img/menu_gray.png"/><ul><li class="menu-item 
menu-item-normal"><a hre [...]
        <script 
src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js";></script>
        <script 
src="https://f.alicdn.com/react/15.4.1/react-dom.min.js";></script>
        <script>
diff --git a/zh-cn/blog/introduction-to-dubbo-spi-2.html 
b/zh-cn/blog/introduction-to-dubbo-spi-2.html
index dd17a73..45019ff 100644
--- a/zh-cn/blog/introduction-to-dubbo-spi-2.html
+++ b/zh-cn/blog/introduction-to-dubbo-spi-2.html
@@ -15,8 +15,8 @@
        <div id="root"><div class="blog-detail-page" data-reactroot=""><header 
class="header-container header-container-normal"><div class="header-body"><a 
href="/zh-cn/index.html"><img class="logo" 
src="/img/dubbo_colorful.png"/></a><div class="search search-normal"><span 
class="icon-search"></span></div><span class="language-switch 
language-switch-normal">En</span><div class="header-menu"><img 
class="header-menu-toggle" src="/img/menu_gray.png"/><ul><li class="menu-item 
menu-item-normal"><a h [...]
 <p>在<a 
href="./introduction-to-dubbo-spi.md">Dubbo可扩展机制实战</a>中,我们了解了Dubbo扩展机制的一些概念,初探了Dubbo中LoadBalance的实现,并自己实现了一个LoadBalance。是不是觉得Dubbo的扩展机制很不错呀,接下来,我们就深入Dubbo的源码,一睹庐山真面目。</p>
 <h2>ExtensionLoader</h2>
-<p>ExtentionLoader是最核心的类,负责扩展点的加载和生命周期管理。我们就以这个类开始吧。
-Extension的方法比较多,比较常用的方法有:</p>
+<p>ExtensionLoader 是最核心的类,负责扩展点的加载和生命周期管理。我们就以这个类开始吧。
+ExtensionLoader 的方法比较多,比较常用的方法有:</p>
 <ul>
 <li><code>public static &lt;T&gt; ExtensionLoader&lt;T&gt; 
getExtensionLoader(Class&lt;T&gt; type)</code></li>
 <li><code>public T getExtension(String name)</code></li>
@@ -50,12 +50,12 @@ Extension的方法比较多,比较常用的方法有:</p>
             loader = (ExtensionLoader&lt;T&gt;) EXTENSION_LOADERS.get(type);
         }
         <span class="hljs-keyword">return</span> loader;
-    }
+}
     
 <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>{
         <span class="hljs-keyword">this</span>.type = type;
         objectFactory = (type == ExtensionFactory.class ? <span 
class="hljs-keyword">null</span> : 
ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
-    }
+}
 </code></pre>
 <ol start="2">
 <li>getExtension方法</li>
@@ -78,9 +78,9 @@ Extension的方法比较多,比较常用的方法有:</p>
             }
         }
         <span class="hljs-keyword">return</span> (T) instance;
-    }
+}
 </code></pre>
-<p>getExtention方法中做了一些判断和缓存,主要的逻辑在createExtension方法中。我们继续看createExtention方法。</p>
+<p>getExtension 方法中做了一些判断和缓存,主要的逻辑在 createExtension 方法中。我们继续看 createExtension 
方法。</p>
 <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>{
         <span class="hljs-comment">// 
根据扩展点名称得到扩展类,比如对于LoadBalance,根据random得到RandomLoadBalance类</span>
         Class&lt;?&gt; clazz = getExtensionClasses().get(name);
@@ -107,8 +107,8 @@ Extension的方法比较多,比较常用的方法有:</p>
 <ol>
 <li>先根据name来得到对应的扩展类。从ClassPath下<code>META-INF</code>文件夹下读取扩展点配置文件。</li>
 <li>使用反射创建一个扩展类的实例</li>
-<li>对扩展类实例的属性进行依赖注入,即IoC。</li>
-<li>如果有wrapper,添加wrapper。即AoP。</li>
+<li>对扩展类实例的属性进行依赖注入,即IOC。</li>
+<li>如果有wrapper,添加wrapper。即AOP。</li>
 </ol>
 <p>下面我们来重点看下这4个过程</p>
 <ol>
@@ -127,10 +127,10 @@ Extension的方法比较多,比较常用的方法有:</p>
             }
         }
         <span class="hljs-keyword">return</span> classes;
-    }
+}
 
-    <span class="hljs-comment">// synchronized in getExtensionClasses</span>
-    <span class="hljs-keyword">private</span> Map&lt;String, 
Class&lt;?&gt;&gt; loadExtensionClasses() {
+<span class="hljs-comment">// synchronized in getExtensionClasses</span>
+<span class="hljs-keyword">private</span> Map&lt;String, Class&lt;?&gt;&gt; 
loadExtensionClasses() {
         <span class="hljs-keyword">final</span> SPI defaultAnnotation = 
type.getAnnotation(SPI.class);
         <span class="hljs-keyword">if</span> (defaultAnnotation != <span 
class="hljs-keyword">null</span>) {
             String value = defaultAnnotation.value();
@@ -148,7 +148,7 @@ Extension的方法比较多,比较常用的方法有:</p>
         loadFile(extensionClasses, DUBBO_DIRECTORY);
         loadFile(extensionClasses, SERVICES_DIRECTORY);
         <span class="hljs-keyword">return</span> extensionClasses;
-    }
+}
 </code></pre>
 <p>过程很简单,先从缓存中获取,如果没有,就从配置文件中加载。配置文件的路径就是之前提到的:</p>
 <ul>
@@ -193,13 +193,13 @@ Extension的方法比较多,比较常用的方法有:</p>
 </code></pre>
 
<p>objectFacory本身也是一个扩展,通过<code>ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension())</code>来获取。</p>
 <p><img 
src="https://raw.githubusercontent.com/vangoleo/wiki/master/dubbo/dubbo-extensionfactory.png";
 alt="Dubbo-ExtensionFactory | left"></p>
-<p>ExtensionLoader有三个实现:</p>
+<p>ExtensionFactory 有三个实现:</p>
 <ol>
-<li>SpiExtensionLoader:Dubbo自己的Spi去加载Extension</li>
-<li>SpringExtensionLoader:从Spring容器中去加载Extension</li>
-<li>AdaptiveExtensionLoader: 自适应的AdaptiveExtensionLoader</li>
+<li>SpiExtensionFactory:Dubbo自己的Spi去加载Extension</li>
+<li>SpringExtensionFactory:从Spring容器中去加载Extension</li>
+<li>AdaptiveExtensionFactory: 自适应的AdaptiveExtensionLoader</li>
 </ol>
-<p>这里要注意AdaptiveExtensionLoader,源码如下:</p>
+<p>这里要注意 AdaptiveExtensionFactory,源码如下:</p>
 <pre><code class="language-java"><span class="hljs-meta">@Adaptive</span>
 <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>{
 
@@ -226,8 +226,8 @@ Extension的方法比较多,比较常用的方法有:</p>
 }
 </code></pre>
 
<p>AdaptiveExtensionLoader类有@Adaptive注解。前面提到了,Dubbo会为每一个扩展创建一个自适应实例。如果扩展类上有@Adaptive,会使用该类作为自适应类。如果没有,Dubbo会为我们创建一个。所以<code>ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension())</code>会返回一个AdaptiveExtensionLoader实例,作为自适应扩展实例。
-AdaptiveExtentionLoader会遍历所有的ExtensionFactory实现,尝试着去加载扩展。如果找到了,返回。如果没有,在下一个ExtensionFactory中继续找。Dubbo内置了两个ExtensionFactory,分别从Dubbo自身的扩展机制和Spring容器中去寻找。由于ExtensionFactory本身也是一个扩展点,我们可以实现自己的ExtensionFactory,让Dubbo的自动装配支持我们自定义的组件。比如,我们在项目中使用了Google的guice这个IoC容器。我们可以实现自己的GuiceExtensionFactory,让Dubbo支持从guice容器中加载扩展。</p>
-<h2>Dubbo SPI高级用法之AoP</h2>
+AdaptiveExtensionLoader会遍历所有的ExtensionFactory实现,尝试着去加载扩展。如果找到了,返回。如果没有,在下一个ExtensionFactory中继续找。Dubbo内置了两个ExtensionFactory,分别从Dubbo自身的扩展机制和Spring容器中去寻找。由于ExtensionFactory本身也是一个扩展点,我们可以实现自己的ExtensionFactory,让Dubbo的自动装配支持我们自定义的组件。比如,我们在项目中使用了Google的guice这个
 IOC 容器。我们可以实现自己的GuiceExtensionFactory,让Dubbo支持从guice容器中加载扩展。</p>
+<h2>Dubbo SPI高级用法之 AOP</h2>
 <p>在用Spring的时候,我们经常会用到AOP功能。在目标类的方法前后插入其他逻辑。比如通常使用Spring AOP来实现日志,监控和鉴权等功能。
 
Dubbo的扩展机制,是否也支持类似的功能呢?答案是yes。在Dubbo中,有一种特殊的类,被称为Wrapper类。通过装饰者模式,使用包装类包装原始的扩展点实例。在原始扩展点实现前后插入其他逻辑,实现AOP功能。</p>
 <h3>什么是Wrapper类</h3>
@@ -241,10 +241,10 @@ Dubbo的扩展机制,是否也支持类似的功能呢?答案是yes。在Dub
 </code></pre>
 <p>类A有一个构造函数<code>public A(A 
a)</code>,构造函数的参数是A本身。这样的类就可以成为Dubbo扩展机制中的一个Wrapper类。Dubbo中这样的Wrapper类有ProtocolFilterWrapper,
 ProtocolListenerWrapper等, 大家可以查看源码加深理解。</p>
 <h3>怎么配置Wrapper类</h3>
-<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>
-<pre><code 
class="language-text">filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
-listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
-mock=com.alibaba.dubbo.rpc.support.MockProtocol
+<p>在Dubbo中Wrapper类也是一个扩展点,和其他的扩展点一样,也是在<code>META-INF</code>文件夹中配置的。比如前面举例的ProtocolFilterWrapper和ProtocolListenerWrapper就是在路径<code>dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol</code>中配置的:</p>
+<pre><code 
class="language-text">filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper
+listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper
+mock=org.apache.dubbo.rpc.support.MockProtocol
 </code></pre>
 <p>在Dubbo加载扩展配置文件时,有一段如下的代码:</p>
 <pre><code class="language-java"><span class="hljs-keyword">try</span> {  
@@ -258,7 +258,7 @@ mock=com.alibaba.dubbo.rpc.support.MockProtocol
 } <span class="hljs-keyword">catch</span> (NoSuchMethodException e) {}
 </code></pre>
 
<p>这段代码的意思是,如果扩展类有复制构造函数,就把该类存起来,供以后使用。有复制构造函数的类就是Wrapper类。通过<code>clazz.getConstructor(type)</code>来获取参数是扩展点接口的构造函数。注意构造函数的参数类型是扩展点接口,而不是扩展类。
-以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>。
+以Protocol为例。配置文件<code>dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol</code>中定义了<code>filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper</code>。
 ProtocolFilterWrapper代码如下:</p>
 <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>{
 
@@ -271,6 +271,7 @@ ProtocolFilterWrapper代码如下:</p>
         }
         <span class="hljs-keyword">this</span>.protocol = protocol;
     }
+}
 </code></pre>
 <p>ProtocolFilterWrapper有一个构造函数<code>public ProtocolFilterWrapper(Protocol 
protocol)</code>,参数是扩展点Protocol,所以它是一个Dubbo扩展机制中的Wrapper类。ExtensionLoader会把它缓存起来,供以后创建Extension实例的时候,使用这些包装类依次包装原始扩展点。</p>
 <h2>扩展点自适应</h2>
@@ -309,7 +310,7 @@ ProtocolFilterWrapper代码如下:</p>
 <pre><code class="language-java"><span class="hljs-keyword">private</span> 
Class&lt;?&gt; createAdaptiveExtensionClass() {
         String code = createAdaptiveExtensionClassCode();
         ClassLoader classLoader = findClassLoader();
-        com.alibaba.dubbo.common.compiler.Compiler compiler = 
ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
+        org.apache.dubbo.common.compiler.Compiler compiler = 
ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
         <span class="hljs-keyword">return</span> compiler.compile(code, 
classLoader);
     }
 </code></pre>
@@ -321,44 +322,44 @@ ProtocolFilterWrapper代码如下:</p>
 </code></pre>
 
<p>createAdaptiveExtensionClassCode()方法中使用一个StringBuilder来构建自适应类的Java源码。方法实现比较长,这里就不贴代码了。这种生成字节码的方式也挺有意思的,先生成Java源代码,然后编译,加载到jvm中。通过这种方式,可以更好的控制生成的Java类。而且这样也不用care各个字节码生成框架的api等。因为xxx.java文件是Java通用的,也是我们最熟悉的。只是代码的可读性不强,需要一点一点构建xx.java的内容。
 下面是使用createAdaptiveExtensionClassCode方法为Protocol创建的自适应类的Java代码范例:</p>
-<pre><code class="language-java"><span class="hljs-keyword">package</span> 
com.alibaba.dubbo.rpc;
+<pre><code class="language-java"><span class="hljs-keyword">package</span> 
org.apache.dubbo.rpc;
 
-<span class="hljs-keyword">import</span> 
com.alibaba.dubbo.common.extension.ExtensionLoader;
+<span class="hljs-keyword">import</span> 
org.apache.dubbo.common.extension.ExtensionLoader;
 
-<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>{
+<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">Adaptive</span> 
<span class="hljs-keyword">implements</span> <span 
class="hljs-title">org</span>.<span class="hljs-title">apache</span>.<span 
class="hljs-title">dubbo</span>.<span class="hljs-title">rpc</span>.<span 
class="hljs-title">Protocol</span> </span>{
     <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>{
-        <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>);
+        <span class="hljs-keyword">throw</span> <span 
class="hljs-keyword">new</span> UnsupportedOperationException(<span 
class="hljs-string">"method public abstract void 
org.apache.dubbo.rpc.Protocol.destroy() of interface 
org.apache.dubbo.rpc.Protocol is not adaptive method!"</span>);
     }
 
     <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>{
-        <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>);
+        <span class="hljs-keyword">throw</span> <span 
class="hljs-keyword">new</span> UnsupportedOperationException(<span 
class="hljs-string">"method public abstract int 
org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface 
org.apache.dubbo.rpc.Protocol is not adaptive method!"</span>);
     }
 
-    <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>{
-        <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>);
+    <span class="hljs-keyword">public</span> org.apache.dubbo.rpc.<span 
class="hljs-function">Exporter <span class="hljs-title">export</span><span 
class="hljs-params">(org.apache.dubbo.rpc.Invoker arg0)</span> <span 
class="hljs-keyword">throws</span> org.apache.dubbo.rpc.RpcException </span>{
+        <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">"org.apache.dubbo.rpc.Invoker argument == null"</span>);
         <span class="hljs-keyword">if</span> (arg0.getUrl() == <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 getUrl() == 
null"</span>);
-        com.alibaba.dubbo.common.URL url = arg0.getUrl();
+            <span class="hljs-keyword">throw</span> <span 
class="hljs-keyword">new</span> IllegalArgumentException(<span 
class="hljs-string">"org.apache.dubbo.rpc.Invoker argument getUrl() == 
null"</span>);
+        org.apache.dubbo.common.URL url = arg0.getUrl();
         String extName = (url.getProtocol() == <span 
class="hljs-keyword">null</span> ? <span class="hljs-string">"dubbo"</span> : 
url.getProtocol());
         <span class="hljs-keyword">if</span> (extName == <span 
class="hljs-keyword">null</span>)
-            <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>);
-        com.alibaba.dubbo.rpc.Protocol extension = 
(com.alibaba.dubbo.rpc.Protocol) 
ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
+            <span class="hljs-keyword">throw</span> <span 
class="hljs-keyword">new</span> IllegalStateException(<span 
class="hljs-string">"Fail to get extension(org.apache.dubbo.rpc.Protocol) name 
from url("</span> + url.toString() + <span class="hljs-string">") use 
keys([protocol])"</span>);
+        org.apache.dubbo.rpc.Protocol extension = 
(org.apache.dubbo.rpc.Protocol) 
ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
         <span class="hljs-keyword">return</span> extension.export(arg0);
     }
 
-    <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>{
+    <span class="hljs-keyword">public</span> org.apache.dubbo.rpc.<span 
class="hljs-function">Invoker <span class="hljs-title">refer</span><span 
class="hljs-params">(java.lang.Class arg0, org.apache.dubbo.common.URL 
arg1)</span> <span class="hljs-keyword">throws</span> 
org.apache.dubbo.rpc.RpcException </span>{
         <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>);
-        com.alibaba.dubbo.common.URL url = arg1;
+        org.apache.dubbo.common.URL url = arg1;
         String extName = (url.getProtocol() == <span 
class="hljs-keyword">null</span> ? <span class="hljs-string">"dubbo"</span> : 
url.getProtocol());
         <span class="hljs-keyword">if</span> (extName == <span 
class="hljs-keyword">null</span>)
-            <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>);
-        com.alibaba.dubbo.rpc.Protocol extension = 
(com.alibaba.dubbo.rpc.Protocol) 
ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
+            <span class="hljs-keyword">throw</span> <span 
class="hljs-keyword">new</span> IllegalStateException(<span 
class="hljs-string">"Fail to get extension(org.apache.dubbo.rpc.Protocol) name 
from url("</span> + url.toString() + <span class="hljs-string">") use 
keys([protocol])"</span>);
+        org.apache.dubbo.rpc.Protocol extension = 
(org.apache.dubbo.rpc.Protocol) 
ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
         <span class="hljs-keyword">return</span> extension.refer(arg0, arg1);
     }
 }
 </code></pre>
 
<p>大致的逻辑和开始说的一样,通过url解析出参数,解析的逻辑由@Adaptive的value参数控制,然后再根据得到的扩展点名获取扩展点实现,然后进行调用。如果大家想知道具体的构建.java代码的逻辑,可以看<code>createAdaptiveExtensionClassCode</code>的完整实现。
-在生成的Protocol$Adpative中,发现getDefaultPort和destroy方法都是直接抛出异常的,这是为什么呢?来看看Protocol的源码</p>
+在生成的 Protocol$Adaptive 
中,发现getDefaultPort和destroy方法都是直接抛出异常的,这是为什么呢?来看看Protocol的源码</p>
 <pre><code class="language-java"><span class="hljs-meta">@SPI</span>(<span 
class="hljs-string">"dubbo"</span>)
 <span class="hljs-keyword">public</span> <span class="hljs-class"><span 
class="hljs-keyword">interface</span> <span class="hljs-title">Protocol</span> 
</span>{
 
@@ -371,8 +372,9 @@ ProtocolFilterWrapper代码如下:</p>
     &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>;
 
     <span class="hljs-function"><span class="hljs-keyword">void</span> <span 
class="hljs-title">destroy</span><span class="hljs-params">()</span></span>;
+}
 </code></pre>
-<p>可以看到Protocol接口中有4个方法,但只有export和refer两个方法使用了@Adaptive注解。Dubbo自动生成的自适应实例,只有@Adaptive修饰的方法才有具体的实现。所以,Protocol$Adpative类中,也只有export和refer这两个方法有具体的实现,其余方法都是抛出异常。</p>
+<p>可以看到Protocol接口中有4个方法,但只有export和refer两个方法使用了@Adaptive注解。Dubbo自动生成的自适应实例,只有@Adaptive修饰的方法才有具体的实现。所以,Protocol$Adaptive
 类中,也只有export和refer这两个方法有具体的实现,其余方法都是抛出异常。</p>
 </section><footer class="footer-container"><div class="footer-body"><img 
src="/img/dubbo_gray.png"/><img class="apache" src="/img/apache_logo.png"/><div 
class="cols-container"><div class="col col-12"><h3>Disclaimer</h3><p>Apache 
Dubbo is an effort undergoing incubation at The Apache Software Foundation 
(ASF), sponsored by the Incubator. Incubation is required of all newly accepted 
projects until a further review indicates that the infrastructure, 
communications, and decision making proce [...]
        <script 
src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js";></script>
        <script 
src="https://f.alicdn.com/react/15.4.1/react-dom.min.js";></script>
diff --git a/zh-cn/blog/introduction-to-dubbo-spi-2.json 
b/zh-cn/blog/introduction-to-dubbo-spi-2.json
index f8f5e70..b046e8f 100644
--- a/zh-cn/blog/introduction-to-dubbo-spi-2.json
+++ b/zh-cn/blog/introduction-to-dubbo-spi-2.json
@@ -1,6 +1,6 @@
 {
   "filename": "introduction-to-dubbo-spi-2.md",
-  "__html": "<h1>Dubbo可扩展机制源码解析</h1>\n<p>在<a 
href=\"./introduction-to-dubbo-spi.md\">Dubbo可扩展机制实战</a>中,我们了解了Dubbo扩展机制的一些概念,初探了Dubbo中LoadBalance的实现,并自己实现了一个LoadBalance。是不是觉得Dubbo的扩展机制很不错呀,接下来,我们就深入Dubbo的源码,一睹庐山真面目。</p>\n<h2>ExtensionLoader</h2>\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) [...]
+  "__html": "<h1>Dubbo可扩展机制源码解析</h1>\n<p>在<a 
href=\"./introduction-to-dubbo-spi.md\">Dubbo可扩展机制实战</a>中,我们了解了Dubbo扩展机制的一些概念,初探了Dubbo中LoadBalance的实现,并自己实现了一个LoadBalance。是不是觉得Dubbo的扩展机制很不错呀,接下来,我们就深入Dubbo的源码,一睹庐山真面目。</p>\n<h2>ExtensionLoader</h2>\n<p>ExtensionLoader
 是最核心的类,负责扩展点的加载和生命周期管理。我们就以这个类开始吧。\nExtensionLoader 
的方法比较多,比较常用的方法有:</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(Stri [...]
   "link": "/zh-cn/blog/introduction-to-dubbo-spi-2.html",
   "meta": {
     "title": "Dubbo可扩展机制源码解析",
diff --git a/zh-cn/docs/dev/principals/configuration.html 
b/zh-cn/docs/dev/principals/configuration.html
index 9a70ad5..7435083 100644
--- a/zh-cn/docs/dev/principals/configuration.html
+++ b/zh-cn/docs/dev/principals/configuration.html
@@ -16,7 +16,7 @@
 <blockquote>
 <p><a 
href="http://javatar.iteye.com/blog/949527";>http://javatar.iteye.com/blog/949527</a></p>
 </blockquote>
-<p>Dubbo 
现在的设计是完全无侵入,也就是使用者只依赖于配置契约。经过多个版本的发展,为了满足各种需求场景,配置越来越多。为了保持兼容,配置只增不减,里面潜伏着各种风格,约定,规则。新版本也将配置做了一次调整,去掉了
 dubbo.properties,改为全 spring 配置。将想到的一些记在这,备忘。</p>
+<p>Dubbo 
现在的设计是完全无侵入,也就是使用者只依赖于配置契约。经过多个版本的发展,为了满足各种需求场景,配置越来越多。为了保持兼容,配置只增不减,里面潜伏着各种风格,约定,规则。新版本也将配置做了一次调整,将想到的一些记在这,备忘。</p>
 <h2>配置分类</h2>
 <p>首先,配置的用途是有多种的,大致可以分为:</p>
 <ol start="0">
@@ -30,9 +30,20 @@
 <p>另外扩展配置,可能不尽相同。如果只是策略接口实现类替换,可以考虑 properties 等结构。如果有复杂的生命周期管理,可能需要 XML 
等配置。有时候扩展会通过注册接口的方式提供。</p>
 <h2>配置加载</h2>
 <p>对于环境配置,在 java 世界里,比较常规的做法,是在 classpath 下约定一个以项目为名称的 properties 
配置,比如:log4j.properties,velocity.properties等。产品在初始化时,自动从 classpath 
下加载该配置。我们平台的很多项目也使用类似策略,如:dubbo.properties,comsat.xml 
等。这样有它的优势,就是基于约定,简化了用户对配置加载过程的干预。但同样有它的缺点,当 classpath 存在同样的配置时,可能误加载,以及在 
ClassLoader 隔离时,可能找不到配置,并且,当用户希望将配置放到统一的目录时,不太方便。</p>
-<p>Dubbo 新版本去掉了 dubbo.properties,因为该约定经常造成配置冲突。</p>
 <p>而对于描述配置,因为要参与业务逻辑,通常会嵌到应用的生命周期管理中。现在使用 spring 的项目越来越多,直接使用 spring 
配置的比较普遍,而且 spring 允许自定义 schema,配置简化后很方便。当然,也有它的缺点,就是强依赖 
spring,可以提编程接口做了配套方案。</p>
-<p>在 Dubbo 即存在描述配置,也有环境配置。一部分用 spring 的 schema 配置加载,一部分从 classpath 扫描 
properties 配置加载。用户感觉非常不便,所以在新版本中进行了合并,统一放到 spring 的 schema 配置加载,也增加了配置的灵活性。</p>
+<p>在 Dubbo 既存在描述配置也有环境配置。一部分用 spring 的 schema 做配置加载,一部分从 classpath 扫描 
properties 做配置加载。在新版本中做了一个优先级约定,统一以 spring 的 schema 
驱动配置加载,dubbo.properties作为配置补充。</p>
+<p>同时,在 Spring 的场景下,除了使用 schema 外,还支持完全以 application.properties 的方式配置:</p>
+<pre><code class="language-xml"># Dubbo Application
+## The default value of dubbo.application.name is ${spring.application.name}
+## dubbo.application.name=${spring.application.name}
+
+# Dubbo Protocol
+dubbo.protocol.name=dubbo
+dubbo.protocol.port=12345
+
+## Dubbo Registry
+dubbo.registry.address=N/A
+</code></pre>
 <p>扩展配置,通常对配置的聚合要求比较高。因为产品需要发现第三方实现,将其加入产品内部。在 java 世界里,通常是约定在每个 jar 
包下放一个指定文件加载,比如:eclipse 的 plugin.xml,struts2 的 struts-plugin.xml 等,这类配置可以考虑 java 
标准的服务发现机制,即在 jar 包的 META-INF/services 下放置接口类全名文件,内容为每行一个实现类类名,就像 jdk 
中的加密算法扩展,脚本引擎扩展,新的 JDBC 驱动等,都是采用这种方式。参见:<a 
href="https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html";>ServiceProvider
 规范</a>。</p>
 <p>Dubbo 旧版本通过约定在每个 jar 包下,放置名为 dubbo-context.xml 的 spring 配置进行扩展与集成,新版本改成用 
jdk 自带的 META-INF/services 方式,去掉过多的 spring 依赖。</p>
 <h2>可编程配置</h2>
diff --git a/zh-cn/docs/dev/principals/configuration.json 
b/zh-cn/docs/dev/principals/configuration.json
index 2fae2b2..4b78e0d 100644
--- a/zh-cn/docs/dev/principals/configuration.json
+++ b/zh-cn/docs/dev/principals/configuration.json
@@ -1,6 +1,6 @@
 {
   "filename": "configuration.md",
-  "__html": "<h1>配置设计</h1>\n<blockquote>\n<p><a 
href=\"http://javatar.iteye.com/blog/949527\";>http://javatar.iteye.com/blog/949527</a></p>\n</blockquote>\n<p>Dubbo
 
现在的设计是完全无侵入,也就是使用者只依赖于配置契约。经过多个版本的发展,为了满足各种需求场景,配置越来越多。为了保持兼容,配置只增不减,里面潜伏着各种风格,约定,规则。新版本也将配置做了一次调整,去掉了
 dubbo.properties,改为全 spring 
配置。将想到的一些记在这,备忘。</p>\n<h2>配置分类</h2>\n<p>首先,配置的用途是有多种的,大致可以分为:</p>\n<ol 
start=\"0\">\n<li>环境配置,比如:连接数,超时等配置。</li>\n<li>描述配置,比如:服务接口描述,服务版本等。</li>\n<li>扩展配置,比如:协议扩展,策略扩展等。</li>\n</ol>\n<h2>配置格式</h2>\
 [...]
+  "__html": "<h1>配置设计</h1>\n<blockquote>\n<p><a 
href=\"http://javatar.iteye.com/blog/949527\";>http://javatar.iteye.com/blog/949527</a></p>\n</blockquote>\n<p>Dubbo
 
现在的设计是完全无侵入,也就是使用者只依赖于配置契约。经过多个版本的发展,为了满足各种需求场景,配置越来越多。为了保持兼容,配置只增不减,里面潜伏着各种风格,约定,规则。新版本也将配置做了一次调整,将想到的一些记在这,备忘。</p>\n<h2>配置分类</h2>\n<p>首先,配置的用途是有多种的,大致可以分为:</p>\n<ol
 
start=\"0\">\n<li>环境配置,比如:连接数,超时等配置。</li>\n<li>描述配置,比如:服务接口描述,服务版本等。</li>\n<li>扩展配置,比如:协议扩展,策略扩展等。</li>\n</ol>\n<h2>配置格式</h2>\n<p>通常环境配置,用
 properties 配置会比较方便,因为都 [...]
   "link": "/zh-cn/docs/dev/principals/configuration.html",
   "meta": {}
 }
\ No newline at end of file
diff --git a/zh-cn/docs/developers/developers_dev.html 
b/zh-cn/docs/developers/developers_dev.html
index a212f02..00ab76e 100644
--- a/zh-cn/docs/developers/developers_dev.html
+++ b/zh-cn/docs/developers/developers_dev.html
@@ -236,6 +236,13 @@
 <td>Committer</td>
 <td>+8</td>
 </tr>
+<tr>
+<td>biyuhao</td>
+<td>Yuhao Bi</td>
+<td>Asiainfo-sec</td>
+<td>Committer</td>
+<td>+8</td>
+</tr>
 </tbody>
 </table>
 <h3>贡献者</h3>
@@ -262,12 +269,6 @@
 <td>+8</td>
 </tr>
 <tr>
-<td>biyuhao</td>
-<td><a href="https://github.com/biyuhao";>https://github.com/biyuhao</a></td>
-<td>Asiainfo-sec</td>
-<td>+8</td>
-</tr>
-<tr>
 <td>huyuechy</td>
 <td><a href="https://github.com/huyuechy";>https://github.com/huyuechy</a></td>
 <td></td>
diff --git a/zh-cn/docs/developers/developers_dev.json 
b/zh-cn/docs/developers/developers_dev.json
index 767407b..d3c7ebb 100644
--- a/zh-cn/docs/developers/developers_dev.json
+++ b/zh-cn/docs/developers/developers_dev.json
@@ -1,6 +1,6 @@
 {
   "filename": "developers_dev.md",
-  "__html": 
"<h2>开发人员</h2>\n<p>本页面展示了Dubbo的开发团队。请通过提交PR的方式把自己的信息添加到列表上。注:排名不分先后</p>\n<h3>提交者</h3>\n<table>\n<thead>\n<tr>\n<th>Apache
 
ID</th>\n<th>姓名</th>\n<th>组织</th>\n<th>角色</th>\n<th>时区</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>jmclean</td>\n<td>Justin
 
Mclean</td>\n<td>Apache</td>\n<td>Mentor</td>\n<td>+11</td>\n</tr>\n<tr>\n<td>markt</td>\n<td>Mark
 
Thomas</td>\n<td>Apache</td>\n<td>Mentor</td>\n<td>+0</td>\n</tr>\n<tr>\n<td>wave</td>\n<td>Dave
 Fisher</td>\n<td></td>\n<td>Mentor</td>\ [...]
+  "__html": 
"<h2>开发人员</h2>\n<p>本页面展示了Dubbo的开发团队。请通过提交PR的方式把自己的信息添加到列表上。注:排名不分先后</p>\n<h3>提交者</h3>\n<table>\n<thead>\n<tr>\n<th>Apache
 
ID</th>\n<th>姓名</th>\n<th>组织</th>\n<th>角色</th>\n<th>时区</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>jmclean</td>\n<td>Justin
 
Mclean</td>\n<td>Apache</td>\n<td>Mentor</td>\n<td>+11</td>\n</tr>\n<tr>\n<td>markt</td>\n<td>Mark
 
Thomas</td>\n<td>Apache</td>\n<td>Mentor</td>\n<td>+0</td>\n</tr>\n<tr>\n<td>wave</td>\n<td>Dave
 Fisher</td>\n<td></td>\n<td>Mentor</td>\ [...]
   "link": "/zh-cn/docs/developers/developers_dev.html",
   "meta": {}
 }
\ No newline at end of file
diff --git a/zh-cn/docs/source_code_guide/export-service.html 
b/zh-cn/docs/source_code_guide/export-service.html
index 6b18f49..00b042d 100644
--- a/zh-cn/docs/source_code_guide/export-service.html
+++ b/zh-cn/docs/source_code_guide/export-service.html
@@ -1116,7 +1116,7 @@
 }
 </code></pre>
 <p>以上就是 NettyServer 创建的过程,dubbo 默认使用的 NettyServer 是基于 netty 3.x 版本实现的,比较老了。因此 
Dubbo 另外提供了 netty 4.x 版本的 NettyServer,大家可在使用 Dubbo 的过程中按需进行配置。</p>
-<p>到此,关于服务导出的过程就分析完了。整个过程比较复杂,大家在分析的过程中耐心一些。并且多写 Demo 进行进行调试,以便能够更好的理解代码逻辑。</p>
+<p>到此,关于服务导出的过程就分析完了。整个过程比较复杂,大家在分析的过程中耐心一些。并且多写 Demo 进行调试,以便能够更好的理解代码逻辑。</p>
 <p>本节内容先到这里,接下来分析服务导出的另一块逻辑 — 服务注册。</p>
 <h3>2.2.4 服务注册</h3>
 <p>本节我们来分析服务注册过程,服务注册操作对于 Dubbo 
来说不是必需的,通过服务直连的方式就可以绕过注册中心。但通常我们不会这么做,直连方式不利于服务治理,仅推荐在测试服务时使用。对于 Dubbo 
来说,注册中心虽不是必需,但却是必要的。因此,关于注册中心以及服务注册相关逻辑,我们也需要搞懂。</p>
diff --git a/zh-cn/docs/source_code_guide/export-service.json 
b/zh-cn/docs/source_code_guide/export-service.json
index cd890a0..f5f0703 100644
--- a/zh-cn/docs/source_code_guide/export-service.json
+++ b/zh-cn/docs/source_code_guide/export-service.json
@@ -1,6 +1,6 @@
 {
   "filename": "export-service.md",
-  "__html": "<h2>1.简介</h2>\n<p>本篇文章,我们来研究一下 Dubbo 导出服务的过程。Dubbo 服务导出过程始于 
Spring 容器发布刷新事件,Dubbo 在接收到事件后,会立即执行服务导出逻辑。整个逻辑大致可分为三个部分,第一部分是前置工作,主要用于检查参数,组装 
URL。第二部分是导出服务,包含导出服务到本地 
(JVM),和导出服务到远程两个过程。第三部分是向注册中心注册服务,用于服务发现。本篇文章将会对这三个部分代码进行详细的分析。</p>\n<h2>2.源码分析</h2>\n<p>服务导出的入口方法是
 ServiceBean 的 onApplicationEvent。onApplicationEvent 是一个事件响应方法,该方法会在收到 Spring 
上下文刷新事件后执行服务导出操作。方法代码如下:</p>\n<pre><code class=\"language-java\"><span 
class=\"hljs-function\"><span class=\"hljs-keyword\">public</span> <s [...]
+  "__html": "<h2>1.简介</h2>\n<p>本篇文章,我们来研究一下 Dubbo 导出服务的过程。Dubbo 服务导出过程始于 
Spring 容器发布刷新事件,Dubbo 在接收到事件后,会立即执行服务导出逻辑。整个逻辑大致可分为三个部分,第一部分是前置工作,主要用于检查参数,组装 
URL。第二部分是导出服务,包含导出服务到本地 
(JVM),和导出服务到远程两个过程。第三部分是向注册中心注册服务,用于服务发现。本篇文章将会对这三个部分代码进行详细的分析。</p>\n<h2>2.源码分析</h2>\n<p>服务导出的入口方法是
 ServiceBean 的 onApplicationEvent。onApplicationEvent 是一个事件响应方法,该方法会在收到 Spring 
上下文刷新事件后执行服务导出操作。方法代码如下:</p>\n<pre><code class=\"language-java\"><span 
class=\"hljs-function\"><span class=\"hljs-keyword\">public</span> <s [...]
   "link": "/zh-cn/docs/source_code_guide/export-service.html",
   "meta": {
     "title": "服务导出",
diff --git a/zh-cn/docs/source_code_guide/refer-service.html 
b/zh-cn/docs/source_code_guide/refer-service.html
index a81d8d5..83062bf 100644
--- a/zh-cn/docs/source_code_guide/refer-service.html
+++ b/zh-cn/docs/source_code_guide/refer-service.html
@@ -13,9 +13,9 @@
 </head>
 <body>
        <div id="root"><div class="documentation-page" 
data-reactroot=""><header class="header-container header-container-normal"><div 
class="header-body"><a href="/zh-cn/index.html"><img class="logo" 
src="/img/dubbo_colorful.png"/></a><div class="search search-normal"><span 
class="icon-search"></span></div><span class="language-switch 
language-switch-normal">En</span><div class="header-menu"><img 
class="header-menu-toggle" src="/img/menu_gray.png"/><ul><li class="menu-item 
menu-item-normal"><a [...]
-<p>上一篇文章详细分析了服务导出的过程,本篇文章我们趁热打铁,继续分析服务引用过程。在 Dubbo 
中,我们可以通过两种方式引用远程服务。第一种是使用服务直联的方式引用服务,第二种方式是基于注册中心进行引用。服务直联的方式仅适合在调试或测试服务的场景下使用,不适合在线上环境使用。因此,本文我将重点分析通过注册中心引用服务的过程。从注册中心中获取服务配置只是服务引用过程中的一环,除此之外,服务消费者还需要经历
 Invoker 创建、代理类创建等步骤。这些步骤,将在后续章节中一一进行分析。</p>
+<p>上一篇文章详细分析了服务导出的过程,本篇文章我们趁热打铁,继续分析服务引用过程。在 Dubbo 
中,我们可以通过两种方式引用远程服务。第一种是使用服务直连的方式引用服务,第二种方式是基于注册中心进行引用。服务直连的方式仅适合在调试或测试服务的场景下使用,不适合在线上环境使用。因此,本文我将重点分析通过注册中心引用服务的过程。从注册中心中获取服务配置只是服务引用过程中的一环,除此之外,服务消费者还需要经历
 Invoker 创建、代理类创建等步骤。这些步骤,将在后续章节中一一进行分析。</p>
 <h2>2.服务引用原理</h2>
-<p>Dubbo 服务引用的时机有两个,第一个是在 Spring 容器调用 ReferenceBean 的 afterPropertiesSet 
方法时引用服务,第二个是在 ReferenceBean 
对应的服务被注入到其他类中时引用。这两个引用服务的时机区别在于,第一个是饿汉式的,第二个是懒汉式的。默认情况下,Dubbo 
使用懒汉式引用服务。如果需要使用饿汉式,可通过配置 &lt;dubbo:reference&gt; 的 init 属性开启。下面我们按照 Dubbo 
默认配置进行分析,整个分析过程从 ReferenceBean 的 getObject 方法开始。当我们的服务被注入到其他类中时,Spring 会第一时间调用 
getObject 
方法,并由该方法执行服务引用逻辑。按照惯例,在进行具体工作之前,需先进行配置检查与收集工作。接着根据收集到的信息决定服务用的方式,有三种,第一种是引用本地 
(JVM) 服务,第二是通过直联方式引用远程服务,第三是通过注册中心引�
 ��远程服务。不管是哪种引用方式,最后都会得到一个 Invoker 实例。如果有多个注册中心,多个服务提供 [...]
+<p>Dubbo 服务引用的时机有两个,第一个是在 Spring 容器调用 ReferenceBean 的 afterPropertiesSet 
方法时引用服务,第二个是在 ReferenceBean 
对应的服务被注入到其他类中时引用。这两个引用服务的时机区别在于,第一个是饿汉式的,第二个是懒汉式的。默认情况下,Dubbo 
使用懒汉式引用服务。如果需要使用饿汉式,可通过配置 &lt;dubbo:reference&gt; 的 init 属性开启。下面我们按照 Dubbo 
默认配置进行分析,整个分析过程从 ReferenceBean 的 getObject 方法开始。当我们的服务被注入到其他类中时,Spring 会第一时间调用 
getObject 
方法,并由该方法执行服务引用逻辑。按照惯例,在进行具体工作之前,需先进行配置检查与收集工作。接着根据收集到的信息决定服务用的方式,有三种,第一种是引用本地 
(JVM) 服务,第二是通过直连方式引用远程服务,第三是通过注册中心引�
 ��远程服务。不管是哪种引用方式,最后都会得到一个 Invoker 实例。如果有多个注册中心,多个服务提供 [...]
 <p>以上就是服务引用的大致原理,下面我们深入到代码中,详细分析服务引用细节。</p>
 <h2>3.源码分析</h2>
 <p>服务引用的入口方法为 ReferenceBean 的 getObject 方法,该方法定义在 Spring 的 FactoryBean 
接口中,ReferenceBean 实现了这个方法。实现代码如下:</p>
@@ -310,7 +310,7 @@
             }
         }
 
-        <span class="hljs-comment">// 单个注册中心或服务提供者(服务直联,下同)</span>
+        <span class="hljs-comment">// 单个注册中心或服务提供者(服务直连,下同)</span>
         <span class="hljs-keyword">if</span> (urls.size() == <span 
class="hljs-number">1</span>) {
             <span class="hljs-comment">// 调用 RegistryProtocol 的 refer 构建 
Invoker 实例</span>
             invoker = refprotocol.refer(interfaceClass, urls.get(<span 
class="hljs-number">0</span>));
@@ -357,7 +357,7 @@
     <span class="hljs-keyword">return</span> (T) 
proxyFactory.getProxy(invoker);
 }
 </code></pre>
-<p>上面代码很多,不过逻辑比较清晰。首先根据配置检查是否为本地调用,若是,则调用 InjvmProtocol 的 refer 方法生成 
InjvmInvoker 实例。若不是,则读取直联配置项,或注册中心 url,并将读取到的 url 存储到 urls 中。然后根据 urls 
元素数量进行后续操作。若 urls 元素数量为1,则直接通过 Protocol 自适应拓展类构建 Invoker 实例接口。若 urls 
元素数量大于1,即存在多个注册中心或服务直联 url,此时先根据 url 构建 Invoker。然后再通过 Cluster 合并多个 Invoker,最后调用 
ProxyFactory 生成代理类。Invoker 的构建过程以及代理类的过程比较重要,因此接下来将分两小节对这两个过程进行分析。</p>
+<p>上面代码很多,不过逻辑比较清晰。首先根据配置检查是否为本地调用,若是,则调用 InjvmProtocol 的 refer 方法生成 
InjvmInvoker 实例。若不是,则读取直连配置项,或注册中心 url,并将读取到的 url 存储到 urls 中。然后根据 urls 
元素数量进行后续操作。若 urls 元素数量为1,则直接通过 Protocol 自适应拓展类构建 Invoker 实例接口。若 urls 
元素数量大于1,即存在多个注册中心或服务直连 url,此时先根据 url 构建 Invoker。然后再通过 Cluster 合并多个 Invoker,最后调用 
ProxyFactory 生成代理类。Invoker 的构建过程以及代理类的过程比较重要,因此接下来将分两小节对这两个过程进行分析。</p>
 <h4>3.2.1 创建 Invoker</h4>
 <p>Invoker 是 Dubbo 的核心模型,代表一个可执行体。在服务提供方,Invoker 用于调用服务提供类。在服务消费方,Invoker 
用于执行远程调用。Invoker 是由 Protocol 实现类构建而来。Protocol 实现类有很多,本节会分析最常用的两个,分别是 
RegistryProtocol 和 DubboProtocol,其他的大家自行分析。下面先来分析 DubboProtocol 的 refer 
方法源码。如下:</p>
 <pre><code class="language-java"><span class="hljs-keyword">public</span> 
&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; 
serviceType, URL url)</span> <span class="hljs-keyword">throws</span> 
RpcException </span>{
diff --git a/zh-cn/docs/source_code_guide/refer-service.json 
b/zh-cn/docs/source_code_guide/refer-service.json
index b5906b5..1acb696 100644
--- a/zh-cn/docs/source_code_guide/refer-service.json
+++ b/zh-cn/docs/source_code_guide/refer-service.json
@@ -1,6 +1,6 @@
 {
   "filename": "refer-service.md",
-  "__html": "<h2>1. 简介</h2>\n<p>上一篇文章详细分析了服务导出的过程,本篇文章我们趁热打铁,继续分析服务引用过程。在 
Dubbo 
中,我们可以通过两种方式引用远程服务。第一种是使用服务直联的方式引用服务,第二种方式是基于注册中心进行引用。服务直联的方式仅适合在调试或测试服务的场景下使用,不适合在线上环境使用。因此,本文我将重点分析通过注册中心引用服务的过程。从注册中心中获取服务配置只是服务引用过程中的一环,除此之外,服务消费者还需要经历
 Invoker 创建、代理类创建等步骤。这些步骤,将在后续章节中一一进行分析。</p>\n<h2>2.服务引用原理</h2>\n<p>Dubbo 
服务引用的时机有两个,第一个是在 Spring 容器调用 ReferenceBean 的 afterPropertiesSet 方法时引用服务,第二个是在 
ReferenceBean 对应的服务被注入到其他类中时引用。这两�
 ��引用服务的时机区别在于,第一个是饿汉式的,第二个是懒汉式的。默认情况下,Dubbo 使用懒汉式引用服务。如果需要使用饿汉式,可通过配置 &lt [...]
+  "__html": "<h2>1. 简介</h2>\n<p>上一篇文章详细分析了服务导出的过程,本篇文章我们趁热打铁,继续分析服务引用过程。在 
Dubbo 
中,我们可以通过两种方式引用远程服务。第一种是使用服务直连的方式引用服务,第二种方式是基于注册中心进行引用。服务直连的方式仅适合在调试或测试服务的场景下使用,不适合在线上环境使用。因此,本文我将重点分析通过注册中心引用服务的过程。从注册中心中获取服务配置只是服务引用过程中的一环,除此之外,服务消费者还需要经历
 Invoker 创建、代理类创建等步骤。这些步骤,将在后续章节中一一进行分析。</p>\n<h2>2.服务引用原理</h2>\n<p>Dubbo 
服务引用的时机有两个,第一个是在 Spring 容器调用 ReferenceBean 的 afterPropertiesSet 方法时引用服务,第二个是在 
ReferenceBean 对应的服务被注入到其他类中时引用。这两�
 ��引用服务的时机区别在于,第一个是饿汉式的,第二个是懒汉式的。默认情况下,Dubbo 使用懒汉式引用服务。如果需要使用饿汉式,可通过配置 &lt [...]
   "link": "/zh-cn/docs/source_code_guide/refer-service.html",
   "meta": {
     "title": "服务引用",

Reply via email to