码迷,mamicode.com
首页 > 其他好文 > 详细

关于JDK动态代理的具体实现

时间:2018-04-19 01:48:43      阅读:207      评论:0      收藏:0      [点我收藏+]

标签:垃圾   because   his   ceo   weak   ast   reac   loop   一点   

  最近学习了关于jdk动态代理的相关内容,记录如下:

  jdk动态代理中主要涉及到的相关类:

  1、jdk实现动态代理主要通过目标接口实现,被代理的目标类和生成的代理类必须实现相同的接口

   以下举例:

 1 //共同实现的接口
 2 public interface Base {
 3     void say();
 4 }
 5 
 6 //目标类
 7 public class Subject implements Base {
 8 
 9     public void say(){
10         System.out.println("我是原始类,我说话了");
11     }
12 }

  2、InvocationHandler 接口:这个是java反射包中的一个接口。我将它理解为一个调度者的角色。这个接口只有一个方法。对于每个代理类都会有一个相关的Handler实现。

//方法有三个参数,分别是代理类实例,方法,以及方法的参数
public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;

当我们调用代理类的具体方法时,实际上调用的是Handler的这个方法,后面可以证明。

  3、ClassLoader对象,类加载器。当我们生成一个代理对象实例时,需要指定某一个类加载器来加载生成的代理类。

  4、Proxy类,通过这个类的 静态方法 newProxyInstance 方法能够生成代理类的实例。该方法需要三个参数,分别为:类加载器,接口集合,handler对象实例。其结果就是 通过制定的类加载器生成了一个实现了接口集合的代理类实例,调用该对象的方法需要调用handler的invoke方法。

 

一个简单的动态代理的demo:

//实现自己的Handler
public class MyHandler implements InvocationHandler {

    //这里保留了一个目标对象
    private Base base;

    public MyHandler(Base base){
        this.base = base;
    }

    
    //重写invoke方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("handler 的invoke方法开始调用");
        Object o =  method.invoke(base,args);
        System.out.println("handler 的invoke方法调用完成");
        return o;
    }
}





//测试类
public class Test {


    public static void main(String[] args) {
        // 目标对象
        Subject subject = new Subject();

        //自己定义的handler对象
        MyHandler myHandler = new MyHandler(subject);

        //类加载器
        ClassLoader classLoader = myHandler.getClass().getClassLoader();

        //接口数组,目标对象所有实现的接口
        Class[] interfaces = subject.getClass().getInterfaces();

        Base proxy = (Base) Proxy.newProxyInstance(classLoader,interfaces,myHandler);

        proxy.say();



    }
}

 

 执行结果:

技术分享图片

 

  那么在整个过程重到底发生了什么?

 

代理对象生成在于 :

 Base proxy = (Base) Proxy.newProxyInstance(classLoader,interfaces,myHandler);

点进去看看:

    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);  //关键一,拿到代理类的class类,参数分别为类加载器和接口数组

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
        //以代理类的class类 拿到构造方法
            final Constructor<?> cons = cl.getConstructor(constructorParams);
        //获取构造函数需要的参数,即是handler的实现。
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});//关键二,通过构造函数生成实例并返回,注意这里的构造函数中需要一个handler数组对象。 } 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类。那么这个方法里面是什么呢,点进去看看。

 

 

  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对象是Proxy类的一个成员变量,它的 类型为 WeakCache,从描述来看是一个专门用来缓存Proxy Class的元素。

    /**
     * a cache of proxy classes
     */
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

 对于我来说这个类是一个很难搞得类型,里面所涉及到的东西有很多我都不太懂,只能看个大概。

大体上来说,这是具有二级缓存功能的类。

先看成员变量和构造函数。

//这个变量暂时不用理会,大体上是一个和垃圾回收有关的变量,我也不懂
private
final ReferenceQueue<K> refQueue = new ReferenceQueue<>();
// the key type is Object for supporting null key

//这个map就是用来保存缓存内容的map集合了,前面的concurrent表明这是一个线程安全的map类型,具体实现不清楚,暂时理解为一个普通的map。
//其实从这个map的value的形式也能大致看出,这个value:ConcurrentMap<Object,Supplier<V>>就是二级缓存的部分了,同样是一个map结构。 private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map = new ConcurrentHashMap<>();
private final ConcurrentMap<Supplier<V>, Boolean> reverseMap = new ConcurrentHashMap<>();

//这个BiFunction简单理解为一个函数,它是一个接口,下面用到了再说。
private final BiFunction<K, P, ?> subKeyFactory; private final BiFunction<K, P, V> valueFactory; //构造函数,就是初始化了两个成员变量 public WeakCache(BiFunction<K, P, ?> subKeyFactory, BiFunction<K, P, V> valueFactory) { this.subKeyFactory = Objects.requireNonNull(subKeyFactory); this.valueFactory = Objects.requireNonNull(valueFactory); }

 以上的内容先有个印象,重点在于它的get方法,看源码。

 

