JDK代理:Proxy源码详解

Proxy类主要提供了以下功能:

  • 为JVM从启动后的运行过程中生成的所有代理类提供了一个缓存,以便用户在获取相同类型的代理类对象时,直接从缓存中取类型,提高性能。
  • 为用户提供了获取代理类对象的API方法:newProxyInstance( … ) 方法。

Proxy类通过一个WeakCache类的实例来缓存代理类。

WeakCache类,顾名思义——弱引用缓存,其缓存的对象都是弱引用对象,把要被缓存的对象封装到一个弱引用实例中,再缓存这个弱引用实例。(了解弱引用,可参考:弱引用——WeakReference——所引用的对象的回收规则

虽然称之为缓存,但是对于缓存空间的管理,WeakCache类并没有主动地提供根据timeout的淘汰功能、或者根据缓存空间大小来淘汰的功能。而是利用GC对弱引用对象的及时清理来实现淘汰功能的,也即对缓存空间的管理。

WeakCache类中,定义了一个类型为 ConcurrentHashMap 的成员变量 map,缓存的数据实际上是存储在这个 map 中,我们称之为cache-map。

private final ConcurrentHashMap<Object, ConcurrentHashMap<Object, Supplier<V>>> 
	map = new ConcurrentHashMap<>();

可以看出,cache-map的 value 又是一个ConcurrentHashMap。

对于Proxy类,实际缓存数据的cache-map中的数据的类型如下:

  • cache-map的key的实际存储的是代理类被加载时所使用的ClassLoader,但是为了实现缓存空间的自动管理,需要将它封装到一个弱引用实例中。WeakCache类中定义了一个名为CacheKey的类,它继承了WeakReference类,用来封装加载代理类的ClassLoader。
  • cache-map的value又是一个ConcurrentHashMap,我们称之为value-map。value-map中存储的是被cache-map中相应的key的classLoader加载的所有代理类。相当于是根据classLoader对所有代理类做了分组,cache-map中的每一个k-v键值对,是一个组,分组依据就是加载代理类的classLoader。
  • value-map的key的类型是Class<?>[] interfaces,存储代理类实现的所有接口。
  • value-map的value实际存储的是被加载的代理类的class对象,但Proxy又把它封装到了一个弱引用实例中了。WeakCache类中定义了一个名为 CacheValue 的类 ,它继承了 WeakReference类,其 referent 引用的是被加载的代理类的 class 对象。

源码

public class Proxy implements java.io.Serializable {

	private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());  // 缓存JVM生成的所有代理类的class对象
...
}
final class WeakCache<K, P, V> {
 
    // the key type is Object for supporting null key
    private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map
        = new ConcurrentHashMap<>();
...
	private static final class CacheKey<K> extends WeakReference<K>{
		private final int hash;
		CacheKey(K key, ReferenceQueue refQueue){
			super(k, refQueue);
			this.hash = System.identityHashCode(key);
		}
	}
	
	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
        }

        @Override
        public int hashCode() {
            return hash;
        }
}        

如上,存放代理类的缓存的类型是WeakCache,在这个类中,定义了一个map来缓存数据。

获取代理类对象

先根据classLoader和要实现的接口数组,从cache中获取代理类的class对象cl。
再调用cl.newInstance(new Object[]{h})方法构造代理类对象。

	@CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        final Class<?>[] intfs = interfaces.clone();        
        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);	// 从缓存中获取代理类的class对象

        /*
         * Invoke its constructor with the designated invocation handler.
         */  

            final Constructor<?> cons = cl.getConstructor(constructorParams);

            return cons.newInstance(new Object[]{h});       
    }

如上,在Proxy类中,为用户提供了静态方法newProxyInstance来生成并获取代理类。其中的三个参数:

  • 第一个参数是用于加载代理类的ClassLoader,
  • 第二个参数是代理类要实现的所有接口组成的一个数组,
  • 第三个参数是一个InvocationHandler对象,这个对象中封装了被代理类对象、和invoke方法。invoke方法中封装的就是代理职责功能的具体实现代码,也就是说代理增强的具体实现。

newProxyInstance方法中,首先以给定的类加载器为key、以被代理类实现的所有接口为sub-key,从cache-map缓存中获取被代理对象的代理类(如果缓存中没有,则生成并存入缓存),接着生成代理类实例并返回。

生成代理类

