首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【小家Spring】探索Spring AOP中aopalliance的Joinpoint、MethodInvocation、Interceptor、MethodInterceptor...

【小家Spring】探索Spring AOP中aopalliance的Joinpoint、MethodInvocation、Interceptor、MethodInterceptor...

作者头像
YourBatman
发布2019-09-03 16:16:53
2.7K0
发布2019-09-03 16:16:53
举报
前言

在这篇博文:【小家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

  1. org.aspectj.lang.JoinPoint:该对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,可以很方便的获得更多信息。(一般用于@Aspect标注的切面的方法入参里),它的API很多,常用的有下面几个:
  2. Signature getSignature(); :封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息
  3. Object[] getArgs();:传入目标方法的参数们
  4. Object getTarget();:被代理的对象(目标对象)
  5. Object getThis();:该代理对象

备注:ProceedingJoinPoint对象是JoinPoint的子接口,该对象只用在@Around的切面方法中

  1. 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提供的对aopallianceMethodInvocation的继承扩展接口

// 这是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();
	}

}

从这里我们需要注意到的是:ProxyMethodInvocationReflectiveMethodInvocation)是代理执行的入口。然后内部会把所有的 增强器 都拿出来 递归执行(比如前置通知,就在目标方法之前执行) **这就实现了指定次序的链式调用**

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定义的通知们(增强器们),或者是自己实现的MethodBeforeAdviceAfterReturningAdvice…(总是都是org.aopalliance.aop.Advice一个通知器),最终都会被包装成一个org.aopalliance.intercept.MethodInterceptor,最终交给MethodInvocation(其子类ReflectiveMethodInvocation)去执行,它会把你所有的增强器都给执行了,这就是我们面向切面编程的核心思路过程。

这里面其实有两个标记接口(没有任何方法):

顶层接口:Advice 中文意思:建议,忠告。 实现通知的方式可议是任何方式,比如Interceptors拦截器得方式

中间层接口:Interceptor 继承自Advice接口。它就是以拦截器方式去实现通知的效果

此处需要说明的是,Interceptor得子接口有两个:MethodInterceptorConstructorInterceptor,但是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 {
	...
}

上面三个拦截器,可议参考适配器:

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自己提供的BeforeAdviceAfterAdvice都是对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这个组件的

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年04月09日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • org.aopalliance.intercept.Joinpoint
  • org.aopalliance.intercept.Invocation
  • org.aopalliance.intercept.MethodInvocation
    • org.springframework.aop.ProxyMethodInvocation
    • ReflectiveMethodInvocation
      • CglibMethodInvocation
      • org.aopalliance.intercept.MethodInterceptor
        • 总结
        相关产品与服务
        云顾问
        云顾问(Tencent Cloud Smart Advisor)是一款提供可视化云架构IDE和多个ITOM领域垂直应用的云上治理平台,以“一个平台,多个应用”为产品理念,依托腾讯云海量运维专家经验,助您打造卓越架构,实现便捷、灵活的一站式云上治理。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档