Java 动态代理是 Java 编程中常用的一种设计模式,它允许开发者在不修改原有类代码的情况下,通过代理类对原有类的功能进行扩展。JDK 动态代理和 CGLIB 是两种主要的实现方式,它们在实现机制、性能表现以及适用场景上存在显著差异。
JDK 动态代理
JDK 动态代理是 Java 标准库提供的一种基于接口的代理机制。它利用 Java 的反射机制,在运行时动态地创建代理类,这些代理类实现了被代理的接口,并通过 InvocationHandler 来处理方法的调用。
示例代码
以下是一个简单的 JDK 动态代理示例:
java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 定义一个接口
interface MyInterface {
void doSomething();
}
// 实现接口的目标类
class MyTarget implements MyInterface {
@Override
public void doSomething() {
System.out.println("Target method executed.");
}
}
// 自定义 InvocationHandler
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("Before method execution.");
Object result = method.invoke(target, args);
System.out.println("After method execution.");
return result;
}
}
// 创建代理对象并调用方法
public class JDKProxyDemo {
public static void main(String[] args) {
MyInterface target = new MyTarget();
MyInvocationHandler handler = new MyInvocationHandler(target);
MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler
);
proxy.doSomething(); // 输出代理逻辑
}
}
CGLIB 动态代理
CGLIB(Code Generation Library)是一个开源项目,通过继承的方式来实现动态代理。它可以在运行时动态地生成被代理类的子类,从而允许代理没有实现接口的类。CGLIB 使用 ASM 字节码框架来生成代理类,因此其性能通常比 JDK 动态代理更高。
示例代码
虽然 CGLIB 的使用通常需要借助第三方库(如 Spring),但以下是一个简化的概念性示例,展示其工作原理:
java
// 注意:实际使用CGLIB时,通常不会直接编写如下代码,而是通过框架如Spring AOP来使用
// 假设有一个没有接口的类
class MyClass {
public void doSomething() {
System.out.println("Original method executed.");
}
}
// 假设的CGLIB代理类(实际由CGLIB生成)
class MyClassProxy extends MyClass {
@Override
public void doSomething() {
System.out.println("Before method execution.");
super.doSomething(); // 调用原始方法
System.out.println("After method execution.");
}
}
// 实际应用中,不会直接创建这个类,而是通过CGLIB API来动态生成
区别总结
实现机制:JDK 动态代理基于接口,通过反射机制实现;CGLIB 动态代理基于继承,通过字节码技术生成子类。
性能:由于 CGLIB 生成的代理类更底层,通常性能更高,但启动时间可能稍长。
适用场景:JDK 动态代理适用于接口代理;CGLIB 动态代理适用于类代理,特别是当类没有实现接口时。
限制:CGLIB 不能代理 final 方法和类,且在某些特殊场景(如 Android 开发)中可能有限制。
通过对比 JDK 动态代理和 CGLIB,开发者可以根据实际需求选择最适合的代理机制。