解析JDK动态代理实现原理

JDK动态代理使用实例

代理模式UML图

代理模式的类图如上。关于静态代理的示例网上有很多,在这里就不讲了。

因为本篇讲述要点是JDK动态代理的实现原理,直接从JDK动态代理实例开始。

首先是Subject接口类。

package proxy.pattern;
​
public interface Subject {
    void request() throws Exception;
}

接着是RealSubject类。

package proxy.pattern;
​
public class RealSubject implements Subject {
​
    public void request() {
        System.out.println("RealSubject execute request()");
    }
}

下面是代理对象的InvocationHandler接口实现类。

package proxy.dynamic;
​
import proxy.pattern.RealSubject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
​
public class JdkProxySubject implements InvocationHandler {
​
    private RealSubject realSubject;
​
    public JdkProxySubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }
​
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before");
        Object result = null;
        try {
            result = method.invoke(realSubject, args);
        } catch (Exception e) {
            throw e;
        } finally {
            System.out.println("after");
        }
        return result;
    }
}

InvocationHandler接口的定义如下。

/**
 * {@code InvocationHandler} is the interface implemented by
 * the <i>invocation handler</i> of a proxy instance.
 *
 * <p>Each proxy instance has an associated invocation handler.
 * When a method is invoked on a proxy instance, the method
 * invocation is encoded and dispatched to the {@code invoke}
 * method of its invocation handler.
 */
//每一个代理对象都有一个相应的invocation handler。
//此接口应当由proxy instance的invocation handler实现
​
//当代理对象的方法被调用时,方法调用将会委派为invocation handler的invoke方法
//(这里有个疑问就是:方法委派是如何实现的?
//为什么调用代理对象的方法时,会调用invocation handler的invoke方法。
//答案在生成的代理类的源代码里,可以看最下面对代理类的源代码的分析)
public interface InvocationHandler {
  
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

客户端代码如下。

package proxy.dynamic;
​
import proxy.pattern.RealSubject;
import proxy.pattern.Subject;
import java.lang.reflect.Proxy;
​
public class Client {
​
    public static void main(String[] args) throws Exception {
        //通过设置参数,将生成的代理类的.class文件保存在本地
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        //通过调用Proxy.newProxyInstance生成代理对象
        //方法参数为:1)classLoader  2)要代理的接口 3)代理对象的InvocationHandler
        //(通过方法参数也可以看出来,JDK代理只能通过代理接口来来实现动态代理)
        Subject subject = (Subject) Proxy.newProxyInstance(Client.class.getClassLoader(),
                new Class[]{Subject.class}, new JdkProxySubject(new RealSubject()));
        //调用代理对象的request方法。
        //(根据InvocationHandler接口的定义,可以知道实际调用的是JdkProxySubject里的invoke方法)
        subject.request();
    }
}

运行结果如下。

before
RealSubject execute request()
after

JDK动态代理实现原理分析

生成代理对象的方法调用链为Proxy.newProxyInstance()-------->getProxyClass0()------->ProxyClassFactory.apply()-------->ProxyGenerator.generateProxyClass()。我们下面依次对各个阶段进行分析。

Proxy.newProxyInstance()

newProxyInstance方法的完整代码如下。

    @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;
                    }
                });
            }
            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);
        }
    }

我们将错误判断等无用代码去掉后,代码如下。

@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
  throws IllegalArgumentException {
        final Class<?>[] intfs = interfaces.clone();
        /*
         * Look up or generate the designated proxy class.
         */
        //根据提供的接口(在我们的例子中,即Subject接口),生成代理类
        Class<?> cl = getProxyClass0(loader, intfs);
​
        /*
         * Invoke its constructor with the designated invocation handler.
         */
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        //调用代理类的构造器,构造器参数为InvocationHandler的接口实现类(在我们的例子中,即JdkProxySubject)
        return cons.newInstance(new Object[]{h});
}

下面,我们看看getProxyClass0方法,看看代理类是如何生成的。

getProxyClass0()

private static Class<?> getProxyClass0(ClassLoader loader,
                                       Class<?>... interfaces) {
  if (interfaces.length > 65535) {
    throw new IllegalArgumentException("interface limit exceeded");
  }
​
  // If the proxy class defined by the given loader implementing
  // the given interfaces exists, this will simply return the cached copy;
  // otherwise, it will create the proxy class via the ProxyClassFactory
  //已经生成过代理类会放到cache里,没有生成过的话,会由ProxyClassFactory创建。
  //因此,我们可以直接找到ProxyClassFactory,查看代理类是如何创建的。
  return proxyClassCache.get(loader, interfaces);
}

