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