本文从一个 BUG 入手,手把手教你 dubbogo 调用 dubbogo 或 dubbo 服务

一、前言

昨天邹部长在群里@我让看一个关于 dubbogo 调用 dubbo 报错的问题,问题issue地址,于是我跑了 dubbogo + dubbbo 的测试代码来定位这个问题,因为之前也没跨语言调用,从零开始搭建,踩到了一些新人使用 dubbogo 的坑,把这个过程记录下供大家参考。

二、解决问题

2.1 准备 dubbo 服务提供者

2.1.1 基本定义

定义 DemoService 接口:

public interface DemoService {String sayHello(String name);String sayHello(User user);String sayHello(User user, String name);}

定义 User 对象:

public class User implements Serializable {private String name;private int age;......
}

2.1.2 启动 dubbo 服务提供者

用的 dubbo 官方示例代码:

public static void main(String[] args) throws IOException {// 服务实现DemoService demoService = new DemoServiceImpl();// 当前应用配置ApplicationConfig application = new ApplicationConfig();application.setName("demoProvider");// 连接注册中心配置RegistryConfig registry = new RegistryConfig();registry.setAddress("127.0.0.1:2181");registry.setProtocol("zookeeper");registry.setUsername("");registry.setPassword("");// 服务提供者协议配置ProtocolConfig protocol = new ProtocolConfig();protocol.setName("dubbo");protocol.setPort(12345);protocol.setThreads(200);// 注意:ServiceConfig为重对象,内部封装了与注册中心的连接,以及开启服务端口// 服务提供者暴露服务配置ServiceConfig<DemoService> service = new ServiceConfig<>(); // 此实例很重,封装了与注册中心的连接,请自行缓存,否则可能造成内存和连接泄漏service.setApplication(application);service.setRegistry(registry); // 多个注册中心可以用setRegistries()service.setProtocol(protocol); // 多个协议可以用setProtocols()service.setInterface(DemoService.class);service.setRef(demoService);service.setVersion("1.0.0");service.setGroup("tc");service.setTimeout(60 * 1000);// 暴露及注册服务service.export();System.in.read();
}

查看 zookeeper 看是否注册成功:

$ls /dubbo/com.funnycode.DemoService/providers
[dubbo%3A%2F%2F127.0.0.1%3A12345%2Fcom.funnycode.DemoService%3Fanyhost%3Dtrue%26application%3DdemoProvider%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26generic%3Dfalse%26group%3Dtc%26interface%3Dcom.funnycode.DemoService%26methods%3DsayHello%26pid%3D18167%26release%3D2.7.7%26revision%3D1.0.0%26side%3Dprovider%26threads%3D200%26timestamp%3D1606896020691%26version%3D1.0.0]

如上的输出表示服务提供方已经启动。

2.2 准备 dubbo 服务消费者

2.2.1 基本定义

定义 User 对象:

type User struct {Name stringAge  int
}func (User) JavaClassName() string {return "com.funnycode.User"
}

定义 DemoProvider 接口:

type DemoProvider struct {SayHello  func(ctx context.Context, name string) (string, error)            `dubbo:"sayHello"`SayHello2 func(ctx context.Context, user User) (string, error)              `dubbo:"sayHello"`SayHello3 func(ctx context.Context, user User, name string) (string, error) `dubbo:"sayHello"`
}func (p *DemoProvider) Reference() string {return "DemoProvider"
}

2.2.2 启动 dubbogo 消费者

func main() {config.Load()gxlog.CInfo("\n\n\nstart to test dubbo")res, err := demoProvider.SayHello(context.TODO(), "tc")if err != nil {panic(err)}gxlog.CInfo("response result: %v\n", res)user := User{Name: "tc",Age:  18,}res, err = demoProvider.SayHello2(context.TODO(), user)if err != nil {panic(err)}gxlog.CInfo("response result: %v\n", res)res, err = demoProvider.SayHello3(context.TODO(), user, "tc")if err != nil {panic(err)}gxlog.CInfo("response result: %v\n", res)initSignal()
}

2.3 请求结果分析

