highlight: arduino-light
5.JdkDynamicAopProxy#getProxy
大家可以看到,首先我们根据java规范来编写代码,也就是源码xxx.java文件,接着会使用javac命令将源码文件xxx.java编译生成字节码文件xxx.class,接着有类加载器将字节码xxx.class加载到Java虚拟机中,也就是我们常说的JVM,当字节码xxx.class被加载到JVM中后,这个类就可以被正常调用了,大概就是这个流程。
那现在大家思考一下,我们即将要分析的jdk动态代理是不是也是这样运行的呢?
答案当然是肯定的,jdk动态代理不就是一个代理类嘛,这个代理类也是java代码,只不过我们没有手动编写代理类的xxx.java文件,而是直接生成了代理类的字节码,也就是xxx.class文件,但是要想运行代理类的代码,同样也需要将代理类的字节码通过类加载器给加载到JVM中的。
说白了就是在运行代理类代码之前,一定会先生成代理类的字节码,接着将代理类的字节码通过类加载器加载到JVM,然后才可以运行代理类的构造方法创建出来一个代理对象出来,大概是这样子的流程。
JdkDynamicAopProxy 实现了InvocationHandler接口
JdkDynamicAopProxy中的advised是我们的代理工厂ProxyFactory
JdkDynamicAopProxy#getProxy
java @Override public Object getProxy(@Nullable ClassLoader classLoader) { /* proxiedInterfaces = {Class[4]@1801} 0 = {Class@1765} "interface aop.LogService" 1 = {Class@1794} "interface org.springframework.aop.SpringProxy" 2 = {Class@1782} "interface org.springframework.aop.framework.Advised" 3 = {Class@1795} "interface org.springframework.core.DecoratingProxy" */ //拿到要被代理对象的所有接口 Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); //this是JdkDynamicAopProxy 实现了InvocationHandler接口 //JdkDynamicAopProxy中的属性advised是我们的代理工厂ProxyFactory //ProxyFactory封装了各种参数比如被代理类的实例以及advisors //advisor中又封装了方法和方法的切面表达式 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }
Proxy.newProxyInstance()
Proxy.newProxyInstance()方法有三个比较核心的参数。
分别是类加载器、被代理对象的所有接口列表以及回调程序。
在这里我们可以看到,Spring先调用completeProxiedInterfaces()方法获取到了被代理对象要代理的所有接口,然后将这个接口作为入参传了进去。
另外我们还看到传给Proxy.newProxyInstance()方法的回调程序竟然是this,说白了就是将当前的JdkDynamicAopProxy对象作为回调程序传了进去。
this是JdkDynamicAopProxy 实现了InvocationHandler接口
JdkDynamicAopProxy中的属性advised是我们的代理工厂ProxyFactory
ProxyFactory封装了各种参数比如被代理类的实例以及advisors,advisor中又封装了方法和方法的切面表达式。
参数都设置完毕后,我们就可以通过Proxy.newProxyInstance()方法拿到一个jdk代理对象了。
其实这个newProxyInstance()方法的代码还是比较清晰的,就是先获取代理类的Class对象,然后再获取构造方法,最后通过构造方法创建了代理类的对象。 ```java /* InvocationHandler是JdkDynamicAopProxy JdkDynamicAopProxy 实现了InvocationHandler接口 JdkDynamicAopProxy中的属性advised是我们的代理工厂ProxyFactory ProxyFactory封装了各种参数比如被代理类的实例以及advisors,advisor中又封装了增强方法和增强方法的切面表达式。 */ 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);
}
/***
查找或生成指定的代理类,核心逻辑就在这里
这里主要做两件事儿
其一就是生成代理类字节码
其二将生成的字节码加载到JVM中
***/
Class<?> cl = getProxyClass0(loader, intfs);
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
// 获取代理类的构造方法
// private static final Class<?>[] constructorParams
// = { InvocationHandler.class };
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;
}
});
}
/***
使用反射通过构造方法创建代理类对象
h是JdkDynamicAopProxy 实现了InvocationHandler接口
JdkDynamicAopProxy中的属性advised是我们的代理工厂ProxyFactory
ProxyFactory封装了各种参数比如被代理类的实例以及advisors
advisor中又封装了增强方法和增强方法的切面表达式。
***/
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);
}
} ```
5.1动态生成字节码文件
java Class<?> cl = getProxyClass0(loader, intfs);
在getProxyClass0()方法中,在这个方法中不但生成了代理类,还将生成的代理类加载到了JVM中,这样我们才可以获取到代理类中的构造方法。此时我们打开getProxyClass0()方法,然后我们会看到下边的代码:
```java // 初始化proxyClassCache,注意它的value是ProxyClassFactory类型 private static final WeakCache [], Class>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
private static Class> getProxyClass0(ClassLoader loader, Class>... interfaces) { if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); }
// 缓存中存在就从缓存中获取代理类,缓存中不存在就使用ProxyClassFactory创建代理类
return proxyClassCache.get(loader, interfaces);
} ```
代码所在类的全限定类名:java.lang.reflect.Proxy#getProxyClass0
5.2使用InvocationHandler构建实例
java /*** 使用反射通过构造方法创建代理类对象 h是JdkDynamicAopProxy 实现了InvocationHandler接口 JdkDynamicAopProxy中的属性advised是我们的代理工厂ProxyFactory ProxyFactory封装了各种参数比如被代理类的实例以及advisors advisor中又封装了增强方法和增强方法的切面表达式。 ***/ return cons.newInstance(new Object[]{h});
5.2.1newInstance
java public T newInstance(Object ... initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{ if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { Class<?> caller = Reflection.getCallerClass(); checkAccess(caller, clazz, null, modifiers); } } if ((clazz.getModifiers() & Modifier.ENUM) != 0) throw new IllegalArgumentException ("Cannot reflectively create enum objects"); ConstructorAccessor ca = constructorAccessor; if (ca == null) { ca = acquireConstructorAccessor(); } @SuppressWarnings("unchecked") T inst = (T) ca.newInstance(initargs); return inst; }
6.怎么查看代理类\$Proxy的代码?
我们可以通过添加JVM运行参数来解决
然后在虚拟机参数一栏中添加JVM运行参数:-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true
需要注意的是我这边的测试类是AopTest,大家到时候选择自己的测试类配置就可以了。
JVM运行参数配置完毕后,再执行一下测试类,比如我这里是AopTest,这个时候就会将运行时生成的代理类给保存到com.sun.proxy。
或者使用 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
```java
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; import jdk代理.Calculator1; import jdk代理.Calculator2; //我们生成的代理类继承了Proxy //在spring中 Proxy类型的 或者是 接口类型的 都必须使用jdk动态代理哦 public final class $Proxy extends Proxy implements Calculator1, Calculator2 { private static Method m1; private static Method m2; private static Method m3; private static Method m4; private static Method m5; private static Method m6; private static Method m0;
public $Proxy(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
//可以看到这里把 当前代理对象实例 原始方法 原始方法参数都传递给了
//InvocationHandler#invoke方法
//参数this 代理类实例
//参数m1 当前执行的equals方法
//参数 new Object[]{var1} 当前执行的方法的参数
//super是Proxy
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);
}
}
public final int add(int var1, int var2) throws {
try {
return (Integer)super.h.invoke(this, m3, new Object[]{var1, var2});
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
public final int sub(int var1, int var2) throws {
try {
return (Integer)super.h.invoke(this, m4, new Object[]{var1, var2});
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
public final int mult(int var1, int var2) throws {
try {
return (Integer)super.h.invoke(this, m5, new Object[]{var1, var2});
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
public final int div(int var1, int var2) throws {
try {
return (Integer)super.h.invoke(this, m6, new Object[]{var1, var2});
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
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("jdk代理.Calculator1").getMethod("add", Integer.TYPE, Integer.TYPE);
m4 = Class.forName("jdk代理.Calculator1").getMethod("sub", Integer.TYPE, Integer.TYPE);
m5 = Class.forName("jdk代理.Calculator2").getMethod("mult", Integer.TYPE, Integer.TYPE);
m6 = Class.forName("jdk代理.Calculator2").getMethod("div", Integer.TYPE, Integer.TYPE);
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
} ```
可以看到这个构造方法的入参是InvocationHandler类型的,那这个构造方法会在哪里使用呢?
会在之前分析的newProxyInstance()方法中 md // 获取代理类中的构造方法 final Constructor<?> cons = cl.getConstructor(constructorParams); // 使用反射通过构造方法创建代理类对象,注意这里会将回调程序h传递到代理类中 return cons.newInstance(new Object[]{h});
父类的这个构造方法非常简单,其实就是将子类传递过来的InvocationHandler赋值给了h属性,而子类此时传递过来的InvocationHandler其实就是JdkDynamicAopProxy,也就是说此时父类中的这个h属性就是JdkDynamicAopProxy。
创建代理时有下面这么一句代码 java public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException { if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) { throw new AopConfigException(); } this.advised = config; } /*** this是JdkDynamicAopProxy 实现了InvocationHandler接口 重点JdkDynamicAopProxy中的属性advised advised是我们的代理工厂ProxyFactory ProxyFactory封装了各种参数比如被代理类的实例以及advisors advisor中又封装了增强方法和增强方法的切面表达式。 ***/ return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
所以在方法调用的时候需要看JdkDynamicAopProxy的invoke方法,其实是InvocationHandler的invoke方法 java public final boolean equals(Object var1) throws { try { //可以看到这里把 当前代理对象实例 原始方法 原始方法参数都传递给了 //InvocationHandler#invoke方法 //参数this 代理类实例 //参数m1 当前执行的equals方法 //参数 new Object[]{var1} 当前执行的方法的参数 //super是Proxy return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } }
直接调用父类h属性的invoke()方法,我们知道现在父类Proxy中的h属性是JdkDynamicAopProxy。
所以只要代理类类的equals方法被调用,那么就会执行JdkDynamicAopProxy类的invoke()方法!
之所以调用代理对象的方法会自动回调到InvocationHandler的invoke()方法。
是因为jdk在生成代理类时,为每个方法都生成了一行 super.h.invoke() 这样的代码。 java //可以看到这里把 当前代理对象实例 原始方法 原始方法参数都传递给了 //InvocationHandler#invoke方法 //参数this 代理类实例 //参数m1 当前执行的equals方法 //参数 new Object[]{var1} 当前执行的方法的参数 //super是Proxy return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
而这个h其实就是一个InvocationHandler,因此才可以回调到InvocationHandler的invoke()方法了。