`InvocationHandler`中`invoke`方法,第一个参数`Object proxy`是什么

120 阅读2分钟

InvocationHandler

在平常使用JDK代理时,都是实现InvocationHandler,传进被代理的实例,重写invoke方法,如下:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
    doBefore();
    method.invoke(instance,args);
    doAfter();
}

大多数时候proxy都被我们忽略了,所以proxy到底是什么?

InvocationHandlerinvoke方法,第一个参数Object proxy是什么

proxy 参数代表调用 invoke 方法的代理对象本身,但在 InvocationHandler 中通常不直接使用它。在多个代理对象共享同一个 InvocationHandler 时,它可能有助于区分调用的代理对象。

示例

举一个多个代理对象共享同一个 InvocationHandler 的例子,并展示如何利用 proxy 参数区分不同的代理对象。

假设我们有两个接口 ServiceAServiceB,都使用同一个 InvocationHandler 来进行动态代理。在 InvocationHandlerinvoke 方法中,通过 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
    }
}

代码解析

  1. 接口定义ServiceAServiceB 接口分别定义了各自的方法 performTaskA()performTaskB()

  2. 共享的 CommonInvocationHandler:该 InvocationHandler 在构造时接收两个代理对象的引用,用于区分代理调用。

  3. 代理对象的创建

    • 分别为 ServiceAServiceB 创建代理对象 serviceAProxyserviceBProxy,它们共享 CommonInvocationHandler 实例。
    • 创建代理对象后,将 serviceAProxyserviceBProxy 的引用赋值给 handler 中的对应字段,以便在 invoke 方法中进行判断。
  4. 区分代理对象

    • 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 参数,我们可以准确识别调用的代理对象,进而在多接口场景中实现特定代理对象的独立处理逻辑。