JDK动态代理的深入理解

每一个Proxy实例对象都有一个与之相关联的InvocationHandler实例,当在Proxy对象上调用代理的方法时,该方法就会被分发(dispatched)到这个InvocationHandler对象的invoke()方法上。

package java.lang.reflect;

/**
 * {@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.
 *
 * @author      Peter Jones
 * @see         Proxy
 * @since       1.3
 */
public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

一、入门示例

1. 目标类和代理类需要实现的共同接口IPayment

package com.yxf.dynamicproxy;
public interface IPayment {
    long pay(int amount);
    long price();
}

2. 目标类CreditCard

package com.yxf.dynamicproxy;

public class CreditCard implements IPayment {

    @Override
    public long pay(int amount) {
        return price() * amount;
    }

    @Override
    public long price() {
        return 99;
    }
}

3. 调用者需要提供的InvocationHandler实例

package com.yxf.dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler{
    private final Object target;

    public MyInvocationHandler(Object object) {
        this.target = object;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if(target == null) {
            return null;
        }

        return method.invoke(target, args);
    }
}

4. 使用方法

package com.yxf.dynamicproxy;

import java.lang.reflect.Proxy;

public class Client {
    public static void main(String[] args) {
        testDynamicProxy();
    }

    private static void testDynamicProxy() {
        IPayment target = new CreditCard();
        //System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        //sun.misc.Launcher$AppClassLoader
        System.out.println("IPayment.class.getClassLoader: " + IPayment.class.getClassLoader().getClass().getName());
        IPayment proxy = null;
        try {
            proxy = (IPayment) Proxy.newProxyInstance(IPayment.class.getClassLoader(), new Class[]{IPayment.class},
                    new MyInvocationHandler(target));
            System.out.println("proxy: " + proxy.getClass().getName()); //com.sun.proxy.$Proxy0
            long money = proxy.pay(2000);
            System.out.println("proxy.price: " + money);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

五、生成的Proxy实例class

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

package com.sun.proxy;

import com.yxf.dynamicproxy.IPayment;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

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

    public $Proxy0(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 long price() throws  {
        try {
            return (Long)super.h.invoke(this, m4, (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 long pay(int var1) throws  {
        try {
            return (Long)super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    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"));
            m4 = Class.forName("com.yxf.dynamicproxy.IPayment").getMethod("price");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.yxf.dynamicproxy.IPayment").getMethod("pay", Integer.TYPE);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

二、Proxy的newProxyInstance()方法

public class Proxy implements java.io.Serializable {
    private static final long serialVersionUID = -2222568056686623797L;

    /** parameter types of a proxy class constructor */
    private static final Class<?>[] constructorParams =
        { InvocationHandler.class };

    ...

    @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对象。
        Class<?> cl = getProxyClass0(loader, intfs);

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

            //获取代理类的构造方法,其中constructorParams为构造方法的参数。
            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;
                    }
                });
            }
            //使用Constructor反射的方式创建代理类的实例,其中构造方法的参数为new Object[]{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);
        }
    }

    /**
     * A factory function that generates, defines and returns the proxy class given
     * the ClassLoader and array of interfaces.
     */
    //给定一个ClassLoader和一个Interface的Class[]数组,生成代理类。
    private static final class ProxyFactory
            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();

        public Class<?> apply(ClassLoader classLoader, Class<?>[] classes) {
            //...

            String proxyPkg = null;     // package to define proxy class in

            /*
             * 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());
            }
        }
    }

    //JVM native方法, 用于将字节流转化为Class对象。
    private static native Class<?> defineClass0(ClassLoader loader, String name,
                                                byte[] b, int off, int len);
}

三、ProxyGenerator类的generateClassFile()方法

关键代码:
[sun/misc/ProxyGenerator.java]

package sun.misc;
/**
 * ProxyGenerator contains the code to generate a dynamic proxy class
 * for the java.lang.reflect.Proxy API.
 *
 * The external interfaces to ProxyGenerator is the static
 * "generateProxyClass" method.
 *
 * @author      Peter Jones
 * @since       1.3
 */
public class ProxyGenerator {

    /* 预加载的java.lang.Object类的Method实例。*/
    private static Method hashCodeMethod;
    private static Method equalsMethod;
    private static Method toStringMethod;
    static {
        try {
            hashCodeMethod = Object.class.getMethod("hashCode");
            equalsMethod = Object.class.getMethod("equals", new Class<?>[] { Object.class });
            toStringMethod = Object.class.getMethod("toString");
        } catch (NoSuchMethodException e) {
            throw new NoSuchMethodError(e.getMessage());
        }
    }

    /** 保存生成class文件的调试开关 */
    private final static boolean saveGeneratedFiles =
            java.security.AccessController.doPrivileged(
                    new GetBooleanAction(
                            "sun.misc.ProxyGenerator.saveGeneratedFiles")).booleanValue();


    /**
     * Generate a proxy class given a name and a list of proxy interfaces.
     *
     * @param name        the class name of the proxy class
     * @param interfaces  proxy interfaces
     * @param accessFlags access flags of the proxy class
     */
    public static byte[] generateProxyClass(final String name,
                                            Class<?>[] interfaces,
                                            int accessFlags)
    {
        ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
        final byte[] classFile = gen.generateClassFile();

        if (saveGeneratedFiles) {
            //调试使用
        }

        return classFile;
    }

    /**
     * 生成Proxy类的.class文件
     *
     * @return
     */
    private byte[] generateClassFile() {
        //生成Java.lang.Object的hashCode、equals和toString方法.
        addProxyMethod(hashCodeMethod, Object.class);
        addProxyMethod(equalsMethod, Object.class);
        addProxyMethod(toStringMethod, Object.class);

        for (Class<?> intf : interfaces) {
            for (Method m : intf.getMethods()) {
                addProxyMethod(m, intf);
            }
        }

        for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
            checkReturnTypes(sigmethods);
        }

        try {
            methods.add(generateConstructor());
            for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
                for (ProxyMethod pm : sigmethods) {
                    //添加static的Method字段变量
                    fields.add(new FieldInfo(pm.methodFieldName,
                            "Ljava/lang/reflect/Method;",
                            ACC_PRIVATE | ACC_STATIC));

                    methods.add(pm.generateMethod());
                }
            }
            methods.add(generateStaticInitializer());
        } catch (IOException e) {
            throw new InternalError("unexpected I/O Exception", e);
        }

        if (methods.size() > 65535) {
            throw new IllegalArgumentException("method limit exceeded");
        }
        if (fields.size() > 65535) {
            throw new IllegalArgumentException("field limit exceeded");
        }

        cp.getClass(dotToSlash(className));
        cp.getClass(superclassName);
        for (Class<?> intf : interfaces) {
            cp.getClass(dotToSlash(intf.getName()));
        }

        cp.setReadOnly();

        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        DataOutputStream dout = new DataOutputStream(bout);

        try {
            dout.writeInt(0xCAFEBABE); // u4 magic;
            dout.writeShort(CLASSFILE_MINOR_VERSION); // u2 minor_version;
            dout.writeShort(CLASSFILE_MAJOR_VERSION); // u2 major_version;
            cp.write(dout);  // (write constant pool)

            dout.writeShort(accessFlags); // u2 access_flags;
            dout.writeShort(cp.getClass(dotToSlash(className))); // u2 this_class;
            dout.writeShort(cp.getClass(superclassName)); // u2 super_class;
            dout.writeShort(interfaces.length); // u2 interfaces_count;

            // u2 interfaces[interfaces_count];
            for (Class<?> intf : interfaces) {
                dout.writeShort(cp.getClass(
                        dotToSlash(intf.getName())));
            }

            // u2 fields_count;
            dout.writeShort(fields.size());
            // field_info fields[fields_count];
            for (FieldInfo f : fields) {
                f.write(dout);
            }

            // u2 methods_count;
            dout.writeShort(methods.size());
            // method_info methods[methods_count];
            for (MethodInfo m : methods) {
                m.write(dout);
            }

            // u2 attributes_count;
            dout.writeShort(0); // (no ClassFile attributes for proxy classes)
        } catch (IOException e) {
            throw new InternalError("unexpected I/O Exception", e);
        }

        return bout.toByteArray();
    }
}

参见代码:
https://github.com/JetBrains/jdk8u_jdk/blob/master/src/share/classes/sun/misc/ProxyGenerator.java
posted @ 2021-09-05 21:53  羊之草原  阅读(40)  评论(0)    收藏  举报