为了利用WeakReference来自动清理缓存空间,value-map的key也必须是可以被GC按照弱引用规则回收的对象。
WeakCache类被设计为一个高度抽象的通用的缓存类,其并没有直接定义一个继承了WeakReference类的类来封装value-map的key,而是将value-map的key定义为了Object类型,并声明了一个成员变量: private final BiFunction<K, P, ?> subKeyFactory,用户只需提供一个函数式接口 subKeyFactory ,其接口方法只要能把真正的key封装到一个可以被GC按照弱引用规则及时回收的对象中去即可。如此,就把对key的封装的实现延迟到了用户那里。为用户提供了极大的灵活性,只要能确保key能被GC按照弱引用规则及时回收,用户可以随意自行定义生成封装kye的方式。

同理,WeakCache对value-map的value的设计也是如此,其声明了一个函数式接口类型的成员变量private final BiFunction<K, P, V> valueFactory; ,让用户自行定义生成value的方法。

如下:

    private final BiFunction<K, P, ?> subKeyFactory;	// 用于生成subKey的接口函数。subKey是value-map的key
    private final BiFunction<K, P, V> valueFactory;		// 用于生成value-map的value的接口函数。
    
    public WeakCache(BiFunction<K, P, ?> subKeyFactory,
                     BiFunction<K, P, V> valueFactory) {
        this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
        this.valueFactory = Objects.requireNonNull(valueFactory);
    }    

在Proxy类中,分别定义了如下函数式接口:KeyFactory 和 ProxyClassFactory 用于生成value-map的 key 和 value。
其中KeyFactory ,会把用户给定的代理类需要实现的所有接口,中的每一个接口都封装成一个WeakReference实例,而不是将整个数组封装到一个weakRefer实例中。
而ProxyClassFactory ,则肩负了Proxy类的最重要的功能:根据给定代理类要实现的接口,生成代理类的字节码数组;然后使用给定的classLoader,加载代理类的字节码到JVM,并生成相应的代理类的class对象。

KeyFactory会根据代理类要实现的接口数组Class<?> [] interfaces生成value-map的key,那么其生成的key的hashCode()和equals()方法必须符合集合元素的要求。因此Proxy中专门定义了几个类Key1\Key2\KeyX来定义不同个数的接口情况下的key的hashCode和equals。这几个Key类的主要代码就是重写hashCode和equals方法,并定义了hash属性。

尽管KeyFactory是一个BiFunction函数,输入参数是类加载器classLoader、和代理类要实现的接口数组Class<?> [] inters,但实际上生成Key类对象时,仅使用了interfs参数。

ProxyClassFactory则用于生成value-map的value,即生成代理类。
它也是一个BiFunction函数,输入参数有一个类加载器ClassLoader loader、和被代理类实现的所有接口数组Class<?> [] inters
在用于生成并返回代理类的apply方法中:

  • 首先校验参数inters数组中的所有接口是否在所给类加载器loader中,
  • 根据接口数组的信息来判断要生成的代理类的包路径pkgName,再生成代理类的类名称
  • 调用byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags);生成代理类的字节码
  • 最后调用本地方法,使用loader加载代理类,加载代理类的字节码,生成代理类的Class对象,并返回此对象
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); 
        
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);
            }
        }
    }
private static final class KeyX {
        private final int hash;
        private final WeakReference<Class<?>>[] refs;	// 每个接口类,都被封装到一个weakRefer实例中。

        @SuppressWarnings("unchecked")
        KeyX(Class<?>[] interfaces) {
            hash = Arrays.hashCode(interfaces);
            refs = (WeakReference<Class<?>>[])new WeakReference<?>[interfaces.length];
            for (int i = 0; i < interfaces.length; i++) {
                refs[i] = new WeakReference<>(interfaces[i]);
            }
        }

        @Override
        public int hashCode() {
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            return this == obj ||
                   obj != null &&
                   obj.getClass() == KeyX.class &&
                   equals(refs, ((KeyX) obj).refs);
        }

