使用Java的InvocationHandler实现动态代理

2,278 阅读2分钟

说在前面,本篇文章只讲解InvocationHandler的使用。在阅读本篇文章之前,需要了解设计模式中的代理模式。

直接贴代码,这段代码是代表Subject的IHello接口

/**
 * Subject
 * RealSubject和Proxy需要实现这个接口
 */
public interface IHello {

    void sayHello(String name);
}

代表RealSubject的ConcreteHello类,实现了IHello接口,是实际执行操作的对象

/**
 * RealSubject
 * 实现IHello接口,是实际执行操作的对象
 */
public class ConcreteHello implements IHello {

    @Override
    public void sayHello(String name) {
        System.out.println("Hello" + name);
    }
}

动态代理就是Proxy的class文件在程序运行前是不存在,其字节码是在运行的时候自动生成的。在这里代理类,我们借助Proxy的newProxyInstance方法在运行时自动创建。

/**
 * 实现Java自带的InvocationHandler接口,重写invoke方法来调用RealSubject的方法
 * 自定义getProxy来获取代理对象。该方法通过Proxy的newProxyInstance方法来生成代理对象。
 */
public class HelloHandler implements InvocationHandler {

    //持有RealSubject的引用,即持有被代理对象的引用
    private IHello concreteHello;

    /**
     * 接收RealSubject,生成并返回Proxy对象
     * @param concreteHello 被代理对象
     * @return 返回动态生成的Proxy对象
     */
    public Object getProxy(IHello concreteHello) {
        this.concreteHello = concreteHello;
        // Proxy.newProxyInstance方法用来生成目标对象的代理类
        // 第一个参数是 目标对象的类加载器
        // 第二个参数是 目标对象的接口列表
        // 第三个参数是 InvocationHandler的实现类
        return Proxy.newProxyInstance(
                this.concreteHello.getClass().getClassLoader(),
                this.concreteHello.getClass().getInterfaces(),
                this
        );
    }

    /**
     * 调用目标对象的方法,可以在方法执行前后添加自己的操作
     * @param proxy 代理对象
     * @param method RealSubject对象中被Proxy调用的方法
     * @param args 被Proxy调用的方法参数列表
     * @return Proxy调用的方法的返回值
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //我们可以在方法调用之前添加自己的操作
        System.out.println("before invoke");
        //调用RealSubject的方法
        Object result = method.invoke(this.concreteHello, args);
        //我们可以在方法调用之后添加自己的操作
        System.out.println("after invoke");
        return result;
    }
}

下面我们来测试看是不是能执行成功

public class InvocationHandlerTest {

    public static void main(String[] args) {
        //ConcreteSubject
        IHello concreteHello = new ConcreteHello();
        //辅助生成Proxy对象
        HelloHandler helloHandler = new HelloHandler();
        //Proxy
        IHello iHello = (IHello)helloHandler.getProxy(concreteHello);
        //通过Proxy调用RealSubject的sayHello方法
        iHello.sayHello("Jerry");
    }
}