十分钟带你搞明白JDK动态代理

380 阅读2分钟

一、demo

Tom找中介租房

  • 1.首先,定义一个接口HouseRenting类,表示租房这个共同的行为
public interface HouseRenting {
    void rent();
}
    1. 被代理类Tom,表示要实现的行为,Tom要租房
public class Tom implements HouseRenting {
    @Override
    public void rent() {
        System.out.println("Tom want to rent a house");
    }
}
  • 3.代理类JDKProxyHandler
public class JDKProxyHandler implements InvocationHandler {

    private Object object;

    public JDKProxyHandler(Object object){
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //before
        System.out.println("带Tom看房前-到达约定地点");

        Object invoke = method.invoke(object, args);

        //after
        System.out.println("带Tom看房后-签合同");

        return invoke;
    }

    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), object.getClass().getInterfaces(), this);
    }
}
  • 4.测试方法
public class Main {

    public static void main(String[] args) {

        Tom tom = new Tom();
        JDKProxyHandler handler = new JDKProxyHandler(tom);
        HouseRenting proxy = (HouseRenting) handler.getProxy();
        proxy.rent();

    }
}
  • 5.输出结果
带Tom看房前-到达约定地点
Tom want to rent a house
带Tom看房后-签合同

二、看源码

  • 6.生成$Proxy0.class方法
public class JdkProxySourceClass {

    public static void main(String[] args) {
        byte[] classFile = ProxyGenerator.generateProxyClass("$proxy0", new Class[]{HouseRenting.class});
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream("/Users/test/$Proxy0.class");
            fos.write(classFile);
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

}
    1. $Proxy0.class部分代码
public final class $proxy0 extends Proxy implements HouseRenting {
    
    private static Method m3;

    //构造方法通过调用父类Proxy.class的构造方法,给成员变量invocationHandler赋值
    public $proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

   //调用父类中的成员变量InvocationHandler 的 invoke ()方法
    public final void rent() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
  
    static {
        try {
           //static代码块中创建了被代理类的方法
            m3 = Class.forName("proxy.staticproxy.HouseRenting").getMethod("rent");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
    1. Java动态代理实现原理
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
      /*
         * Look up or generate the designated proxy class.
         *通过类加载器和接口生成代理类
         *cl值为:class com.sun.proxy.$Proxy0
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         *调用特定的构造器
         *cons值为:public com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler)
         */
        try {
           final Constructor<?> cons = cl.getConstructor(constructorParams);
           //反射创建实例
            return cons.newInstance(new Object[]{h});
  • 9.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
        return proxyClassCache.get(loader, interfaces);
    }
    1. 上一个步骤中的proxyClassCache.get的缓存值最终会从调用ProxyClassFactory#apply获取值
{

            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) {
                }
                
            /*
             * 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) {
                
                throw new IllegalArgumentException(e.toString());
            }
        }
}

可以发现, 用于产生代理类字节码的代码是:ProxyGenerator.generateProxyClass,接着再调用native的defineClass0加载字节码生成类对象。