2.3.1 直接调用

确认问题的存在

第一个接口的参数是字符串,可以正常返回 [2020-12-03/18:59:12 main.main: client.go: 29] response result: Hello tc
第二、三两个接口是 User 对象,无法调用成功。错误信息如下:

2020-12-02T17:10:47.739+0800    INFO    getty/listener.go:87    session{session session-closed, Read Bytes: 924, Write Bytes: 199, Read Pkgs: 0, Write Pkgs: 1} got error{java exception:Fail to decode request due to: java.lang.IllegalArgumentException: Service not found:com.funnycode.DemoService, sayHelloat org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation.decode(DecodeableRpcInvocation.java:134)at org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation.decode(DecodeableRpcInvocation.java:80)at org.apache.dubbo.remoting.transport.DecodeHandler.decode(DecodeHandler.java:57)at org.apache.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:44)at org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:57)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:748)
}, will be closed.

正如 issue 中描述的一模一样,因为直接给出了 Java 那边的错误信息,所以直接去看 DecodeableRpcInvocation.decode#134

2.3.2 断点查看

代码如下:

public class DecodeableRpcInvocation extends RpcInvocation implements Codec, Decodeable {public Object decode(Channel channel, InputStream input) throws IOException {......if (serviceDescriptor != null) {MethodDescriptor methodDescriptor = serviceDescriptor.getMethod(getMethodName(), desc);if (methodDescriptor != null) {pts = methodDescriptor.getParameterClasses();this.setReturnTypes(methodDescriptor.getReturnTypes());}}if (pts == DubboCodec.EMPTY_CLASS_ARRAY) {if (!RpcUtils.isGenericCall(path, getMethodName()) && !RpcUtils.isEcho(path, getMethodName())) {throw new IllegalArgumentException("Service not found:" + path + ", " + getMethodName());}pts = ReflectUtils.desc2classArray(desc);}......}
}
  • 查看 MethodDescriptor,即找方法是否存在,存在的话就会设置好 ParameterClasses
  • 如果上面没找到,pts == DubboCodec.EMPTY_CLASS_ARRAY 就会满足条件,进而判断是否是泛化调用或者是 echo 调用,如果都不是则报服务找不到方法错误
  • desc 是 Ljava/lang/Object ,很明显并没有参数是 Object 的方法,所以必然是会报错的

补充说明:

方法查询

代码如下:

public MethodDescriptor getMethod(String methodName, String params) {Map<String, MethodDescriptor> methods = descToMethods.get(methodName);if (CollectionUtils.isNotEmptyMap(methods)) {return methods.get(params);}return null;
}

优点:

