apache / apache/dubbo-go

[Feature] 泛化调用优化

Open
#3,472 2 comments 0 reactions 1 assignee Claimed by @Snow-kal View on GitHub
✏️ Feature 3.3.3
Dominant language
Go
Stars
5k
Forks
1k
Avg merge
2d 8h
Merged PRs (30d)
31

Description

# [Feature] 泛化调用优化

## 背景

在 #3167 中,dubbo-go 已经围绕 Java Dubbo 泛化调用补齐了一批核心能力,包括:

- `protobuf-json` 泛化序列化
- `generic.include.class` 配置
- `InvokeWithType` 响应自动反序列化
- `generic=bean` 序列化
- `GenericException` 异常类型保留

目前这些能力已经基本可用,但在实际用于网关、测试平台、跨语言调用时,仍然有一些体验和一致性问题需要继续优化。

这次 issue 希望基于 #3167 继续收敛泛化调用能力,重点提升:

- typed result 行为定义
- generic mode 校验一致性
- 用户侧异常识别和配置 API 清晰度

## 现状

| 功能 | 当前状态 | 需要优化的点 |
|------|----------|--------------|
| Map 泛化调用 (`generic=true`) | 已支持 | typed result 行为需要继续保持稳定 |
| Gson 泛化调用 (`generic=gson`) | 已支持 | typed result / `InvokeWithType` 支持范围需要明确 |
| Protobuf-JSON 泛化调用 (`generic=protobuf-json`) | 已接入 | typed result 行为需要明确 |
| Bean 泛化调用 (`generic=bean`) | 已支持 | 与 `InvokeWithType`、Triple generic 判断的关系需要明确 |
| `InvokeWithType` | 已支持 | 当前只使用 `MapGeneralizer`,无法感知当前 generic mode |
| 普通泛化调用 typed reply | 已支持部分场景 | `OnResponse` 会按 generic mode 取 generalizer,但缺少统一行为定义和测试矩阵 |
| `GenericException` | 已支持 | 类型暴露位置偏底层,用户使用不够方便 |
| `generic.include.class` | 已支持 | 当前通过全局配置读取,用户 API 和文档说明不够清晰 |
| 非法 `generic` 配置 | 当前可能 fallback | 应该尽量早失败并给出明确错误 |
| `protobuf` / `protobuf-json` | 存在兼容差异 | 需要明确 `protobuf` 是否继续作为兼容值保留 |

## 需要补充的功能

### 1. 明确 typed result 与 `InvokeWithType` 的行为边界

目前 `InvokeWithType` 可以把 Map 泛化结果自动反序列化到结构体:

```go
var user User
err := genericService.InvokeWithType(
ctx,
"GetUser",
[]string{"java.lang.String"},
[]hessian.Object{"A003"},
&user,
)
```

但当前实现中,`InvokeWithType` 固定使用 `MapGeneralizer`,主要面向 `generic=true` 的 Map 模式。

同时,普通泛化调用中的 typed reply 路径会在 `OnResponse` 中根据 URL 上的 generic mode 选择 generalizer。这两个路径需要明确区分:

- `InvokeWithType`:需要新增 generic mode 感知能力,或在不支持的 mode 下返回明确错误;
- 普通 typed reply:需要补齐 `true`、`bean`、`gson`、`protobuf-json` 的行为定义和测试覆盖。

另外,当前 `GenericService` 本身不保存 `WithGenericType(...)` 的结果,因此 `InvokeWithType` 无法知道当前是 `bean`、`gson` 还是 `protobuf-json`。需要在实现中明确一种方案:

- 将 generic mode 从 `client.NewGenericService(...)` 传递到 `filter/generic.GenericService`;
- 或定义新的 typed invoke 入口,显式传入 generic mode;
- 或仅声明 `InvokeWithType` 支持 `generic=true`,其他 mode 返回明确错误。

验收效果:

- `generic=true` 下 `InvokeWithType` 保持现有行为;
- `bean`、`gson`、`protobuf-json` 的 typed result 支持情况有明确文档;
- 不支持的 `InvokeWithType` + generic mode 组合返回明确错误,不能 panic 或静默失败;
- 普通 typed reply 的 `OnResponse` 行为有测试矩阵覆盖。

### 2. 提升 `GenericException` 的用户侧可用性

目前 `GenericException` 能保留 Java 异常类名和异常消息,例如:

```go
type GenericException struct {
ExceptionClass string
ExceptionMessage string
}
```

但它现在主要位于较底层的协议包里。业务用户如果想判断 Java 业务异常,需要 import 比较底层的包,不太符合泛化调用的使用直觉。

希望在 `filter/generic` 层提供更友好的入口。建议使用类型别名而不是新增重复类型,例如:

```go
type GenericException = hessian2.GenericException
```

用户侧可以这样使用:

```go
var ge *generic.GenericException
if errors.As(err, &ge) {
fmt.Println(ge.ExceptionClass)
fmt.Println(ge.ExceptionMessage)
}
```

验收效果:

- 用户可以通过 `filter/generic` 包识别泛化异常;
- `errors.As` 能匹配现有底层异常类型;
- Java 业务异常的 class 和 message 不丢失;
- 保持现有底层异常类型兼容。

