2.0.1 新特性介绍: 泛化调用

泛化调用指在不知道 Provider 接口定义信息的情况下,访问 Provider 提供的服务。 与泛化调用对应的方式包括透明 RPC(POJO)和 RestTemplate。 透明 RPC 需要提供 Provider 对应的接口, RestTemplate 需要提供 Provider 对应的 URL 和 数据 Model 。 泛化 调用需要提供 Provider 的服务元数据: 微服务名称, 版本, Schema ID, Operation ID, 契约参数等信息。

java-chassis 很早就提供了泛化调用, 本文重点介绍 2.0.1 的功能。 2.0.1 对于泛化调用的接口进行了优化, 支持指定响应类型, 早期的版本的响应类型取决于运行上下文, 是不确定的。

使用泛化调用

假设 Provider 采用透明 RPC 的方式提供了如下服务:

  1. @RpcSchema(schemaId = "InvokerEndpoint")
  2. public class InvokerEndpoint {
  3. public ServerModel model(ServerModel request) {
  4. return request;
  5. }
  6. }
  7. public class ServerModel {
  8. private String name;
  9. private int code;
  10. public String getName() {
  11. return name;
  12. }
  13. public void setName(String name) {
  14. this.name = name;
  15. }
  16. public int getCode() {
  17. return code;
  18. }
  19. public void setCode(int code) {
  20. this.code = code;
  21. }
  22. }

可以采用 InvokerUtils 访问这个服务:

  1. Map<String, Object> args = new HashMap<>();
  2. ClientModel model = new ClientModel();
  3. model.setCode(200);
  4. model.setName("hello");
  5. args.put("request", model);
  6. ClientModel modelResult = InvokerUtils.syncInvoke("pojo", "InvokerEndpoint", "model", args, ClientModel.class);
  7. TestMgr.check(model.getCode(), modelResult.getCode());
  8. TestMgr.check(model.getName(), modelResult.getName());
  9. public class ClientModel {
  10. private String name;
  11. private int code;
  12. public String getName() {
  13. return name;
  14. }
  15. public void setName(String name) {
  16. this.name = name;
  17. }
  18. public int getCode() {
  19. return code;
  20. }
  21. public void setCode(int code) {
  22. this.code = code;
  23. }
  24. }

可以看出,在泛化调用的情况下, Provider 和 Consumer 可以使用不一样 package 的 Model。 Consumer 还可以不使用任何 Model, 而采用 Map 的方式访问:

  1. Map<String, Object> args = new HashMap<>();
  2. Map model = new HashMap();
  3. model.put("code", 20);
  4. model.put("name", "hello");
  5. args.put("request", model);
  6. ClientModel modelResult = InvokerUtils.syncInvoke("pojo", "InvokerEndpoint", "model", args, ClientModel.class);
  7. TestMgr.check(model.get("code"), modelResult.getCode());
  8. TestMgr.check(model.get("name"), modelResult.getName());

需要特别说明的是参数 swaggerArguments , 这个参数是和 Provider 接口生成的契约对应的, 不关注 Provider 是采用透明 RPC, 还是 采用 Spring MVC , 或者 JAX RS 开发的服务。 需要注意 swaggerArguments 可能和 Provider 的接口定义的参数列表不一样,比如透明 RPC 开发模式下多个参数的场景, Spring MVC 的 Bean Param 的场景等等。

采用 reactive API

2.0.1 泛化调用还增加了对应的 reactive API, 这样更加方便采用 reactive 方式调用 Provider 的服务。

  1. CountDownLatch countDownLatch = new CountDownLatch(1);
  2. InvokerUtils.reactiveInvoke("pojo", "InvokerEndpoint", "model", args, ClientModel.class, response -> {
  3. ClientModel reactiveResult = response.getResult();
  4. TestMgr.check(model.getCode(), reactiveResult.getCode());
  5. TestMgr.check(model.getName(), reactiveResult.getName());
  6. countDownLatch.countDown();
  7. });
  8. countDownLatch.await();

2.0.1 版本之前的 API

2.0.1 版本之前的 API 不能够指定 responseType , 因此返回值类型是不确定的, 这个取决于运行的上下文。 如果 Consumer 没有加载 任何 @RpcReference 信息, 并且不存在 Provider 返回值 Model , 那么返回值类型是 Map ; 否则返回结果可能是和 Provider 具备相同 package 类的实例, 这个返回接口的类型还可能和加载顺序有关。 由于这种不确定性, 早期的 API 使用 @Deprecated 声明为废弃。 将 responseType 设置为 null , 能够获得和早期 API 一样的效果。