一句话概括:不写死代理类,在程序运行时自动生成代理对象,用来在不修改原代码的前提下,统一加功能(日志、事务、权限、统计等)。
一、两种动态代理
-
JDK 动态代理
- 基于 接口
- 被代理类 必须实现接口
- Java 原生,无需依赖
-
CGLIB 动态代理
- 基于 继承
- 可以代理 没有接口的类
- 需要引入 cglib 依赖(Spring 内置)
二、JDK 动态代理(最常用)
核心类
InvocationHandler:处理逻辑的接口Proxy.newProxyInstance():生成代理对象
步骤
- 定义 接口
- 写 实现类(目标对象)
- 写 InvocationHandler 实现类 ,在
invoke里加增强逻辑 - 通过
Proxy生成代理对象
极简示例
1. 接口
java
运行
public interface UserService {
void add();
}
2. 实现类
java
运行
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("添加用户");
}
}
3. 代理处理器
java
运行
public class MyHandler implements InvocationHandler {
private Object target;
public MyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法前:日志");
Object result = method.invoke(target, args); // 执行原方法
System.out.println("方法后:提交事务");
return result;
}
}
4. 测试
java
运行
public class Test {
public static void main(String[] args) {
UserService target = new UserServiceImpl();
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new MyHandler(target)
);
proxy.add();
}
}
输出
plaintext
方法前:日志
添加用户
方法后:提交事务
三、CGLIB 动态代理(无接口也能用)
核心类
MethodInterceptorEnhancer
示例(关键代码)
java
运行
public class CglibInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("前增强");
Object result = proxy.invokeSuper(obj, args);
System.out.println("后增强");
return result;
}
}
// 生成代理
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback(new CglibInterceptor());
UserService proxy = (UserService) enhancer.create();
proxy.add();
四、常见面试要点
-
JDK vs CGLIB
- JDK:接口、快、原生
- CGLIB:继承、可代理普通类、Spring 常用
-
动态代理用途
- Spring AOP
- MyBatis Mapper 代理
- 全局日志、权限校验、事务管理
-
为什么 JDK 必须要接口? 因为生成的代理类 已经继承了 Proxy,Java 单继承,只能通过接口扩展。