比之前的版本加了方法的元信息缓存起来,不使用反射可以提高效率,可以理解用空间换时间。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GDuYLuJN-1607674165410)(https://raw.githubusercontent.com/cityiron/tuchuang/master/blog/dubbo-decode.01.jpg)]

2.4 解决问题

因为直接撸代码并 hold 不住,所以通过比较来查看问题所在。

2.4.1 启动 dubbo 服务消费者

通过 api 模式启动,参考官方例子。启动这个是为了查看 Java 版本的传输内容。

public static void main(String[] args) throws InterruptedException {// 当前应用配置ApplicationConfig application = new ApplicationConfig();application.setName("demoProvider2");// 连接注册中心配置RegistryConfig registry = new RegistryConfig();registry.setAddress("127.0.0.1:2181");registry.setProtocol("zookeeper");registry.setUsername("");registry.setPassword("");// 注意:ReferenceConfig为重对象,内部封装了与注册中心的连接,以及与服务提供方的连接// 引用远程服务ReferenceConfig<DemoService> reference= new ReferenceConfig<>(); // 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏reference.setApplication(application);reference.setRegistry(registry); // 多个注册中心可以用setRegistries()reference.setInterface(DemoService.class);reference.setVersion("1.0.0");reference.setGroup("tc");reference.setCheck(true);reference.setTimeout(1000 * 60);// 和本地bean一样使用xxxServiceDemoService demoService = reference.get(); // 注意:此代理对象内部封装了所有通讯细节,对象较重,请缓存复用System.out.println(demoService.sayHello(new User("tc", 18)));TimeUnit.MINUTES.sleep(10);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZSta0GIN-1607674165412)(https://raw.githubusercontent.com/cityiron/tuchuang/master/blog/image-20201202205049730.png)]

desc 肉眼可见的是 Lcom/funnycode/User,这个就是正确的对象了。

2.4.2 查找dubbogo为什么不对

感谢提 issue 的同学,把代码已经贴出来了

代码位置:

protocol/dubbo/impl/hessian.go:120#marshalRequest

代码实现:

func marshalRequest(encoder *hessian.Encoder, p DubboPackage) ([]byte, error) {service := p.Servicerequest := EnsureRequestPayload(p.Body)encoder.Encode(DEFAULT_DUBBO_PROTOCOL_VERSION)encoder.Encode(service.Path)encoder.Encode(service.Version)encoder.Encode(service.Method)args, ok := request.Params.([]interface{})if !ok {logger.Infof("request args are: %+v", request.Params)return nil, perrors.Errorf("@params is not of type: []interface{}")}types, err := getArgsTypeList(args)if err != nil {return nil, perrors.Wrapf(err, " PackRequest(args:%+v)", args)}encoder.Encode(types)for _, v := range args {encoder.Encode(v)}......
}

断点可以发现,types 返回的时候就已经是 Object 了,没有返回 User,那么继续跟进去查看代码。

  • protocol/dubbo/impl/hessian.go:394#getArgsTypeList
  • protocol/dubbo/impl/hessian.go:418#getArgType
func getArgType(v interface{}) string {// 常见的类型处理......default:t := reflect.TypeOf(v)if reflect.Ptr == t.Kind() {t = reflect.TypeOf(reflect.ValueOf(v).Elem())}switch t.Kind() {case reflect.Struct:return "java.lang.Object"}......
}

很明显当发现是 reflect.Struct 的时候就返回了 java.lang.Object,所以参数就变成了 Object,那么因为 Java 代码那边依赖这个类型所以就调用失败了。

2.4.3 其它版本验证

因为反馈是 2.7.7 出错,所以先考虑到在之前的版本是否功能正常,于是把服务提供者切换到 dubbo 2.7.3,发现调用仍然有错误,如下:

2020-12-02T21:52:25.945+0800    INFO    getty/listener.go:85    session{session session-closed, Read Bytes: 4586, Write Bytes: 232, Read Pkgs: 0, Write Pkgs: 1} got error{java exception:org.apache.dubbo.rpc.RpcException: Failed to invoke remote proxy method sayHello to registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=demoProvider&dubbo=2.0.2&export=dubbo%3A%2F%2F192.168.0.113%3A12345%2Fcom.funnycode.DemoService%3Fanyhost%3Dtrue%26application%3DdemoProvider%26bind.ip%3D192.168.0.113%26bind.port%3D12345%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26generic%3Dfalse%26group%3Dtc%26interface%3Dcom.funnycode.DemoService%26methods%3DsayHello%26pid%3D23889%26register%3Dtrue%26release%3D2.7.3%26revision%3D1.0.0%26side%3Dprovider%26threads%3D200%26timeout%3D60000%26timestamp%3D1606916702204%26version%3D1.0.0&pid=23889&registry=zookeeper&release=2.7.3&timestamp=1606916702193, cause: Not found method "sayHello" in class com.funnycode.DemoServiceImpl.
org.apache.dubbo.rpc.RpcException: Failed to invoke remote proxy method sayHello to registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=demoProvider&dubbo=2.0.2&export=dubbo%3A%2F%2F192.168.0.113%3A12345%2Fcom.funnycode.DemoService%3Fanyhost%3Dtrue%26application%3DdemoProvider%26bind.ip%3D192.168.0.113%26bind.port%3D12345%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26generic%3Dfalse%26group%3Dtc%26interface%3Dcom.funnycode.DemoService%26methods%3DsayHello%26pid%3D23889%26register%3Dtrue%26release%3D2.7.3%26revision%3D1.0.0%26side%3Dprovider%26threads%3D200%26timeout%3D60000%26timestamp%3D1606916702204%26version%3D1.0.0&pid=23889&registry=zookeeper&release=2.7.3&timestamp=1606916702193, cause: Not found method "sayHello" in class com.funnycode.DemoServiceImpl.at org.apache.dubbo.rpc.proxy.AbstractProxyInvoker.invoke(AbstractProxyInvoker.java:107)at org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker.invoke(DelegateProviderMetaDataInvoker.java:56)at org.apache.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:56)at org.apache.dubbo.rpc.filter.ExceptionFilter.invoke(ExceptionFilter.java:55)at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82)at org.apache.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:92)at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82)at org.apache.dubbo.rpc.filter.TimeoutFilter.invoke(TimeoutFilter.java:48)at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82)at org.apache.dubbo.rpc.protocol.dubbo.filter.TraceFilter.invoke(TraceFilter.java:81)at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82)at org.apache.dubbo.rpc.filter.ContextFilter.invoke(ContextFilter.java:96)at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82)at org.apache.dubbo.rpc.filter.GenericFilter.invoke(GenericFilter.java:148)at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82)at org.apache.dubbo.rpc.filter.ClassLoaderFilter.invoke(ClassLoaderFilter.java:38)at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82)at org.apache.dubbo.rpc.filter.EchoFilter.invoke(EchoFilter.java:41)at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82)at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$CallbackRegistrationInvoker.invoke(ProtocolFilterWrapper.java:157)at org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol$1.reply(DubboProtocol.java:152)at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.handleRequest(HeaderExchangeHandler.java:102)at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.received(HeaderExchangeHandler.java:193)at org.apache.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:51)at org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:57)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:748)
Caused by: org.apache.dubbo.common.bytecode.NoSuchMethodException: Not found method "sayHello" in class com.funnycode.DemoServiceImpl.at org.apache.dubbo.common.bytecode.Wrapper1.invokeMethod(Wrapper1.java)at org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory$1.doInvoke(JavassistProxyFactory.java:47)at org.apache.dubbo.rpc.proxy.AbstractProxyInvoker.invoke(AbstractProxyInvoker.java:84)... 27 more
}, will be closed.

