Skip to content

[Feature] 完善泛化调用功能,补齐与 Java 版本的差距 #3167

@Tsukikage7

Description

@Tsukikage7

背景

目前 dubbo-go 的泛化调用已经支持了核心功能(Map 序列化、Gson 序列化、Triple 协议等),但在实际使用中发现还有一些功能缺失,影响了跨语言调用的体验。

经过对比 Java dubbo 的实现,整理出以下需要补充的功能点。

现状

功能 Java dubbo dubbo-go
Map 序列化 (generic=true) 支持 支持
Gson 序列化 支持 支持
Consumer/Provider Filter 支持 支持
Triple 协议支持 支持 支持
GenericException 异常 支持 缺失
响应自动反序列化 支持 缺失
generic.include.class 配置 支持 缺失
protobuf-json 序列化 支持 代码有了但没接入
Bean 序列化 支持 缺失

需要补充的功能

1. GenericException 异常处理

当 dubbo-go 调用 Java 服务时,如果 Java 端抛出业务异常,目前只能拿到一个字符串错误信息,原始的异常类型丢了。

比如 Java 端抛出 UserNotFoundException,dubbo-go 这边只能拿到 "用户不存在" 这个字符串,没办法知道这是什么类型的异常,也就没法做针对性的处理。

如果能拿到完整的异常信息就好了:

type GenericException struct {
    ExceptionClass   string // 比如 "com.example.UserNotFoundException"
    ExceptionMessage string // 比如 "用户不存在"
}

可以参考 Java dubbo 的 GenericException.java
dubbo-common/src/main/java/org/apache/dubbo/rpc/service/GenericException.java


2. 响应自动反序列化

现在泛化调用返回的是 map[string]any,每次都要自己手动转成结构体,写起来挺烦的:

result, _ := genericService.Invoke(ctx, "getUser", []string{"String"}, []any{"123"})
m := result.(map[string]any)
user := &User{
    Name: m["name"].(string),
    Age:  int(m["age"].(float64)),
}

要是能直接反序列化到结构体就方便多了:

var user User
genericService.InvokeWithType(ctx, "getUser", []string{"String"}, []any{"123"}, &user)

改动点在 filter/generic/filter.goOnResponse 方法。


3. generic.include.class 配置

Java dubbo 有个 generic.include.class 配置,控制序列化时要不要带 class 字段:

  • true{"class":"com.example.User", "name":"张三"}
  • false{"name":"张三"}

如果 Java 端配置了 generic.include.class=false,dubbo-go 得能正确处理才行。

改动点:

  • common/constant/key.go 加个常量
  • filter/generic/generalizer/map.go 读配置控制行为

4. protobuf-json 序列化接入

ProtobufJsonGeneralizer 代码已经写好了(在 filter/generic/generalizer/protobuf_json.go),Triple 协议层也支持了,但 Filter 层没接上,导致实际用不了。

问题在 filter/generic/util.go

// isGeneric 只认 "true",不认 protobuf-json
func isGeneric(generic string) bool {
    lowerGeneric := strings.ToLower(generic)
    return lowerGeneric == constant.GenericSerializationDefault
}

// getGeneralizer 没有 protobuf-json 的 case
func getGeneralizer(generic string) (g generalizer.Generalizer) {
    switch strings.ToLower(generic) {
    case constant.GenericSerializationDefault:
        g = generalizer.GetMapGeneralizer()
    case constant.GenericSerializationGson:
        g = generalizer.GetGsonGeneralizer()
    // 缺少 protobuf-json
    default:
        g = generalizer.GetMapGeneralizer()
    }
    return
}

改动点:

  • filter/generic/util.goisGenericgetGeneralizer 加上 protobuf-json 的支持

5. Bean 序列化

Java dubbo 支持 generic=bean 序列化,用 JavaBeanDescriptor 来描述对象。如果要调用的 Java 服务配了 generic=bean,现在 dubbo-go 处理不了。

可以参考 Java dubbo 的实现:
dubbo-common/src/main/java/org/apache/dubbo/common/beanutil/JavaBeanDescriptor.java

相关文件

dubbo-go 需要改动的文件

功能 文件
GenericException filter/generic/exception.go (新建)
GenericException filter/generic/service_filter.go
响应反序列化 filter/generic/filter.go
include.class common/constant/key.go
include.class filter/generic/generalizer/map.go
protobuf-json filter/generic/util.go
Bean 序列化 filter/generic/generalizer/bean.go (新建)

Java dubbo 参考文件

功能 文件
GenericException dubbo-common/.../rpc/service/GenericException.java
响应处理 dubbo-rpc/.../filter/GenericImplFilter.java
include.class dubbo-common/.../utils/PojoUtils.java
Bean 序列化 dubbo-common/.../beanutil/JavaBeanDescriptor.java

Metadata

Metadata

Assignees

Type

No fields configured for Task.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions