Java 的动态代理是一种强大的机制,它允许在运行时创建代理对象,从而在不修改原始类代码的情况下,对方法调用进行拦截和增强。动态代理主要基于以下两个核心概念:
-
接口(Interface):动态代理要求被代理的对象必须实现一个或多个接口。
-
InvocationHandler 接口:这是 Java 提供的一个接口,用于处理代理实例上的方法调用。
动态代理的工作原理
动态代理的核心是 java.lang.reflect.Proxy
类和 java.lang.reflect.InvocationHandler
接口。以下是动态代理的工作原理:
-
定义接口:首先,定义一个或多个接口,这些接口包含需要代理的方法。
-
实现 InvocationHandler:创建一个类,实现
InvocationHandler
接口,并重写invoke
方法。这个方法会在代理对象的每个方法调用时被调用。 -
创建代理对象:使用
Proxy.newProxyInstance
方法创建代理对象。这个方法需要三个参数:-
类加载器(ClassLoader)
-
接口数组(Class[])
-
InvocationHandler 实例
-
示例代码
下面通过一个简单的示例来详细说明动态代理的使用。
1. 定义接口
public interface Calculator {
int add(int a, int b);
int subtract(int a, int b);
}
2. 实现接口
public class CalculatorImpl implements Calculator {
@Override
public int add(int a, int b) {
return a + b;
}
@Override
public int subtract(int a, int b) {
return a - b;
}
}
3. 实现 InvocationHandler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class CalculatorHandler implements InvocationHandler {
private Object target;
public CalculatorHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在方法调用前执行一些操作
System.out.println("Method " + method.getName() + " is called with arguments: " + Arrays.toString(args));
// 调用目标对象的方法
Object result = method.invoke(target, args);
// 在方法调用后执行一些操作
System.out.println("Method " + method.getName() + " result: " + result);
return result;
}
}
4. 创建代理对象
import java.lang.reflect.Proxy;
public class DynamicProxyExample {
public static void main(String[] args) {
// 创建目标对象
Calculator calculator = new CalculatorImpl();
// 创建 InvocationHandler 实例
CalculatorHandler handler = new CalculatorHandler(calculator);
// 创建代理对象
Calculator proxy = (Calculator) Proxy.newProxyInstance(
Calculator.class.getClassLoader(),
new Class[]{Calculator.class},
handler
);
// 使用代理对象调用方法
int resultAdd = proxy.add(3, 5);
System.out.println("Result of add: " + resultAdd);
int resultSubtract = proxy.subtract(10, 4);
System.out.println("Result of subtract: " + resultSubtract);
}
}
运行结果
Method add is called with arguments: [3, 5]
Method add result: 8
Result of add: 8
Method subtract is called with arguments: [10, 4]
Method subtract result: 6
Result of subtract: 6
总结
通过上述示例,我们可以看到动态代理的强大之处。它允许我们在不修改原始类代码的情况下,对方法调用进行拦截和增强。这在很多场景中都非常有用,比如日志记录、性能监控、事务管理等。动态代理的核心在于 Proxy
类和 InvocationHandler
接口的结合使用,通过这种方式,我们可以在运行时动态地创建代理对象,并对方法调用进行灵活的处理。