JDK动态代理源码分析之一

来源:互联网 发布:大数据时代下的教育 编辑:程序博客网 时间:2024/06/13 19:47


一、JDK动态代理的Demo

接口实现类:

package com.weili.cn;/** * Created by weili on 17/6/23. */public class Animal implements AnimalInterface {    public void sound() {        System.out.println("Animal miao miao  miao");    }}


接口:

package com.weili.cn;/** * Created by weili on 17/6/23. */public interface AnimalInterface {    void sound();}


代理实现类:

package com.weili.cn;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;/** * Created by weili on 17/6/23. */public class AnimalProxyHandler implements InvocationHandler {    private Object proxyied; //代理对象    public AnimalProxyHandler(Object proxyied){        this.proxyied = proxyied;  //初始化代理对象    }    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("代理调用前");        return method.invoke(proxyied,args);    }}

调用类:

package com.weili.cn;import javax.security.auth.Subject;import java.lang.reflect.Proxy;/** * Hello world! * */public class App {    public static void main( String[] args )    {        Animal animal = new Animal();        AnimalInterface  animalInterface = (AnimalInterface) Proxy.newProxyInstance(AnimalInterface.class.getClassLoader(),        new Class[]{AnimalInterface.class},        new AnimalProxyHandler(animal));        animalInterface.sound();    }}

输出

代理调用前Animal miao miao  miao


二、动态代理原理

从上述代码可以看出,JDK的动态代理是针对接口的,它是动态的,是因为它的加载可以通过代理类实现动态的加载。代理类不会因为业务对象的增多而增多。另外需要在这里着重说的是,虽然程序的输出是看起来像是Animal这个类输出的,但是事实上并不是。在JDK的动态代理的过程中,JDK会生成新的class文件,实际上执行的是这个class文件中的内容。

对于作为用户的我们而言,要实现动态代理,基本只要如下几步:1.定义接口和实现类  2.写代理类,实现InvocationHandler接口。 3.代理调用

可以看出,有了JDK的封装,实现动态代理变的很容易。

三、源码分析

从Proxy.newProxyInstance看起,

    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);        }    }
相应的主要说明,直接写在了注释上。从上面可以看出JDK内部帮我们实例化出class的实例,返回这个实例后,被强制转换为接口类型,但是调用方法时候,调用这个class实例里面的方法。

接下来,看一下JDK是怎么创建代理类的,即

getProxyClass0(loader, intfs)
进入后,先判断异常

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

