Java 动态代理
Java 的动态代理(Dynamic Proxy)是 Java 反射机制的重要应用之一,主要用于AOP(面向切面编程)、权限控制、日志记录、事务管理等场景。动态代理分为两种方式:
- JDK 动态代理(基于接口)
- CGLIB 动态代理(基于子类继承)
1. JDK 动态代理
JDK 动态代理依赖 Java 的 java.lang.reflect.Proxy 和 java.lang.reflect.InvocationHandler,只能代理实现了接口的类。
示例
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 1. 定义接口
interface Service {
void doSomething();
}
// 2. 目标对象(被代理对象)
class RealService implements Service {
public void doSomething() {
System.out.println("业务逻辑执行中...");
}
}
// 3. 创建动态代理处理器
class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(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. 生成代理对象
public class JDKProxyExample {
public static void main(String[] args) {
// 创建目标对象
Service realService = new RealService();
// 生成代理对象
Service proxyService = (Service) Proxy.newProxyInstance(
realService.getClass().getClassLoader(),
new Class[]{Service.class},
new MyInvocationHandler(realService)
);
// 调用代理方法
proxyService.doSomething();
}
}
输出
方法执行前的操作...
业务逻辑执行中...
方法执行后的操作...
JDK 动态代理特点
✅ 优点:
- 无需手写代理类,利用
Proxy生成代理对象,避免硬编码。 - 支持 AOP,可在方法调用前后加入额外逻辑(如日志、事务)。
- 性能较好(比反射调用快)。
⚠️ 缺点:
- 只能代理接口,不能代理普通类。
- 底层使用反射,性能比 CGLIB 略差。
2. CGLIB 动态代理
CGLIB(Code Generation Library) 是一个基于字节码增强的库,可以代理没有实现接口的类,底层使用 ASM 直接操作字节码,性能比 JDK 代理更优。
示例
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
// 1. 目标类(没有实现接口)
class RealService {
public void doSomething() {
System.out.println("业务逻辑执行中...");
}
}
// 2. 创建 CGLIB 代理拦截器
class CglibProxyHandler 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;
}
}
// 3. 生成代理对象
public class CglibProxyExample {
public static void main(String[] args) {
// 创建 Enhancer
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealService.class); // 设置目标类
enhancer.setCallback(new CglibProxyHandler()); // 设置回调拦截器
// 创建代理对象
RealService proxyService = (RealService) enhancer.create();
// 调用代理方法
proxyService.doSomething();
}
}
输出
方法执行前的操作...
业务逻辑执行中...
方法执行后的操作...
CGLIB 动态代理特点
✅ 优点:
- 支持代理普通类,不要求目标类必须实现接口。
- 性能比 JDK 动态代理更优(因为直接操作字节码)。
- Spring AOP 默认使用 CGLIB(除非目标对象实现了接口)。
⚠️ 缺点:
- 不能代理
final方法(因为 CGLIB 依赖子类继承)。 - 生成的代理类比 JDK 代理类体积大。
3. JDK 代理 vs CGLIB 代理
| 方式 | 代理对象要求 | 代理方式 | 性能 |
|---|---|---|---|
| JDK 代理 | 需要实现接口 | 反射调用 | 一般 |
| CGLIB 代理 | 不需要接口 | 直接修改字节码 | 更快 |
选择建议:
- 如果类实现了接口,优先使用 JDK 动态代理(默认方式)。
- 如果类没有接口,使用 CGLIB 动态代理。
- Spring AOP 默认使用 JDK 代理(如果类实现了接口),否则使用 CGLIB。
4. Spring AOP 与动态代理
Spring 的 AOP 主要使用JDK 动态代理和CGLIB,默认策略如下:
- 如果目标类实现了接口 → 使用 JDK 动态代理。
- 如果目标类没有实现接口 → 使用 CGLIB 代理。

5601

被折叠的 条评论
为什么被折叠?



