This is an automated email from the ASF dual-hosted git repository.
liujun 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 ef71019 update async blog: format source
ef71019 is described below
commit ef7101962ec68c82a8cd75358048cbd35dd3077e
Author: ken.lj <[email protected]>
AuthorDate: Fri Apr 19 00:17:11 2019 +0800
update async blog: format source
---
blog/zh-cn/dubbo-new-async.md | 151 +++++++++++-------------------------------
1 file changed, 38 insertions(+), 113 deletions(-)
diff --git a/blog/zh-cn/dubbo-new-async.md b/blog/zh-cn/dubbo-new-async.md
index 79e8f66..d3aab4c 100644
--- a/blog/zh-cn/dubbo-new-async.md
+++ b/blog/zh-cn/dubbo-new-async.md
@@ -15,15 +15,15 @@ description: 本文回顾了 2.6.x 版本的异步实现,然后引出了 2.7.0
> 2. 你是否需要RPC请求可以是Cold,在subscribe后触发,CompletableFuture总是hot的
> 3. 你的依赖的编程上下文中是否已经在大量使用Reactive的编程接口
> 4. 你是否需要Rx框架提供的更丰富的Operator,而这点和1又是密切相关的
-
-关于参数回调,其本质上是一种服务端的数据推送能力,这是终端应用很常见的一种需求,关于这部分的重构计划,不在本文讨论范围。
-
+
## 2.6.x版本之前的异步方式
在2.6.x及之前的版本提供了一定的异步编程能力,包括Consumer端[异步调用](http://dubbo.apache.org/zh-cn/docs/user/demos/async-call.html)、[参数回调](http://dubbo.apache.org/zh-cn/docs/user/demos/callback-parameter.html)、[事件通知](http://dubbo.apache.org/zh-cn/docs/user/demos/events-notify.html)等,在上面的文档链接中有关于使用方式的简单介绍和Demo。
+关于参数回调,其本质上是一种服务端的数据推送能力,这是终端应用很常见的一种需求,关于这部分的重构计划,不在本文讨论范围。
+
但当前的异步方式存在以下问题:
- Future获取方式不够直接
@@ -34,13 +34,13 @@ description: 本文回顾了 2.6.x 版本的异步实现,然后引出了 2.7.0
1. 定义一个普通的同步接口并声明支持异步调用
-```
+```java
public interface FooService {
String findFoo(String name);
}
```
-```
+```xml
<dubbo:reference id="fooService" interface="com.alibaba.foo.FooService">
<dubbo:method name="findFoo" async="true" />
</dubbo:reference>
@@ -48,7 +48,7 @@ public interface FooService {
2. 通过RpcContext获取Future
-```
+```java
// 此调用会立即返回null
fooService.findFoo(fooId);
// 拿到调用的Future引用,当结果返回后,会被通知和设置到此Future
@@ -58,7 +58,7 @@ fooFuture.get();
或
-```
+```java
// 此调用会立即返回null
fooService.findFoo(fooId);
// 拿到Dubbo内置的ResponseFuture并设置回调
@@ -92,14 +92,11 @@ Dubbo在2.7.0版本已经升级了对Java 8的支持,同时基于CompletableFu
- ```
+ ```java
public interface AsyncService {
CompletableFuture<String> sayHello(String name);
}
```
-
-
-
2.
如果你不想将接口的返回值定义为Future类型,或者存在定义好的同步类型接口,则可以选择重载原始方法并为新方法定义CompletableFuture类型返回值。
@@ -131,7 +128,9 @@ Dubbo在2.7.0版本已经升级了对Java 8的支持,同时基于CompletableFu
这样,Provider依然可以只实现sayHi方法;而Consumer通过直接调用新增的sayHi重载方法可以拿到一个Future实例。
-3. 如果你的原始接口定义是同步的,这时要实现Provider端异步,则可以使用AsyncContext(类似Servlet
3.0里的AsyncContext的编程接口)。注意:在已有CompletabeFuture返回类型的接口上,不建议再使用AsyncContext,请直接利用CompletableFuture带来的异步能力。
+3. 如果你的原始接口定义是同步的,这时要实现Provider端异步,则可以使用AsyncContext(类似Servlet
3.0里的AsyncContext的编程接口)。
+
+>
注意:在已有CompletabeFuture返回类型的接口上,不建议再使用AsyncContext,请直接利用CompletableFuture带来的异步能力。
```
@@ -172,31 +171,23 @@ Dubbo在2.7.0版本已经升级了对Java 8的支持,同时基于CompletableFu
## 示例1:CompletableFuture类型接口
-CompletableFuture类型的接口既可以用作同步调用,也可以实现Consumer或Provider的异步调用。本示例实现了Consumer和Provider端异步调用,代码参见[dubbo-samples-async-original-future](https://github.com/apache/incubator-dubbo-samples/tree/master/dubbo-samples-async/dubbo-samples-async-original-future)。
+CompletableFuture类型的接口既可以用作同步调用,也可以实现Consumer或Provider的异步调用。本示例实现了Consumer和Provider端异步调用,代码参见[dubbo-samples-async-original-future](https://github.com/apache/incubator-dubbo-samples/tree/3.x/dubbo-samples-async/dubbo-samples-async-original-future)。
1. 定义接口
-
-
- ```
+ ```java
public interface AsyncService {
CompletableFuture<String> sayHello(String name);
}
```
-
-
注意接口的返回类型是`CompletableFuture<String>`。
2. Provider端
-
-
- 实现
-
-
- ```
+ ```java
public class AsyncServiceImpl implements AsyncService {
public CompletableFuture<String> sayHello(String name) {
return CompletableFuture.supplyAsync(() -> {
@@ -211,46 +202,29 @@ CompletableFuture类型的接口既可以用作同步调用,也可以实现Con
}
```
-
-
可以看到这里通过supplyAsync将业务代码切换到了新的线程执行,因此实现了Provider端异步。
- 配置
-
-
- ```
+ ```xml
<bean id="asyncService"
class="com.alibaba.dubbo.samples.async.impl.AsyncServiceImpl"/>
<dubbo:service
interface="com.alibaba.dubbo.samples.async.api.AsyncService"
ref="asyncService"/>
```
-
-
- 配置方式和普通接口是一样。
+ 配置方式和普通接口是一样的。
3. Consumer端
-
-
- 配置
-
-
- ```
+ ```xml
<dubbo:reference id="asyncService" timeout="10000"
interface="com.alibaba.dubbo.samples.async.api.AsyncService"/>
```
-
-
-
- 配置方式和普通接口是一样。
-
-
+ 配置方式和普通接口是一样的。
- 调用远程服务
-
-
- ```
+ ```java
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new
ClassPathXmlApplicationContext(new
String[]{"META-INF/spring/async-consumer.xml"});
context.start();
@@ -269,8 +243,6 @@ CompletableFuture类型的接口既可以用作同步调用,也可以实现Con
}
```
-
-
`CompletableFuture<String> future = asyncService.sayHello("async call
request");`很自然的返回了Future示例,这样就实现了Consumer端的异步服务调用。
## 示例2:重载同步接口
@@ -279,41 +251,32 @@ CompletableFuture类型的接口既可以用作同步调用,也可以实现Con
1. 定义接口
-
-
- ```
+ ```java
@DubboAsync
public interface GreetingsService {
String sayHi(String name);
}
```
-
-
修改接口,增加重载方法
```java
public interface GreetingsService {
String sayHi(String name);
- default CompletableFuture<String> sayHi(String name, boolean
placeHolder) {
+ default CompletableFuture<String> sayHi(String name, boolean isAsync) {
return CompletableFuture.completedFuture(sayHello(name));
}
}
```
-
-
-
2. Provider端
-
- 配置
-
- ```
+ ```xml
<bean id="greetingsService"
class="com.alibaba.dubbo.samples.async.impl.GreetingsServiceImpl"/>
<dubbo:service interface="com.alibaba.dubbo.samples.api.GreetingsService"
ref="greetingsService"/>
```
@@ -322,9 +285,7 @@ CompletableFuture类型的接口既可以用作同步调用,也可以实现Con
- 服务实现
-
-
- ```
+ ```java
public class GreetingsServiceImpl implements GreetingsService {
@Override
public String sayHi(String name) {
@@ -335,33 +296,21 @@ CompletableFuture类型的接口既可以用作同步调用,也可以实现Con
3. Consumer端
-
-
- 配置
-
-
- ```
+ ```xml
<dubbo:reference id="greetingsService"
interface="com.alibaba.dubbo.samples.api.GreetingsService"/>
```
-
-
- 注意,服务接口用的是**GreetingsServiceAsync**
-
-
-
- 调用服务
-
-
- ```
+ ```java
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new
ClassPathXmlApplicationContext(new
String[]{"META-INF/spring/async-consumer.xml"});
context.start();
GreetingsService greetingsService = (GreetingsService)
context.getBean("greetingsService");
- CompletableFuture<String> future = greetingsService.sayHi("async
call reqeust");
+ CompletableFuture<String> future = greetingsService.sayHi("async
call reqeust", true);
System.out.println("async call ret :" + future.get());
System.in.read();
@@ -370,46 +319,34 @@ CompletableFuture类型的接口既可以用作同步调用,也可以实现Con
- 这样,我们就可以直接使用`CompletableFuture<String> future =
greetingsService.sayHi("async call reqeust");`,直接返回CompletableFuture。
+ 这样,我们就可以直接使用`CompletableFuture<String> future =
greetingsService.sayHi("async call reqeust", true);`,直接返回CompletableFuture。
## 示例3:使用AsyncContext
本示例演示了如何在同步接口的基础上,通过AsyncContext实现Provider端异步执行,示例代码参见[dubbo-samples-async-provider](https://github.com/apache/incubator-dubbo-samples/tree/3.x/dubbo-samples-async/dubbo-samples-async-provider)。
-1. 定义接口
+> 之前已经提到过,已经是CompletableFuture签名的接口,要实现Provider端异步没必要再用AsyncContext。
-
+1. 定义接口
- ```
+ ```java
public interface AsyncService {
String sayHello(String name);
}
```
-
-
-
-
2. Provider端,和普通provider端配置完全一致
-
-
- 配置
-
-
- ```
+ ```xml
<bean id="asyncService"
class="com.alibaba.dubbo.samples.async.impl.AsyncServiceImpl"/>
<dubbo:service async="true"
interface="com.alibaba.dubbo.samples.async.api.AsyncService"
ref="asyncService"/>
```
-
-
- 异步执行实现
-
-
- ```
+ ```java
public class AsyncServiceImpl implements AsyncService {
public String sayHello(String name) {
final AsyncContext asyncContext = RpcContext.startAsync();
@@ -429,23 +366,15 @@ CompletableFuture类型的接口既可以用作同步调用,也可以实现Con
3. Consumer端
-
-
- 配置
-
-
- ```
+ ```xml
<dubbo:reference id="asyncService"
interface="com.alibaba.dubbo.samples.async.api.AsyncService"/>
```
-
-
- 服务调用
-
-
- ```
+ ```java
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new
ClassPathXmlApplicationContext(new
String[]{"META-INF/spring/async-consumer.xml"});
context.start();
@@ -457,19 +386,15 @@ CompletableFuture类型的接口既可以用作同步调用,也可以实现Con
}
```
-
-
-
-
## 异步引入的新问题
### Filter链
-以下是一次普通Dubbo调用的完整Filter链
+以下是一次普通Dubbo调用的完整Filter链(Filter链路图待补充)。
而采用异步调用后,由于异步结果在异步线程中单独执行,所以流经后半段Filter链的Result是空值,当真正的结果返回时已无法被Filter链处理。
-为了解决这个问题,2.7.0中引入了PostProcessFilter和AbstractPostProcessFilter,其中,PostProcessFilter接口继承自Filter接口,AbstractPostProcessFilter是PostProcessFilter的抽象实现。
+为了解决这个问题,2.7.0中为Filter增加了回调接口onResponse。
以下是一个扩展Filter并支持异步Filter链的例子
@@ -496,7 +421,7 @@ public class AsyncPostprocessFilter implements Filter {
当前我们考虑的上下文主要是指保存在RpcContext中的数据,大多数场景是需要用户在切换业务线程前自己完成Context的传递。
-```
+```java
public class AsyncServiceImpl implements AsyncService {
// 保存当前线程的上下文
RpcContext context = RpcContext.getContext();
@@ -517,7 +442,7 @@ public class AsyncServiceImpl implements AsyncService {
不过AsyncContext也提供了signalContextSwitch()的方法来实现方便的Context切换。
-```
+```java
public class AsyncServiceImpl implements AsyncService {
public String sayHello(String name) {
final AsyncContext asyncContext = RpcContext.startAsync();