然后进入proxyClassCache.get方法

   public V get(K key, P parameter) {        Objects.requireNonNull(parameter);        expungeStaleEntries();        Object cacheKey = CacheKey.valueOf(key, refQueue);        // lazily install the 2nd level valuesMap for the particular cacheKey        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);        if (valuesMap == null) {            ConcurrentMap<Object, Supplier<V>> oldValuesMap                = map.putIfAbsent(cacheKey,                                  valuesMap = new ConcurrentHashMap<>());            if (oldValuesMap != null) {                valuesMap = oldValuesMap;            }        }        // create subKey and retrieve the possible Supplier<V> stored by that        // subKey from valuesMap        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));        Supplier<V> supplier = valuesMap.get(subKey);        Factory factory = null;        while (true) {            if (supplier != null) {                // supplier might be a Factory or a CacheValue<V> instance                V value = supplier.get();    //获取相应的实例类                if (value != null) {                    return value;                }            }            // else no supplier in cache            // or a supplier that returned null (could be a cleared CacheValue            // or a Factory that wasn't successful in installing the CacheValue)            // lazily construct a Factory            if (factory == null) {                factory = new Factory(key, parameter, subKey, valuesMap);            }            if (supplier == null) {                supplier = valuesMap.putIfAbsent(subKey, factory);                if (supplier == null) {                    // successfully installed Factory                    supplier = factory;                }                // else retry with winning supplier            } else {                if (valuesMap.replace(subKey, supplier, factory)) {                    // successfully replaced                    // cleared CacheEntry / unsuccessful Factory                    // with our Factory                    supplier = factory;                } else {                    // retry with current supplier                    supplier = valuesMap.get(subKey);                }            }        }    }

上面是jdk1.8的实现,
supplier.get()

用来获取最终的实例类,那么进入这个方法,

        public synchronized V get() { // serialize access            // re-check            Supplier<V> supplier = valuesMap.get(subKey);            if (supplier != this) {                // something changed while we were waiting:                // might be that we were replaced by a CacheValue                // or were removed because of failure ->                // return null to signal WeakCache.get() to retry                // the loop                return null;            }            // else still us (supplier == this)            // create new value            V value = null;            try {                value = Objects.requireNonNull(valueFactory.apply(key, parameter));//在apply方法中进行生成class类            } finally {                if (value == null) { // remove us on failure                    valuesMap.remove(subKey, this);                }            }            // the only path to reach here is with non-null value            assert value != null;            // wrap value with CacheValue (WeakReference)            CacheValue<V> cacheValue = new CacheValue<>(value);            // try replacing us with CacheValue (this should always succeed)            if (valuesMap.replace(subKey, this, cacheValue)) {                // put also in reverseMap                reverseMap.put(cacheValue, Boolean.TRUE);            } else {                throw new AssertionError("Should not reach here");            }            // successfully replaced us with new CacheValue -> return the value            // wrapped by it            return value;        }    }

接下来进入注释说明的方法,

    private static final class ProxyClassFactory        implements BiFunction<ClassLoader, Class<?>[], Class<?>>    {        // prefix for all proxy class names        private static final String proxyClassNamePrefix = "$Proxy"; //JDK代理生成的class文件的前缀名字        // 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);//获取接口的class                } 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(// 这里是生成class文件字节码的地方                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());            }        }    }

进入generateProxyClass

    public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {        ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);        final byte[] var4 = var3.generateClassFile();//最终产生class文件的地方        if(saveGeneratedFiles) {//默认JDK代理产生的class文件是不输出的,可以设置这个进行输出            AccessController.doPrivileged(new PrivilegedAction<Void>() {                public Void run() {                    try {                        int var1 = var0.lastIndexOf(46);                        Path var2;                        if(var1 > 0) {                            Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar), new String[0]);                            Files.createDirectories(var3, new FileAttribute[0]);                            var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");                        } else {                            var2 = Paths.get(var0 + ".class", new String[0]);                        }                        Files.write(var2, var4, new OpenOption[0]);                        return null;                    } catch (IOException var4x) {                        throw new InternalError("I/O exception saving generated file: " + var4x);                    }                }            });        }        return var4;    }
进入generateClassFile方法

private byte[] generateClassFile() {        this.addProxyMethod(hashCodeMethod, Object.class);        this.addProxyMethod(equalsMethod, Object.class);        this.addProxyMethod(toStringMethod, Object.class);        Class[] var1 = this.interfaces;        int var2 = var1.length;        int var3;        Class var4;        for(var3 = 0; var3 < var2; ++var3) {            var4 = var1[var3];            Method[] var5 = var4.getMethods();            int var6 = var5.length;            for(int var7 = 0; var7 < var6; ++var7) {                Method var8 = var5[var7];                this.addProxyMethod(var8, var4);            }        }        Iterator var11 = this.proxyMethods.values().iterator();        List var12;        while(var11.hasNext()) {            var12 = (List)var11.next();            checkReturnTypes(var12);        }        Iterator var15;        try {            this.methods.add(this.generateConstructor());            var11 = this.proxyMethods.values().iterator();            while(var11.hasNext()) {                var12 = (List)var11.next();                var15 = var12.iterator();                while(var15.hasNext()) {                    ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();                    this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));                    this.methods.add(var16.generateMethod());                }            }            this.methods.add(this.generateStaticInitializer());        } catch (IOException var10) {            throw new InternalError("unexpected I/O Exception", var10);        }        if(this.methods.size() > '\uffff') {            throw new IllegalArgumentException("method limit exceeded");        } else if(this.fields.size() > '\uffff') {            throw new IllegalArgumentException("field limit exceeded");        } else {            this.cp.getClass(dotToSlash(this.className));            this.cp.getClass("java/lang/reflect/Proxy");            var1 = this.interfaces;            var2 = var1.length;            for(var3 = 0; var3 < var2; ++var3) {                var4 = var1[var3];                this.cp.getClass(dotToSlash(var4.getName()));            }            this.cp.setReadOnly();            ByteArrayOutputStream var13 = new ByteArrayOutputStream();            DataOutputStream var14 = new DataOutputStream(var13);            try {                var14.writeInt(-889275714);                var14.writeShort(0);                var14.writeShort(49);                this.cp.write(var14);                var14.writeShort(this.accessFlags);                var14.writeShort(this.cp.getClass(dotToSlash(this.className)));                var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));                var14.writeShort(this.interfaces.length);                Class[] var17 = this.interfaces;                int var18 = var17.length;                for(int var19 = 0; var19 < var18; ++var19) {                    Class var22 = var17[var19];                    var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));                }                var14.writeShort(this.fields.size());                var15 = this.fields.iterator();                while(var15.hasNext()) {                    ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();                    var20.write(var14);                }                var14.writeShort(this.methods.size());                var15 = this.methods.iterator();                while(var15.hasNext()) {                    ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();                    var21.write(var14);                }                var14.writeShort(0);                return var13.toByteArray();            } catch (IOException var9) {                throw new InternalError("unexpected I/O Exception", var9);            }        }    }

默认情况下,JDK产生的class文件是不会输出的成文件的。但是可以设置true',使得输出生成的class文件。这点会在下一篇讲解。

以上就是JDK动态代理的基本流程。