虽然和 2.7.7 的代码是不一样的,但是通过错误也能看出来是在代理增强类里面方法找不到,大概率是反射找不到方法,所以归根结底也是参数的问题。

2.4.4 修复问题

修复相对简单,就是拿到 struct 定义的 JavaClassName

case reflect.Struct:v, ok := v.(hessian.POJO)if ok {return v.JavaClassName()}return "java.lang.Object"

2.4.3 验证结果

再次执行消费者,运行(提供方 2.7.7 和 2.7.3)正常,输出如下:

[2020-12-03/20:04:06 main.main: client.go: 29] response result: Hello tc
...
[2020-12-03/20:04:09 main.main: client.go: 41] response result: Hello tc You are 18
...
[2020-12-03/20:04:09 main.main: client.go: 48] response result: Hello tc You are 18

三、细节叨叨

3.1 如何配置 dubbgo 消费者

细心的你是否已经发现,在我 dubbogo 的消费端接口叫 DemoProvider,然后发现提供者叫 DemoService,这个又是如何正常运行的?

实际上和 client.yml 中配置项 references 有关,在配置文件详细说明了 interfaceversiongroup 等,你还可以通过 methods 配置方法的超时时间等信息。

references:"DemoProvider":# 可以指定多个registry,使用逗号隔开;不指定默认向所有注册中心注册registry: "zk1"protocol: "dubbo"interface: "com.funnycode.DemoService"cluster: "failover"version: "1.0.0"group: "tc"methods:- name: "SayHello"retries: 3......

3.2 全局的 group 和 version 怎么配置

配置文件如下:

