本文目录导读:

- 核心思想:封装与拦截
- 方案一:基于AOP + 自定义注解(最灵活,推荐)
- 方案二:基于模板方法模式(适合固定流程)
- 方案三:基于 Feign + 拦截器(适合微服务间调用)
- 关键公共逻辑清单(建议都做)
- 总结与推荐
统一Java接口调用流程,核心目标是:将调用过程中通用的、重复的逻辑(如鉴权、日志、熔断、重试、异常处理)与业务逻辑解耦,让开发者只关注“发什么请求”和“怎么处理响应”。
以下是几种主流的统一方案,从简单到复杂,适用于不同场景。
核心思想:封装与拦截
- 封装:创建一个统一的客户端(Client)或工具类(Utility),所有外部接口调用都通过它进行。
- 拦截:利用切面(AOP)或过滤器(Filter),在调用前后插入公共逻辑。
基于AOP + 自定义注解(最灵活,推荐)
这是最经典、侵入性最低的方案,业务代码只需打上一个注解,公共逻辑由切面自动处理。
定义自定义注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface UnifiedCall {
// 可以定义一些元数据,如重试次数、降级策略等
int retryTimes() default 0;
boolean enableCircuitBreaker() default false;
String desc() default "";
}
编写AOP切面
@Aspect
@Component
public class UnifiedCallAspect {
@Around("@annotation(unifiedCall)") // 拦截所有标注了@UnifiedCall的方法
public Object aroundCall(ProceedingJoinPoint joinPoint, UnifiedCall unifiedCall) throws Throwable {
// ---------- 前置统一处理 ----------
// 1. 请求日志
// 2. 生成TraceID(用于全链路追踪)
// 3. 鉴权/令牌获取
// 4. 初始化熔断器、限流器
try {
// ---------- 执行目标方法(即真正的HTTP调用或RPC调用) ----------
Object result = joinPoint.proceed();
// ---------- 后置统一处理 ----------
// 1. 成功日志
// 2. 响应结果格式化
// 3. 响应数据脱敏
return result;
} catch (Exception e) {
// ---------- 异常统一处理 ----------
// 1. 异常日志记录
// 2. 重试逻辑(根据注解的retryTimes)
// 3. 熔断降级
// 4. 统一异常转换(将外部异常转为内部业务异常)
throw convertToBizException(e);
} finally {
// ---------- 最终处理 ----------
// 1. 统计耗时(监控)
// 2. 清理上下文
}
}
}
业务代码使用
@Service
public class OrderService {
@UnifiedCall(retryTimes = 2, desc = "查询用户订单")
public OrderDTO queryOrder(String orderId) {
// 这里只需写真正的HTTP调用代码
// 比如使用RestTemplate或FeignClient
String response = httpClient.get("http://user-service/order/" + orderId);
return JSON.parseObject(response, OrderDTO.class);
}
}
优点:对业务代码零侵入,逻辑清晰,易于扩展。
缺点:需要引入Spring AOP依赖。
基于模板方法模式(适合固定流程)
如果调用流程非常固定(如:获取凭证 → 签名 → 发送请求 → 验证响应 → 处理结果),可以用抽象类定义骨架。
定义抽象模板
public abstract class AbstractApiClient<T, R> {
// 模板方法,定义好了固定的调用顺序(final防止子类重写)
public final R callApi(T request) {
// 1. 前置处理
preProcess(request);
// 2. 签名
String sign = generateSign(request);
// 3. 发送请求(由子类实现具体的HTTP/RPC调用)
String responseStr = doSend(request, sign);
// 4. 验证响应
validateResponse(responseStr);
// 5. 后置处理
R result = postProcess(responseStr);
return result;
}
protected void preProcess(T request) {
// 通用:日志、鉴权
log.info("开始调用接口,请求参数: {}", request);
}
protected abstract String generateSign(T request); // 签名算法子类自己实现
protected abstract String doSend(T request, String sign); // 发送请求子类自己实现
protected void validateResponse(String response) {
// 通用:检查HTTP状态码,是否超时等
}
protected abstract R postProcess(String response); // 解析结果子类自己实现
}
具体实现
@Component
public class UserApiClient extends AbstractApiClient<UserRequest, UserResponse> {
@Override
protected String generateSign(UserRequest request) {
// 具体的签名逻辑
}
@Override
protected String doSend(UserRequest request, String sign) {
// 真正的HTTP调用
return restTemplate.postForObject(url, request, String.class);
}
@Override
protected UserResponse postProcess(String response) {
return JSON.parseObject(response, UserResponse.class);
}
}
优点:流程固化,代码复用率高,子类只需关心差异部分。
缺点:不够灵活,如果流程需要频繁变动,模板会变得臃肿。
基于 Feign + 拦截器(适合微服务间调用)
如果使用Spring Cloud,Feign是最常见的HTTP客户端,可以通过重写 RequestInterceptor 来统一处理所有Feign调用。
实现 Feign 请求拦截器
@Component
public class FeignUnifiedInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
// 1. 统一添加Header(如Token, TraceID)
template.header("Authorization", "Bearer " + getToken());
template.header("Trace-Id", MDC.get("traceId"));
// 2. 统一修改请求体(如加密)
// template.body(encrypt(template.body()));
}
}
结合 Hystrix / Sentinel 进行熔断配置
feign:
sentinel:
enabled: true # 开启Sentinel熔断
client:
config:
default: # 全局配置
connectTimeout: 5000
readTimeout: 5000
loggerLevel: BASIC
业务代码直接使用 FeignClient
@FeignClient(name = "user-service", fallback = UserClientFallback.class)
public interface UserClient {
@GetMapping("/user/{id}")
UserResponse getUser(@PathVariable("id") Long id);
}
优点:Feign框架本身已经封装了连接池、负载均衡、重试、熔断,拦截器机制非常完善。
缺点:强依赖Spring Cloud生态;如果对接的是非RESTful接口(如SOAP,Dubbo),需要额外适配。
关键公共逻辑清单(建议都做)
无论采用哪种方案,这些逻辑都应该被统一处理:
| 分类 | 实现方式 | |
|---|---|---|
| 请求统一 | 签名/鉴权、TraceID注入、请求加密、公共Header | AOP / 拦截器 |
| 传输优化 | 连接池管理、超时设置、重试机制、限流/熔断(Sentinel / Hystrix) | 客户端配置(如OkHttp / Feign) |
| 响应处理 | 统一解包、状态码校验、数据脱敏、响应对象转换 | AOP 后置处理 |
| 监控告警 | 请求耗时、成功/失败数、QPS统计 | AOP + Micrometer / Prometheus |
| 异常处理 | 网络异常重试、业务异常统一包装、降级返回默认值 | AOP catch + 异常映射 |
总结与推荐
- 如果是单体应用或调用少量外部接口:推荐 方案一(AOP + 注解),灵活,业务代码干净,后续扩展方便。
- 如果是一套标准的外部API(如微信支付、阿里云):推荐 方案二(模板方法),流程固定,子类结构清晰。
- 如果是Spring Cloud微服务架构:推荐 方案三(Feign + 拦截器),原生支持,无需额外维护切面,且集成了大量的微服务治理能力。
最终的目标是:在业务代码中,你只看到类似这样的调用:
@UnifiedCall // 或直接 @Autowired UserClient userClient; UserResponse response = userClient.getUser(id);
而所有的连接、鉴权、重试、熔断、日志、监控,都在您统一的底层框架中自动完成了。