        private static boolean equals(WeakReference<Class<?>>[] refs1,
                                      WeakReference<Class<?>>[] refs2) {
            if (refs1.length != refs2.length) {
                return false;
            }
            for (int i = 0; i < refs1.length; i++) {
                Class<?> intf = refs1[i].get();
                if (intf == null || intf != refs2[i].get()) {
                    return false;
                }
            }
            return true;
        }
    }
    
        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) {

            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            

            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)) {	//  如果接口不是public的,那么其实现类必须和它同包,才能访问到这个接口
                    accessFlags = Modifier.FINAL;
                    String name = intf.getName();	// 实现类必须和接口同一个pkg
                    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);	// 生成代理类的字节码,存放在字节数组中
           
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);	// 使用给定的类加载器,加载代理类的字节码,返回值是代理类的class对象。
           
        }
    }

WeakCache源码

由于WeakCache中用于缓存代理类的cache-map的key是弱引用实例,JVM的GC线程会不断地清理这些弱引用实例(设置其referent=null,即断开对对象引用),并不断监测弱引用对象(被弱引用实例引用的对象)的状态,当弱引用对象状态处于某个特定值时,GC会将相应的弱引用实例入队到pending列表中。另有一个最高优先级的线程会不断地处理pending列表中的弱引用实例、将弱引用实例enque到它们创建时注册到的queue中。

之所以对Reference实例做如此麻烦的处理(GC不断监测并将其添加到pending列表、另有线程不断将pending列表中的实例enque到队列中),是为了告知用户哪些弱引用实例即将被GC回收,给用户清理与之相关 的数据机会。因为如果用户不清理的话,有可能造成内存泄漏。

WeakCache中定义了一个名为refQueue的ReferenceQueue类实例。WeakCache类在做任何操作前,都必须先从map中清理掉已经存在于refQueue中的弱引用实例,再进行要执行的操作。如从缓存cache-map中查找并获取需要的代理类时:


public V get(K key, P parameter) {	// 根据给定的key-classLoader,和parameter-Interfaces[],从map中获取相应的代理类
        expungeStaleEntries();
        ...
}
private void expungeStaleEntries() {	// 从cache-map中清理value-map中的key已经被GC回收的entry
        CacheKey<K> cacheKey;
        while ((cacheKey = (CacheKey<K>)refQueue.poll()) != null) {
            cacheKey.expungeFrom(map, reverseMap);
        }
    }        
 private static final class CacheKey<K> extends WeakReference<K> {
        
        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);	// 此处会置cache-map的value=null
            // remove also from reverseMap if needed
            if (valuesMap != null) {
                for (Object cacheValue : valuesMap.values()) {
                    reverseMap.remove(cacheValue);	 //	由于reverseMap也是一个全局的map,生命周期与JVM相同,因此也要手动清理相应的数据
                }
            }
        }
    }    

在上述代码中,我们可以看到一个reverseMap,这个Map中存储的是所有被GC的代理类的Class对象。之所以要定义这样一个map,是因为size()方法,需要返回JVM生成的现存的代理类的个数,而非cache-map的大小,如下:

 public int size() {
        expungeStaleEntries();
        return reverseMap.size();
 }

查看生成的代理类的源码

在调用Proxy.newProxyInstance方法前,加上一行代码:

//jdk1.8及之前版本使用这个 (我的是1.8,没试过其他版本)
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
//新版本jdk使用这个
System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");

就会在项目根目录生成一个目录:com/sum/proxy/$Proxy0.class。
以下是用户代码:

public class Test {
	
	public static class ComparableProxy implements InvocationHandler{
		
		Object target;
		
		public ComparableProxy(Object target) {
			this.target = target;
		}
		
		@Override
		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			System.out.println(target.toString());
			return method.invoke(target, args);
		}
					
	}
	public static void main(String[] args) {
		ComparableProxy comparableProxy = new ComparableProxy(12);
		System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
		Object proxy = Proxy.newProxyInstance(null, new Class<?>[] {Comparable.class}, comparableProxy);
		System.out.println(proxy.getClass());
	}

}

以下是JVM生成的代理类反编译后的源码:

package com.sun.proxy;

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 Comparable
{
  private static Method m1;
  private static Method m3;
  private static Method m2;
  private static Method m0;

  public $Proxy0(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);
    }
  }

  public final int compareTo(Object paramObject) throws {
    try {
      return ((Integer)this.h.invoke(this, m3, new Object[] { paramObject }))
		.intValue();
    }catch (Error|RuntimeException localError) {
      throw localError;
    } catch (Throwable localThrowable) {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final String toString() throws {
    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() throws {
    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("java.lang.Comparable").getMethod("compareTo", new Class[] { Class.forName("java.lang.Object") });
      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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值