前言
在这篇博文:【小家Spring】详解Spring AOP中底层代理模式之JdkDynamicAopProxy和CglibAopProxy(ObjenesisCglibAopProxy)的源码分析
我们已经能够知道了,代理对象创建好后,其实最终的拦截工作都是交给了MethodInvocation
,JDK交给:ReflectiveMethodInvocation
,CGLIB交给CglibMethodInvocation
备注:此处所说的
MethodInvocation
是AOP联盟包里的,也就是org.aopalliance.intercept.MethodInvocation
。 AOP联盟包里和cglib包里都有的叫:MethodInterceptor
,不要弄混了。
org.aopalliance.intercept.Joinpoint
首先需要注意的是,一般我们会接触到两个Joinpoint
org.aspectj.lang.JoinPoint
:该对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,可以很方便的获得更多信息。(一般用于@Aspect
标注的切面的方法入参里),它的API很多,常用的有下面几个:Signature getSignature();
:封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息Object[] getArgs();
:传入目标方法的参数们Object getTarget();
:被代理的对象(目标对象)Object getThis();
:该代理对象
备注:
ProceedingJoinPoint
对象是JoinPoint
的子接口,该对象只用在@Around的切面方法中
org.aopalliance.intercept.Joinpoint
是本文的重点,下面主要看看它的解释和相关方法:
// 此接口表示运行时的连接点(AOP术语) (和aspectj里的连接点意思有点像)
public interface Joinpoint {
// 执行此拦截点,并进入到下一个连接点
Object proceed() throws Throwable;
// 返回保存当前连接点静态部分【的对象】。 这里一般指的target
Object getThis();
// 返回此静态连接点 一般就为当前的Method(至少目前的唯一实现是MethodInvocation,所以连接点得静态部分肯定就是本方法喽)
AccessibleObject getStaticPart();
}
org.aopalliance.intercept.Invocation
它的中文意思:祈祷; 乞求
,它继承自Joinpoint
。
这个类没有同名的,只有的aopalliance
里有。
// 此接口表示程序中的调用~
// 该调用是一个可以被拦截器拦截的连接点
public interface Invocation extends Joinpoint {
// 获得参数们。比如方法的入参们
Object[] getArguments();
}
org.aopalliance.intercept.MethodInvocation
接口到了这一层,就比较具象了。它表示方法的执行器
,显然就是和Method方法有关喽
// 方法调用时,对这部分进行描述
public interface MethodInvocation extends Invocation {
// 返回正在被调用得方法~~~ 返回的是当前Method对象。
// 此时,效果同父类的AccessibleObject getStaticPart() 这个方法
Method getMethod();
}
MethodInvocation
作为aopalliance
里提供的最底层接口了。Spring提供了相关的实现,如下图:
Spring自己也定义了一个接口,来进行扩展和统一管理:ProxyMethodInvocation
org.springframework.aop.ProxyMethodInvocation
这个接口是Spring提供的对aopalliance
里MethodInvocation
的继承扩展接口
// 这是Spring提供的对MethodInvocation 的一个扩展。
// 它允许访问 方法被调用的代理对象以及其它相关信息
public interface ProxyMethodInvocation extends MethodInvocation {
// 返回代理对象
Object getProxy();
// 克隆一个,使用的Object得clone方法
MethodInvocation invocableClone();
MethodInvocation invocableClone(Object... arguments);
// 设置参数 增强器、通知们执行的时候可能会用到
void setArguments(Object... arguments);
// 添加一些属性kv。这些kv并不会用于AOP框架内,而是保存下来给特殊的一些拦截器实用
void setUserAttribute(String key, @Nullable Object value);
@Nullable
Object getUserAttribute(String key);
}
下面我们就是主菜了,Spring给我们提供的唯一
(其实算唯二吧)的实现类,它执行着拦截的核心逻辑。会让所有的通知器都执行~~
ReflectiveMethodInvocation
Reflective
中文意思:可被反射的
显然它作为实现类,需要实现包括父接口在内的所有的方法们。
它也是JdkDynamicAopProxy
最终执行时
候new出来的执行对象,话不多说,下面看看具体的逻辑吧~~
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
protected final Object proxy; // 代理对象
@Nullable
protected final Object target; // 目标对象
protected final Method method; // 被拦截的方法
protected Object[] arguments = new Object[0];
@Nullable
private final Class<?> targetClass;
@Nullable
private Map<String, Object> userAttributes;
protected final List<?> interceptorsAndDynamicMethodMatchers;
// currentInterceptorIndex初始值为 -1
private int currentInterceptorIndex = -1;
// 唯一的构造函数。注意是protected 相当于只能本包内、以及子类可以调用。外部是不能直接初始化的此对象的(显然就是Spring内部使用的类了嘛)
//invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// proxy:代理对象
// target:目标对象
// method:被代理的方法
// args:方法的参数们
// targetClass:目标方法的Class (target != null ? target.getClass() : null)
// interceptorsAndDynamicMethodMatchers:拦截链。 this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)这个方法找出来的
protected ReflectiveMethodInvocation(
Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
@Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
this.proxy = proxy;
this.target = target;
this.targetClass = targetClass;
// 找到桥接方法,作为最后执行的方法。至于什么是桥接方法,自行百度关键字:bridge method
// 桥接方法是 JDK 1.5 引入泛型后,为了使Java的泛型方法生成的字节码和 1.5 版本前的字节码相兼容,由编译器自动生成的方法(子类实现父类的泛型方法时会生成桥接方法)
this.method = BridgeMethodResolver.findBridgedMethod(method);
// 对参数进行适配
this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}
@Override
public final Object getProxy() {
return this.proxy;
}
@Override
@Nullable
public final Object getThis() {
return this.target;
}
// 此处:getStaticPart返回的就是当前得method
@Override
public final AccessibleObject getStaticPart() {
return this.method;
}
// 注意:这里返回的可能是桥接方法哦
@Override
public final Method getMethod() {
return this.method;
}
@Override
public final Object[] getArguments() {
return this.arguments;
}
@Override
public void setArguments(Object... arguments) {
this.arguments = arguments;
}
// 这里就是核心了,要执行方法、执行通知、都是在此处搞定的
// 这里面运用 递归调用 的方式,非常具有技巧性
@Override
@Nullable
public Object proceed() throws Throwable {
// currentInterceptorIndex初始值为 -1 如果执行到链条的末尾 则直接调用连接点方法 即 直接调用目标方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 这个方法相当于调用了目标方法~~~下面会分析
return invokeJoinpoint();
}
// 获取集合中的 MethodInterceptor(并且currentInterceptorIndex 1了哦)
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get( this.currentInterceptorIndex);
//InterceptorAndDynamicMethodMatcher它是Spring内部使用的一个类。很简单,就是把MethodInterceptor实例和MethodMatcher放在了一起。看看在advisor chain里面是否能够匹配上
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
// 去匹配这个拦截器是否适用于这个目标方法 试用就执行拦截器得invoke方法
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// 如果不匹配。就跳过此拦截器,而继续执行下一个拦截器
// 注意:这里是递归调用 并不是循环调用
return proceed();
}
}
else {
// 直接执行此拦截器。说明之前已经匹配好了,只有匹配上的方法才会被拦截进来的
// 这里传入this就是传入了ReflectiveMethodInvocation,从而形成了一个链条了
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
// 其实就是简单的一个:method.invoke(target, args);
// 子类可以复写此方法,去执行。比如它的唯一子类CglibAopProxy内部类 CglibMethodInvocation就复写了这个方法 它对public的方法做了一个处理(public方法调用MethodProxy.invoke)
@Nullable
protected Object invokeJoinpoint() throws Throwable {
// 此处传入的是target,而不能是proxy,否则进入死循环
return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}
@Override
public MethodInvocation invocableClone() {
Object[] cloneArguments = this.arguments;
if (this.arguments.length > 0) {
// Build an independent copy of the arguments array.
cloneArguments = new Object[this.arguments.length];
System.arraycopy(this.arguments, 0, cloneArguments, 0, this.arguments.length);
}
return invocableClone(cloneArguments);
}
@Override
public MethodInvocation invocableClone(Object... arguments) {
if (this.userAttributes == null) {
this.userAttributes = new HashMap<>();
}
try {
ReflectiveMethodInvocation clone = (ReflectiveMethodInvocation) clone();
clone.arguments = arguments;
return clone;
} catch (CloneNotSupportedException ex) {
throw new IllegalStateException(
"Should be able to clone object of type [" getClass() "]: " ex);
}
}
@Override
public void setUserAttribute(String key, @Nullable Object value) {
if (value != null) {
if (this.userAttributes == null) {
this.userAttributes = new HashMap<>();
}
this.userAttributes.put(key, value);
}
else {
if (this.userAttributes != null) {
this.userAttributes.remove(key);
}
}
}
@Override
@Nullable
public Object getUserAttribute(String key) {
return (this.userAttributes != null ? this.userAttributes.get(key) : null);
}
public Map<String, Object> getUserAttributes() {
if (this.userAttributes == null) {
this.userAttributes = new HashMap<>();
}
return this.userAttributes;
}
@Override
public String toString() {
// Don't do toString on target, it may be proxied.
StringBuilder sb = new StringBuilder("ReflectiveMethodInvocation: ");
sb.append(this.method).append("; ");
if (this.target == null) {
sb.append("target is null");
}
else {
sb.append("target is of class [").append(this.target.getClass().getName()).append(']');
}
return sb.toString();
}
}
从这里我们需要注意到的是:ProxyMethodInvocation
(ReflectiveMethodInvocation
)是代理执行的入口。然后内部会把所有的 增强器 都拿出来 递归执行
(比如前置通知,就在目标方法之前执行) **这就实现了指定次序的链式调用**
CglibMethodInvocation
它是继承自ReflectiveMethodInvocation
,是CglibAopProxy
自己使用的执行器。
private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
private final MethodProxy methodProxy;
private final boolean publicMethod;
public CglibMethodInvocation(Object proxy, @Nullable Object target, Method method,
Object[] arguments, @Nullable Class<?> targetClass,
List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {
// 调用父类的构造 完成基本参数得初始化
super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
// 自己的个性化参数:
// 这个参数是子类多传的,表示:它是CGLIb拦截的时候的类MethodProxy
//MethodProxy为生成的代理类对方法的代理引用。cglib生成用来代替Method对象的一个对象,使用MethodProxy比调用JDK自身的Method直接执行方法效率会有提升
// 它有两个重要的方法:invoke和invokeSuper
this.methodProxy = methodProxy;
// 方法是否是public的 对应下面的invoke方法的处理 见下面
this.publicMethod = Modifier.isPublic(method.getModifiers());
}
@Override
protected Object invokeJoinpoint() throws Throwable {
// 如果是public的方法,调用methodProxy去执行目标方法
// 否则直接执行method即可
if (this.publicMethod) {
// 此处务必注意的是,传入的是target,而不能是proxy,否则进入死循环
return this.methodProxy.invoke(this.target, this.arguments);
} else {
return super.invokeJoinpoint();
}
}
}
org.aopalliance.intercept.MethodInterceptor
需要说明的cglib包里也存在一个MethodInterceptor
,它的主要作用是CGLIB内部使用,一般是和Enhancer
一起来使用而创建一个动态代理对象。
而本处我们讲到的 org.aopalliance.intercept.MethodInterceptor
,那些@AspectJ
定义的通知们(增强器们),或者是自己实现的MethodBeforeAdvice
、AfterReturningAdvice
…(总是都是org.aopalliance.aop.Advice
一个通知器),最终都会被包装成一个org.aopalliance.intercept.MethodInterceptor
,最终交给MethodInvocation
(其子类ReflectiveMethodInvocation
)去执行,它会把你所有的增强器都给执行了,这就是我们面向切面编程的核心思路过程。
这里面其实有两个标记接口(没有任何方法):
顶层接口:Advice
中文意思:建议,忠告。 实现通知的方式可议是任何方式,比如Interceptors
拦截器得方式
中间层接口:Interceptor
继承自Advice接口。它就是以拦截器方式去实现通知的效果
代码语言:javascript复制此处需要说明的是,
Interceptor
得子接口有两个:MethodInterceptor
和ConstructorInterceptor
,但是ConstructorInterceptor
连Spring都没有提供实现类,因此本文不会讲述本接口。
// 从名字里都能看出来,它是通过拦截方法的执行来实现通知得效果的~~~~
@FunctionalInterface
public interface MethodInterceptor extends Interceptor {
// 可议在此方法里 在方法执行之前、之后做对应的处理。
// 需要执行的时候,调用invocation.proceed()方法即可
Object invoke(MethodInvocation invocation) throws Throwable;
}
Spring给我们提供的MethodInterceptor
实现非常非常的多:
有很多我们非常熟悉的面孔。下面就抽出几个,简单的看看实现代码:
关于AspectJ切面相关的增强器
一共5个对应着AspectJ
提供的那五个注解。每个注解都是一个最终被包装好的Advice(其实是个AspectJAfterAdvice
) 此处知道就可,暂时此处不做详细介绍~~
MethodBeforeAdviceInterceptor
这个源代码很简单,就是一层代理。把MethodBeforeAdvice
包装成了一个MethodInterceptor
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
private MethodBeforeAdvice advice;
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
// 在目标方法执行之前,先执行advice得before方法~~~
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
// 注意此处继续调用了 mi.proceed()。相当于去执行下一个增强器。类似于递归执行了,这样就行程了一个链式得调用执行
return mi.proceed();
}
}
AfterReturningAdviceInterceptor
显然它是对AfterReturningAdvice
的一个包装
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
private final AfterReturningAdvice advice;
public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
// 嗲用afterReturning,它是能够享受到返回值的
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
}
ThrowsAdviceInterceptor
包装的ThrowsAdvice
,实际处理起来稍微复杂点~~~
public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice {
...
}
上面三个拦截器,可议参考适配器:
代码语言:javascript复制public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
...
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
...
}
CacheInterceptor / AsyncExecutionInterceptor
这两个分别涉及到Spring的cache部分以及Async异步部分,这在讲述这块的时候会具体的进行分析。
总结
aopalliance
属于AOP联盟,定义了一些标准。一共只几个接口,总结如下:
org.aopalliance.aop
包
- Advice:通知的标记接口。实现可以是任意类型,比如下面的
Interceptor
- AspectException:所有的AOP框架产生异常的父类。它是个RuntimeException
org.aopalliance.intercept
包
- Interceptor:它继承自
Advice
,它通过拦截器得方式实现通知的效果(也属于标记接口) - MethodInterceptor:具体的接口。拦截方法 (Spring提供了非常多的具体实现类)
- ConstructorInterceptor:具体接口。拦截构造器 (Spring并没有提供实现类)
- Joinpoint:AOP运行时的连接点(顶层接口)
- Invocation:继承自Joinpoint。 表示执行,提供了Object[] getArguments()来获取执行所需的参数
- MethodInvocation:(和
MethodInterceptor
对应,它的invoke方法入参就是它)表示一个和方法有关的执行器。提供方法Method getMethod()
(Spring提供了唯一(唯二)实现类:ProxyMethodInvocation
) - ConstructorInvocation:和构造器有关。
Constructor<?> getConstructor();
(Spring没有提供任何实现类)
这就是AOP联盟为我们提供的所有的类,它里面全部是接口(那个异常类除外),相当于它定义了一套AOP的标准类。Spring对核心的Method相关的拦截、执行器做了对应的实现。
注意,Spring的AOP实现并不依赖于AspectJ任何类,它自己实现了一套AOP的。比如它Spring自己提供的
BeforeAdvice
和AfterAdvice
都是对AOP联盟规范的标准实现。以及Spring自己抽象出来的对Advice的包装:org.springframework.aop.Advisor
贯穿Spring AOP的始终 但是在当前注解驱动的流行下,基于POJO(xml方式)以及编程的方式去书写AOP代理,显得非常的繁琐。因此Spring提供了另外一种实现:基于AspectJ,到这才使用到了AspectJ的相关注解、以及类。 但是还需要说明一点:哪怕使用到了AspectJ的相关注解和类,但核心的AOP织入的逻辑,还都是Spring自己用动态代理去实现的,没用AspectJ它那种特殊的语法和特有的编译器
最后说一句,若在Spring AOP中想使用AspectJ
的方式去实现(也是当下最流行的方式),必须导入Jar包:aspectjweaver-1.9.2.jar
,而Spring的这个包org.springframework.aop.aspectj
下面的所有类,都是专门为了使用@Aspect
的方式去服务的,毕竟AOP功能是Spring自己实现的,而不是依赖于AspectJ
这个组件的