weibocom / motan

A cross-language remote procedure call(RPC) framework for rapid development of high performance distributed services.
Other
5.88k stars 1.78k forks source link

motan泛化调用不支持List<T>类型 #1042

Open coderDylan opened 1 year ago

coderDylan commented 1 year ago

motan支持POJO作为参数的情况,例如: User rename(User user, String name) throws Exception; 通过定义Map作为参数,并指定POJO全限定名时,可以正常完成泛化调用,服务端反序列化正常的,代码如下: CommonClient service = referer.getRef(); Map<String, Object> person = new HashMap<String, Object>(); person.put("name", "xxx"); person.put("id", 999); Request request = MotanClientUtil.buildRequest("com.weibo.motan.demo.service.MotanDemoService", "rename", "com.weibo.motan.demo.service.model.User,java.lang.String", new Object[]{person,"dinglang"}, null); service.call(request, Object.class);

但是,当参数是List类型时,服务端反序列化正常,但因为T缺失,所以无法完成泛化调用。例如: void batchSave(List list); 这种情况下,传递的参数是ArrayList,指定的参数类型是"java.util.List",调用代码如下: ` CommonClient client = referer.getRef();

    Map<String, Object> person = new HashMap<String, Object>();
    person.put("name", "xxx");
    person.put("id", 999);

    Map<String, Object> user = new HashMap<String, Object>();
    user.put("name", "yyy");
    user.put("id", 110);

    List<Object> list = new ArrayList<>();
    list.add(person);
    list.add(user);

    Request request2 = MotanClientUtil.buildRequest("com.weibo.motan.demo.service.MotanDemoService", "batchSave", "java.util.List", new Object[]{list}, null);
    client.call(request2, Object.class);`

这种,会导致服务端com.weibo.api.motan.rpc.DefaultProvider#invoke这里最终调用Impl实现失败。 com.weibo.api.motan.transport.ProviderMessageRouter#processLazyDeserialize这里反序列化是正常的,不过因为反序列化出来的结果是List,而实际方法是List list,所以最终无法成功调用

coderDylan commented 1 year ago

@rayzhang0603 这个问题现在有解吗?Dubbo是可以直接这样调用的

rayzhang0603 commented 1 year ago

Motan框架并没有对泛化调用做特别支持,上面case中的map方式可以调用成功是hessian2序列化提供的能力。

Motan中的CommonClient的设计意图是方便跨语言调用,其他语言提供的服务在java侧并不会有对应的service,这时就可以使用CommonClient来进行调用。 不同语言间的数据传递主要依赖不同序列化方式。比如使用ProtoBuf或者Breeze序列化

Motan没有支持泛型主要是基于下面考虑:

  1. 泛化只能解决简单对象的无依赖调用,实际业务使用的复杂对象很难用泛化来描述
  2. 泛化一般与使用的序列化实现相关,泛化能力也很难在多语言中达成能力一致。
  3. java的泛化通过反射来实现,对于不需要使用泛化的场景会增加额外的性能开销。
  4. 泛化会破坏RPC强契约的形式,容易让client侧和server侧对接口、对象的维护变得困难,除了一些通用服务测试场景外,基本也没有什么使用泛化的场景。而通用测试场景可以通过流量录制回放方式,直接在二进制流方面进行处理,效率比泛化会更高,不过对二次开发能力要求较高。
  5. 如果泛化的目的是为了与其他语言交互,建议通过ProtoBuf或者Breeze这些强契约的方式来实现,更适合服务的长期维护。