代理详解(jdk动态代理-源码分析)

上篇文章我们简单看了下jdk动态代理的例子代理详情(jdk动态代理),我们通过Proxy类的静态方法newProxyInstance方法去生成一个代理类,这个静态方法接收三个参数,分别是目标类的类加载器,目标类实现的接口集合,InvocationHandler实例,最后返回一个Object类型的代理类。我们先从该方法开始,看看代理类是怎样一步一步造出来的,废话不多说,直接上代码

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

       
        //重点:获取代理的class对象  
        Class<?> cl = getProxyClass0(loader, intfs);

        
        try {
            //验证权限
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
            //获取class对象中的参数为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;
                    }
                });
            }
            //通过构造方法构造对象
            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);
        }
    }

重点方法是getProxyClass0,该方法返回的是代理类的class对象,虽然不知道获取细节,但是我们了解了构造的一些流程,构造代理class对象->获取class中的带有InvocationHandler类型的构造方法->传入InvocationHandler构造对象。

我们可以简单的想一个这个class中应该有个构造方法,并且是带有InvocationHandler参数的,这个类的部分应该长这样

想象代理类

public class XXXProxy{
    
    InvocationHandler invocationHandler ;

    public XXXProxy(InvocationHandler h){
        this.invocationHandler =h;
    }

    sayHello(String name){
        invocationHandler.invoke(参数。。。。)

    }


}

是不是应该是这样的?在不考虑其他的情况下,按说应该是这样的,我们继续解析。

接下来看getProxyClass0方法

private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        //接口数量验证,我们一般开发实现接口有1-2个就不错了。。。。
        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
        //上面解释很清楚了,优先从缓存获取,如果没有获取到在通过ProxyClassFactory创建
        return proxyClassCache.get(loader, interfaces);
    }

这里又涉及到一个cache,从注释上看是用来存储代理对象的,下面看下proxyClassCache

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

这里看到了两个类KeyFactory, ProxyClassFactory,ProxyClassFactory是用来创建代理的,前面说过,KeyFactory暂且还不知道,后面再说。

我们看下WeakCache类,其中成员变量与构造方法如下

    //引用队列,涉及到java的四种引用类型,强,软,弱,虚
    private final ReferenceQueue<K> refQueue
        = new ReferenceQueue<>();
    // the key type is Object for supporting null key
    //缓存的底层实现, 双层map实现
    private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map
        = new ConcurrentHashMap<>();
    //reverseMap记录了所有代理类生成器是否可用, 这是为了实现缓存的过期机制
    private final ConcurrentMap<Supplier<V>, Boolean> reverseMap
        = new ConcurrentHashMap<>();
    //生成二级缓存key的工厂, 这里传入的是KeyFactory
    private final BiFunction<K, P, ?> subKeyFactory;
    //生成value的工厂,这里传入的是ProxyClassFactory
    private final BiFunction<K, P, V> valueFactory;

    /**
     * Construct an instance of {@code WeakCache}
     *
     * @param subKeyFactory a function mapping a pair of
     *                      {@code (key, parameter) -> sub-key}
     * @param valueFactory  a function mapping a pair of
     *                      {@code (key, parameter) -> value}
     * @throws NullPointerException if {@code subKeyFactory} or
     *                              {@code valueFactory} is null.
     */
    public WeakCache(BiFunction<K, P, ?> subKeyFactory,
                     BiFunction<K, P, V> valueFactory) {
        this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
        this.valueFactory = Objects.requireNonNull(valueFactory);
    }

成员变量与方法,主要定义了一些数据结构,map用来存储代理类,reverseMap是为了实现缓存的过期机制。

首先先看一下WeakCache中的几个内部类

内部类1:CacheKey

用来生成一级缓存的key和回收reverseMap的过期value,这个类继成了WeakReference弱引用,当其在gc运行时回收其引用对象.

private static final class CacheKey<K> extends WeakReference<K> {

        // a replacement for null keys
        private static final Object NULL_KEY = new Object();

        static <K> Object valueOf(K key, ReferenceQueue<K> refQueue) {
            return key == null
                   // null key means we can't weakly reference it,
                   // so we use a NULL_KEY singleton as cache key
                   ? NULL_KEY
                   // non-null key requires wrapping with a WeakReference
                   : new CacheKey<>(key, refQueue);
        }


。。。。
      
    void expungeFrom(ConcurrentMap<?, ? extends ConcurrentMap<?, ?>> map,
                         ConcurrentMap<?, Boolean> reverseMap) {
            // removing just by key is always safe here because after a CacheKey
            // is cleared and enqueue-ed it is only equal to itself
            // (see equals method)...
            ConcurrentMap<?, ?> valuesMap = map.remove(this);
            // remove also from reverseMap if needed
            if (valuesMap != null) {
                for (Object cacheValue : valuesMap.values()) {
                    reverseMap.remove(cacheValue);
                }
            }
        }
}

内部类2:Factory

通过ProxyClassFactory的apply方法获取代理类class对象,并把代理类放入reverseMap,与二级缓存缓存起来。

