Java 动态代理是一种在运行时创建代理对象以拦截对目标对象方法调用的机制。它通常用于实现接口的代理,而不直接代理具体的类。Java 动态代理的核心是 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口。

日常生活中的类比

想象一下,你是一家公司的员工,你的工作是处理客户的订单。但是,公司有一个规定:每次你处理订单之前,都需要先向你的上级汇报,并在处理完订单后再向他反馈结果。

在这个场景中:

  • 是执行实际工作的对象(原始对象)。
  • 你的上级 是需要被通知的对象(虽然在这个类比中他并不直接参与工作,但他是信息流通的关键)。
  • 向上级汇报和反馈 是你在处理订单前后需要做的额外工作(自定义逻辑)。

现在,如果公司决定引入一个“助手”角色,这个助手会在你每次处理订单之前和之后自动帮你向上级汇报和反馈,那么你就可以专注于处理订单本身,而不需要每次都手动去汇报和反馈了。

这个“助手”的角色,就类似于Java动态代理中的代理对象

以下是实现 Java 动态代理的基本步骤:

  1. 定义一个或多个接口:被代理的对象必须实现这些接口。动态代理将基于这些接口生成代理类。
  2. 实现 InvocationHandler 接口:创建一个实现了 InvocationHandler 接口的类,并重写 invoke 方法。invoke 方法将在代理对象的方法被调用时执行。
  3. 使用 Proxy.newProxyInstance 方法创建代理对象:将目标对象的类加载器、目标对象实现的接口数组以及 InvocationHandler 实例传递给 Proxy.newProxyInstance 方法,它将返回一个实现了指定接口的代理对象。

以下是一个简单的示例:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 定义一个接口
interface Service {
    void execute();
}

// 实现接口的类
class ServiceImpl implements Service {
    @Override
    public void execute() {
        System.out.println("Executing Service...");
    }
}

// 实现 InvocationHandler 接口的类
class ServiceInvocationHandler implements InvocationHandler {
    private final Object target;

    public ServiceInvocationHandler(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;
    }
}

public class DynamicProxyDemo {
    public static void main(String[] args) {
        // 创建目标对象
        Service service = new ServiceImpl();

        // 创建 InvocationHandler 对象
        InvocationHandler handler = new ServiceInvocationHandler(service);

        // 创建代理对象
        Service proxyInstance = (Service) Proxy.newProxyInstance(
                service.getClass().getClassLoader(),
                service.getClass().getInterfaces(),
                handler
        );

        // 调用代理对象的方法
        proxyInstance.execute();
    }
}

在这个示例中:

  • Service 是一个接口,定义了一个 execute 方法。
  • ServiceImplService 接口的一个实现类。
  • ServiceInvocationHandler 实现了 InvocationHandler 接口,并在 invoke 方法中添加了方法调用前后的处理逻辑。
  • DynamicProxyDemomain 方法中,创建了 ServiceImpl 的实例作为目标对象,然后创建了 ServiceInvocationHandler 的实例,并将目标对象传递给它。接着,使用 Proxy.newProxyInstance 方法创建了代理对象。最后,通过代理对象调用了 execute 方法,此时会触发 ServiceInvocationHandlerinvoke 方法。

运行此程序将输出:

Before method call
Executing Service...
After method call

这表明在调用目标对象的 execute 方法之前和之后,都执行了 ServiceInvocationHandler 中的处理逻辑