This is an automated email from the ASF dual-hosted git repository.
albumenj pushed a commit to branch refactor/next-2
in repository https://gitbox.apache.org/repos/asf/dubbo-website.git
The following commit(s) were added to refs/heads/refactor/next-2 by this push:
new 75acae3d83 add development's document (#2230)
75acae3d83 is described below
commit 75acae3d8349b1ad8eac3cc7b1a41daf875d18fa
Author: Starfish-Ning <[email protected]>
AuthorDate: Tue Feb 14 14:46:52 2023 +0800
add development's document (#2230)
Co-authored-by: liuningbo <liuningbo.nbugs.com>
---
content/zh-cn/overview/tasks/develop/async.md | 157 ++++++++++++++++++++-
content/zh-cn/overview/tasks/develop/context.md | 62 +++++++-
content/zh-cn/overview/tasks/develop/generic.md | 66 ++++++++-
.../overview/tasks/develop/service_reference.md | 124 +++++++++++++++-
.../zh-cn/overview/tasks/develop/version_group.md | 68 +++++++++
5 files changed, 468 insertions(+), 9 deletions(-)
diff --git a/content/zh-cn/overview/tasks/develop/async.md
b/content/zh-cn/overview/tasks/develop/async.md
index 5b1eb726b6..3bc1b89683 100644
--- a/content/zh-cn/overview/tasks/develop/async.md
+++ b/content/zh-cn/overview/tasks/develop/async.md
@@ -1,7 +1,160 @@
---
type: docs
title: "异步调用"
-linkTitle: "异步调用"
+linkTitle: "Provider端和Consumer端异步调用"
weight: 3
-description: ""
+description: "某些情况下希望dubbo接口异步调用,避免不必要的等待。"
---
+## 异步调用
+Dubbo异步调用分为Provider端异步调用和Consumer端异步调用。
+Provider端异步执行将阻塞的业务从Dubbo内部线程池切换到业务自定义线程,
+避免Dubbo线程池的过度占用,有助于避免不同服务间的互相影响。异步执行无异于节省资源或提升RPC响应性能。
+
+*<font color='#FF7D00' size=4 > 注意 </font>*
+
+> Provider 端异步执行和 Consumer 端异步调用是相互独立的,你可以任意正交组合两端配置
+> + Consumer同步 - Provider同步
+> + Consumer异步 - Provider同步
+> + Consumer同步 - Provider异步
+> + Consumer异步 - Provider异步
+
+## 使用场景
+* 对于Provider端来说,如果接口比较耗时,避免dubbo线程被阻塞,可以使用异步将线程切换到业务线程。
+* 对于Consumer端来说,调用Dubbo接口没有严格时序上的关系、不是原子操作、不影响逻辑情况下可以使用异步调用。
+
+
+## Provider异步
+
+### 1、使用CompletableFuture实现异步
+
+接口定义:
+```java
+public interface AsyncService {
+ /**
+ * 同步调用方法
+ */
+ String invoke(String param);
+ /**
+ * 异步调用方法
+ */
+ CompletableFuture<String> asyncInvoke(String param);
+}
+
+```
+服务实现:
+```java
+@DubboService
+public class AsyncServiceImpl implements AsyncService {
+
+ @Override
+ public String invoke(String param) {
+ try {
+ long time = ThreadLocalRandom.current().nextLong(1000);
+ Thread.sleep(time);
+ StringBuilder s = new StringBuilder();
+ s.append("AsyncService invoke
param:").append(param).append(",sleep:").append(time);
+ return s.toString();
+ }
+ catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ return null;
+ }
+
+ @Override
+ public CompletableFuture<String> asyncInvoke(String param) {
+ // 建议为supplyAsync提供自定义线程池
+ return CompletableFuture.supplyAsync(() -> {
+ try {
+ // Do something
+ long time = ThreadLocalRandom.current().nextLong(1000);
+ Thread.sleep(time);
+ StringBuilder s = new StringBuilder();
+ s.append("AsyncService asyncInvoke
param:").append(param).append(",sleep:").append(time);
+ return s.toString();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ return null;
+ });
+ }
+}
+
+```
+通过 return CompletableFuture.supplyAsync() ,业务执行已从 Dubbo 线程切换到业务线程,避免了对 Dubbo
线程池的阻塞。
+
+### 2、使用AsyncContext实现异步
+
+Dubbo 提供了一个类似 Servlet 3.0 的异步接口AsyncContext,在没有 CompletableFuture
签名接口的情况下,也可以实现 Provider 端的异步执行。
+
+接口定义:
+```java
+public interface AsyncService {
+ String sayHello(String name);
+}
+
+```
+
+服务实现:
+
+```java
+public class AsyncServiceImpl implements AsyncService {
+ public String sayHello(String name) {
+ final AsyncContext asyncContext = RpcContext.startAsync();
+ new Thread(() -> {
+ // 如果要使用上下文,则必须要放在第一句执行
+ asyncContext.signalContextSwitch();
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ // 写回响应
+ asyncContext.write("Hello " + name + ", response from provider.");
+ }).start();
+ return null;
+ }
+}
+
+```
+
+## Consumer异步
+```java
+@DubboReference
+private AsyncService asyncService;
+
+@Override
+public void run(String... args) throws Exception {
+ //调用异步接口
+ CompletableFuture<String> future1 = asyncService.asyncInvoke("async call
request1");
+ future1.whenComplete((v, t) -> {
+ if (t != null) {
+ t.printStackTrace();
+ } else {
+ System.out.println("AsyncTask Response-1: " + v);
+ }
+ });
+ //两次调用并非顺序返回
+ CompletableFuture<String> future2 = asyncService.asyncInvoke("async call
request2");
+ future2.whenComplete((v, t) -> {
+ if (t != null) {
+ t.printStackTrace();
+ } else {
+ System.out.println("AsyncTask Response-2: " + v);
+ }
+ });
+ //consumer异步调用
+ CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
+ return asyncService.invoke("invoke call request3");
+ });
+ future3.whenComplete((v, t) -> {
+ if (t != null) {
+ t.printStackTrace();
+ } else {
+ System.out.println("AsyncTask Response-3: " + v);
+ }
+ });
+
+ System.out.println("AsyncTask Executed before response return.");
+}
+```
diff --git a/content/zh-cn/overview/tasks/develop/context.md
b/content/zh-cn/overview/tasks/develop/context.md
index d867aee995..b751527fc4 100644
--- a/content/zh-cn/overview/tasks/develop/context.md
+++ b/content/zh-cn/overview/tasks/develop/context.md
@@ -1,7 +1,65 @@
---
type: docs
title: "上下文参数传递"
-linkTitle: "上下文参数"
+linkTitle: "上下文参数传递"
weight: 5
-description: ""
+description: "通过 Dubbo 中的 Attachment 在服务消费方和提供方之间传递参数"
---
+## 上下文参数传递
+在 Dubbo 3 中,RpcContext
被拆分为四大模块(ServerContext、ClientAttachment、ServerAttachment 和 ServiceContext)。
+
+它们分别承担了不同的职责:
+
+* ServiceContext:在 Dubbo 内部使用,用于传递调用链路上的参数信息,如 invoker 对象等
+* ClientAttachment:在 Client 端使用,往 ClientAttachment 中写入的参数将被传递到 Server 端
+* ServerAttachment:在 Server 端使用,从 ServerAttachment 中读取的参数是从 Client 中传递过来的
+* ServerContext:在 Client 端和 Server 端使用,用于从 Server 端回传 Client 端使用,Server 端写入到
ServerContext 的参数在调用结束后可以在 Client 端的 ServerContext 获取到
+
+## 使用场景
+1、Dubbo系统间调用时,想传递一些通用参数,可通过Dubbo提供的扩展如Filter等实现统一的参数传递
+
+2、Dubbo系统间调用时,想传递接口定义之外的参数,可在调用接口前使用setAttachment传递参数。
+
+## 使用方式
+setAttachment 设置的 KV 对,在完成下面一次远程调用会被清空,即多次远程调用要多次设置。
+
+接口定义:
+```java
+public interface ContextService {
+ String invoke(String param);
+}
+
+```
+服务实现:
+```java
+@DubboService
+public class ContextServiceImpl implements ContextService{
+ @Override
+ public String invoke(String param) {
+ //ServerAttachment接收客户端传递过来的参数
+ Map<String, Object> serverAttachments =
RpcContext.getServerAttachment().getObjectAttachments();
+ System.out.println("ContextService serverAttachments:" +
JSON.toJSONString(serverAttachments));
+ //往客户端传递参数
+ RpcContext.getServerContext().setAttachment("serverKey","serverValue");
+ StringBuilder s = new StringBuilder();
+ s.append("ContextService param:").append(param);
+ return s.toString();
+ }
+}
+
+```
+
+接口调用:
+```java
+ //往服务端传递参数
+
RpcContext.getClientAttachment().setAttachment("clientKey1","clientValue1");
+ String res = contextService.invoke("context1");
+ //接收传递回来参数
+ Map<String, Object> clientAttachment =
RpcContext.getServerContext().getObjectAttachments();
+ System.out.println("ContextTask clientAttachment:" +
JSON.toJSONString(clientAttachment));
+ System.out.println("ContextService Return : " + res);
+
+```
+
+*<font color='#FF7D00' size=4 > 注意 </font>*
+> path, group, version, dubbo, token, timeout 几个 key 是保留字段,请使用其它值。
\ No newline at end of file
diff --git a/content/zh-cn/overview/tasks/develop/generic.md
b/content/zh-cn/overview/tasks/develop/generic.md
index ce11529b39..7a655156a1 100644
--- a/content/zh-cn/overview/tasks/develop/generic.md
+++ b/content/zh-cn/overview/tasks/develop/generic.md
@@ -1,7 +1,69 @@
---
type: docs
-title: "泛化调用"
+title: "开发服务"
linkTitle: "泛化调用"
weight: 6
-description: ""
+description: "在调用方没有服务方提供的 API(SDK)的情况下,对服务方进行调用"
---
+## 泛化调用
+泛化调用(客户端泛化调用)是指在调用方没有服务方提供的 API(SDK)的情况下,对服务方进行调用,并且可以正常拿到调用结果。
+
+## 使用场景
+调用方没有接口及模型类元,知道服务的接口的全限定类名和方法名的情况下,可以通过泛化调用调用对应接口。
+比如:实现一个通用的服务测试框架
+
+## 使用方式
+
+本示例中使用"发布和调用" 中示例代码
+
+接口定义:
+```java
+public interface DevelopService {
+ String invoke(String param);
+}
+```
+
+接口实现1:
+```java
+@DubboService(group = "group1",version = "1.0")
+public class DevelopProviderServiceV1 implements DevelopService{
+ @Override
+ public String invoke(String param) {
+ StringBuilder s = new StringBuilder();
+ s.append("ServiceV1 param:").append(param);
+ return s.toString();
+ }
+}
+```
+
+## 客户端调用
+
+```java
+@Component
+public class GenericTask implements CommandLineRunner {
+
+ @Override
+ public void run(String... args) throws Exception {
+ GenericService genericService =
buildGenericService("org.apache.dubbo.samples.develop.DevelopService","group2","2.0");
+ //传入需要调用的方法,参数类型列表,参数列表
+ Object result = genericService.$invoke("invoke", new
String[]{"java.lang.String"}, new Object[]{"g1"});
+ System.out.println("GenericTask Response: " +
JSON.toJSONString(result));
+ }
+
+ private GenericService buildGenericService(String interfaceClass, String
group, String version) {
+ ReferenceConfig<GenericService> reference = new ReferenceConfig<>();
+ reference.setInterface(interfaceClass);
+ reference.setVersion(version);
+ //开启泛化调用
+ reference.setGeneric("true");
+ reference.setTimeout(30000);
+ reference.setGroup(group);
+ ReferenceCache cache = SimpleReferenceCache.getCache();
+ try {
+ return cache.get(reference);
+ } catch (Exception e) {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+}
+```
\ No newline at end of file
diff --git a/content/zh-cn/overview/tasks/develop/service_reference.md
b/content/zh-cn/overview/tasks/develop/service_reference.md
index a8ff03010e..911d4d05a2 100644
--- a/content/zh-cn/overview/tasks/develop/service_reference.md
+++ b/content/zh-cn/overview/tasks/develop/service_reference.md
@@ -1,7 +1,125 @@
---
type: docs
-title: "发布和调用 Dubbo 服务"
-linkTitle: "发布和调用"
+title: "开发服务"
+linkTitle: "发布和调用 Dubbo 服务"
weight: 2
-description: ""
+description: "通过示例简单展示一个Dubbo服务的发布和调用"
---
+## 发布和调用
+通过一个简单的Springboot实例代码,展示Dubbo服务的发布和调用
+
+本文将基于 Dubbo Samples 示例演示如何快速搭建并部署一个微服务应用。
+代码地址:[dubbo-samples-develop](https://github.com/apache/dubbo-samples/10-task/dubbo-samples-develop)
+代码分为三个模块,如下图:
+
+
+## 准备
+本示例代码基于Springboot 3.0
+
+1、首先需要一个可用的注册中心Zookeeper,Nacos,Redis均可。
+
+2、新建一个maven工程,添加如下依赖
+```xml
+ <!-- registry dependency -->
+ <dependency>
+ <groupId>com.alibaba.nacos</groupId>
+ <artifactId>nacos-client</artifactId>
+ <version>${nacos.version}</version>
+ </dependency>
+
+ <!-- dubbo dependency-->
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-spring-boot-starter</artifactId>
+ <version>${dubbo.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter</artifactId>
+ </dependency>
+
+```
+本示例使用的注册中心为Nacos,使用ZK请将nacos-client包替换为对应版本zk客户端包。
+
+## 发布服务
+1、定义服务接口
+```java
+public interface DevelopService {
+ String invoke(String param);
+}
+```
+2、服务接口实现
+```java
+@DubboService(group = "group1",version = "1.0")
+public class DevelopProviderServiceV1 implements DevelopService{
+ @Override
+ public String invoke(String param) {
+ StringBuilder s = new StringBuilder();
+ s.append("ServiceV1 param:").append(param);
+ return s.toString();
+ }
+}
+```
+使用@DubboService 注解,Dubbo会将对应的服务注册到spring,
+在spring启动后调用对应的服务导出方法,将服务注册到注册中心,
+这样Consumer端才能发现我们发布的服务并调用
+
+3、添加Dubbo配置
+
+添加application.properties相关配置,也可新建dubbo.properties保存dubbo相关配置,内容如下:
+```properties
+dubbo.application.name=provider
+
+# Enable token verification for each invocation
+dubbo.provider.token=false
+
+# Specify the registry address
+# dubbo.registry.address=nacos://localhost:8848?username=nacos&password=nacos
+dubbo.registry.address=nacos://${nacos.address:localhost}:8848?username=nacos&password=nacos
+
+dubbo.protocol.name=dubbo
+dubbo.protocol.port=20881
+```
+
+4、启动服务
+
+创建Springboot启动类,需添加@EnableDubbo注解,开启Dubbo自动配置功能
+```java
+@EnableDubbo
+@SpringBootApplication
+public class DevelopApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(DevelopApplication.class, args);
+ }
+}
+
+```
+启动成功后,在注册中心可以看到对应的服务列表,如图:
+
+
+## 调用服务
+
+创建DemoTask类,通过@DubboReference注解对需要调用的服务进行引入。即可像调用本地方法一样调用远程服务了。
+
+```java
+//实现CommandLineRunner 让Springboot启动后调用run方法
+@Component
+public class DemoTask implements CommandLineRunner {
+ @DubboReference(group = "group1",version = "1.0")
+ private DevelopService developService;
+
+ @Override
+ public void run(String... args) throws Exception {
+ //调用DevelopService的group1分组实现
+ System.out.println("Dubbo Remote Return ======> " +
developService.invoke("1"));
+ }
+}
+```
+
+启动服务 打印
+
+`Dubbo Remote Return ======> ServiceV1 param:1`
+
+说明服务调用成功
diff --git a/content/zh-cn/overview/tasks/develop/version_group.md
b/content/zh-cn/overview/tasks/develop/version_group.md
index b8787b672d..2883384442 100644
--- a/content/zh-cn/overview/tasks/develop/version_group.md
+++ b/content/zh-cn/overview/tasks/develop/version_group.md
@@ -5,3 +5,71 @@ linkTitle: "版本与分组"
weight: 4
description: ""
---
+## 版本与分组
+Dubbo服务中,接口并不能唯一确定一个服务,只有接口+分组+版本号才能唯一确定一个服务。
+
+## 使用场景
+*
当同一个接口针对不同的业务场景、不同的使用需求或者不同的功能模块等场景,可使用服务分组来区分不同的实现方式。同时,这些不同实现所提供的服务是可并存的,也支持互相调用。
+* 当接口实现需要升级又要保留原有实现的情况下,即出现不兼容升级时,我们可以使用不同版本号进行区分。
+
+
+## 使用方式
+使用 @DubboService 注解,添加 group 参数和 version 参数
+本示例中使用"发布和调用" 中示例代码
+
+接口定义:
+```java
+public interface DevelopService {
+ String invoke(String param);
+}
+```
+
+接口实现1:
+```java
+@DubboService(group = "group1",version = "1.0")
+public class DevelopProviderServiceV1 implements DevelopService{
+ @Override
+ public String invoke(String param) {
+ StringBuilder s = new StringBuilder();
+ s.append("ServiceV1 param:").append(param);
+ return s.toString();
+ }
+}
+```
+接口实现2:
+```java
+@DubboService(group = "group2",version = "2.0")
+public class DevelopProviderServiceV2 implements DevelopService{
+ @Override
+ public String invoke(String param) {
+ StringBuilder s = new StringBuilder();
+ s.append("ServiceV2 param:").append(param);
+ return s.toString();
+ }
+}
+```
+
+启动服务后,可以在注册中心看到对应的服务列表,如下:
+
+
+
+客户端接口调用:
+
+> 使用 @DubboReference 注解,添加 group 参数和 version 参数
+
+```java
+@DubboReference(group = "group1",version = "1.0")
+private DevelopService developService;
+
+@DubboReference(group = "group2",version = "2.0")
+private DevelopService developServiceV2;
+
+@Override
+public void run(String... args) throws Exception {
+ //调用DevelopService的group1分组实现
+ System.out.println("Dubbo Remote Return ======> " +
developService.invoke("1"));
+ //调用DevelopService的另一个实现
+ System.out.println("Dubbo Remote Return ======> " +
developServiceV2.invoke("2"));
+}
+```
+