上篇文章我们简单看了下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());
}
}
}