跟着小马哥学系列之 Spring AOP( ReflectiveMethodInvocation/CglibMethodInvocation 详解)

  • Post author:
  • Post category:其他



学好路更宽,钱多少加班。 ——小马哥



版本修订

  • 2021.5.19:去除目录



简介

大家好,我是

小马哥

成千上万粉丝中的一员!2019年8月有幸在

叩丁狼教育

举办的猿圈活动中知道有这么一位大咖,从此结下了不解之缘!此系列在

多次学习


极客时间《小马哥讲Spring AOP 编程思想》

基础上形成的个人一些总结。希望能帮助各位小伙伴, 祝小伙伴早日学有所成。



类图

在这里插入图片描述



相关接口或者类介绍



Joinpoint

这个接口表示一个通用的运行时连接点(在AOP术语中)。运行时连接点是发生在静态连接点(即程序中的一个位置)上的事件。例如,调用方法(静态连接点)是运行时连接点。可以使用 getStaticPart() 方法通用地检索给定连接点的静态部分。在拦截框架的上下文中,运行时连接点是对可访问对象(方法、构造函数、字段)访问的具体化,即连接点的静态部分。它被传递给安装在静态连接点上的拦截器。


方法介绍

  • proceed():进入链中的下一个拦截器。此方法的实现和语义取决于实际的连接点类型(请参阅子接口)
  • getThis():返回保存当前连接点的静态部分的对象(如果可访问对象是静态的,则可以为空)
  • getStaticPart():返回此连接点的静态部分。静态部分是一个可访问的对象,在该对象上安装了一系列拦截器



Invocation

对 Joinpoint 接口扩展,这个接口表示程序中的一个调用。调用是一个连接点,可以被拦截器拦截。主要是通过 getArguments () 方法以数组对象的形式获取参数。可以通过改变数组中的元素值来改变参数。



MethodInvocation

对 Invocation 接口扩展,方法调用的描述,在方法调用时提供给拦截器。方法调用是一个连接点,可以被方法拦截器拦截。主要是通过 getMethod() (获取被调用的方法。此方法是Joinpoint.getStaticPart()方法的友好实现(结果相同))获取 Method



ProxyMethodInvocation

对 MethodInvocation 接口的扩展,允许访问代理通过方法被调用。如果有必要(例如,如果调用目标返回本身),可以使用代理替换返回值。


方法介绍

  • getProxy():获取代理
  • invocableClone():创建此对象的克隆。 在 proceed() 方法调用之前完成克隆,每调用一次 proceed() 方法则克隆一次。
  • invocableClone(Object… arguments):带有参数的克隆
  • setArguments(Object… arguments):设置参数被用于此链中后续调用的任何 advice 。
  • setUserAttribute(String key, @Nullable Object value):将具有给定值的指定用户属性添加到此调用中。这样的属性在AOP框架本身中没有使用。它们只是作为调用对象的一部分保存,用于特殊的拦截器。
  • getUserAttribute(String key):返回指定用户属性的值。


ReflectiveMethodInvocation

Spring 实现了 AOP 联盟 MethodInvocation 接口,实现了扩展的 ProxyMethodInvocation 接口。使用反射调用目标对象。子类可以覆盖 invokeJoinpoint() 方法来更改此行为。可以使用 invocableClone() 方法克隆调用,重复调用proceed()(每个克隆一次)。还可以使用 setUserAttribute()/getUserAttribute() 方法为调用附加自定义属性。主要用于

JdkDynamicAopProxy

@Override
@Nullable
public Object proceed() throws Throwable {
	// 如果是没有 advice 链,或者 advice 链已经调用完,则通过反射执行目标方法
	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
		return invokeJoinpoint();
	}
	
	Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
	if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
		
		InterceptorAndDynamicMethodMatcher dm =
				(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
		Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
		// 动态匹配,如果匹配上执行 advice 的 invoke 方法并把 MethodInvocation 对象当成参数传过去,在 invoke 方法中执行 MethodInvocation#proceed 方法
		if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
			return dm.interceptor.invoke(this);
		}
		else {
			// 匹配不上执行下一个拦截器
			return proceed();
		}
	}
	else {
		// 执行 advice 的 invoke 方法并把 MethodInvocation 对象当成参数传过去,在 invoke 方法中执行 MethodInvocation#proceed 方法
		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
	}
}


CglibMethodInvocation

扩展 ReflectiveMethodInvocation 类以支持 CGLIB 代理主要是覆盖了 invokeJoinpoint() 方法,如果有 MethodProxy 对象,则通过调用 MethodProxy#invoke 方法否则通过反射调用 。主要用于

CglibAopProxy

中。在 proceed() 方法中有个细节,就是有异常的时候,如果是

RuntimeException

(运行时异常)类型的异常则抛出,如果不是(指检查类型的异常)则检查方法签名上是否声明了该异常类型,否则将抛出

UndeclaredThrowableException



版权声明:本文为qq_42419406原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。