一:JDK动态代理
实现方式:Java.lang.reflect包中的Proxy类和InvocationHandler接口生成了动态代理类的能力。
实现代码示例:
1.先写一个接口
public interface Subject {
void doSomething();
}
2.实现接口
public class RealSubject implements Subject {
@Override
public void doSomething() {
System.out.println("RealSubject is doing something...");
}
}
3. 创建InvocationHandler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicProxyHandler implements InvocationHandler {
private Object target; // 目标对象
public DynamicProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method call...");
Object result = method.invoke(target, args);
System.out.println("After method call...");
return result;
}
}
4.获取代理实例并调用方法
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
// 实例化真实主题对象
Subject realSubject = new RealSubject();
// 创建动态代理
Subject proxySubject = (Subject) Proxy.newProxyInstance(
RealSubject.class.getClassLoader(),
new Class[]{Subject.class},
new DynamicProxyHandler(realSubject)
);
// 调用代理方法
proxySubject.doSomething();
}
}
核心方法解读
Proxy.newProxyInstance 方法是JDK动态代理的核心,用于创建一个指定接口的代理实例。这个方法有三个参数,每个参数都有其特定的作用:
1. ClassLoader loader: 这个参数是用来指定代理类的类加载器。通常情况下,我们会传入被代理类的类加载器,这样可以确保代理类和被代理类位于相同的类加载上下文中,避免一些类可见性的问题。可以通过 RealSubject.class.getClassLoader() 来获取。
Class<?>[] interfaces: 这是一个接口数组,指定了代理类需要实现的接口列表。代理类会实现传入的所有接口,并且在调用这些接口的方法时,会转而执行 InvocationHandler 的 invoke 方法。因此,这个参数确保了代理对象能够像真正的接口实现一样被使用。例如,new Class[]{Subject.class} 表示代理类需要实现 Subject 接口。
3. InvocationHandler: 这是最重要的参数,是一个 InvocationHandler 对象。当通过代理对象调用任何接口方法时,这个处理器的 invoke 方法会被自动调用。在 invoke 方法中,你可以添加任何你需要的预处理或后处理逻辑,然后再调用实际目标对象的方法。例如,new DynamicProxyHandler(realSubject) 创建了一个处理器实例,它持有真实对象的引用,并定义了如何处理方法调用。
二:Cglib动态代理
实现方式:依靠一个第三方代码生成类库,运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展。
实现代码示例:
1.定义目标类
public class TargetObject {
public void businessMethod() {
System.out.println("Business method executed.");
}
}
2. 创建MethodInterceptor
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxyInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method call...");
Object result = proxy.invokeSuper(obj, args); // 调用父类方法
System.out.println("After method call...");
return result;
}
}
3. 获取代理实例并调用方法
import net.sf.cglib.proxy.Enhancer;
public class Main {
public static void main(String[] args) {
// 创建Enhancer对象,类似于JDK动态代理的Proxy类
Enhancer enhancer = new Enhancer();
// 设置目标类的类型
enhancer.setSuperclass(TargetObject.class);
// 设置回调方法,即拦截器
enhancer.setCallback(new CglibProxyInterceptor());
// 创建代理对象
TargetObject proxyObject = (TargetObject) enhancer.create();
// 调用代理对象的方法
proxyObject.businessMethod();
}
}
三: 两者区别
JDK动态代理需要实现一个或多个接口如果想代理没有实现接口的类可以使用cglib动态代理
Cglib通过一个字节码处理框架ASM来转换字节码并生成新的类。可以达到代理类无侵入。
为什么JDK代理一定要实现接口
JDK动态代理实现的代理类要继承Proxy类,基于java单继承的特性因此代理类只能和被代理目标的接口建立代理关系。