//先看参数,对应上面的关键三,K是类加载器,P 是接口数组,这个方法的核心逻辑就是通过类加载器和接口类型数组获取缓存中的代理类Class 对象。   
public V get(K key, P parameter) {
     Objects.requireNonNull(parameter); expungeStaleEntries();     // 简单理解就是通过类加载器对象生成一个一级缓存,map中的key。 Object cacheKey
= CacheKey.valueOf(key, refQueue); // lazily install the 2nd level valuesMap for the particular cacheKey
    //然后根据生成的cacheKey,在map里面找二级缓存的map,就是这里的valueMap
    //通过这里其实就看出来,对于不同的类加载器,所对应的代理类是不同的。一级缓存Map中的Key,其实就是类加载器。 ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);

    //对于第一次取值的时候,valueMap肯定是空,需要完成初始化。这里涉及到一点同步的设计,
if (valuesMap == null) { ConcurrentMap<Object, Supplier<V>> oldValuesMap
      //putIfAbsent方法的核心逻辑是:如果cacheKey是map中的一个key,则返回这个key所对应的value;否则就执行map.put(cacheKey,valueMap=new ConcurrentHashMap<>())。
      //这个方法将对于第一次执行时显然应该执行map.put(cacheKey,valueMap=new ConcurrentHashMap<>()),它会返回null。  
= map.putIfAbsent(cacheKey, valuesMap = new ConcurrentHashMap<>());
        //正常情况下,这里的oldValue应该是位null,如果不为NULL,则表明在同时有另外的线程同时进行了这部分初始化的内容,为了保证一致性,执行下面的代码。
if (oldValuesMap != null) { valuesMap = oldValuesMap; } } // create subKey and retrieve the possible Supplier<V> stored by that // subKey from valuesMap
    //这个我理解为生成二级缓存map中的key,可以看出,二级缓存的key是有类加载器和接口数组共同组成的。
    //subKeyFactory 是成员变量中的一个函数对象,这个函数的apply方法就是你给它参数,他根据参数返回一个对象,有点类似工厂模式,所以这个函数的命名也叫subKeyFactory,这个subKey就是二级缓存map中的key。 Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));

     //通过key,在二级缓存中找value Supplier
<V> supplier = valuesMap.get(subKey);

     //先留着,往下看 Factory factory
= null;
     //循环
while (true) {
        //第二次循环执行这里:
if (supplier != null) { // supplier might be a Factory or a CacheValue<V> instance
          //关键四,这里的supplier实际上是factory,factory.get()是什么? 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
        //这里初始化了factory对象 if (factory == null) { factory = new Factory(key, parameter, subKey, valuesMap); }
        //第一次循环先执行这里,和上面同步的思路类似,第一次value(supplier)放的是一个factory。
if (supplier == null) { supplier = valuesMap.putIfAbsent(subKey, factory); if (supplier == null) { // successfully installed Factory supplier = factory; } // else retry with winning supplier } else {
          //这里是第二次请求get()方法时运行的代码
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); } } } }


到目前为止,还是没有搞清楚代理类的class是怎么来的还需要看Factory类的get()方法。

    private final class Factory implements Supplier<V> {

        private final K key;
        private final P parameter;
        private final Object subKey;
        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;
        }

    //这里就是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()近似的理解为确保不为空,还要继续深入。 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.put(cacheValue, Boolean.TRUE); // try replacing us with CacheValue (this should always succeed) 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; } }


继续查看valueFactory,更具Proxy类中weakCeach属性,可知valueFactory是一个ProxyClassFactory,终于要看到曙光了。

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
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

        @Override
    //需要两个参数,一个类加载器,一个接口数组。
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
        //通过参数中的类加载器将所有的接口数组中的接口Class加载到虚拟机中 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. */

        //对于不是public类型的接口,代理类将定义在相同的包中。验证所有的非public接口在同一个包中,不在一个包中会抛异常。 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( proxyName, interfaces, accessFlags);
try {
          //这里的defineClass0方法的实现是一个本地方法,不用管了,有字节数组就够了。
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()); } } }


既然    ProxyGenerator.generateProxyClass()方法能生成一个字节数组,那我们就来看看这这数组到底是什么。

测试一下:

public class Test1 {
    public static void main(String[] args) {

        Subject sub = new Subject();

        Class[] interfaces = sub.getClass().getInterfaces();

       byte[] classFile =  ProxyGenerator.generateProxyClass("SubProxy",interfaces);

        FileOutputStream out = null;

        try {
            out = new FileOutputStream(new File("SubProxy.class"));
            out.write(classFile);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

得到文件    SubProxy.class

反编译看看:

import com.caiyan.entitry.Base;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class SubProxy extends Proxy implements Base {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

//构造函数,对应了上面的关键二的部分。
public SubProxy(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 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); } } //每个代理方法都调用了handler的invoke方法 public final void say() throws { try { super.h.invoke(this, m3, (Object[])null); } 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); } 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")); m2 = Class.forName("java.lang.Object").getMethod("toString"); m3 = Class.forName("com.caiyan.entitry.Base").getMethod("say"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }


截止目前,基本理清了jdk动态代理的大体实现。

参考了其他的两篇博客:

https://blog.csdn.net/bluetjs/article/details/52263410

https://www.jianshu.com/p/9f5566b5e7fb

 

感谢学习路上能遇到那些贡献经验的大神~

 

关于JDK动态代理的具体实现

标签:垃圾   because   his   ceo   weak   ast   reac   loop   一点   

原文地址:https://www.cnblogs.com/wsppwpswpmt/p/8877870.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!