【源码】Spring AOP 3 Joinpoint
前言
本章节,我们解析 Joinpoin 接口,它是对整个 AOP 下 Join point 的概念的抽象
接口
Joinpoint
public interface Joinpoint {
// 执行方法到下一个拦截器
Object proceed() throws Throwable;
// 获取 target object
Object getThis();
// 返回 static part
AccessibleObject getStaticPart();
}
Interceptors chain 的传递基于 proceed()
方法。此处的 “static part” 概念比较抽象,我们姑且将其理解为 “method”
Invocation
public interface Invocation extends Joinpoint {
Object[] getArguments();
}
拓展了 Joinpoint ,并提供了获取参数的方法。
如之前说过的,此处我们忽略 ConstructorInvocation,只看 MethodInvocation
MethodInvocation
public interface MethodInvocation extends Invocation {
Method getMethod();
}
针对方法的抽象,提供了 getMethod()
方法。此时,getMethod()
等同于 getStaticPart()
可以发现,整个 Joinpoint 的结构还是比较简单清晰的
ProxyMethodInvocation
public interface ProxyMethodInvocation extends MethodInvocation {
// 获取代理对象
Object getProxy();
// 克隆,如果克隆之前 proceed 方法还未执行,则会执行多次
MethodInvocation invocableClone();
MethodInvocation invocableClone(Object... arguments);
void setArguments(Object... arguments);
/**
* 自定义属性,不用于 AOP 框架本身,而是作为 invocation 对象的一部分,
* 供给指定的拦截器使用
*/
void setUserAttribute(String key, @Nullable Object value);
@Nullable
Object getUserAttribute(String key);
}
对 MethodInvocation 的拓展,支持对代理对象的访问
该接口有且仅有一(两)个实现类。众所周知,Spring 实现代理的方式只有两种
- JDK动态代理
- CGLIB代理
而这两个实现类就分别是上述两种代理方式对应的 Invocation
实现类
ReflectiveMethodInvocation
重点看看核心的 proceed()
方法
@Override
@Nullable
public Object proceed() throws Throwable {
// 计数器初始值为-1,此处表示拦截链执行完后就执行目标方法了(基于反射)
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 取出并递增计数器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
/**
* 此处判断该 interceptor 是否是 InterceptorAndDynamicMethodMatcher
* (该类内部实际也维护了一个 MethodInterceptor)
* 此处如果匹配成功则执行内部 MethodInterceptor 的 invoke 方法
* 否则跳过该 interceptor 并 proceed 执行下一个 interceptor
*/
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
return proceed();
}
}
else {
/**
* 此处就是我们眼熟的 MethodInterceptor,调用它的 invoke 方法并传入 this
* 实际上,invoke 内部又调用了 this.proceed() 方法
* e.g.
* public Object invoke(MethodInvocation mi) throws Throwable {
* Object retVal = mi.proceed();
* this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
* return retVal;
* }
* 于是巧妙地形成了递归,配合计数器,最终在 interceptors 执行完后调用目标方法
*/
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
this.interceptorsAndDynamicMethodMatchers
持有所有的拦截器链,其内部会依次调用它们的invoke
方法- 根据之前
MethodInterceptor
的相关学习,可以发现MethodInterceptor#invoke
和MethodInvocation#proceed
最终形成递归
CglibMethodInvocation
CglibMethodInvocation
是 ReflectiveMethodInvocation
的一个拓展,主要是带来性能上的提升,细节我也不清楚,略
类图
序列图
总结
整个 Joinpoint 的抽象还是比较清晰简单,重点是其实现类 ReflectiveMethodInvocation 的 preceed()
方法,巧妙的将 MethodInterceptor 和 MethodInvocation 结合了起来
截止当前, aopalliance 下的抽象已经解析完了,下一章节了解下 Spring AOP 下的 Pointcut 抽象体系
上一篇:【源码】Spring AOP 2 Advice
下一篇:【源码】Spring AOP 4 Pointcut
参考
【小家Spring】探索Spring AOP中aopalliance的Joinpoint、MethodInvocation、Interceptor、MethodInterceptor…