在Java中,有两种常见的动态代理:JDK动态代理和CGLib动态代理。
-
JDK动态代理:
- 原理:JDK动态代理是基于接口的代理,它利用Java的反射机制,在运行时创建一个实现指定接口的代理类。代理类调用方法时会委托给InvocationHandler(调用处理器)来处理具体的逻辑。
- 区别:JDK动态代理要求目标对象必须实现接口,因为代理类需要实现相同的接口以提供统一的方法调用方式。
- 示例代码:
interface MyInterface {
void doSomething();
}
class MyRealClass implements MyInterface {
public void doSomething() {
System.out.println("Doing something.");
}
}
class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method invocation");
Object result = method.invoke(target, args);
System.out.println("After method invocation");
return result;
}
}
public class Main {
public static void main(String[] args) {
MyRealClass realObject = new MyRealClass();
MyInvocationHandler handler = new MyInvocationHandler(realObject);
MyInterface proxyObject = (MyInterface) Proxy.newProxyInstance(
realObject.getClass().getClassLoader(),
realObject.getClass().getInterfaces(),
handler
);
proxyObject.doSomething();
}
}
CGLib动态代理:
- 原理:CGLib动态代理通过生成目标类的子类来实现代理,不需要目标类实现接口。它使用了字节码生成技术,在运行时动态创建一个目标类的子类,并重写其中的方法实现代理逻辑。
- 区别:CGLib动态代理不要求目标对象实现接口,可以直接代理普通的类。
- 示例代码:
class MyRealClass {
public void doSomething() {
System.out.println("Doing something.");
}
}
class MyMethodInterceptor implements MethodInterceptor {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method invocation");
Object result = proxy.invokeSuper(obj, args);
System.out.println("After method invocation");
return result;
}
}
public class Main {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyRealClass.class);
enhancer.setCallback(new MyMethodInterceptor());
MyRealClass proxyObject = (MyRealClass) enhancer.create();
proxyObject.doSomething();
}
}
总结:
- JDK动态代理是基于接口的,需要目标对象实现接口;CGLib动态代理则是基于继承的,可以代理普通类。
- JDK动态代理利用反射机制创建代理类,而CGLib动态代理通过生成目标类的子类来实现代理。
- JDK动态代理相对于CGLib动态代理在性能上略有差异,CGLib通常更快,但在某些情况下(如目标类被final修饰)只能使用JDK动态代理。