# application config
application:organization: "dubbogoproxy.com"name: "Demo Micro Service"module: "dubbogoproxy tc client"version: "1.0.0"group: "tc"owner: "ZX"environment: "dev"references:"DemoProvider":# 可以指定多个registry,使用逗号隔开;不指定默认向所有注册中心注册registry: "zk1"protocol: "dubbo"interface: "com.funnycode.DemoService"cluster: "failover"
#    version: "1.0.0"
#    group: "tc"methods:- name: "SayHello"retries: 3

从使用的习惯来讲,肯定是 application 表示了全局的配置,但是我发现启动的时候在 application 配置的 versiongroup 并不会赋值给接口,启动会报服务提供方找不到,如下:

2020-12-03T20:15:42.208+0800    DEBUG   zookeeper/registry.go:237       Create a zookeeper node:/dubbo/com.funnycode.DemoService/consumers/consumer%3A%2F%2F30.11.176.107%2FDemoProvider%3Fapp.version%3D1.0.0%26application%3DDemo+Micro+Service%26async%3Dfalse%26bean.name%3DDemoProvider%26cluster%3Dfailover%26environment%3Ddev%26generic%3Dfalse%26group%3D%26interface%3Dcom.funnycode.DemoService%26ip%3D30.11.176.107%26loadbalance%3D%26methods.SayHello.loadbalance%3D%26methods.SayHello.retries%3D3%26methods.SayHello.sticky%3Dfalse%26module%3Ddubbogoproxy+tc+client%26name%3DDemo+Micro+Service%26organization%3Ddubbogoproxy.com%26owner%3DZX%26pid%3D38692%26protocol%3Ddubbo%26provided-by%3D%26reference.filter%3Dcshutdown%26registry.role%3D0%26release%3Ddubbo-golang-1.3.0%26retries%3D%26side%3Dconsumer%26sticky%3Dfalse%26timestamp%3D1606997742%26version%3D

versiongroup 都是空。必须把 DemoProvider 下的 versiongroup 注释打开。这个细节后面分析配置文件解析的时候会展开说明。

3.3 怎么指定调用的方法名

3.3.1 go 调用 java

dubbogo 调用 dubbo,因为 go 是大写的方法名,java 里面是小写的方法名,所以会出现如下错误:

2020-12-02T17:10:47.739+0800    INFO    getty/listener.go:87    session{session session-closed, Read Bytes: 924, Write Bytes: 199, Read Pkgs: 0, Write Pkgs: 1} got error{java exception:Fail to decode request due to: java.lang.IllegalArgumentException: Service not found:com.funnycode.DemoService, SayHello
java.lang.IllegalArgumentException: Service not found:com.funnycode.DemoService, SayHelloat org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation.decode(DecodeableRpcInvocation.java:134)at org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation.decode(DecodeableRpcInvocation.java:80)at org.apache.dubbo.remoting.transport.DecodeHandler.decode(DecodeHandler.java:57)at org.apache.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:44)at org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:57)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:748)
}, will be closed.

关联的issue

细心的读者可能已经注意到了,我在消费端的接口声明是有个 dubbo:"sayHello" 的,表示方法名是 sayHello,这样在服务提供方就可以得到 sayHello 这个方法名。

还有我声明的三个方法都指明它们的方法名叫 dubbo:"sayHello",这是因为 Java 可以方法名字一样进行重载,而 go 是不能方法名重复的。

扯淡:在 go 里面看到 java 的错误熟悉的味道,奇怪的感觉

3.3.2 go 调用 go

直接贴能跑通的代码

我的提供者接口:

type DemoProvider struct{}func (p *DemoProvider) SayHello(ctx context.Context, name string) (string, error) {return "Hello " + name, nil
}func (p *DemoProvider) SayHello4(ctx context.Context, user *User) (string, error) {return "Hello " + user.Name + " You are " + strconv.Itoa(user.Age), nil
}func (p *DemoProvider) SayHello5(ctx context.Context, user *User, name string) (string, error) {return "Hello " + name + " You are " + strconv.Itoa(user.Age), nil
}func (p *DemoProvider) Reference() string {return "DemoProvider"
}func (p *DemoProvider) MethodMapper() map[string]string {return map[string]string{"SayHello": "sayHello",}
}

