远程调用代码封装杂谈,如何打造?

摘要:上周处理了一个线上问题,经过排查发现是RPC远端调用超时,框架抛出的超时异常没有被捕捉,导致数据进入中间态,无法推进后续处理。好在影响不大,及时修复掉了。 关于这部分的代码规范,之前也有所思考,正好有这个契机做一下整理。 讨论背景和范围 做
上周处理了一个线上问题,经过排查发现是RPC远端调用超时,框架抛出的超时异常没有被捕捉,导致数据进入中间态,无法推进后续处理。好在影响不大,及时修复掉了。 关于这部分的代码规范,之前也有所思考,正好有这个契机做一下整理。 讨论背景和范围 做应用分层架构时,有一种实践方式是将代表外部服务的类如UserService,包装成一个UserServiceClient类,上层业务调用统一使用UserServiceClient,是一种简单的代理模式。 本文的讨论实例,即UserService、UserServiceClient以及其实现UserServiceClientImpl,形式化的定义如下: // 远程RPC接口 public interface UserService { /** * 用户查询 */ ResultDTO<UserInfo> query(QueryRequest param); /** * 用户创建 */ ResultDTO<String> create(CreateRequest param); } // 本地接口 public interface UserServiceClient { /** * 用户查询 */ Result<UserInfo> query(QueryReequest param); /** * 用户创建 */ Result<String> create(CreateRequest param); } // 本地接口实现 public classe UserServiceClientImpl implement UserServiceClient { @Autorwire private UserService userSerivce; /** * 用户查询 */ @override Result<UserInfo> query(QueryReequest param) { // 包装调用代码片段 } /** * 用户创建 */ @override Result<String> create(CreateRequest param) { // 包装调用代码片段 } } 一、不做任何处理/不封装 Client类没有任何的处理,仅仅是对Servie类的调用及原样返回。 // 本地接口实现 public classe UserServiceClientImpl implement UserServiceClient { @Autorwire private UserService userSerivce; /** * 用户查询 */ @override Result<UserInfo> query(QueryReequest param) { return userSerivce.query(param); } /** * 用户创建 */ @override Result<String> create(CreateRequest request) { return userSerivce.create(param); } } 非常不推荐,原因可以和后续的几种形式中对比来看。 这种写法实际上跟lombok提供的@Delegate注解是一样的,这个注解一样不推荐。 @Component public class UserServiceClient { @Autowired @Delegate private UserService userService; } 二、结果统一再封装 RPC调用的目标可能是不同的系统,调用的封装结果也有所不同。为了便于上层业务处理,减少对外部的感知,可以定义一个通用的Result类来包装。
阅读全文