Java 动态代理(Dynamic Proxy) 一、什么是动态代理 Java 动态代理是一种在运行时创建代理类并处理方法调用的机制,它不需要事先写好代理类,而是通过反射 API 动态生成代理对象。
它常用于以下场景:
日志记录
权限控制
性能监控
Spring AOP 实现原理
二、JDK 动态代理原理 JDK 动态代理主要依赖两个核心类/接口:
java.lang.reflect.Proxy
java.lang.reflect.InvocationHandler
JDK 动态代理要求被代理的类 必须实现接口 。
三、使用步骤 1. 定义接口 1 2 3 4 java复制编辑public interface UserService { void login(String username); void logout(); }
2. 实现该接口的类(目标类) 1 2 3 4 5 6 7 8 9 10 11 java复制编辑public class UserServiceImpl implements UserService { @Override public void login(String username) { System.out.println(username + " 登录了系统"); } @Override public void logout() { System.out.println("用户退出系统"); } }
3. 实现 InvocationHandler 接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 java复制编辑import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class LogHandler implements InvocationHandler { private final Object target; public LogHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("[日志] 调用方法:" + method.getName()); Object result = method.invoke(target, args); // 反射调用目标方法 System.out.println("[日志] 方法调用结束:" + method.getName()); return result; } }
4. 生成代理对象并调用方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 java复制编辑import java.lang.reflect.Proxy; public class Main { public static void main(String[] args) { UserService target = new UserServiceImpl(); InvocationHandler handler = new LogHandler(target); UserService proxy = (UserService) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), // 必须是接口类型 handler ); proxy.login("张三"); proxy.logout(); } }
四、运行结果 1 2 3 4 5 6 css复制编辑[日志] 调用方法:login 张三 登录了系统 [日志] 方法调用结束:login [日志] 调用方法:logout 用户退出系统 [日志] 方法调用结束:logout
五、JDK 动态代理的限制
优点
缺点
灵活,无需编写代理类
只能代理接口,不能代理类
支持运行时增强行为
运行时使用反射,性能略下降
应用于 AOP、RPC、事务等场景
六、CGLIB 动态代理(补充) 如果目标类没有接口,可以使用 CGLIB,它基于继承生成代理类。Spring 在默认配置下也使用它来代理非接口类。
1 2 3 4 5 6 7 8 9 10 11 12 13 java复制编辑Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserServiceImpl.class); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("[CGLIB日志] 调用方法:" + method.getName()); Object result = proxy.invokeSuper(obj, args); System.out.println("[CGLIB日志] 方法调用结束:" + method.getName()); return result; } }); UserServiceImpl proxy = (UserServiceImpl) enhancer.create(); proxy.login("李四");
CGLIB 需要额外依赖库(如 cglib-nodep
)
七、动态代理的应用场景总结
AOP(面向切面编程)
日志拦截器
安全控制
缓存管理
RPC 调用封装
数据库事务处理