private final class Factory implements Supplier<V> {

        private final K key;//类加载器一级缓存key
        private final P parameter;//接口
        private final Object subKey;//二级缓存key
        private final ConcurrentMap<Object, Supplier<V>> valuesMap; //二级缓存

        Factory(K key, P parameter, Object subKey,
                ConcurrentMap<Object, Supplier<V>> valuesMap) {
            this.key = key;
            this.parameter = parameter;
            this.subKey = subKey;
            this.valuesMap = valuesMap;
        }

        @Override
        public synchronized V get() { // serialize access
            // 获取二级缓存value
            Supplier<V> supplier = valuesMap.get(subKey);
            //不是本身返回空,这里supplier 可能是Factory也可能是CacheValue
            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
            //如果是工厂则调用ProxyClassFactory的apply生成代理类
            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);

            // put into reverseMap
            //放到reverseMap中用于过期删除
            reverseMap.put(cacheValue, Boolean.TRUE);

            // try replacing us with CacheValue (this should always succeed)
            //生成的value放到二级缓存中,一定成功
            if (!valuesMap.replace(subKey, this, cacheValue)) {
                throw new AssertionError("Should not reach here");
            }

            // successfully replaced us with new CacheValue -> return the value
            // wrapped by it
            //返回代理类
            return value;
        }
    }

内部类3:CacheValue

此类是把代理包装成弱引用类型,gc进行垃圾回收时,回收此类引用对象

private static final class CacheValue<V>
        extends WeakReference<V> implements Value<V>
    {
        private final int hash;

        CacheValue(V value) {
            super(value);
            this.hash = System.identityHashCode(value); // compare by identity
        }

内部类4:Proxy中的KeyFactory

此类的作用是根据接口数量去去生成key,此处可以看到做常用的类就一个接口

private static final class KeyFactory
        implements BiFunction<ClassLoader, Class<?>[], Object>
    {
        @Override
        public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
            switch (interfaces.length) {
                case 1: return new Key1(interfaces[0]); // the most frequent
                case 2: return new Key2(interfaces[0], interfaces[1]);
                case 0: return key0;
                default: return new KeyX(interfaces);
            }
        }
    }

内部类5:Proxy中的ProxyClassFactory

1. 在代码中可以看到JDK生成的代理类的类名是“$Proxy”+序号。

2. 如果接口是public的,代理类默认是public final的,并且生成的代理类默认放到com.sun.proxy这个包下。

3. 如果接口是非public的,那么代理类也是非public的,并且生成的代理类会放在对应接口所在的包下。

4. 如果接口是非public的,并且这些接口不在同一个包下,那么就会报错。

5.字节码是用ProxyGenerator类生成的

private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        //代理类前缀
        private static final String proxyClassNamePrefix = "$Proxy";

        //用原子类来生成代理类的序号, 以此来确定唯一的代理类
        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) {
                
                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");
                }
                //是否为接口
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                //是否重复
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }
            //代理生成的包
            String proxyPkg = null;  
            //生成代理类的访问标志,默认 public final  
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            
            for (Class<?> intf : interfaces) {
                //接口访问标志
                int flags = intf.getModifiers();
                //接口不是public,生成的代理类和接口在同一包下
                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)) {
                        //这里表示接口不是public且接口在不同的包报错
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }
            //接口都是public 那生成的代理类都放到默认的包下:com.sun.proxy
            if (proxyPkg == null) {
                
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }

            //生成代理类的序号
            long num = nextUniqueNumber.getAndIncrement();
            //生成代理类全限定名,结构为包名+前缀+序号
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            //用ProxyGenerator类生成类的字节码,重点
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                //调用本地方法根据字节码生成class对象
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
         
                throw new IllegalArgumentException(e.toString());
            }
        }
    }

还有一个方法需要讲一下

WeakCache的expungeStaleEntries方法

用于回收过期的值,这里有个引用队列refQueue,这个队列一般和除强引用的引用类一起用,这里和弱引用一起用,作用是,当gc进行垃圾回收时,弱引用关联的对象被回收,回收时会把弱引用对象放到引用队列中。如果回收队列中有值则表明此对象已经被回收。

private void expungeStaleEntries() {
        CacheKey<K> cacheKey;
        //引用队列中不为空,说明有对象或者说是key被gc了,需要在缓存中去掉
        while ((cacheKey = (CacheKey<K>)refQueue.poll()) != null) {
            //缓存删除
            cacheKey.expungeFrom(map, reverseMap);
        }
    }

调用CacheKey的expungeFrom方法

 void expungeFrom(ConcurrentMap<?, ? extends ConcurrentMap<?, ?>> map,
                         ConcurrentMap<?, Boolean> reverseMap) {
            // removing just by key is always safe here because after a CacheKey
            // is cleared and enqueue-ed it is only equal to itself
            // (see equals method)...
            //先从一级缓存去除key
            ConcurrentMap<?, ?> valuesMap = map.remove(this);
            // remove also from reverseMap if needed
            if (valuesMap != null) {
                //再从reverseMap去除所有关联的cacheValue
                for (Object cacheValue : valuesMap.values()) {
                    reverseMap.remove(cacheValue);
                }
            }
        }

 

