java中可通过jdk动态代理或cglib统一拦截外部接口调用并统计次数,核心是代理对象+线程安全计数器(concurrenthashmap),配合invocationhandler实现方法级计数;对feign可自定义invocationhandlerfactory,对resttemplate/webclient等则用spring aop或http客户端拦截器;统计结果通过actuator端点暴露并集成micrometer上报prometheus。

Java 中可以通过动态代理(如 JDK 动态代理或 CGLIB)在不修改原有接口调用逻辑的前提下,统一拦截外部接口调用并统计次数。核心思路是:将对外部服务的调用统一走代理对象,代理中增加计数逻辑。
使用 JDK 动态代理统计 HTTP 客户端调用
适用于外部接口已封装为标准 Java 接口(如 FeignClient、自定义 Service 接口),且目标类实现了接口。
- 定义一个通用的 InvocationHandler,内部维护一个线程安全的计数器(如
ConcurrentHashMap<string atomiclong></string>),键为接口名 + 方法名 - 在
invoke()中先执行计数:counters.computeIfAbsent(methodKey, k -> new AtomicLong()).incrementAndGet() - 再调用原方法:
method.invoke(target, args) - 代理创建示例:
Proxy.newProxyInstance(classLoader, interfaces, handler)
对接 Spring Cloud OpenFeign 的统计方案
Feign 本身支持拦截器(RequestInterceptor),但仅能捕获请求发送,无法区分不同接口方法。更精准的方式是利用 Feign 的 Contract 或 InvocationHandlerFactory 自定义代理逻辑。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 实现自定义
InvocationHandlerFactory,返回带计数逻辑的InvocationHandler - 在
Feign.Builder中通过.invocationHandlerFactory(...)注入 - 配合 Spring Boot,可将该 Builder 声明为
@Bean,使所有@FeignClient自动生效
无接口场景(如直接使用 RestTemplate / WebClient)
若调用未抽象为接口(如直写 restTemplate.getForObject(...)),JDK 代理不可用,需改用其他方式:
-
Spring AOP:对 RestTemplate 的
execute、getForObject等方法做环绕通知,提取 URL 或 serviceId 统计 -
HTTP Client 拦截器:如 Apache HttpClient 添加
HttpRequestInterceptor,OkHttp 使用Interceptor,记录 Host/Path -
WebClient(Reactor):通过自定义
ExchangeFilterFunction在请求前后计数
统计结果的收集与暴露
计数数据应支持实时查看和监控集成:
- 用
@RestController提供 /actuator/external-calls 端点,返回各接口调用次数 - 对接 Micrometer,注册
Counter(如counter("external.call", "service", "user-api")),自动上报 Prometheus - 避免内存泄漏:对高频动态生成的 key(如含参数的 URL)做归一化(如正则替换 ID 为 `{id}`)
不复杂但容易忽略的是 key 的设计和线程安全——用 ConcurrentHashMap + AtomicLong 是稳妥选择;若系统已引入 Micrometer,优先复用其计量能力,而非自己维护计数器。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










