spring动态代理的方式有两种,本文主要是介绍jdk方式,我们另外一篇主要介绍另外一种方式,也就是cglib方式
spring 的aop的动态代理都是为了给实现了接口的类做增强(必须是实现了接口),比如增加日志的功能。
我们从这个文章中应该能知道生成的代理对象是什么样的;同时就能知道代理对象对象方法执行流程,
首先我们看下代理后的对象张什么样,其中ConfigInterface是我们需要代理的对象。
//这里删掉了一些不重要的方法。
package com.sun.proxy;
#ConfigInterface 用户自己的接口,需要代理的接口
public final class $Proxy23 extends Proxy implements ConfigInterface, SpringProxy, Advised, DecoratingProxy {
private static Method m1;
private static Method m13;
private static Method m24;
private static Method m21;
private static Method m16;
public $Proxy23(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
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 void haha() throws {
try {
super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
lic final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m4, (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("org.springframework.mytest.ConfigInterface").getMethod("haha");
。。。省略
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
看到类的签名 public final class $Proxy23 extends Proxy implements ConfigInterface, SpringProxy, Advised, DecoratingProxy
其中ConfigInterface是我自己定义的,其他都是系统的。在代理类的静态代码块,分别初始化了各个方法。其中的haha方法是用户自定义的。
我们看看haha方法。
我们发现所有的方法都有h.invoke() 我们看看这个h是什么?
这里的super是Proxy,我们看下Proxy中有没有h。
父类中还真有一个h对象,h的类型是InvocationHandler。我们所谓的增强操作就是在这个InvocationHandler接口的实现类内部实现的。我们找下spring aop中的代理对象是什么时候指定了自己的InvocationHandler。(我们把增加日志,增加事务控制叫做增强,不叫通知)
我们发现Spring aop传入的InvocationHandler 就是 对象JdkDynamicAopProxy,也就是上文中关键的对象h就是JdkDynamicAopProxy吗?。那JdkDynamicAopProxy到底是不是InvocationHandler类型呢?我们看下类JdkDynamicAopProxy的签名。
果然是的。
那我们接下来应该看看 JdkDynamicAopProxy的invoke方法。因为前面代理类中方法都执行了InvocationHandler的invoke方法。那JdkDynamicAopProxy的invoke方法到底是怎样?
先不看代码,我们想下,接下来的invoke方法中应该有些什么逻辑。
1、用户自己定义的方法需要执行;2、那些匹配的切面,我有时候又称之为增强(比如日志,事务等)需要执行,
接下来看代码。
# JdkDynamicAopProxy
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
//省略一些不打紧的。
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
Class targetClass = (target != null ? target.getClass() : null);
List
这段代码首先是获取拦截器链,然后 如果拦截器链为空,则直接执行用户自己的方法(目标方法)也就是没有对方法进行增强。(一个代理类并不是所有方法都被增强,只有匹配的才会);如果拦截器不为空,则将拦截器链与目标方法,封装为一个MethodInvocation的对象。这里的拦截器可以认为是那些切面中的增强方法。
我们看下MethodInvocation的proceed方法是怎样处理这些拦截器的。MethodInvocation只是一个接口,真正的实现类是ReflectiveMethodInvocation。我们截取其proceed 方法。
从这个方法的设计上来看,包含两块,一个是调用用户的方法,另一个是拦截器方法。
下面我们盗取人家大v的一张图片。
首先从MethodInvocation的proceed方法开始,进入前置拦截器执行,前置拦截器又递归调用MethodInvocation的proceed方法。如此依次递归所有的拦截器。
注意这里要区分不同类型拦截器的设计,有点像我们数据结构里面学的二叉树的遍历(先序遍历、后序遍历、中序遍历)
下图贴出一次完整的调用栈。
然后贴出前置拦截器的内部实现。
到此为止,一个方法被增强的方法的执行流程就说完了。
可能此时你已经知道一个代理对象实现是什么样?
执行逻辑是怎么样?
但是对于如何将这里的切面变成拦截器,封装到对应的代理对象,这里并没有详细说。我们在其他博客再深入讨论。
谢谢您的阅读。