接下来看下WeakCache的get方法,其调用是从proxyClassCache.get(loader, interfaces)开始的,传入类加载器和接口。

public V get(K key, P parameter) {
        //判断空
        Objects.requireNonNull(parameter);
        //清除过期缓存
        expungeStaleEntries();
        //根据类加载器生成一级缓存的key,key被包装成弱引用
        Object cacheKey = CacheKey.valueOf(key, refQueue);

        // lazily install the 2nd level valuesMap for the particular cacheKey
        //根据key获取二级缓存
        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
        //二级缓存为空
        if (valuesMap == null) {
             //putIfAbsent方法,如果map中存在key则返回存在的值,不存在则放入并返回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
        //构造二级缓存的subkey,根据keyFactory构造
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        //根据subkey获取value的值
        Supplier<V> supplier = valuesMap.get(subKey);
        Factory factory = null;

        while (true) {
            //supplier 不为空说明有值
            if (supplier != null) {
                // supplier 可能是Factory 或者CacheValue<V>,如果是CacheValue则调用其get
                //方法返回value值,如果是Factory则调用get方法生成类
                //取value值,不为空则返回
                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
            //supplier 为空
            if (factory == null) {
                //构造factory 
                factory = new Factory(key, parameter, subKey, valuesMap);
            }

            if (supplier == null) {
                //factory 作为二级缓存的值
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    // successfully installed Factory
                    supplier = factory;
                }
                //如果此时supplier 不为空则继续循环
                // 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);
                }
            }
        }
    }

ok基本上所有的源码都翻了接下来写下流程

1、Proxy.newProxyInstance生成代理,主要做了三件事,@1 验证 @2  getProxyClass0方法获取class对象 @3 根据class对象利用反射获取带有InvocationHandler参数的构造函数,根据此构造函数(cons.newInstance(new Object[]{h}))构造对象

2、getProxyClass0方法获取class对象,委托给proxyClassCache缓存,从proxyClassCache缓存中去get

3、proxyClassCache.get方法,@1 清除缓存过期的key与value @2 根据key构造CacheKey,并根据cachekey从缓存中取出二级缓存 @3 生成二级缓存的key 并根据二级缓存的key去获取value,调用value(supplier)的get方法获取class对象 

4、supplier.get方法返回class对象 这里分两种情况 第一种、如果supplier是cachevalue则直接调用其get方法返回class对象,如果supplier是factory对象则调用get方法去生成class对象

5、针对4的第二种情况,factory.get方法,@1 ProxyClassFactory.apply方法生成value,并封装成弱引用CacheValue @2 把生成的cahcevalue放入缓存中 @3 返回没包装的class对象

6、ProxyClassFactory.apply,@1 验证接口正确性 @2 生成代理类包名 @3 ProxyGenerator.generateProxyClass生成class对象字节码 @4 根据字节码生成class对象

7、ProxyGenerator.generateProxyClass这个方法不解析,但是分享一篇文章ProxyGenerator生成代理类的字节码文件解析

虽然不解析,我们要看下这个类生成的字节码长什么样,所以我们自己调用一下这个方法,代码如下

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                "com.example.lrn_manager.proxy.jdk.$Proxy1", new Class[]{Hello.class}, Modifier.PUBLIC | Modifier.FINAL);
        String path = "D://$Proxy1.class";
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(path);
            out.write(proxyClassFile);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

生成的字节码我们写到文件,然后用反编译软件查看其内容如下,和我们猜想的基本一致

1.代理类默认继承Porxy类,因为Java中只支持单继承,所以JDK动态代理只能去实现接口。

2.代理方法都会去调用InvocationHandler的invoke()方法,因此我们需要重写InvocationHandler的invoke()方法。

3.调用invoke()方法时会传入代理实例本身,目标方法和目标方法参数。解释了invoke()方法的参数是怎样来的。

package com.example.lrn_manager.proxy.jdk;

import com.example.lrn_manager.proxy.jdk_proxy.Hello;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
//代理类实现了我们的接口,并且继承了proxy类
public final class $Proxy1
  extends Proxy
  implements Hello
{
  private static Method m1;
  private static Method m3;
  private static Method m2;
  private static Method m0;
  //有个带有InvocationHandler 参数的构造方法
  public $Proxy1(InvocationHandler paramInvocationHandler)
  {
    super(paramInvocationHandler);
  }
  
  public final boolean equals(Object paramObject)
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  //代理类的sayHello去调用了我们的InvocationHandler 的invoke方法
  public final void sayHello(String paramString)
  {
    try
    {
      //m3为目标函数
      this.h.invoke(this, m3, new Object[] { paramString });
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final String toString()
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final int hashCode()
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("com.example.lrn_manager.proxy.jdk_proxy.Hello").getMethod("sayHello", new Class[] { Class.forName("java.lang.String") });
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jackson陈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值