聊聊JDK的动态代理机制

174 阅读4分钟
原文链接: mp.weixin.qq.com

使用过spring的读者都会知道,spring有一个强大的功能——面向切面编程(AOP)。AOP底层其实是基于Java的动态代理的。本篇文章就来了解一下动态代理机制。

Java的动态代理机制实现方式有两种,一种是基于JDK自带的动态代理机制,一种是基于cglib的动态代理机制。说到JDK自带的动态代理机制,我们不得不说一下InvocationHandler接口。我们看一下JDK中InvocationHandler源码:

  1. public interface InvocationHandler {

  2.     /**

  3.     * 集中处理代理类的方法调用

  4.     *

  5.     * @param proxy  代理类的实例

  6.     * @param method 代理类调用的方法实例

  7.     * @param args   调用方法参数

  8.     * @return

  9.     * @throws Throwable

  10.     */

  11.    public Object invoke(Object proxy, Method method, Object[] args)

  12.        throws Throwable;

  13. }

可以看到,InvocationHandler是一个接口,里面只提供一个invoke方法。所有需要动态代理类都需要实现此接口,并且每一个代理类都关联到一个InvocationHandler,当我们调用代理类的方法的时候,就会触发invoke方法。

在Java动态代理机制中,我们还会使用到Proxy类,这个类负责创建具体代理类的实例,我们可以调用Proxy的静态方法newProxyInstance来创建具体代理类的实例。

下面,我们通过一个例子来学习JDK自带的动态代理机制:

创建一个接口
  1. public interface IProgrammer {

  2.    void code();

  3.    void commit();

  4. }

实现接口(被代理的类)
  1. public class WebProgrammer implements IProgrammer {

  2.    public void code() {

  3.        System.out.println("工程师编写代码");

  4.    }

  5.    public void commit() {

  6.        System.out.println("工程师提交代码");

  7.    }

  8. }

创建一个类,实现InvocationHandler的接口(用于创建代理类)
  1. public class ProgrammerProxy implements InvocationHandler {

  2.    /**

  3.     * 被代理类实例

  4.     */

  5.    private Object delegate;

  6.    /**

  7.     * 绑定被代理对象,返回代理类实例

  8.     *

  9.     * @param delegate 被代理类的对象

  10.     * @return 代理类实例

  11.     */

  12.    public Object bind(Object delegate) {

  13.        this.delegate = delegate;

  14.        return Proxy.newProxyInstance(this.delegate.getClass().getClassLoader(),

  15.                this.delegate.getClass().getInterfaces(), this);

  16.    }

  17.    /**

  18.     * 集中处理代理类的方法调用

  19.     *

  20.     * @param proxy  代理类的实例

  21.     * @param method 代理类调用的方法实例

  22.     * @param args   调用方法参数

  23.     * @return

  24.     * @throws Throwable

  25.     */

  26.    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

  27.        Object rs = null;

  28.        System.out.println(" method " + method.getName() + " is executing");

  29.        if (method.getName().equals("code")) {

  30.            System.out.println("工程师和产品经理确认需求,需求清晰");

  31.        } else if (method.getName().equals("commit")) {

  32.            System.out.println("CTO进行代码评审,代码质量可靠");

  33.        }

  34.        rs = method.invoke(this.delegate, args);

  35.        return rs;

  36.    }

  37. }

测试代码
  1. public class Client {

  2.    public static void main(String[] args) {

  3.        ProgrammerProxy proxy = new ProgrammerProxy();

  4.        WebProgrammer webProgrammer = new WebProgrammer();

  5.        IProgrammer programmer = (IProgrammer) proxy.bind(webProgrammer);

  6.        programmer.code();

  7.        programmer.commit();

  8.    }

  9. }

运行测试类,输出
  1. method code is executing

  2. 工程师和产品经理确认需求,需求清晰

  3. 工程师编写代码

  4. method commit is executing

  5. CTO进行代码评审,代码质量可靠

  6. 工程师提交代码


分析例子,我们可以知道,使用JDK自带的动态代理机制,我需要如下步骤:

  • 创建代理类生成器,实现InvocationHandler接口(ProgrammerProxy)

  • 创建被代理类(WebProgrammer)

  • 使用代理类生成器创建代理类

  • 执行代理类方法 

     

那么,JDK的动态代理机制有哪些使用场景呢?开篇说了,Spring的AOP就是基于Java的动态代理机制的。凡是AOP可以使用到的地方,都是Java动态代理机制的使用场景。然而,不一定是JDK自带的动态代理机制的使用场景,因为Spring的AOP可以基于cglib进行对类的动态代理,而JDK自带的动态代理机制是对接口的动态代理,也就是说所有代理类都需要实现同一接口InvocationHandler。总之,Spring的AOP大多数的使用场景都是JDK自带动态代理的使用场景。