本文最后更新于263 天前,其中的信息可能已经过时,如有错误请发送邮件到2192492965@qq.com
1. 前言
在 Java 开发中,动态代理是一种很有用的技术,尤其在 日志、权限管理、事务处理 这些场景下很常见。JDK 自带了一套动态代理机制,不需要我们自己写代理类,而是可以在运行时动态创建代理对象。
这篇文章会用一个简单的例子,来讲解 JDK 动态代理 是怎么工作的,同时也会分享一些优化方法,让代码更加简洁和高效。
2. 什么是 JDK 动态代理?
动态代理的核心有三个部分:
- 接口(Proxy Interface):规定了被代理对象可以执行哪些方法。
- 被代理对象(Target Object):真正要执行方法的类。
- InvocationHandler:拦截方法调用,在执行前后加上额外逻辑。
JDK 通过 Proxy.newProxyInstance() 这个方法,来动态生成代理对象。
3. 代码示例
3.1 定义接口
public interface ProxyBody {
void execute();
}
3.2 被代理的类
public class ProxyBodyImpl implements ProxyBody {
@Override
public void execute() {
System.out.println("ProxyBodyImpl.execute");
}
}
3.3 定义 Wrapping(类似 AOP 切面)
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class WrappingImpl implements Wrapping {
@Override
public void before(Object proxy, Method method, Object[] args) {
System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss")));
}
@Override
public void after(Object proxy, Method method, Object[] args) {
System.out.println("执行完毕: " + method.getName());
}
}
3.4 InvocationHandler 拦截方法
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class ServiceInvocationHandler implements InvocationHandler {
private final Object target;
private final Wrapping wrapping;
public ServiceInvocationHandler(Object target, Wrapping wrapping) {
this.target = target;
this.wrapping = wrapping;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
wrapping.before(proxy, method, args);
Object result = method.invoke(target, args);
wrapping.after(proxy, method, args);
return result;
}
}
3.5 创建代理对象的方法
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.lang.reflect.Proxy;
public class ProxyHelper {
private static final Map<Class<?>, Object> CACHE = new ConcurrentHashMap<>();
@SuppressWarnings("unchecked")
public <T> T getProxyInstance(T target, Wrapping wrapping) {
return (T) CACHE.computeIfAbsent(target.getClass(), clazz ->
Proxy.newProxyInstance(
clazz.getClassLoader(),
target.getClass().getInterfaces(),
new ServiceInvocationHandler(target, wrapping)
));
}
}
3.6 代理工厂(使用单例模式)
public class ProxyHelperFactory {
private static final ProxyHelper INSTANCE = new ProxyHelper();
private ProxyHelperFactory() {}
public static ProxyHelper getInstance() {
return INSTANCE;
}
}
3.7 运行测试
public class Main {
public static void main(String[] args) {
ProxyBody serviceInstance = new ProxyBodyImpl();
Wrapping wrapping = new WrappingImpl();
ProxyBody proxyInstance = ProxyHelperFactory.getInstance().getProxyInstance(serviceInstance, wrapping);
proxyInstance.execute();
}
}
4. 运行效果
执行 Main.main() 之后,会看到这样的输出:
2025.03.17 14:00:00
ProxyBodyImpl.execute
执行完毕: execute
表示:
- 方法执行前,输出当前时间。
- 调用
ProxyBodyImpl.execute()方法。 - 方法执行后,打印方法名称。
5. 总结
JDK 自带的 动态代理 让我们可以在不修改原代码的情况下,添加一些功能,比如 日志、权限管理、事务处理。
这里我们做了几点优化:
✅ 用缓存减少代理对象的重复创建
✅ 用单例模式管理代理对象
✅ 优化 Wrapping 逻辑,避免无效代码
✅ 封装代理创建逻辑,让代码更清晰
6. 动态代理能用在哪?
- AOP(面向切面编程),如 Spring AOP
- 日志记录,在方法执行前后自动打印日志
- 权限控制,拦截请求,检查用户权限
- 方法调用监控,统计方法的执行时间