### 3. 统一 generic mode 校验与兼容策略

当前泛化模式包括:

| 模式 | 参数值 |
|------|--------|
| Map | `true` |
| Gson | `gson` |
| Protobuf-JSON | `protobuf-json` |
| Bean | `bean` |

需要统一校验这些模式,避免传入未知值时静默 fallback 到 Map。

例如:

```go
client.WithGenericType("bad-type")
```

应该在创建引用或调用前返回明确错误,而不是继续执行。

同时需要明确 `protobuf` 的兼容策略。当前部分注释和 Triple 协议判断仍把 `protobuf` 当作合法 generic 值,但本次提案希望收敛到 `protobuf-json`。这里需要明确:

- 如果保留 `protobuf`:应作为兼容值写入文档和校验逻辑;
- 如果不保留 `protobuf`:应拒绝该值,并同步修正注释、测试和 Triple generic 判断。

建议本 issue 采用收敛策略:只接受 `true`、`gson`、`protobuf-json`、`bean`,不再把 `protobuf` 作为新 API 推荐值。

验收效果:

- `client.NewGenericService(..., client.WithGenericType("bad-type"))` 返回明确错误;
- `filter/generic.getGeneralizer` 不再对未知值静默 fallback,或调用方在进入前完成校验;
- Triple generic 判断与 `filter/generic` 使用同一组合法模式;
- `bean` 被 Triple generic 判断识别;
- `protobuf` / `protobuf-json` 的关系在注释和文档中保持一致。

### 4. 优化泛化调用配置入口和文档说明

当前 `client.NewGenericService` 默认使用 Map 泛化方式,并可以通过 `client.WithGenericType(...)` 调整泛化模式。

```go
genericService, err := cli.NewGenericService(
"org.apache.dubbo.samples.UserProvider",
client.WithURL("tri://127.0.0.1:50052"),
client.WithGenericType("bean"),
)
```

但从用户视角看,generic mode、transport serialization、`generic.include.class` 等配置容易混淆。需要补充更清晰的 API 注释和文档说明:

- `generic` 表示泛化格式;
- `serialization` 表示传输序列化方式;
- `generic.include.class` 只影响 Map 泛化中的 `class` 字段;
- `NewGenericService` 默认泛化格式为 `true`;
- `NewGenericService` 默认传输序列化为 Hessian2。

如果本次希望新增用户侧配置入口,需要明确 API,例如:

```go
client.WithGenericIncludeClass(false)
```

如果本次不新增 API,则需要在 issue 中明确:本项仅补充注释和文档,不改变配置入口。

验收效果:

- 用户能清楚区分 generic mode 和 transport serialization;
- `NewGenericService` 的默认行为和可选行为有明确说明;
- `generic.include.class` 的作用范围有明确文档;
- 相关 API 注释与文档保持一致。

## 文件完成情况

| 文件 | 完成情况 | 负责人 |
|------|----------|--------|
| `filter/generic/service.go` | 待处理:补充 `InvokeWithType` generic mode 感知或明确不支持错误 | - |
| `filter/generic/filter.go` | 待处理:明确普通 typed reply 的 `OnResponse` 行为和错误处理 | - |
| `client/options.go` | 待处理:统一 `WithGenericType` 注释和 generic mode 校验入口 | - |
| `filter/generic/util.go` | 待处理:移除未知 generic mode 静默 fallback,或配合调用方返回明确错误 | https://github.com/apache/dubbo-go/pull/3500 |
| `protocol/triple/triple.go` | 待处理:同步合法 generic mode 集合,补充 `bean`,明确 `protobuf` 策略 | - |
| `filter/generic` | 待处理:通过类型别名暴露 `GenericException` | - |
| `filter/generic/generalizer` | 待处理:补齐 Map / Bean / Gson / Protobuf-JSON typed result 行为说明和测试 | -|
| `client/client.go` | 待处理:补充 `NewGenericService` 默认 generic mode 和默认 serialization 说明 | - |
| `filter/generic/*_test.go` | 待处理:补充 typed result、非法 generic mode、`GenericException` 识别测试 | - |
| `protocol/triple/triple_test.go` | 待处理:同步 Triple generic mode 判断测试,覆盖 `bean` 和 `protobuf` 策略 | -|

## 相关文件

dubbo-go 可能需要改动的文件:

| 功能 | 文件 |
|------|------|
| `InvokeWithType` 模式感知 | `filter/generic/service.go` |
| 普通 typed reply 行为 | `filter/generic/filter.go` |
| 泛化模式校验 | `client/options.go` |
| 泛化模式校验 | `filter/generic/util.go` |
| Triple generic mode 判断 | `protocol/triple/triple.go` |
| `GenericException` 用户侧暴露 | `filter/generic` |
| Bean / Map / Gson / Protobuf-JSON typed result | `filter/generic/generalizer` |
| 配置说明和注释 | `client/client.go` |
| 配置说明和注释 | `client/options.go` |
| 相关测试 | `filter/generic/*_test.go` |
| Triple generic 判断测试 | `protocol/triple/triple_test.go` |

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.