You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@dubbo.apache.org by GitBox <gi...@apache.org> on 2018/09/04 01:17:34 UTC

[GitHub] diecui1202 closed pull request #130: Fix a broken link and use a general format for blog md file

diecui1202 closed pull request #130: Fix a broken link and use a general format for blog md file
URL: https://github.com/apache/incubator-dubbo-website/pull/130
 
 
   

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

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

diff --git a/blog/en-us/dubbo-generic-invoke.md b/blog/en-us/dubbo-generic-invoke.md
index dfb73b28..98f7fbf9 100644
--- a/blog/en-us/dubbo-generic-invoke.md
+++ b/blog/en-us/dubbo-generic-invoke.md
@@ -1,5 +1,7 @@
 # Generic invoke of Dubbo
+
 The generic invoke could be considered to be used in the following cases:
+
 - Service test platform
 - API service gateway
 
@@ -9,7 +11,7 @@ Generic invoke does not require attention on the server and can be exposed as no
 
 Next, let's take a look at how the consumer uses generic invoke for service call.
 
-### Generic invoke through Spring XML configuration
+## Generic invoke through Spring XML configuration
 
 Declare `generic="true"` in Spring configuration, such as
 
@@ -38,7 +40,7 @@ Among them,
    
    iii.	If it is a POJO, use the full class name directly, such as `com.alibaba.dubbo.samples.generic.api.Params`.
 
-### Generic invoke through API programming
+## Generic invoke through API programming
 
 ```java
 ApplicationConfig application = new ApplicationConfig()ApplicationConfig application = new ApplicationConfig();
@@ -66,7 +68,7 @@ System.out.println(name);
 
 Through the API, you don't need to configure the service in advance like XML. You can dynamically construct ReferenceConfig; the API is more common than XML.
 
-### The case where parameters or return values are POJOs
+## The case where parameters or return values are POJOs
 
 For example, the method signature is `User get(Params params)`, where `User` has two attributes, id and name, and `Params` has one attribute, query.
 
@@ -90,11 +92,11 @@ sample one result: {name=charles, id=1, class=com.alibaba.dubbo.samples.generic.
 Here, the Dubbo framework will automatically convert the return value from POJO to Map.
 It can be seen that the return value `user` is a HashMap, which stores three k/vs, name, id, and class.
 
-### Generic interface implementation
+## Generic interface implementation
 
 The implementation of the generic interface is mainly used when the server does not have an API interface. All POJOs in the parameters and return values are represented by Map, which is usually used for framework integration. For example, to implement a generic remote service Mock framework, all service requests can be handled by implementing the interface GenericService.
 
-#### Implementation GenericService on the server
+### Implementation GenericService on the server
 
 ```java
 public class GenericServiceImpl implements GenericService {
@@ -111,7 +113,7 @@ public class GenericServiceImpl implements GenericService {
 }
 ```
 
-#### Server exposed service
+### Server exposed service
 
 ```java
 ApplicationConfig application = new ApplicationConfig();
@@ -139,7 +141,7 @@ service2.export();
 
 Similarly, you can expose the service using XML configuration; in this case, the server does not depend on the two interfaces HiService and HelloService.
 
-#### Service invoke on the consumer
+### Service invoke on the consumer
 
 ```java
 ApplicationConfig application = new ApplicationConfig();
@@ -172,7 +174,7 @@ Similarly, the consumer can also reference the service using an XML configuratio
 So far, a simple service Mock platform has been successfully launched!
 
 
-### Others
+## Others
+
 -	The generic invoke and generic interface implementations introduced in this article are all based on the native Dubbo protocol. Prior to version 2.6.2, other protocols such as http/hessian don't support generic invoke. Version 2.6.3 will support the generic invoke of these two protocols.
 -	The relevant sample codes mentioned in this article can be found in dubbo-samples: https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-generic
-
diff --git a/blog/en-us/introduction-to-dubbo-spi-2.md b/blog/en-us/introduction-to-dubbo-spi-2.md
index 9d31cf3c..97870351 100644
--- a/blog/en-us/introduction-to-dubbo-spi-2.md
+++ b/blog/en-us/introduction-to-dubbo-spi-2.md
@@ -1,15 +1,18 @@
 # Dubbo extensible mechanism source code analysis
 ---
 
-In the [actual implementation of the Dubbo extensibility mechanism](#/blog/introduction-to-dubbo-spi.md), 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.
+In the [actual implementation of the Dubbo extensibility mechanism](./introduction-to-dubbo-spi.md), 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.
+
+## ExtensionLoader
+
+`ExtentionLoader` 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:
 
-# ExtensionLoader
-ExtentionLoader 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:
 * `public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type)`
 * `public T getExtension(String name)`
 * `public T getAdaptiveExtension()`
 
 The common usages are:
+
 * `LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(loadbalanceName)`
 * `RouterFactory routerFactory = ExtensionLoader.getExtensionLoader(RouterFactory.class).getAdaptiveExtension()`
 
@@ -149,7 +152,8 @@ This process is very simple. Get the extension class from the cache first, and i
 
 After the above 4 steps, Dubbo creates and initializes an extended instance. The dependencies of this instance are injected and packaged as needed. At this point, this extended instance can be used.
 
-# Auto-assembly of Dubbo SPI advanced usage
+## Auto-assembly of Dubbo SPI advanced usage
+
 The relevant code for auto-assembly is in the injectExtension method:
 
 ```java
