设计模式--JDK动态代理的实现与原理解析(2)

来源:互联网 发布:怎么样做淘宝客赚钱 编辑:程序博客网 时间:2024/06/06 18:36

在上一篇博客中,实现了JDK的动态代理。但是,我们不仅要学会如何使用,更要理解其内部的具体实现。
我们是通过此方法获得对目标对象的代理类:

    public Object getProxy() {        //参数意义:1. 当前类加载器 2. 目标类的class对象 3. 目标类的所有接口 4. 实现InvocationHandler接口的类        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this);    }

接下来,进入newProxyInstance()中看一下其实现逻辑(JDK1.8的实现):具体的解释都在代码中体现

 public static Object newProxyInstance(ClassLoader loader,                                          Class<?>[] interfaces,                                          InvocationHandler h)        throws IllegalArgumentException    {        //Objects提供了操作Object类的一些实用方法。判断h不为空,为空抛出空指针异常        Objects.requireNonNull(h);        // 复制接口的class对象        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            //private static final Class<?>[] constructorParams ={ InvocationHandler.class };            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;                    }                });            }            //利用构造函数,创建代理类实例,参数是自己实现了InvocationHandler的代理逻辑类            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);        }    }

上边的源码中其实核心点就是我注释的那几行。其中生成代理类的class对象的方法为:

Class<?> cl = getProxyClass0(loader, intfs);

进入此方法中看一下:

    private static Class<?> getProxyClass0(ClassLoader loader,                                           Class<?>... interfaces) {        //当被代理的目标类的接口大于65535,则抛出异常。---估计没人会写这种代码吧        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);    }

这个方法是获得代理类对象的关键。

return proxyClassCache.get(loader, interfaces);

通过上边的注释,就可知道,对代理类进行了缓存,当查找缓存中没有时,就会通过ProxyClassFactory来创建代理类。可以查看proxyClassCache变量的定义:

    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

从定义上可以看到,它是通过WeakCache来实现缓存的。WeakCache Java的弱引用。

    public WeakCache(BiFunction<K, P, ?> subKeyFactory,                     BiFunction<K, P, V> valueFactory) {        this.subKeyFactory = Objects.requireNonNull(subKeyFactory);        this.valueFactory = Objects.requireNonNull(valueFactory);    }

构造函数,传入两个类对象:new KeyFactory()和new ProxyClassFactory()。这两个类都是Proxy类的内部类,且都实现了BiFunction接口。
然后,我们接着回到 proxyClassCache.get(loader, interfaces)方法,进入此方法中看一下实现:

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

这里的缓存实现暂不仔细看,主要是看ProxyClassFactory是如何生成代理类的。ProxyClassFactory是实现了BiFunction接口的apply方法。

  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        // 代理类名字的计数器。最后组成代理类名$Proxy0   $Proxy1  ...        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");                    }                }            }            //公共接口包名:默认:com.sun.proxy            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 {               //根据二进制的字节码文件生成代理类的class对象                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());            }        }    }

接下来,我们看一下是如何生成字节码文件的:

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(                proxyName, interfaces, accessFlags);

ProxyGenerator是sun.misc的包。此方法为:

    public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {        ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);        final byte[] var4 = var3.generateClassFile();        if(saveGeneratedFiles) {            AccessController.doPrivileged(new PrivilegedAction() {                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方法才是真正生成代理类字节码文件的方法。

final byte[] var4 = var3.generateClassFile();

这个方法的源码有点长:

private byte[] generateClassFile() {//addProxyMethod系列方法就是将接口的方法和Object的hashCode,equals,toString方法添加到代理方法容器(proxyMethods)        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);            }        }    }

注意开头的三个addProxyMethod方法是只将Object的hashcode,equals,toString方法添加到代理方法容器中,代理类除此之外并没有重写其他Object的方法,所以除这三个方法外,代理类调用其他方法的行为与Object调用这些方法的行为一样不通过Invoke。
没有完全看懂上边的代码。还可以查看addProxyMethod的源码。这里就不看了。

在动态代理中InvocationHandler是核心,每个代理实例都具有一个关联的调用处理程序(InvocationHandler)。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序(InvocationHandler)的 invoke 方法。所以对代理方法的调用都是通InvocationHadler的invoke来实现中,而invoke方法根据传入的代理对象,方法和参数来决定调用代理的哪个方法
我们来看一下生成的代理类$Proxy0:在main函数中生成代理类之前添加如下代码:

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

这会将生成的代理类的class代码写入到磁盘中项目路径下,路径为com.sun.proxy。需要提前创建。
反编译后的class文件为:

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package com.sun.proxy;import com.blog.jdkproxy.IUserDao;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 IUserDao {    private static Method m1;    private static Method m2;    private static Method m3;    private static Method m4;    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})).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);        }    }    public final int add() throws  {        try {            return ((Integer)super.h.invoke(this, m3, (Object[])null)).intValue();        } catch (RuntimeException | Error var2) {            throw var2;        } catch (Throwable var3) {            throw new UndeclaredThrowableException(var3);        }    }    public final int delete() throws  {        try {            return ((Integer)super.h.invoke(this, m4, (Object[])null)).intValue();        } 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)).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("com.blog.jdkproxy.IUserDao").getMethod("add", new Class[0]);            m4 = Class.forName("com.blog.jdkproxy.IUserDao").getMethod("delete", 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作为参数的构造方法。重写了Object类的equals、hashCode、toString,它们都只是简单的调用了InvocationHandler的invoke方法,即可以对其进行特殊的操作,也就是说JDK的动态代理还可以代理上述三个方法。重写了接口的方法:

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

并且利用h.invoke(this, m3, (Object[])null))来调用横切逻辑。这也能看到,利用JDK动态代理来实现时,invoke的横切逻辑(增强)是针对所有方法的。且只能对接口中的方法进行代理

原创粉丝点击