java可通过jdk动态代理(需接口)或cglib(无需接口)实现方法耗时统计:调用前记录开始时间,finally块中计算并输出耗时;推荐结合spring aop、@timed注解、监控集成与采样策略优化。

Java 中可以通过动态代理(如 JDK 动态代理或 CGLIB)在不修改原始方法逻辑的前提下,自动统计方法执行耗时。核心思路是:在方法调用前记录开始时间,调用后计算并打印/上报耗时。
使用 JDK 动态代理实现耗时统计
JDK 动态代理要求目标类实现接口,通过 InvocationHandler 拦截方法调用:
- 定义一个接口(如
Service)和其实现类(如OrderService) - 编写自定义
InvocationHandler,在invoke()中记录耗时 - 用
Proxy.newProxyInstance()创建代理对象
示例关键代码:
public class TimingInvocationHandler implements InvocationHandler {
private final Object target;
<pre class="brush:java;toolbar:false;">public TimingInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = System.nanoTime();
try {
return method.invoke(target, args);
} finally {
long costMs = (System.nanoTime() - start) / 1_000_000;
System.out.printf("[Timing] %s.%s() took %d ms%n",
target.getClass().getSimpleName(), method.getName(), costMs);
}
}}
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
// 使用 Service service = new OrderService(); Service proxy = (Service) Proxy.newProxyInstance( service.getClass().getClassLoader(), service.getClass().getInterfaces(), new TimingInvocationHandler(service) ); proxy.process(); // 调用时自动输出耗时
使用 CGLIB 实现无接口类的耗时代理
当目标类没有实现接口时,JDK 代理不可用,可改用 CGLIB(需引入 cglib-nodep 依赖):
- 继承
MethodInterceptor,重写intercept() - 用
Enhancer创建子类代理实例 - 注意:被代理类不能是
final,方法也不能是final
示例关键代码:
public class TimingMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
long start = System.nanoTime();
try {
return proxy.invokeSuper(obj, args);
} finally {
long costMs = (System.nanoTime() - start) / 1_000_000;
System.out.printf("[CGLIB-Timing] %s.%s() took %d ms%n",
obj.getClass().getSimpleName(), method.getName(), costMs);
}
}
}
<p>// 使用
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OrderServiceImpl.class); // 无接口的类
enhancer.setCallback(new TimingMethodInterceptor());
OrderServiceImpl proxy = (OrderServiceImpl) enhancer.create();
proxy.process();</p>进阶建议:解耦与增强
实际项目中不建议把耗时逻辑硬编码在 Handler 或 Interceptor 中,推荐:
- 将耗时统计抽象为独立切面(如配合 Spring AOP,用
@Around注解) - 支持按注解(如
@Timed)选择性开启统计,避免全量埋点影响性能 - 集成到监控体系:把耗时数据发给 Micrometer、Prometheus 或日志系统(如 ELK)
- 避免在生产环境高频打印,可用采样策略(如只记录 >100ms 的调用)
注意事项
动态代理统计耗时虽方便,但要注意:
- 代理会带来轻微性能开销(纳秒级),对超高频核心路径需评估
- JDK 代理只能代理接口方法;CGLIB 代理的是类,但不支持
private和static方法 - 异常情况下也要确保耗时统计完成(上面示例已用
finally保证) - 若方法内含异步调用(如线程池、CompletableFuture),代理仅统计同步部分耗时
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










