远程调用代码封装杂谈,如何打造?
摘要:上周处理了一个线上问题,经过排查发现是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类来包装。
