JDK动态代理底层原理

JDK动态代理底层原理

写一个代理,就可以到处使用?背后到底发生了什么?让我们看看完整的执行链,就一目了然了。


一、上一篇回顾

上一篇文章(静态代理、JDK和Cglib动态代理的简单使用)对代理模式的使用做了简单的实践。在使用中,我们就像是调用我们自己写的实现类一样,但是功能上确实实现了增强。

使用

@Test
public void testJdkBasedProxy() throws Exception {
    TicketSeller seller = (TicketSeller) new JdkBasedProxy().bind(new Seller12306());
    seller.query();
    seller.sell();
}

/** 输出结果:
***********before***********
您好,您回家的票还有……1张
***********after************
***********before***********
您已购买回家的票!
***********after************
**/

seller.query();
seller.sell();
背后实现逻辑是怎么样的呢?是如何调用到我们的InvocationHandler实现类JdkBasedProxy的呢?这里我们需要去看一看实际生成的代理类中的具体逻辑。

二、生成代理类查看

我们将代理生成的类输出到文件得到字节码文件,并反编译即可

    /**
     * 代理 new Seller12306()
     *
     * @throws IOException
     */
    @Test
    public void testJdkBasedProxy() throws IOException {
        TicketSeller seller = (TicketSeller) new JdkBasedProxy().bindGetProxy(new Seller12306());
        seller.query();
        seller.sell();

        String className = seller.getClass().getName();
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(className,
                seller.getClass().getInterfaces());

        String simpleName = seller.getClass().getSimpleName();
        String realPath = String.format(Path, simpleName);
        saveToFile(proxyClassFile, realPath);
    }

    /**
     * 保存二进制字节流到文件
     */
    private void saveToFile(byte[] proxyClassFile, String path) throws IOException {
        File file = new File(path);
        if (!file.exists()) {
            file.createNewFile();
        }
        try (FileOutputStream outputStream = new FileOutputStream(file)) {
            outputStream.write(proxyClassFile);
            outputStream.flush();
        }
    }

将 .class文件反编译,

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.sun.proxy;

import com.wangjia.sub.TicketSeller;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy2 extends Proxy implements TicketSeller {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m4;
    private static Method m0;

    public $Proxy2(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void query() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void sell() throws  {
        try {
            super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("com.wangjia.sub.TicketSeller").getMethod("query");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m4 = Class.forName("com.wangjia.sub.TicketSeller").getMethod("sell");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

三、生成类分析

可以看到,生成的代理类中 extends Proxy implements TicketSeller.

我们从 query()开始看,

public final void query() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

实际调用的是 super.h中的方式,super当然是 Proxy,看看其中的成员 h(InvocationHandler)

public class Proxy implements java.io.Serializable {
…………
    /**
     * the invocation handler for this proxy instance.
     * @serial
     */
    protected InvocationHandler h;

…………
}

这个 super.h 很明显是 InvocationHandler,也就是我们的增强逻辑类 JdkBasedProxy

//代理类不跟任何具体被代理有强绑定关系,理论上所有需要 doAfter() 和 doAfter()的都可以使用此代理
public class JdkBasedProxy implements InvocationHandler {
    /**
     * 被代理对象
     */
    private Object target;

    public JdkBasedProxy() {
    }

    public JdkBasedProxy(Object target) {
        this.target = target;
    }

    public Object bindAndGetProxy(Object target) {
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        doBefore();
        Object invokeRes = method.invoke(target, args);
        doAfter();
        return invokeRes;
    }

    private void doBefore() {
        System.out.println("***********jdk proxy before***********");
    }

    private void doAfter() {
        System.out.println("**********jdk proxy after************");
    }
}

具体 InvocationHandler h 的设置在

Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
@CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         * 代理类生成
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            //反射,构造函数,参数为h
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

再通过反射实例化Proxy时 return cons.newInstance(new Object[]{h}); 时,设置了h

protected Proxy(InvocationHandler h) {
    Objects.requireNonNull(h);
    this.h = h;
}

生成的代理类,最终将实际工作委托给了InvocationHandler , 其中第二个和第三个参数分别是是 Method和参数列表

public Object invoke(Object proxy, Method method, Object[] args){}

生成的代理类中只需要通过反射获取对应的 Method即可

static {
    try {
        m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
        m3 = Class.forName("com.wangjia.sub.TicketSeller").getMethod("query");
        m2 = Class.forName("java.lang.Object").getMethod("toString");
        m4 = Class.forName("com.wangjia.sub.TicketSeller").getMethod("sell");
        m0 = Class.forName("java.lang.Object").getMethod("hashCode");
    } catch (NoSuchMethodException var2) {
        throw new NoSuchMethodError(var2.getMessage());
    } catch (ClassNotFoundException var3) {
        throw new NoClassDefFoundError(var3.getMessage());
    }
}

四、总结

动态代理可以说是结合静态代理的思想,同时利用反射和字节码生成技术,替我们减少了很多编码工作,实现了代理逻辑的复用,将代理的逻辑抽取出来作为一个通用组件。

发表评论

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