再谈JDK动态代理

之前写过一篇JDK动态代理的,但回看了一遍发现不是很深刻。那时候只是比较粗浅的看了一遍,理解上也不是很清晰,所以这次打算重新写一遍关键流程,希望以后再看的时候能够让我更清晰的理清动态代理的关键步骤。
就取原来分析的主代码:

public class MyProxy {
    public static Object proxy(Object target) {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                new MyInvationHandler(target));
    }

    private static class MyInvationHandler implements InvocationHandler {

        private Object target;

        public MyInvationHandler(Object target) {
            super();
            this.target = target;
        }

        public Object getTarget() {
            return target;
        }

        public void setTarget(Object target) {
            this.target = target;
        }

        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("method:"+method.getName()+"    isInvoked!");
            // 调用被代理对象的方法
            Object res = method.invoke(target, args);
            
            return res;
        }
        
    }
    
}

以及动态代理后自动生成的代码:

package com.sun.proxy;

import Proxy.*;
import java.lang.reflect.*;

public final class $Proxy0 extends Proxy implements Girl
{
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m4;
    private static Method m0;
    
    public $Proxy0(final InvocationHandler invocationHandler) {
        super(invocationHandler);
    }
    
    public final boolean equals(final Object o) {
        try {
            return (boolean)super.h.invoke(this, $Proxy0.m1, new Object[] { o });
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    public final String toString() {
        try {
            return (String)super.h.invoke(this, $Proxy0.m2, null);
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    public final boolean dating(final float n) {
        try {
            return (boolean)super.h.invoke(this, $Proxy0.m3, new Object[] { n });
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    public final void happy() {
        try {
            super.h.invoke(this, $Proxy0.m4, null);
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    public final int hashCode() {
        try {
            return (int)super.h.invoke(this, $Proxy0.m0, null);
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    
    static {
        try {
            $Proxy0.m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            $Proxy0.m2 = Class.forName("java.lang.Object").getMethod("toString", (Class<?>[])new Class[0]);
            $Proxy0.m3 = Class.forName("Proxy.Girl").getMethod("dating", Float.TYPE);
            $Proxy0.m4 = Class.forName("Proxy.Girl").getMethod("happy", (Class<?>[])new Class[0]);
            $Proxy0.m0 = Class.forName("java.lang.Object").getMethod("hashCode", (Class<?>[])new Class[0]);
        }
        catch (NoSuchMethodException ex) {
            throw new NoSuchMethodError(ex.getMessage());
        }
        catch (ClassNotFoundException ex2) {
            throw new NoClassDefFoundError(ex2.getMessage());
        }
    }
}

来进行解析吧。
首先看主代码:

public class MyProxy {
    public static Object proxy(Object target) {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                new MyInvationHandler(target));
    }

    private static class MyInvationHandler implements InvocationHandler {

        private Object target;

        public MyInvationHandler(Object target) {
            super();
            this.target = target;
        }

        public Object getTarget() {
            return target;
        }

        public void setTarget(Object target) {
            this.target = target;
        }

        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("method:"+method.getName()+"    isInvoked!");
            // 调用被代理对象的方法
            Object res = method.invoke(target, args);
            
            return res;
        }
        
    }
    
}

最主要是Proxy这个类,其次是InvocationHandler的实现类;关于JDK动态代理,这两点说的人太多了。
下面主要分析Proxy这个类的newProxyInstance()这个方法:

    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
    	//首先要求这个InvocationHandler不能为空,但InvocationHandler虽然最为主要实现,但对于框架来讲其实InvocationHandler的实现类可以讲的地方不多。
        Objects.requireNonNull(h);
		
		//做一份拷贝,毕竟是做增强,没必要将原来的类进行重写。
        final Class<?>[] intfs = interfaces.clone();
        //这个SM出现在源码里,就我见过的源码中,一般都是为了解决访问权限问题的。
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
         //这个方法很主要,重要的方法我会放在下文按数字顺序进行讲解————————(1)
        //先说下作用,创建代理类的字节码,并缓存在WeakCache这个数据结构中
        //WeakCache这个类也很重要—————————————————————————————————— (2)
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
			//cl为已经生成的字节码了,就是本文的第二大块代码。
			//这里是获得构造器,该构造器的形参为:
			//**InvocationHandler**。
            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<?> cl = getProxyClass0(loader, intfs);

注释已经写了,代码是在这里生成的,就来看看到底是怎么回事吧:

    /**
     * Generate a proxy class.  Must call the checkProxyAccess method
     * to perform permission checks before calling this.
     */
    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
        //这个get方法是生成代码的主要入口(好像也没其他入口了...就当我说了句废话吧
        return proxyClassCache.get(loader, interfaces);
    }

这个proxyClassCache就是我在(2)处说的另外一个重要的类,它有些很关键的内部类,我们边讲边比划:

   public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);
		
		//叫这个名字的方法,一般是处理些过期的Entries
		//印象中ThreadLocal里面也有类似的方法
		//ThreadLocal中是为了解决内存泄露问题的,但不太好用,因为调用时间不确定
		//可能会泄露了很长时间,还没被收集,所以推荐的实践是用完以后手动置null
        expungeStaleEntries();
		
		//key不为空 创建一个新的CacheKey,为空返回一个固定的Object
        Object cacheKey = CacheKey.valueOf(key, refQueue);

        // lazily install the 2nd level valuesMap for the particular cacheKey
        //看注释,懒加载valueMap,map为ConcurrentHashMap,没找到再初始化
        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
        //没找到就创建
        if (valuesMap == null) {
        	//putIfAbsent
            ConcurrentMap<Object, Supplier<V>> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            //put成功了,就为valuesMap赋值
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }

        // create subKey and retrieve the possible Supplier<V> stored by that
        // subKey from valuesMap
        //subKeyFactory,这个是KeyFactory类
        //apply()方法主要看传来了多少个接口,来创建不同的Key类
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        //如果valuesMap刚初始化,则get到的supplier肯定为null
        Supplier<V> supplier = valuesMap.get(subKey);
        Factory factory = null;
		
		//不断的为factory赋值
        while (true) {
            if (supplier != null) {
                // supplier might be a Factory or a CacheValue<V> instance
                //这一行是关键
                //看上去是supplier.get()
                //但最终调用的是ProxyClassFactory.apply()
                //而动态生成的代码的方法就在上面那个apply()方法中
                //但有点绕弯,是Factory.get()里面调用的
                //大概的转向就是:
                //supplier.get == factory.get()[synchronized修饰的] -->
           		//value = Objects.requireNonNull(valueFactory.apply(key, parameter));
           		//构造函数传来的valueFacotry就是ProxyClassFactory
                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
            //为值为null的factory赋值
            if (factory == null) {
                factory = new Factory(key, parameter, subKey, valuesMap);
            }
			//第一次肯定为null
            if (supplier == null) {
            	//CAS将factory插入valuesMap,key为subKey
                supplier = valuesMap.putIfAbsent(subKey, factory);
              	//双重判断  
                if (supplier == null) {
                    // successfully installed Factory
                    //讲supplier赋值为factory
                    //因为Factory是Supplier接口的实现类
                    supplier = factory;
                }
                // else retry with winning supplier
                //进入情况为,并发情况下supplier已经创建好,加入到valuesMap中
                //但factory还没有赋值给supplier
                //这里就尝试将valuesMap中的supplier赋值为factory
                //成功就将factory赋值给supplier
                //不成功就获取当前valuesMap中的factory
            } 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);
                }
            }
        }
    }

大体流程就是这样子了,最后我们粗略的看看怎么实现的吧,就不写注释了,除了处理过程麻烦了点,整体逻辑还是比较简单清晰的:
Factory类中的get():

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

ProxyClassFactory类中的apply()方法:
一堆代码就不贴了,主要看这个,JDK1.8代码在639行

			//处理逻辑在这里:		
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
            	//传入classloader,proxyName,将字节数组转化成Class<>
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            }   

点进去看:

	public static byte[] generateProxyClass(String var0, Class<?>[] var1, int var2) {
      ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
      //看这个
      byte[] var4 = var3.generateClassFile();
      if (saveGeneratedFiles) {
         AccessController.doPrivileged(new 1(var0, var4));
      }

      return var4;
   }

点击去几百行的代码,就不全贴了,贴点…原来那篇文章里猜测的东西吧,只是当时追的不够深:

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

那时候不明白为什么会出现hashCode,equals和toString;在这里就已经很清晰了。
最终我们回到文章开头,第二大块代码那里。
大体上就是这样了。
生成了代理类以后,最终对象的方法调用,大部分都被代理为:

            return (int)super.h.invoke(this, $Proxy0.m?/**?为0-n的整数,取决于有多少个代理方法**/, null);

或者:

            return (boolean)super.h.invoke(this, $Proxy0.m?, new Object[] { n });

h,就是传入的自定义的InvocationHandler。最终通过反射来进行方法的调用。

好了,关于动态代理应该就这么多了,谢谢观看,如果还有问题可以联系我,也可以留言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值