@@ -219,11 +223,13 @@ public class AdaptiveExtensionFactory implements ExtensionFactory {
 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 `ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension())` 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 example, we used Google's guice as an IoC container in our project. We can implement our own GuiceExtensionFactory to enable Dubbo to load extensions from the guice container.
 
-# AoP of Dubbo SPI advanced usage
+## AoP of Dubbo SPI advanced usage
+
 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. 
 
 ### What is the Wrapper class
+
 So what kind of class is the Wrapper class in the Dubbo extension mechanism? The Wrapper class is a class that has a replication constructor and also is a typical decorator pattern. Here's a Wrapper class:
 
 ```java
@@ -235,7 +241,9 @@ class A{
 }
 ```
 Class A has a constructor `public A(A a)`, 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.
+
 ### How to configure the Wrapper class
+
 The Wipper class in Dubbo is also an extension point. Like other extension points, it is also configured in the `META-INF` folder. For example, the ProtocolFilterWrapper and ProtocolListenerWrapper in the previous example are configured in the path `dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol`:
 ```text
 filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
@@ -274,7 +282,8 @@ public class ProtocolFilterWrapper implements Protocol {
 ```
 ProtocolFilterWrapper has a constructor `public ProtocolFilterWrapper(Protocol protocol)`, 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.
 
-# Extension point adaptive
+## Extension point adaptive
+
 As mentioned earlier, Dubbo needs to determine which extension to use based on method parameters at runtime. So there is an extension point adaptive instance. In fact, it is an extension point proxy that delays the selection of extensions from starting Dubbo to calling RPC. Each extension point in Dubbo has an adaptive class. If it is not explicitly provided, Dubbo will automatically create one for us. By default, Javaassist is used. 
 Let's first look at the code to create an adaptive extension class:
 
diff --git a/blog/en-us/spring-boot-dubbo-start-stop-analysis.md b/blog/en-us/spring-boot-dubbo-start-stop-analysis.md
index 27a6c771..531f7719 100644
--- a/blog/en-us/spring-boot-dubbo-start-stop-analysis.md
+++ b/blog/en-us/spring-boot-dubbo-start-stop-analysis.md
@@ -1,13 +1,13 @@
 # Source code analysis of spring-boot+Dubbo App start and stop
 
-### Introduction
+## Introduction
 
 [Dubbo Spring Boot](https://github.com/apache/incubator-dubbo-spring-boot-project) project is dedicated to simplifying the development of the Dubbo RPC framework in the Spring Boot application. It also integrates the feature of Spring Boot:
 
 - [Autoconfigure](https://github.com/apache/incubator-dubbo-spring-boot-project/blob/master/dubbo-spring-boot-autoconfigure) (ex: Annotation driver, Autoconfigure, etc.)
 - [Production-Ready](https://github.com/apache/incubator-dubbo-spring-boot-project/blob/master/dubbo-spring-boot-actuator) (ex: Security, Healthy check, Externalize configuration, etc.)
 
-### The analysis of DubboConsumer startup
+## The analysis of DubboConsumer startup
 
 Have you ever thought about this : since the `DubboConsumerDemo` application in `incubator-dubbo-spring-boot-project` has only one line of code, why not just exit directly when the `main` method is executed?
 
@@ -132,7 +132,7 @@ Since Spring-boot application enables port 8080 and 8081(management port) at the
 
 Next, let's see how this Spring-boot application exits.
 
-### The analysis of DubboConsumer exit
+## The analysis of DubboConsumer exit
 
 As mentioned in the previous description, there is a thread that checks the variable `stopAwait` continuously. So there must be a thread to modify `stopAwait` at Stop, thus break the while loop. But who is modifying this variable?
 
@@ -187,16 +187,16 @@ By reffering the Java API documentation[2], we found that ShutdownHook will be e
 
 Therefore, the normal application will execute the above ShutdownHook during the stop process (except `kill -9 $PID`). Its function is not only to close the Tomcat, but also to perform other cleanup work. It is unnecessary to go into details.
 
-### Summary
+## Summary
 
 1. During the startup of `DubboConsumer`, an independent non-daemon thread is launched to query the status of the variable continuously, thus the process can't exit.
 2. To stop the `DubboConsumer`, one should call ShutdownHook to change the variable to let the thread break the loop.
 
-### Problems
+## Problems
 
 In the example of DubboProvider, we see that Provider doesn't start Tomcat to provide HTTP service, then how does the program stays alive without exiting? We will answer this question in the next article.
 
-#### Notice
+### Notice
 
 By running the following unit test which create a thread in `Intellij IDEA` , we are surprised to find that the program exits with less than 1000s. Why?(The thread being created is a non-daemon thread)
 
diff --git a/blog/zh-cn/dubbo-basic-usage-dubbo-provider-configuration.md b/blog/zh-cn/dubbo-basic-usage-dubbo-provider-configuration.md
index 18f601e9..d1f1f7bc 100644
--- a/blog/zh-cn/dubbo-basic-usage-dubbo-provider-configuration.md
+++ b/blog/zh-cn/dubbo-basic-usage-dubbo-provider-configuration.md
@@ -1,18 +1,18 @@
-Dubbo基本用法-Dubbo Provider配置
+# Dubbo基本用法-Dubbo Provider配置
 ---
 
-# Dubbo基本用法
+## Dubbo基本用法
 
 本章节主要讲述如何配置dubbo,按照配置方式上分,可以分为:XML配置,properties方式配置,注解方式配置,API调用方式配置。
 按照功能角度进行划分,可以分为Dubbo Provider和Dubbo Consumer。接下来章节中,分别对dubbo provider和Dubbo consumer进行讲解。
 
-## Dubbo Provider配置
+### Dubbo Provider配置
 
-### Provider 配置详解
+#### Provider 配置详解
 
 配置Dubbo Provider有4种方式:XML配置,properties方式配置,API调用方式配置,注解方式配置。
 
-#### XML配置
+##### XML配置
 
 ###### 最简单的配置的样例:
 ```
@@ -145,7 +145,7 @@ dubbo.protocol.port=28080
 1. 如果 classpath 根目录下存在多个 dubbo.properties,比如多个 jar 包中有 dubbo.properties,Dubbo 会任意加载,并打印 Error 日志,后续可能改为抛异常。 ↩
 2. 协议的 id 没配时,缺省使用协议名作为 id 
 
-#### annotation
+##### 注解配置
 
 ###### Service注解暴露服务  
 ```
@@ -194,7 +194,8 @@ public class ProviderTestApp {
 <dubbo:annotation package="com.chanshuyi.service.impl" />
 ```
 
-#### api直接触发
+##### 代码配置
+
 ```
 import com.alibaba.dubbo.rpc.config.ApplicationConfig;
 import com.alibaba.dubbo.rpc.config.RegistryConfig;
@@ -240,6 +241,7 @@ service.export();
 一般在spring应用中,不推荐使用这种方式。 具体的含义这里不做解释,可以通过github查看源码。
 
 ### Provider 接口和实现
+
 上面章节更多从配置角度出发,接下来通过一个完整的例子,来讲解下dubbo provider的完整使用。
 
 这个例子中只有一个服务UserReadService,有一个方法 getUserById。 需要将这个服务通过Dubbo暴露给远程的服务。具体的步骤如下:
@@ -278,11 +280,3 @@ public UserReadServiceImpl implements UserReadService{
 </beans>
 ```
 Dubbo配置的其他方式可以参考上一章节的相关配置,或者使用集成dubbo spring boot starter方式。
-
-
-
-
-
-
-
-
diff --git a/blog/zh-cn/dubbo-contribue-to-opensource.md b/blog/zh-cn/dubbo-contribue-to-opensource.md
index 384062dd..43398ffb 100644
--- a/blog/zh-cn/dubbo-contribue-to-opensource.md
+++ b/blog/zh-cn/dubbo-contribue-to-opensource.md
@@ -1,41 +1,41 @@
-以Dubbo为例,聊聊如何向开源项目做贡献
+# 以Dubbo为例,聊聊如何向开源项目做贡献
 ---
 
 Github 上有众多优秀的开源项目,大多数 IT 从业者将其当做了予取予求的工具库,遇到什么需求,先去 Github 搜一把,但有没有想过有一天自己也可以给开源事业做一些贡献呢?本文将会以 incubator-dubbo 项目为例,向你阐释,给开源项目做贡献并不是一件难事。
 
-### 1 为何要给开源贡献力量
+## 1 为何要给开源贡献力量
 
 为开源项目做贡献得到的收益是多方面的,为了让你有足够的信心加入到开源项目中,我在文章最开始列举出它的诸多好处。
 
-#### 1.1 巩固技能
+### 1.1 巩固技能
 
 无论你是提交代码,撰写文档,提交 Issue,组织活动,当你切身参与到一个开源项目中,相关的技能都会得到历练,并且在开源项目中找到自己的位置。一方面,日常工作中我们中的大多数人接触到的是业务场景,并没有太多机会接触到基础架构组件,开源项目为我们提供了一个平台,在这里,你可以尽情挑选自己熟悉的项目为它添砖加瓦(以 Dubbo 为例,并不是所有 IT 公司都有能力自研服务治理框架);另一方面,你所提交的代码,会有管理员协助审核,他们会给出专业的建议,更好的代码规范以及更优的编程思路最终都会变成你的经验。
 
-#### 1.2 结交朋友
+### 1.2 结交朋友
 
 开源社区为你提供了一个平台,在这里,你可以认识很多纯粹的技术爱好者,开源贡献者是最符合 geek 定义的那群人,你所接触到的往往是某个领域最厉害的那批人。
 
-#### 1.3 建立口碑
+### 1.3 建立口碑
 
 这是一个很好的展示个人实力的地方,俗话说:talk is cheap,show me the code. 作为技术人员,没有什么比一个漂亮的 Github 主页更有说服力的了。如果你能够为开源项目做出可观的贡献,你也将收获到业界的知名度,此时开源项目的成就和你是密不可分的。
 
-#### 1.4 传承开源精神
+### 1.4 传承开源精神
 
 只有源源不断的贡献者给开源项目添砖加瓦,才可以为 Github 一类的开源社区形成良好的开源风气。否则,只有输出没有输入,开源会失去活力。
 
-#### 1.5 养成习惯
+### 1.5 养成习惯
 
 相信我,一旦养成了每天提交代码的习惯,就像你不想中断打卡一样,你绝不想中断 commit。不止有英语打卡,健身打卡,还有开源打卡!
 
 ![开源程序员的日常](http://ov0zuistv.bkt.clouddn.com/image-20180827141007663.png)
 
-### 2 贡献代码时的一些疑难杂症
+## 2 贡献代码时的一些疑难杂症
 
 如果你是一名开源界的新手,可能会对贡献的流程心生畏惧。比如:我该怎么修改代码并提交?我的代码要是存在bug怎么办?我的代码别人会不会很 low?我该如何寻找合适的开源项目?开源社区那么多的工具和词汇都是什么意思?
 
 文章的第二部分将从一个**小白**的角度,介绍一下开源中的一些常见问题。
 
-#### 2.1 git 常规操作
+### 2.1 git 常规操作
 
 一般而言,我们选择使用 git 来作为版本管理的工具,你不一定要非常熟练的使用它,在我看来掌握 clone,add,commit,pull,push 即可,遇到复杂的场景,你还有谷歌。
 
@@ -73,7 +73,7 @@ pull request 经常被缩写为 PR,指的是一次向源仓库请求合并的
 
 管理者会对 pull request 涉及的改动进行 review,以确保你的代码是符合规范的,逻辑有没有偏差,以及符合框架的功能需求。
 
-#### 2.2 Travis CI
+### 2.2 Travis CI
 
 一些自动化的 CI 流程被植入在每一次 pull request 的构建之中,用于给开源仓库去校验提交者的代码是否符合既定的规范,如:是否有编译问题,单元测试是否通过,覆盖率是否达标,代码风格是否合规等等。
 
@@ -81,7 +81,7 @@ pull request 经常被缩写为 PR,指的是一次向源仓库请求合并的
 
 一般情况下,必须通过 CI,你的 pull request 才会被管理 review。
 
-#### 2.3 Mailing list
+### 2.3 Mailing list
 
 每个开源项目都会有自己的贡献规范,可以参考首页的 Contributing,来获取具体的信息。incubator-dubbo 作为一个孵化中的 apache 项目,遵守了 apache 的传统,在 [Contributing](https://github.com/apache/incubator-dubbo/blob/master/CONTRIBUTING.md) 中描述道:当你有新特性想要贡献给 Dubbo 时,官方推荐使用 Mailing list 的方式描述一遍你想要做的改动。
 
@@ -91,25 +91,25 @@ Mailing list 简单来说,就是一个邮件通知机制,所有的 Dubbo 开
 
 > 作为一个 modern developer,你可能觉得 mailing list 的交流方式存在滞后性,这样的沟通方式不是特别的高效,但它作为 apache 项目的推荐交流方式存在其特殊的原因,在此不多赘述。总之遵循一个原则:bug fix或者讨论,可以在 github issue 中进行,影响较大的特性和讨论则推荐在 mailing list 中展开。
 
-### 3 其他贡献形式
+## 3 其他贡献形式
 
 不仅仅只有贡献代码,修复 bug 等行为才算作为开源做贡献,以下这些行为也属于主要形式:
 
-#### 3.1 撰写文档
+### 3.1 撰写文档
 
  [Dubbo文档](http://dubbo.apache.org/zh-cn/)是其开源组成成分的重要一环,其内容源文件位于:https://github.com/apache/incubator-dubbo-website。同样也是一个 Git 仓库,任何你想要对 dubbo 知识点的补充,都可以在这儿提交 pull request,只需要一些 markdown 的语法知识,和一些可有可无的 npm 语法即可。如果你觉得贡献代码对于现在的自己仍然有点难度,不妨从贡献文档开始接触开源。
 
-#### 3.2 ISSUE
+### 3.2 ISSUE
 
 无论是 Github 中的 Issue 还是 mailing list 中的讨论,无论是提出问题,汇报 bug,还是回答问题(bugfix 则不仅仅需要 Issue 了),协助管理者 review pull request,都是贡献的一种形式,勿以善小而不为。
 
-#### 3.3 其他行为
+### 3.3 其他行为
 
 任何你能够想到的,可以帮助开源项目变得更好的的行为,都属于开源贡献。例如,给每个 Issue 打上合适的 tag,关闭重复的 Issue,链接相关联的 Issue,线下组织沙龙,回答 Stack Overflow 上相关的问题,以及文档中一个错别字的修改等等。
 
-### 4 开源最佳实践
+## 4 开源最佳实践
 
-#### 4.1 有效沟通
+### 4.1 有效沟通
 
 无论你处于什么样的目的:仅仅是一次性的贡献,亦或是永久性的加入社区,都的和他人进行沟通和交往,这是你要在开源圈发展必须修炼的技能。
 
@@ -153,7 +153,7 @@ Mailing list 简单来说,就是一个邮件通知机制,所有的 Dubbo 开
 
 **以上几点,要铭记在心。** 开源是由来自世界各地的人们共同协作实现的。面临的问题是跨语言、跨文化、不同的地理为止、不同的时区,另外,撰写文字的沟通更是难上加难,无法传达语气和情绪。请让这些会话都充满善意吧!在以下情形中请保持礼貌:推动一个想法、请求更多的上下文、进一步澄清你的立场。既然你在互联网找到了自己的所需,那么请尝试让它变得更好!
 
-#### 4.2 创建 issue
+### 4.2 创建 issue
 
 你应该在遇到下列情况下,去创建一个 issue:
 
@@ -167,7 +167,7 @@ Mailing list 简单来说,就是一个邮件通知机制,所有的 Dubbo 开
 - **如果说某个issue已经开放很久了,** 这可能是已经有人正在解决中,又或者是早已经解决过了,所以也请添加评论,在打算开始工作之前,最好是确认一下。
 - **如果你创建了一个issue,但是没多久自己解决了,** 也要添加评论,让其他人知道,然后关闭该issue。记录本身就是对社区的贡献。
 
-#### 4.3 创建 pull request
+### 4.3 创建 pull request
 
 在下面的情形时,请你务必使用 PR:
 
@@ -185,6 +185,6 @@ Mailing list 简单来说,就是一个邮件通知机制,所有的 Dubbo 开
 - **测试你的改动!** 若测试用例存在的话,跑一遍,以覆盖你的更改,若没有的话,则创建相应的用例。无论测试是否存在,一定要确保你的改动不会破坏掉现有的项目。
 - **和项目现有的风格保持一致** 尽你最大的努力,这也就是意味着在使用缩进、分号、以及注释很可能和你自己的风格大相径庭,但是为了节省维护者的精力,以及未来他人更好的理解和维护,还请你容忍一下。
 
-### 5 成为一个开源贡献者
+## 5 成为一个开源贡献者
 
 如果你有志于参与开源事业,可以尝试从自己最熟悉的项目开始,开源并不是属于高级开发者的专属词汇,它就是由你我这样的人在需求,修复,构建中演进下去的。Let's try it !
\ No newline at end of file
diff --git a/blog/zh-cn/dubbo-generic-invoke.md b/blog/zh-cn/dubbo-generic-invoke.md
index c170c9b9..c86bd340 100644
--- a/blog/zh-cn/dubbo-generic-invoke.md
+++ b/blog/zh-cn/dubbo-generic-invoke.md
@@ -9,7 +9,7 @@
 
 下面来看看消费端如何使用泛化调用进行服务调用。
 
-#### 通过 Spring XML 配置进行泛化调用
+## 通过 Spring XML 配置进行泛化调用
 
 在 Spring 配置申明 `generic="true"`,如:
 
@@ -34,7 +34,7 @@ System.out.println(name);
    2. 如果是基本类型数组,如 int[],则可以使用 `int[].class.getName()`;
    3. 如果是 POJO,则直接使用全类名,如 `com.alibaba.dubbo.samples.generic.api.Params`。
 
-#### 通过 API 编程进行泛化调用
+## 通过 API 编程进行泛化调用
 
 ```
 ApplicationConfig application = new ApplicationConfig()ApplicationConfig application = new ApplicationConfig();
@@ -62,7 +62,7 @@ System.out.println(name);
 
 通过 API 的方式,不需要像 XML 的方式需要提前将服务配置好,可以动态构建 ReferenceConfig;相对 XML 来说,API 的方式更常见。
 
-#### 参数或返回值是 POJO 的场景
+## 参数或返回值是 POJO 的场景
 
 比如方法签名是 `User get(Params params);`其中 User 有 id 和 name 两个属性,Params 有 query 一个属性。
 
@@ -89,7 +89,7 @@ sample one result: {name=charles, id=1, class=com.alibaba.dubbo.samples.generic.
 
 泛接口实现方式主要用于服务端没有 API 接口的情况,参数及返回值中的所有 POJO 均用 Map 表示,通常用于框架集成,如实现一个通用的远程服务 Mock 框架,可通过实现 GenericService 接口处理所有服务请求。
 
-##### 服务端实现 GenericService
+### 服务端实现 GenericService
 
 ```java
 public class GenericServiceImpl implements GenericService {
@@ -106,7 +106,7 @@ public class GenericServiceImpl implements GenericService {
 }
 ```
 
-##### 服务端暴露服务
+### 服务端暴露服务
 
 ```java
 ApplicationConfig application = new ApplicationConfig();
@@ -134,7 +134,7 @@ service2.export();
 
 同样,也可以使用 XML 配置的方式暴露服务;此时服务端是没有依赖 HiService 和 HelloService 这两个接口的。
 
-##### 消费端进行服务调用
+### 消费端进行服务调用
 
 ```java
 ApplicationConfig application = new ApplicationConfig();
@@ -166,7 +166,7 @@ System.out.println(helloService.hello("community"));
 
 到这里为止,一个简易的服务 Mock 平台就成功上线了!
 
-#### 其他
+## 其他
 
 * 本文介绍的泛化调用和泛接口实现,都是在原生的 `Dubbo` 协议之上的。在 2.6.2 版本之前,其他协议如 http/hessian 等是不支持泛化调用的,2.6.3 版本将会对这两个协议的泛化调用做支持。
 * 本文中提到的相关示例代码可以在 dubbo-samples中找到:https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-generic
\ No newline at end of file
diff --git a/blog/zh-cn/dubbo-invoke.md b/blog/zh-cn/dubbo-invoke.md
index 01568f3d..66b7c208 100644
--- a/blog/zh-cn/dubbo-invoke.md
+++ b/blog/zh-cn/dubbo-invoke.md
@@ -7,7 +7,7 @@
 * 参数回调
 * 事件通知
 
-### 同步调用
+## 同步调用
 
 同步调用是一种阻塞式的调用方式,即 Consumer 端代码一直阻塞等待,直到 Provider 端返回为止;
 
@@ -24,7 +24,7 @@
 
 其实,Dubbo 的底层 IO 操作都是异步的。Consumer 端发起调用后,得到一个 Future 对象。对于同步调用,业务线程通过`Future#get(timeout)`,阻塞等待 Provider 端将结果返回;`timeout`则是 Consumer 端定义的超时时间。当结果返回后,会设置到此 Future,并唤醒阻塞的业务线程;当超时时间到结果还未返回时,业务线程将会异常返回。
 
-### 异步调用
+## 异步调用
 
 基于 Dubbo 底层的异步 NIO 实现异步调用,对于 Provider 响应时间较长的场景是必须的,它能有效利用 Consumer 端的资源,相对于 Consumer 端使用多线程来说开销较小。
 
@@ -36,7 +36,7 @@ public interface AsyncService {
 }
 ```
 
-##### Consumer 配置
+### Consumer 配置
 
 ```xml
 <dubbo:reference id="asyncService" interface="com.alibaba.dubbo.samples.async.api.AsyncService">
@@ -46,7 +46,7 @@ public interface AsyncService {
 
 需要异步调用的方法,均需要使用 `<dubbo:method/>`标签进行描述。
 
-##### Consumer 端发起调用
+### Consumer 端发起调用
 
 ```java
 AsyncService service = ...;
@@ -83,11 +83,11 @@ Dubbo Consumer 端发起调用后,同时通过`RpcContext.getContext().getFutu
 
 此示例代码位于:https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-async
 
-### 参数回调
+## 参数回调
 
 参数回调有点类似于本地 Callback 机制,但 Callback 并不是 Dubbo 内部的类或接口,而是由 Provider 端自定义的;Dubbo 将基于长连接生成反向代理,从而实现从 Provider 端调用 Consumer 端的逻辑。
 
-##### Provider 端定义 Service 和 Callback
+### Provider 端定义 Service 和 Callback
 
 ```java
 public interface CallbackService {
@@ -99,7 +99,7 @@ public interface CallbackListener {
 }
 ```
 
-##### Provider 端 Service 实现
+#### Provider 端 Service 实现
 
 ```java
 public class CallbackServiceImpl implements CallbackService {
@@ -140,7 +140,7 @@ public class CallbackServiceImpl implements CallbackService {
 }
 ```
 
-##### Provider 端暴露服务
+#### Provider 端暴露服务
 
 ```xml
 <bean id="callbackService" class="com.alibaba.dubbo.samples.callback.impl.CallbackServiceImpl"/>
@@ -155,7 +155,7 @@ public class CallbackServiceImpl implements CallbackService {
 
 这里,Provider 需要在方法中声明哪个参数是 Callback 参数。
 
-##### Consumer 端实现 Callback 接口
+#### Consumer 端实现 Callback 接口
 
 ```java
 CallbackService callbackService = ...;
@@ -172,7 +172,7 @@ Callback 接口的实现类在 Consumer 端,当方法发生调用时,Consume
 
 这种调用方式有点像消息的发布和订阅,但又有区别。比如当 Consumer 端 完成了Callback 服务的 export 后,如果后续重启了,这时 Provider 端就会调不通;同时 Provider 端如何清理掉这个 proxy 也是一个问题。
 
-### 事件通知
+## 事件通知
 
 事件通知允许 Consumer 端在调用之前、调用之后或出现异常时,触发 `oninvoke`、`onreturn`、`onthrow` 三个事件。
 
diff --git a/blog/zh-cn/introduction-to-dubbo-qos.md b/blog/zh-cn/introduction-to-dubbo-qos.md
index 516b8e95..8e92cb7e 100644
--- a/blog/zh-cn/introduction-to-dubbo-qos.md
+++ b/blog/zh-cn/introduction-to-dubbo-qos.md
@@ -5,7 +5,7 @@ QoS,全称为`Quality of Service`, 是常见于网络设备中的一个术语
 
 在Dubbo中,QoS这个概念被用于动态的对服务进行查询和控制。例如对获取当前提供和消费的所有服务,以及对服务进行动态的上下线,即从注册中心上进行注册和反注册操作。
 
-### QoS工作机制
+## QoS工作机制
 
 从Dubbo 2.5.8开始,默认引入了Qos功能,默认处于启动状态。所有的QoS功能被抽象成一个个的命令,通过执行这些命令,Qos会返回响应的结果。
 
@@ -22,7 +22,7 @@ Qos的工作机制如下图所示:
 3. 针对不同的协议进行解码,解析出需要执行的命令
 4. 执行命令并返回结果
 
-### QoS命令
+## QoS命令
 
 QoS目前支持的命令包括:
 
@@ -34,7 +34,7 @@ QoS目前支持的命令包括:
 
 下面,我们具体来操作一下如何通过用QoS对服务进行动态控制。
 
-#### 通过Telnet方式访问QoS
+### 通过Telnet方式访问QoS
 
 假设我们的Dubbo服务端已经启动,我们通过Telnet方式进行连接:
 
@@ -142,7 +142,7 @@ Connection closed by foreign host.
 
 
 
-#### 通过HTTP方式访问QOS
+### 通过HTTP方式访问QOS
 
 在上面的例子中,我们已经对`org.apache.dubbo.demo.provider.DemoService`进行了下线操作,下面,我们通过对Http方式对上面的服务进行注册操作:
 
@@ -181,7 +181,7 @@ As Consumer side:
 
 
 
-### QoS相关参数说明
+## QoS相关参数说明
 
 QoS提供了一些启动参数,来对启动进行配置,他们主要包括:
 
@@ -202,7 +202,7 @@ QoS参数可以通过如下方式进行配置
 
 其中,上述方式的优先顺序为系统属性 > dubbo.properties > XML/Spring-boot自动装配方式。
 
-#### 使用系统属性方式进行配置
+### 使用系统属性方式进行配置
 
 ```
 -Ddubbo.application.qos.enable=true
@@ -210,7 +210,7 @@ QoS参数可以通过如下方式进行配置
 -Ddubbo.application.qos.accept.foreign.ip=false
 ```
 
-#### 使用dubbo.properties文件进行配置
+### 使用dubbo.properties文件进行配置
 
 在项目的`src/main/resources`目录下添加dubbo.properties文件,内容如下:
 ```
@@ -219,7 +219,7 @@ dubbo.application.qos.port=33333
 dubbo.application.qos.accept.foreign.ip=false
 ```
 
-#### 使用XML方法进行配置
+### 使用XML方法进行配置
 
 如果要通过XML配置响应的QoS相关的参数,可以进行如下配置:
 
@@ -243,7 +243,7 @@ dubbo.application.qos.accept.foreign.ip=false
 </beans>
 ```
 
-#### 使用spring-boot自动装配方式配置
+### 使用spring-boot自动装配方式配置
 
 如果是spring-boot的应用,可以在`application.properties`或者`application.yml`上配置:
 
diff --git a/blog/zh-cn/introduction-to-dubbo-spi-2.md b/blog/zh-cn/introduction-to-dubbo-spi-2.md
index 6e02c1bd..f6ff32dd 100644
--- a/blog/zh-cn/introduction-to-dubbo-spi-2.md
+++ b/blog/zh-cn/introduction-to-dubbo-spi-2.md
@@ -1,9 +1,9 @@
 # Dubbo可扩展机制源码解析
 ---
 
-在[Dubbo可扩展机制实战](#/blog/introduction-to-dubbo-spi.md)中,我们了解了Dubbo扩展机制的一些概念,初探了Dubbo中LoadBalance的实现,并自己实现了一个LoadBalance。是不是觉得Dubbo的扩展机制很不错呀,接下来,我们就深入Dubbo的源码,一睹庐山真面目。
+在[Dubbo可扩展机制实战](./introduction-to-dubbo-spi.md)中,我们了解了Dubbo扩展机制的一些概念,初探了Dubbo中LoadBalance的实现,并自己实现了一个LoadBalance。是不是觉得Dubbo的扩展机制很不错呀,接下来,我们就深入Dubbo的源码,一睹庐山真面目。
 
-# ExtensionLoader
+## ExtensionLoader
 ExtentionLoader是最核心的类,负责扩展点的加载和生命周期管理。我们就以这个类开始吧。
 Extension的方法比较多,比较常用的方法有:
 * `public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type)`
@@ -154,7 +154,7 @@ private Map<String, Class<?>> getExtensionClasses() {
 
 经过上面的4步,Dubbo就创建并初始化了一个扩展实例。这个实例的依赖被注入了,也根据需要被包装了。到此为止,这个扩展实例就可以被使用了。
 
-# Dubbo SPI高级用法之自动装配
+## Dubbo SPI高级用法之自动装配
 自动装配的相关代码在injectExtension方法中:
 
 ```java
@@ -225,7 +225,7 @@ public class AdaptiveExtensionFactory implements ExtensionFactory {
 AdaptiveExtensionLoader类有@Adaptive注解。前面提到了,Dubbo会为每一个扩展创建一个自适应实例。如果扩展类上有@Adaptive,会使用该类作为自适应类。如果没有,Dubbo会为我们创建一个。所以`ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension())`会返回一个AdaptiveExtensionLoader实例,作为自适应扩展实例。
 AdaptiveExtentionLoader会遍历所有的ExtensionFactory实现,尝试着去加载扩展。如果找到了,返回。如果没有,在下一个ExtensionFactory中继续找。Dubbo内置了两个ExtensionFactory,分别从Dubbo自身的扩展机制和Spring容器中去寻找。由于ExtensionFactory本身也是一个扩展点,我们可以实现自己的ExtensionFactory,让Dubbo的自动装配支持我们自定义的组件。比如,我们在项目中使用了Google的guice这个IoC容器。我们可以实现自己的GuiceExtensionFactory,让Dubbo支持从guice容器中加载扩展。
 
-# Dubbo SPI高级用法之AoP
+## Dubbo SPI高级用法之AoP
 在用Spring的时候,我们经常会用到AOP功能。在目标类的方法前后插入其他逻辑。比如通常使用Spring AOP来实现日志,监控和鉴权等功能。
 Dubbo的扩展机制,是否也支持类似的功能呢?答案是yes。在Dubbo中,有一种特殊的类,被称为Wrapper类。通过装饰者模式,使用包装类包装原始的扩展点实例。在原始扩展点实现前后插入其他逻辑,实现AOP功能。
 
@@ -241,7 +241,9 @@ class A{
 }
 ```
 类A有一个构造函数`public A(A a)`,构造函数的参数是A本身。这样的类就可以成为Dubbo扩展机制中的一个Wrapper类。Dubbo中这样的Wrapper类有ProtocolFilterWrapper, ProtocolListenerWrapper等, 大家可以查看源码加深理解。
+
 ### 怎么配置Wrapper类
+
 在Dubbo中Wrapper类也是一个扩展点,和其他的扩展点一样,也是在`META-INF`文件夹中配置的。比如前面举例的ProtocolFilterWrapper和ProtocolListenerWrapper就是在路径`dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol`中配置的:
 ```text
 filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
@@ -280,7 +282,8 @@ public class ProtocolFilterWrapper implements Protocol {
 ```
 ProtocolFilterWrapper有一个构造函数`public ProtocolFilterWrapper(Protocol protocol)`,参数是扩展点Protocol,所以它是一个Dubbo扩展机制中的Wrapper类。ExtensionLoader会把它缓存起来,供以后创建Extension实例的时候,使用这些包装类依次包装原始扩展点。
 
-# 扩展点自适应
+## 扩展点自适应
+
 前面讲到过,Dubbo需要在运行时根据方法参数来决定该使用哪个扩展,所以有了扩展点自适应实例。其实是一个扩展点的代理,将扩展的选择从Dubbo启动时,延迟到RPC调用时。Dubbo中每一个扩展点都有一个自适应类,如果没有显式提供,Dubbo会自动为我们创建一个,默认使用Javaassist。
 先来看下创建自适应扩展类的代码:
 
diff --git a/blog/zh-cn/introduction-to-dubbo-spi.md b/blog/zh-cn/introduction-to-dubbo-spi.md
index acc5c616..8b3dc91e 100644
--- a/blog/zh-cn/introduction-to-dubbo-spi.md
+++ b/blog/zh-cn/introduction-to-dubbo-spi.md
@@ -1,7 +1,7 @@
-Dubbo可扩展机制实战
+# Dubbo可扩展机制实战
 ---
 
-# 1. Dubbo的扩展机制
+## 1. Dubbo的扩展机制
 在Dubbo的官网上,Dubbo描述自己是一个高性能的RPC框架。今天我想聊聊Dubbo的另一个很棒的特性, 就是它的可扩展性。
 如同罗马不是一天建成的,任何系统都一定是从小系统不断发展成为大系统的,想要从一开始就把系统设计的足够完善是不可能的,相反的,我们应该关注当下的需求,然后再不断地对系统进行迭代。在代码层面,要求我们适当的对关注点进行抽象和隔离,在软件不断添加功能和特性时,依然能保持良好的结构和可维护性,同时允许第三方开发者对其功能进行扩展。在某些时候,软件设计者对扩展性的追求甚至超过了性能。
 
@@ -11,7 +11,7 @@ Dubbo可扩展机制实战
 
 Dubbo很好的做到了上面两点。这要得益于Dubbo的微内核+插件的机制。接下来的章节中我们会慢慢揭开Dubbo扩展机制的神秘面纱。
 
-# 2. 可扩展的几种解决方案
+## 2. 可扩展的几种解决方案
 通常可扩展的实现有下面几种:
 * Factory模式
 * IoC容器
@@ -19,7 +19,7 @@ Dubbo很好的做到了上面两点。这要得益于Dubbo的微内核+插件的
 
 Dubbo作为一个框架,不希望强依赖其他的IoC容器,比如Spring,Guice。OSGI也是一个很重的实现,不适合Dubbo。最终Dubbo的实现参考了Java原生的SPI机制,但对其进行了一些扩展,以满足Dubbo的需求。
 
-# 3. Java SPI机制
+## 3. Java SPI机制
 既然Dubbo的扩展机制是基于Java原生的SPI机制,那么我们就先来了解下Java SPI吧。了解了Java的SPI,也就是对Dubbo的扩展机制有一个基本的了解。如果对Java SPI比较了解的同学,可以跳过。
 
 Java SPI(Service Provider Interface)是JDK内置的一种动态加载扩展点的实现。在ClassPath的`META-INF/services`目录下放置一个与接口同名的文本文件,文件的内容为接口的实现类,多个实现类用换行符分隔。JDK中使用`java.util.ServiceLoader`来加载具体的实现。
@@ -77,7 +77,7 @@ Save tom to Mongo
 class:testDubbo.MysqlRepository
 Save tom to Mysql
 
-# 4. Dubbo的SPI机制
+## 4. Dubbo的SPI机制
 
 Java SPI的使用很简单。也做到了基本的加载扩展点的功能。但Java SPI有以下的不足:
 * 需要遍历所有的实现,并实例化,然后我们在循环中才能找到我们需要的实现。
@@ -88,7 +88,7 @@ Java SPI的使用很简单。也做到了基本的加载扩展点的功能。但
 
 所以Java SPI应付一些简单的场景是可以的,但对于Dubbo,它的功能还是比较弱的。Dubbo对原生SPI机制进行了一些扩展。接下来,我们就更深入地了解下Dubbo的SPI机制。
 
-# 5. Dubbo扩展点机制基本概念
+## 5. Dubbo扩展点机制基本概念
 在深入学习Dubbo的扩展机制之前,我们先明确Dubbo SPI中的一些基本概念。在接下来的内容中,我们会多次用到这些术语。
 
 ### 5.1 扩展点(Extension Point)
@@ -132,7 +132,7 @@ roundrobin=com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance
 * `META-INF/dubbo`
 * `META-INF/services`
 
-# 6. Dubbo的LoadBalance扩展点解读
+## 6. Dubbo的LoadBalance扩展点解读
 在了解了Dubbo的一些基本概念后,让我们一起来看一个Dubbo中实际的扩展点,对这些概念有一个更直观的认识。
 
 我们选择的是Dubbo中的LoadBalance扩展点。Dubbo中的一个服务,通常有多个Provider,consumer调用服务时,需要在多个Provider中选择一个。这就是一个LoadBalance。我们一起来看看在Dubbo中,LoadBalance是如何成为一个扩展点的。
@@ -175,7 +175,7 @@ LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtens
 ```
 使用ExtensionLoader.getExtensionLoader(LoadBalance.class)方法获取一个ExtensionLoader的实例,然后调用getExtension,传入一个扩展的别名来获取对应的扩展实例。
 
-# 7. 自定义一个LoadBalance扩展
+## 7. 自定义一个LoadBalance扩展
 本节中,我们通过一个简单的例子,来自己实现一个LoadBalance,并把它集成到Dubbo中。我会列出一些关键的步骤和代码,也可以从这个地址([https://github.com/vangoleo/dubbo-spi-demo](https://github.com/vangoleo/dubbo-spi-demo))下载完整的demo。
 
 ### 7.1 实现LoadBalance接口
@@ -211,7 +211,7 @@ demo=com.dubbo.spi.demo.consumer.DemoLoadBalance
 启动Dubbo,调用一次IHelloService,可以看到控制台会输出一条`DemoLoadBalance: Select the first invoker...`日志。说明Dubbo的确是使用了我们自定义的LoadBalance。
 
 
-# 总结 
+## 总结 
 到此,我们从Java SPI开始,了解了Dubbo SPI 的基本概念,并结合了Dubbo中的LoadBalance加深了理解。最后,我们还实践了一下,创建了一个自定义LoadBalance,并集成到Dubbo中。相信通过这里理论和实践的结合,大家对Dubbo的可扩展有更深入的理解。
 总结一下,Dubbo SPI有以下的特点:
 * 对Dubbo进行扩展,不需要改动Dubbo的源码
diff --git a/blog/zh-cn/spring-boot-dubbo-start-stop-analysis.md b/blog/zh-cn/spring-boot-dubbo-start-stop-analysis.md
index 5448c1fc..5b0ad386 100644
--- a/blog/zh-cn/spring-boot-dubbo-start-stop-analysis.md
+++ b/blog/zh-cn/spring-boot-dubbo-start-stop-analysis.md
@@ -1,13 +1,13 @@
 # Spring-boot+Dubbo应用启停源码分析
 
-### 背景介绍
+## 背景介绍
 
 [Dubbo Spring Boot](https://github.com/apache/incubator-dubbo-spring-boot-project) 工程致力于简化 Dubbo RPC 框架在Spring Boot应用场景的开发。同时也整合了 Spring Boot 特性:
 
 - [自动装配](https://github.com/apache/incubator-dubbo-spring-boot-project/blob/master/dubbo-spring-boot-autoconfigure) (比如: 注解驱动, 自动装配等).
 - [Production-Ready](https://github.com/apache/incubator-dubbo-spring-boot-project/blob/master/dubbo-spring-boot-actuator) (比如: 安全, 健康检查, 外部化配置等).
 
-### DubboConsumer启动分析
+## DubboConsumer启动分析
 
 你有没有想过一个问题?`incubator-dubbo-spring-boot-project`中的`DubboConsumerDemo`应用就一行代码,`main`方法执行完之后,为什么不会直接退出呢?
 
@@ -137,7 +137,7 @@ public void await() {
 
 接下来,我们再看看,这个Spring-boot应用又是如何退出的呢?
 
-### DubboConsumer退出分析
+## DubboConsumer退出分析
 
 在前面的描述中提到,有一个线程持续的在检查`stopAwait`这个变量,那么我们自然想到,在Stop的时候,应该会有一个线程去修改`stopAwait`,打破这个while循环,那又是谁在修改这个变量呢?
 
@@ -192,16 +192,16 @@ run:929, AbstractApplicationContext$2 (org.springframework.context.support)
 
 因此,正常的应用在停止过程中(`kill -9 $PID`除外),都会执行上述ShutdownHook,它的作用不仅仅是关闭tomcat,还有进行其他的清理工作,在此不再赘述。
 
-### 总结
+## 总结
 
 1. 在`DubboConsumer`启动的过程中,通过启动一个独立的非daemon线程循环检查变量的状态,确保进程不退出
 2. 在`DubboConsumer`停止的过程中,通过执行spring容器的shutdownhook,修改了变量的状态,使得程序正常退出
 
-### 问题
+## 问题
 
 在DubboProvider的例子中,我们看到Provider并没有启动Tomcat提供HTTP服务,那又是如何实现不退出的呢?我们将在下一篇文章中回答这个问题。
 
-#### 彩蛋
+### 彩蛋
 
 在`Intellij IDEA`中运行了如下的单元测试,创建一个线程执行睡眠1000秒的操作,我们惊奇的发现,代码并没有线程执行完就退出了,这又是为什么呢?(被创建的线程是非daemon线程)
 


 

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


With regards,
Apache Git Services

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