在Java中,动态代理是一种在运行时动态创建代理类及其对象的技术。与静态代理不同,动态代理的代理类并不是在编译时创建的,而是在运行时根据需要动态生成。这种技术提供了更高的灵活性和可扩展性,因为它允许开发者在运行时根据需要添加或修改代理的行为。
动态代理的实现方式
在Java中,动态代理主要有两种实现方式:基于JDK的动态代理和基于CGLib的动态代理。
1. 基于JDK的动态代理
JDK动态代理主要依赖于`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口。`Proxy`类提供了创建动态代理类和实例的静态方法,而`InvocationHandler`接口则需要用户实现,以定义代理对象的行为。
JDK动态代理主要适用于实现了接口的类。
示例代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 定义一个接口
interface Subject {
void doSomething();
}
// 实现接口的类
class RealSubject implements Subject {
@Override
public void doSomething() {
System.out.println("RealSubject.doSomething()");
}
}
// 实现InvocationHandler接口
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: " + method.getName());
// 调用真实对象的方法
Object result = method.invoke(target, args);
// 在方法执行后可以做一些处理
System.out.println("After method: " + method.getName());
return result;
}
// 获取动态代理的实例
@SuppressWarnings("unchecked")
public static <T> T getProxyInstance(T target, Class<T> interfaceType) {
return (T) Proxy.newProxyInstance(
interfaceType.getClassLoader(), // 类加载器
new Class<?>[]{interfaceType}, // 代理类需要实现的接口列表
new DynamicProxyHandler(target) // 调用处理器
);
}
}
public class DynamicProxyExample {
public static void main(String[] args) {
// 创建真实对象
RealSubject realSubject = new RealSubject();
// 获取动态代理对象
Subject proxySubject = DynamicProxyHandler.getProxyInstance(realSubject, Subject.class);
// 通过代理对象调用方法
proxySubject.doSomething();
}
}
当运行上面的代码时,输出将是:
Before method: doSomething
RealSubject.doSomething()
After method: doSomething
在这个例子中,`DynamicProxyHandler`类实现了`InvocationHandler`接口,并在其`invoke`方法中定义了代理的行为。`getProxyInstance`静态方法用于获取动态代理的实例。注意,这个方法的返回类型是泛型,这允许我们创建任何实现了特定接口的代理对象。
2. 基于CGLib的动态代理
CGLib(Code Generation Library)是一个强大的、高性能的、高质量的Code生成类库,它可以在运行时扩展Java类和实现接口。CGLib通过继承的方式动态地创建目标类的子类,从而实现对目标类方法的拦截。
由于CGLib是通过继承的方式实现动态代理的,因此它不仅可以代理实现了接口的类,还可以代理没有实现任何接口的类。但是,由于Java的单继承限制,CGLib动态代理不能代理final类或者final方法。
示例代码
要使用CGLib,你首先需要将CGLib的jar包添加到你的项目中。以下是一个简单的CGLib动态代理的示例:
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
// 定义一个没有实现接口的类
class RealSubject {
public void doSomething() {
System.out.println("RealSubject.doSomething()");
}
}
// 实现MethodInterceptor接口
class CglibProxyInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 在方法执行前可以做一些处理
System.out.println("Before method: " + method.getName());
// 调用真实对象的方法
Object result = proxy.invokeSuper(obj, args); // 调用父类的方法
// 在方法执行后可以做一些处理
System.out.println("After method: " + method.getName());
return result;
}
}
public class CglibDynamicProxyExample {
public static void main(String[] args) {
// 创建真实对象
RealSubject realSubject = new RealSubject();
// 使用CGLib创建动态代理对象
Enhancer enhancer = Enhancer.create(); // 创建Enhancer实例
enhancer.setSuperclass(RealSubject.class); // 设置代理类的父类为RealSubject类
enhancer.setCallback(new CglibProxyInterceptor()); // 设置回调,即我们要实现的逻辑
RealSubject proxy = (RealSubject) enhancer.create(); // 创建代理对象并返回
// 通过代理对象调用方法
proxy.doSomething();
}
}
当运行上面的代码时,输出结果将是:
Before method: doSomething
RealSubject.doSomething()
After method: doSomething
在这个例子中,我们使用CGLib库中的`Enhancer`类来创建动态代理。我们首先通过`setSuperclass`方法设置代理类的父类为`RealSubject`。然后通过`setCallback`方法设置回调,即我们实现的逻辑。在这个例子中,我们实现了`CglibProxyInterceptor`来定义代理对象的行为。这个类实现了`MethodInterceptor`接口,它有两个主要的方法:`intercept`和`getProxy』。`intercept`方法负责在目标方法的调用前后添加额外的逻辑。在这个例子中,我们在目标方法执行前后打印出日志信息。最后我们通过调用`create`方法来创建代理对象。