因此,我们可以继续找到ProxyClassFactory,查看代理类是如何创建的。

ProxyClassFactory.apply()

ProxyClassFactory类完整的代码如下。

private static final class ProxyClassFactory
  implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        // prefix for all proxy class names
        private static final String proxyClassNamePrefix = "$Proxy";
​
        // next number to use for generation of unique proxy class names
        private static final AtomicLong nextUniqueNumber = new AtomicLong();
​
        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
​
            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<?> intf : interfaces) {
                /*
                 * Verify that the class loader resolves the name of this
                 * interface to the same Class object.
                 */
                Class<?> interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
                /*
                 * Verify that the Class object actually represents an
                 * interface.
                 */
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                /*
                 * Verify that this interface is not a duplicate.
                 */
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }
​
            String proxyPkg = null;     // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
​
            /*
             * Record the package of a non-public proxy interface so that the
             * proxy class will be defined in the same package.  Verify that
             * all non-public proxy interfaces are in the same package.
             */
            for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;
                    String name = intf.getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }
​
            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }
​
            /*
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;
​
            /*
             * Generate the specified proxy class.
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }
        }
    }

我们将无用的代码去掉后,代码如下。

    private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        // prefix for all proxy class names
        private static final String proxyClassNamePrefix = "$Proxy";
​
        // next number to use for generation of unique proxy class names
        private static final AtomicLong nextUniqueNumber = new AtomicLong();
​
        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
            //第一步:确定包名,如果没有非public的代理接口,包名使用com.sun.proxy
            String proxyPkg = null;     // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }
            //第二步:确定类名。(在我们例子中,生成的代理类名为com.sun.proxy.$Proxy0)
            /*
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;
            //第三步:根据类名、代理接口等信息,生成代理类。实际上可以理解为生成.class文件。
            /*
             * Generate the specified proxy class.
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
           //第四步:根据生成的.class文件,返回一个代理类Class。此方法为native方法
           return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            
        }
    }

ProxyGenerator.generateProxyClass()

ProxyGenerator.generateProxyClass生成.class文件的过程其实就是根据.class文件格式来一步步拼接处对应字节数组。
由于代码太长了,不贴了,可以看这个
ProxyGenerator.java

生成的代理对象的.class文件

在创建代理对象前,可以通过下面语句,将生成的代理类的.class保存在本地。

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

生成的代理类的.class文件反编译后,是下面这个样子的。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
​
package com.sun.proxy;
​
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import proxy.pattern.Subject;
​
public final class $Proxy0 extends Proxy implements Subject {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;
​
    public $Proxy0(InvocationHandler h) throws  {
        super(h);//通过这句,将invocationHandler实例传给了父类构造器。
    }
​
    public final boolean equals(Object var1) throws  {
        try {
            return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }
​
    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);
        }
    }
​
    //$Proxy0继承了Proxy,且将InvocationHandler h在构造时传给了Proxy。
    //因此,super.h.invoke(this, m3, (Object[])null)其实就是调用的invoker handler的invoke方法。
    //也正是像InvocationHandler定义中所说的,【当proxy instance的方法被调用时,方法调用将会委派为invocation handler的invoke方法】。
    public final void request() throws Exception {
        try { 
            super.h.invoke(this, m3, (Object[])null);
        } catch (Exception | 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)).intValue();
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
​
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m3 = Class.forName("proxy.pattern.Subject").getMethod("request", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

Proxy中InvocationHandler的定义如下。

public class Proxy implements java.io.Serializable {
​
    /**
     * the invocation handler for this proxy instance.
     * @serial
     */
    protected InvocationHandler h;
    /**
     * Constructs a new {@code Proxy} instance from a subclass
     * (typically, a dynamic proxy class) with the specified value
     * for its invocation handler.
     *
     * @param  h the invocation handler for this proxy instance
     *
     * @throws NullPointerException if the given invocation handler, {@code h},
     *         is {@code null}.
     */
    protected Proxy(InvocationHandler h) {
        Objects.requireNonNull(h);
        this.h = h;
    }
}
posted @ 2018-12-08 12:36  Ye_yang  阅读(6563)  评论(1编辑  收藏  举报