InvocationHandler
在平常使用JDK代理时,都是实现InvocationHandler,传进被代理的实例,重写invoke方法,如下:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
doBefore();
method.invoke(instance,args);
doAfter();
}
大多数时候proxy都被我们忽略了,所以proxy到底是什么?
InvocationHandler
中invoke
方法,第一个参数Object proxy
是什么
proxy 参数代表调用 invoke 方法的代理对象本身,但在 InvocationHandler 中通常不直接使用它。在多个代理对象共享同一个 InvocationHandler 时,它可能有助于区分调用的代理对象。
示例
举一个多个代理对象共享同一个 InvocationHandler
的例子,并展示如何利用 proxy
参数区分不同的代理对象。
假设我们有两个接口 ServiceA
和 ServiceB
,都使用同一个 InvocationHandler
来进行动态代理。在 InvocationHandler
的 invoke
方法中,通过 proxy
参数,我们可以识别到底是哪一个代理对象在调用该方法。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 定义两个接口
interface ServiceA {
void performTaskA();
}
interface ServiceB {
void performTaskB();
}
// 通用的 InvocationHandler,负责处理所有代理对象的调用
class CommonInvocationHandler implements InvocationHandler {
private final Object serviceAProxy;
private final Object serviceBProxy;
public CommonInvocationHandler(Object serviceAProxy, Object serviceBProxy) {
this.serviceAProxy = serviceAProxy;
this.serviceBProxy = serviceBProxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 判断调用的是哪个代理对象
if (proxy == serviceAProxy) {
System.out.println("ServiceA proxy called method: " + method.getName());
} else if (proxy == serviceBProxy) {
System.out.println("ServiceB proxy called method: " + method.getName());
} else {
System.out.println("Unknown proxy called method: " + method.getName());
}
// 这里可以根据代理对象做不同的处理逻辑
return null;
}
}
public class Main {
public static void main(String[] args) {
// 创建代理对象的通用 InvocationHandler,但还没有关联代理对象
CommonInvocationHandler handler = new CommonInvocationHandler(null, null);
// 创建 ServiceA 的代理对象
ServiceA serviceAProxy = (ServiceA) Proxy.newProxyInstance(
ServiceA.class.getClassLoader(),
new Class<?>[]{ServiceA.class},
handler
);
// 创建 ServiceB 的代理对象
ServiceB serviceBProxy = (ServiceB) Proxy.newProxyInstance(
ServiceB.class.getClassLoader(),
new Class<?>[]{ServiceB.class},
handler
);
// 更新 handler 中的代理对象引用
handler.serviceAProxy = serviceAProxy;
handler.serviceBProxy = serviceBProxy;
// 调用方法
serviceAProxy.performTaskA(); // 触发 invoke,proxy == serviceAProxy
serviceBProxy.performTaskB(); // 触发 invoke,proxy == serviceBProxy
}
}
代码解析
-
接口定义:
ServiceA
和ServiceB
接口分别定义了各自的方法performTaskA()
和performTaskB()
。 -
共享的
CommonInvocationHandler
:该InvocationHandler
在构造时接收两个代理对象的引用,用于区分代理调用。 -
代理对象的创建:
- 分别为
ServiceA
和ServiceB
创建代理对象serviceAProxy
和serviceBProxy
,它们共享CommonInvocationHandler
实例。 - 创建代理对象后,将
serviceAProxy
和serviceBProxy
的引用赋值给handler
中的对应字段,以便在invoke
方法中进行判断。
- 分别为
-
区分代理对象:
invoke
方法中,使用if (proxy == serviceAProxy)
来判断调用的是ServiceA
的代理对象;类似地,通过proxy == serviceBProxy
判断是否为ServiceB
的代理对象。- 这样,当调用
serviceAProxy.performTaskA()
时,会打印"ServiceA proxy called method: performTaskA"
;调用serviceBProxy.performTaskB()
时,会打印"ServiceB proxy called method: performTaskB"
。
输出示例
ServiceA proxy called method: performTaskA
ServiceB proxy called method: performTaskB
总结
通过在 InvocationHandler
中使用 proxy
参数,我们可以准确识别调用的代理对象,进而在多接口场景中实现特定代理对象的独立处理逻辑。