之前写过一篇JDK动态代理的,但回看了一遍发现不是很深刻。那时候只是比较粗浅的看了一遍,理解上也不是很清晰,所以这次打算重新写一遍关键流程,希望以后再看的时候能够让我更清晰的理清动态代理的关键步骤。
就取原来分析的主代码:
public class MyProxy {
public static Object proxy(Object target) {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
new MyInvationHandler(target));
}
private static class MyInvationHandler implements InvocationHandler {
private Object target;
public MyInvationHandler(Object target) {
super();
this.target = target;
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method:"+method.getName()+" isInvoked!");
// 调用被代理对象的方法
Object res = method.invoke(target, args);
return res;
}
}
}
以及动态代理后自动生成的代码:
package com.sun.proxy;
import Proxy.*;
import java.lang.reflect.*;
public final class $Proxy0 extends Proxy implements Girl
{
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m4;
private static Method m0;
public $Proxy0(final InvocationHandler invocationHandler) {
super(invocationHandler);
}
public final boolean equals(final Object o) {
try {
return (boolean)super.h.invoke(this, $Proxy0.m1, new Object[] { o });
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
}
public final String toString() {
try {
return (String)super.h.invoke(this, $Proxy0.m2, null);
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
}
public final boolean dating(final float n) {
try {
return (boolean)super.h.invoke(this, $Proxy0.m3, new Object[] { n });
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
}
public final void happy() {
try {
super.h.invoke(this, $Proxy0.m4, null);
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
}
public final int hashCode() {
try {
return (int)super.h.invoke(this, $Proxy0.m0, null);
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
}
static {
try {
$Proxy0.m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
$Proxy0.m2 = Class.forName("java.lang.Object").getMethod("toString", (Class<?>[])new Class[0]);
$Proxy0.m3 = Class.forName("Proxy.Girl").getMethod("dating", Float.TYPE);
$Proxy0.m4 = Class.forName("Proxy.Girl").getMethod("happy", (Class<?>[])new Class[0]);
$Proxy0.m0 = Class.forName("java.lang.Object").getMethod("hashCode", (Class<?>[])new Class[0]);
}
catch (NoSuchMethodException ex) {
throw new NoSuchMethodError(ex.getMessage());
}
catch (ClassNotFoundException ex2) {
throw new NoClassDefFoundError(ex2.getMessage());
}
}
}
来进行解析吧。
首先看主代码:
public class MyProxy {
public static Object proxy(Object target) {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
new MyInvationHandler(target));
}
private static class MyInvationHandler implements InvocationHandler {
private Object target;
public MyInvationHandler(Object target) {
super();
this.target = target;
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method:"+method.getName()+" isInvoked!");
// 调用被代理对象的方法
Object res = method.invoke(target, args);
return res;
}
}
}
最主要是Proxy这个类,其次是InvocationHandler的实现类;关于JDK动态代理,这两点说的人太多了。
下面主要分析Proxy这个类的newProxyInstance()这个方法:
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
//首先要求这个InvocationHandler不能为空,但InvocationHandler虽然最为主要实现,但对于框架来讲其实InvocationHandler的实现类可以讲的地方不多。
Objects.requireNonNull(h);
//做一份拷贝,毕竟是做增强,没必要将原来的类进行重写。
final Class<?>[] intfs = interfaces.clone();
//这个SM出现在源码里,就我见过的源码中,一般都是为了解决访问权限问题的。
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
*/
//这个方法很主要,重要的方法我会放在下文按数字顺序进行讲解————————(1)
//先说下作用,创建代理类的字节码,并缓存在WeakCache这个数据结构中
//WeakCache这个类也很重要—————————————————————————————————— (2)
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
//cl为已经生成的字节码了,就是本文的第二大块代码。
//这里是获得构造器,该构造器的形参为:
//**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;
}
});
}·
//讲自定义的InvocationHandler实现类传入,看方法名,是创建了一个实例
//就不细看了
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);
}
}
动态代理主要还是在动态生成代码上,所以主要来讲讲:
Class<?> cl = getProxyClass0(loader, intfs);
注释已经写了,代码是在这里生成的,就来看看到底是怎么回事吧:
/**
* Generate a proxy class. Must call the checkProxyAccess method
* to perform permission checks before calling this.
*/
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
//这个get方法是生成代码的主要入口(好像也没其他入口了...就当我说了句废话吧
return proxyClassCache.get(loader, interfaces);
}
这个proxyClassCache就是我在(2)处说的另外一个重要的类,它有些很关键的内部类,我们边讲边比划:
public V get(K key, P parameter) {
Objects.requireNonNull(parameter);
//叫这个名字的方法,一般是处理些过期的Entries
//印象中ThreadLocal里面也有类似的方法
//ThreadLocal中是为了解决内存泄露问题的,但不太好用,因为调用时间不确定
//可能会泄露了很长时间,还没被收集,所以推荐的实践是用完以后手动置null
expungeStaleEntries();
//key不为空 创建一个新的CacheKey,为空返回一个固定的Object
Object cacheKey = CacheKey.valueOf(key, refQueue);
// lazily install the 2nd level valuesMap for the particular cacheKey
//看注释,懒加载valueMap,map为ConcurrentHashMap,没找到再初始化
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
//没找到就创建
if (valuesMap == null) {
//putIfAbsent
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
//put成功了,就为valuesMap赋值
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
// create subKey and retrieve the possible Supplier<V> stored by that
// subKey from valuesMap
//subKeyFactory,这个是KeyFactory类
//apply()方法主要看传来了多少个接口,来创建不同的Key类
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
//如果valuesMap刚初始化,则get到的supplier肯定为null
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
//不断的为factory赋值
while (true) {
if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
//这一行是关键
//看上去是supplier.get()
//但最终调用的是ProxyClassFactory.apply()
//而动态生成的代码的方法就在上面那个apply()方法中
//但有点绕弯,是Factory.get()里面调用的
//大概的转向就是:
//supplier.get == factory.get()[synchronized修饰的] -->
//value = Objects.requireNonNull(valueFactory.apply(key, parameter));
//构造函数传来的valueFacotry就是ProxyClassFactory
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
//为值为null的factory赋值
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
//第一次肯定为null
if (supplier == null) {
//CAS将factory插入valuesMap,key为subKey
supplier = valuesMap.putIfAbsent(subKey, factory);
//双重判断
if (supplier == null) {
// successfully installed Factory
//讲supplier赋值为factory
//因为Factory是Supplier接口的实现类
supplier = factory;
}
// else retry with winning supplier
//进入情况为,并发情况下supplier已经创建好,加入到valuesMap中
//但factory还没有赋值给supplier
//这里就尝试将valuesMap中的supplier赋值为factory
//成功就将factory赋值给supplier
//不成功就获取当前valuesMap中的factory
} 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);
}
}
}
}
大体流程就是这样子了,最后我们粗略的看看怎么实现的吧,就不写注释了,除了处理过程麻烦了点,整体逻辑还是比较简单清晰的:
Factory类中的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(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);
// try replacing us with CacheValue (this should always succeed)
if (valuesMap.replace(subKey, this, cacheValue)) {
// put also in reverseMap
reverseMap.put(cacheValue, Boolean.TRUE);
} else {
throw new AssertionError("Should not reach here");
}
// successfully replaced us with new CacheValue -> return the value
// wrapped by it
return value;
}
}
ProxyClassFactory类中的apply()方法:
一堆代码就不贴了,主要看这个,JDK1.8代码在639行
//处理逻辑在这里:
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
//传入classloader,proxyName,将字节数组转化成Class<>
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
}
点进去看:
public static byte[] generateProxyClass(String var0, Class<?>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
//看这个
byte[] var4 = var3.generateClassFile();
if (saveGeneratedFiles) {
AccessController.doPrivileged(new 1(var0, var4));
}
return var4;
}
点击去几百行的代码,就不全贴了,贴点…原来那篇文章里猜测的东西吧,只是当时追的不够深:
private byte[] generateClassFile() {
this.addProxyMethod(hashCodeMethod, Object.class);
this.addProxyMethod(equalsMethod, Object.class);
this.addProxyMethod(toStringMethod, Object.class);
Class[] var1 = this.interfaces;
int var2 = var1.length;
int var3;
Class var4;
for (var3 = 0; var3 < var2; ++var3) {
var4 = var1[var3];
Method[] var5 = var4.getMethods();
int var6 = var5.length;
for (int var7 = 0; var7 < var6; ++var7) {
Method var8 = var5[var7];
this.addProxyMethod(var8, var4);
}
那时候不明白为什么会出现hashCode,equals和toString;在这里就已经很清晰了。
最终我们回到文章开头,第二大块代码那里。
大体上就是这样了。
生成了代理类以后,最终对象的方法调用,大部分都被代理为:
return (int)super.h.invoke(this, $Proxy0.m?/**?为0-n的整数,取决于有多少个代理方法**/, null);
或者:
return (boolean)super.h.invoke(this, $Proxy0.m?, new Object[] { n });
h,就是传入的自定义的InvocationHandler。最终通过反射来进行方法的调用。
好了,关于动态代理应该就这么多了,谢谢观看,如果还有问题可以联系我,也可以留言。