我的消费者使用:

type DemoProvider struct {// 调用 java 和 goSayHello  func(ctx context.Context, name string) (string, error)             `dubbo:"sayHello"`// 只调用 javaSayHello2 func(ctx context.Context, user *User) (string, error)              `dubbo:"sayHello"`SayHello3 func(ctx context.Context, user *User, name string) (string, error) `dubbo:"sayHello"`// 只调用 goSayHello4 func(ctx context.Context, user *User) (string, error)SayHello5 func(ctx context.Context, user *User, name string) (string, error)
}
func main() {config.Load()gxlog.CInfo("\n\n\nstart to test dubbo")res, err := demoProvider.SayHello(context.TODO(), "tc")if err != nil {panic(err)}gxlog.CInfo("response result: %v\n", res)user := &User{Name: "tc",Age:  18,}res, err = demoProvider.SayHello4(context.TODO(), user)if err != nil {panic(err)}gxlog.CInfo("response result: %v\n", res)res, err = demoProvider.SayHello5(context.TODO(), user, "tc")if err != nil {panic(err)}gxlog.CInfo("response result: %v\n", res)initSignal()
}

这里主要注意 MethodMapper 方法,像我请求 SayHello 变成了 sayHello,需要在这个方法中配置这个映射关系,否则还是会找不到方法。

3.4 为什么会用 hessian2

老司机都懂,SPI机制的默认值就是 hessian2

@SPI("hessian2")
public interface Serialization {}

3.5 hessian序列化源码

可以自行断点查看,两边基本上一样,我也是通过两边比出来的,RpcInvocation.getParameterTypesDesc() 就是方法的参数

  • go 代码 protocol/dubbo/impl/hessian.go:120#marshalRequest

  • java 代码 org.apache.dubbo.rpc.protocol.dubbo.DubboCodec#encodeRequestData(org.apache.dubbo.remoting.Channel, org.apache.dubbo.common.serialize.ObjectOutput, java.lang.Object, java.lang.String)

3.6 dubbogo 服务提供者的方法对象需要是指针对象

之前的例子都是 copy 的,这次是纯手打的,才发现了这个问题。

如果你的提供类似:func (p *DemoProvider) SayHello4(ctx context.Context, user User) (string, error),那么会出现如下错误:

2020-12-03T12:42:32.834+0800    ERROR   getty/listener.go:280   OnMessage panic: reflect: Call using *main.User as type main.User
github.com/apache/dubbo-go/remoting/getty.(*RpcServerHandler).OnMessage.func1

参数里面的 User 需要改成 *User

3.7 dubbogo 服务消费者的方法对象可以是非指针对象

SayHello4 func(ctx context.Context, user *User) (string, error)
// or
SayHello4 func(ctx context.Context, user User) (string, error)

因为在参数序列化的时候会对指针做操作:

t := reflect.TypeOf(v)
if reflect.Ptr == t.Kind() {t = reflect.TypeOf(reflect.ValueOf(v).Elem())
}

3.8 繁琐的配置简化

查看我另一篇文章,待发布中

3.9 复现代码

  • https://github.com/cityiron/java_study/tree/master/dubbo2.7.7
  • https://github.com/cityiron/java_study/tree/master/dubbo2.7.7

四、参考

https://dubbo.apache.org/zh/docs/v2.7/user/configuration/api/

