Java动态代理

Java动态代理(Dynamic Proxy)是一种运行时生成代理类的技术,可以在不改变原始类代码的情况下,为其创建一个代理对象,对方法调用进行拦截和增强。

动态代理的实现分为两种方式:基于接口的动态代理和基于类的动态代理。其中,基于接口的动态代理可以为任何实现了接口的类生成代理对象,而基于类的动态代理只能为继承了指定类的子类生成代理对象。

Java动态代理通常由以下三个部分组成:

  1. 接口或父类:被代理对象必须实现的接口或继承的父类。
  2. InvocationHandler(调用处理器):实现InvocationHandler接口,在invoke方法中编写拦截和增强逻辑。
  3. Proxy(代理类):使用Proxy类中的静态方法创建代理对象,并将被代理对象和InvocationHandler传递给它。

动态代理的优点是可以在运行时动态地为目标对象添加功能,同时也可以减少重复代码的编写。经常用于AOP编程、RPC框架和事务管理等方面。

 

下面是一个简单的基于接口的动态代理代码演示:

假设我们有一个接口 HelloService,其中定义了一个方法 sayHello()。我们想要为 HelloService 创建一个代理对象,并在执行 sayHello() 方法时添加一些额外的逻辑。

首先,我们需要编写一个实现了 InvocationHandler 接口的调用处理器类 MyInvocationHandler,并在其中实现拦截和增强逻辑。例如,以下是一个简单的调用处理器类,它将在方法调用前后记录日志信息:

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

public class MyInvocationHandler implements InvocationHandler {
    private Object target;

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

在这里,target 是被代理的目标对象,我们将其传递给构造函数中,然后在 invoke() 方法中使用反射机制调用目标对象的方法,并在方法调用前后输出日志信息。

接下来,在客户端代码中创建一个代理对象。我们可以使用 Proxy.newProxyInstance() 方法来创建代理对象。该方法需要三个参数:

  • 类加载器(ClassLoader):用于加载动态生成的代理类。
  • 接口数组(Class<?>[]):被代理的接口集合。
  • 调用处理器(InvocationHandler):用于拦截和增强方法调用的逻辑。

例如,以下是一个简单的客户端代码,它使用上述调用处理器类创建代理对象:

public class Main {
    public static void main(String[] args) {
        // 创建目标对象
        HelloService helloService = new HelloServiceImpl();
        // 创建调用处理器对象
        MyInvocationHandler handler = new MyInvocationHandler(helloService);
        // 创建代理对象
        HelloService proxy = (HelloService) Proxy.newProxyInstance(
                helloService.getClass().getClassLoader(),
                helloService.getClass().getInterfaces(),
                handler);
        // 调用代理对象的方法
        proxy.sayHello();
    }
}

在这里,我们创建了一个 HelloServiceImpl 对象作为被代理对象,并将其传递给调用处理器 MyInvocationHandler 中。然后,使用 Proxy.newProxyInstance() 方法为该对象创建代理对象,并将其转换为 HelloService 类型。最后,我们调用代理对象的方法 sayHello()

当我们运行上述代码时,将会输出以下日志信息:

Before method sayHello
Hello, world!
After method sayHello

从中可以看出,在调用 sayHello() 方法之前和之后,代理对象会执行拦截和增强逻辑,即输出日志信息。

 

发表评论

邮箱地址不会被公开。 必填项已用*标注