dubbo-go 白话文 | go 和 java 互通有无相关推荐

  1. dubbo调用service后返回对象null_dubbo-go 白话文 | go 和 java 互通有无

    本文从一个 BUG 入手,手把手教你 dubbogo 调用 dubbogo 或 dubbo 服务 一.前言 昨天邹部长在群里@我让看一个关于 dubbogo 调用 dubbo 报错的问题,问题issu ...

  2. 在Dubbo中使用高效的Java序列化(Kryo和FST)

    作者:沈理 文档版权: Apache 2.0许可证 署名-禁止演绎 完善中-- TODO 生成可点击的目录 目录 序列化漫谈 启用Kryo和FST 注册被序列化类 无参构造函数和Serializabl ...

  3. Apache Dubbo已不再局限于Java语言

    2017 年 9 月 7 日,在沉寂了4年之后,Dubbo 悄悄的在 GitHub 发布了 2.5.4 版本.随后又迅速发布了 2.5.5.2.5.6.2.5.7 等release.在 2017年 1 ...

  4. Apache Dubbo是一款高性能Java RPC框架。

  5. dubbo-go 白话文 | 从零搭建 dubbogo 和 dubbo 的简单用例

    作者 | 铁城 dubbo-go 社区 committer 来源|阿里巴巴云原生公众号 本文将手把手教你使用 dubbogo 调用 dubbogo 或 dubbo 提供的服务提供方. 前言 本文基于 ...

  6. Java面试进阶:Dubbo、Zookeeper面试题锦集

    Dubbo面试题锦集 1.默认也推荐使用netty框架,还有mina. 2.默认是阻塞的,可以异步调用,没有返回值的可以这么做. 3.推荐使用zookeeper注册中心,还有redis等不推荐. 4. ...

  7. java warmup,20. dubbo源码-预热warmup过程

    阿飞Javaer,转载请注明原创出处,谢谢! 前言 今天群里小伙伴黄晓峰VIVO咨询一个问题:"dubbo接口怎么做预热呢,每次上线,都会有一小部分超时?",熟悉JVM都知道,JV ...

  8. java分布式服务框架Dubbo的介绍与使用

    1. Dubbo是什么? Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案.简单的说,dubbo就是个服务框架,如果没有分布式的需求,其实是不需 ...

  9. Dubbo 启动报java.lang.NoClassDefFoundError: org/apache/curator/RetryPolicy

    1.## Dubbo 启动报java.lang.NoClassDefFoundError: org/apache/curator/RetryPolicy 2. Failed to subscribe ...

最新文章

  1. R语言使用ggplot2包使用geom_violin函数绘制分组小提琴图(自定义分组的填充色)实战
  2. Common BeanUtils 简介
  3. c语言马秀丽,C语言程序计 清华大学出版社 马秀丽 刘志妩科后习题9答.doc
  4. 20160828_第4周周报
  5. phalapi 数据库锁_phalApi数据库操作
  6. svm中的数学和算法
  7. GPS测量中所涉及的时间系统
  8. C# Halcon 图像放大缩小代码
  9. 信签纸有虚线怎么写_信签纸写作文格式怎么用
  10. css5导弹,世界六大洲际导弹排行榜
  11. Python 爬虫 + 人脸检测 —— 知乎高颜值图片抓取
  12. PHP实现采集淘宝商品信息
  13. 纯正国内的海盗王3.0修复端
  14. php手机模板修改,pc和手机模板自动切换
  15. 第2台计算机的英文简写是,又一IP古装权谋剧来了!那么IP到底是哪两个英文的缩写?...
  16. 布袋除尘器过滤风速多少_布袋除尘器处理风量、过滤风速、过滤面积怎么算?这篇全了...
  17. 你知道CMA与CNAS的区别和联系是什么吗?
  18. python 角度传感器模拟_模拟多圈旋转角度传感器
  19. 天猫精灵X1自动恢复出厂设置解决方法
  20. 今天接到东南融通的面试电话,请问下个人一些具体情况

热门文章

  1. 陳三甲网络笔记:赚钱这件事,你别搞复杂了,简单点
  2. 将App通过XCode上传到AppStore 出现这个错误“An error occurred uploading to the iTunes Store”的解决方法
  3. 临近小区分析-利用ArcGIS构建分析模型
  4. 2022-2028年中国渗滤液处理行业市场全景评估及发展策略分析报告
  5. [C和指针]笔记——01章~18章
  6. 高防CDN跟高防服务器相比,有哪些优势?
  7. 管理日常工作、生活琐事的待办事项提醒工具便签
  8. 基于SVN的项目管理——集中与分散
  9. 长安链赋能北京140余个政务服务应用场景
  10. python中的遍历