Spring AOP源码分析九

上一节我们主要讲了目标方法和增强的匹配过程,简单说就是首先在类级别进行匹配,接着在方法级别进行匹配,如果匹配成功的话,就通过registry.getInterceptors(advisor)这行代码获取advisor对应的拦截器,然后将这些拦截器放到一个集合中,这个集合其实就是拦截器链,最后将拦截器链作为结果进行返回。这个过程还是比较简单的,但是其中有一行代码我们跳了过去,那就是获取advisor对应的拦截器这个过程我们还不清楚,所以这节我们就专门来分析一下这个过程,说白了就是来分析下registry.getInterceptors(advisor)这行代码。首先我们上节在分析获取拦截器链的时候,跳过了下边这行代码的分析,代码如下:
在这里插入图片描述
我们可以看到,针对匹配成功的增强advisor,会通过getInterceptors()方法来获取对应的拦截器。我们到getInterceptors()方法中看一下:
在这里插入图片描述
首先通过getAdvice()方法获取了advice属性,我们们看一下这个getAdvice()方法,在这里插入图片描述
可以看到这个方法是一个接口,在这个接口中有很多的实现,如下图:
在这里插入图片描述
还记得我们是怎样构建Advisor的吗?当时构建Advisor时,使用的就是InstantiationModelAwarePointcutAdvisorImpl类的实例,我们来看一块之前分析过的代码回顾一下,代码如下:
在这里插入图片描述
在这里插入图片描述
我们可以看到,在构建Advisor时,本质就是构建了一个InstantiationModelAwarePointcutAdvisorImpl类的实例,并且在构建的时候,构造方法的入参中传递了一些非常重要的参数,其中就包括切面中声明的增强方法aspectJAdviceMethod。我们到InstantiationModelAwarePointcutAdvisorImpl类中getAdvice()方法中看下:
在这里插入图片描述
我们发现上边的代码,其实是在初始化一个Advice实例,在进入这个getAdvice()方法的时候,首先会看一下instantiatedAdvice是否为null,如果为null的话,那么表示是第一次调用这个getAdvice()方法,此时就会通过instantiateAdvice()方法创建一个Advice实例出来,接着将这个Advice实例返回。我们现在是第一次进来,此时就会调用instantiateAdvice()方法来创建Advice实例了,这个instantiateAdvice()方法代码如下:
在这里插入图片描述
我们发现,这里通过调用一个叫getAdvice()方法来获取Advice的,同时将自己内部的aspectJAdviceMethod属性作为入参传递了进去,通过前边的分析,我们知道这个aspectJAdviceMethod其实就是切面中声明的增强方法。
好了,看情况接下来我们要继续往下深入了,其实就是来看下上边的getAdvice()方法了,此时我们点进去后,可以发现getAdvice()方法的代码如下:

public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

		Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
		validate(candidateAspectClass);

		// 找到切面中增强方法上面的aspectJ注解
		AspectJAnnotation<?> aspectJAnnotation =
				AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
		if (aspectJAnnotation == null) {
			return null;
		}

		// If we get here, we know we have an AspectJ method.
		// Check that it's an AspectJ-annotated class
		if (!isAspect(candidateAspectClass)) {
			throw new AopConfigException("Advice must be declared inside an aspect type: " +
					"Offending method '" + candidateAdviceMethod + "' in class [" +
					candidateAspectClass.getName() + "]");
		}

		if (logger.isDebugEnabled()) {
			logger.debug("Found AspectJ method: " + candidateAdviceMethod);
		}

		AbstractAspectJAdvice springAdvice;

		// 不同的AspectJ注解类型构建不同的Advice实例
		// 这里主要就是将切面中定义的增强方法candidateAdviceMethod通过构造方法注入到Advice实例中,
		// 后续使用反射调用增强方法时会使用到
		switch (aspectJAnnotation.getAnnotationType()) {
			case AtPointcut:
				if (logger.isDebugEnabled()) {
					logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
				}
				return null;
			case AtAround:
				springAdvice = new AspectJAroundAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtBefore:
				springAdvice = new AspectJMethodBeforeAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtAfter:
				springAdvice = new AspectJAfterAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtAfterReturning:
				springAdvice = new AspectJAfterReturningAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
				if (StringUtils.hasText(afterReturningAnnotation.returning())) {
					springAdvice.setReturningName(afterReturningAnnotation.returning());
				}
				break;
			case AtAfterThrowing:
				springAdvice = new AspectJAfterThrowingAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
				if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
					springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
				}
				break;
			default:
				throw new UnsupportedOperationException(
						"Unsupported advice type on method: " + candidateAdviceMethod);
		}

		// Now to configure the advice...
		springAdvice.setAspectName(aspectName);
		springAdvice.setDeclarationOrder(declarationOrder);
		String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
		if (argNames != null) {
			springAdvice.setArgumentNamesFromStringArray(argNames);
		}
		springAdvice.calculateArgumentBindings();

		return springAdvice;
	}

在进去这个getAdvice()方法后,首先就是执行下边这块代码了:
在这里插入图片描述
通过上图,我们可以看到这里主要就是调用了findAspectJAnnotationOnMethod()方法,而这个方法我们也是比较熟悉的,它其实就是在指定的方法中寻找AspectJ的注解。那我们接着往下看,此时就会看到下边这块代码:
在这里插入图片描述
上边的这块代码就比较核心了,可以看到,这里根据前边扫描出来的AspectJ注解类型,会创建不同实现的Advice实例。那这个AspectJ注解类型是什么呢?我们点进去看一下就知道了,此时我们会发现这个annotationType其实就是一个枚举罢了,而枚举的定义如下:
在这里插入图片描述
上图这个枚举其实比较简单,它就对应着我们切面中增强方法上添加的六种注解,比如@Before注解的annotationType属性的值就是AtBefore。接着我们继续往下分析,假如此时扫描到的注解是@Before注解,那么annotationType的值就是AtBefore,那么接着就会执行下边这个case分支:
在这里插入图片描述
通过上边的代码,可以看到,这里会new出来一个AspectJMethodBeforeAdvice类的对象出来,通过这个类名,我们可以猜测出,这个AspectJMethodBeforeAdvice类是专门给@Before注解使用的,说白了就是专门给前置处理使用的。同时我们可以看到,这里还将切面中定义的增强方法candidateAdviceMethod作为入参传递了进去,那么我们来看下这个构造方法都有哪些逻辑,此时AspectJMethodBeforeAdvice的构造方法如下:
在这里插入图片描述
在这里插入图片描述
通过上边的代码,我们可以看到,其实AspectJMethodBeforeAdvice类的构造方法没什么逻辑,主要就是将这些核心属性又传递给了父类AbstractAspectJAdvice的构造方法,而父类拿到这些核心属性后,就将这些核心属性赋值给了自己的成员变量,而这里边最最重要的属性,其实就是这个增强方法aspectJAdviceMethod了。那这个增强方法aspectJAdviceMethod到底有什么用呢?目前我们还不知道,我们可以想一下。在执行目标方法时,这些增强方法肯定也会执行,那么具体怎么执行呢?我们会发现这个增强方法aspectJAdviceMethod其实是Method类型,而这个Method是反射包下的一个类,所以执行增强方法时,会不会是通过反射调用的?说白了就是通过aspectJAdviceMethod.invoke()这样的形式来调用增强方法。如果此时是@AfterReturning注解,那么就会执行下边下边的代码:
在这里插入图片描述
在这里插入图片描述
通过上边的代码,我们可以看到,在AtAfterReturning的处理中,会构建出来一个AspectJAfterReturningAdvice类的实例,说白了就是@AfterReturning注解专门对应的增强类。最后我们再看一个@After注解,看下它的处理是不是也是一样的,此时AtAfter的代码如下:
在这里插入图片描述在这里插入图片描述
通过上边的代码,我们可以看到,AtAfter的处理也是一样的,就是将增强方法aspectJBeforeAdviceMethod等关键属性传递给父类,然后父类进行初始化。但是我们也发现了不一样的地方,那就是这个AspectJAfterAdvice类中多出来一个invoke()方法,虽然目前我们不知道这个invoke()方法是干嘛的,但是这个invoke()方法是非常重要的。我们还发现invoke()方法上有一个@Override的注解,很明显这个invoke()方法是从某一个接口继承过来的,那么到底是哪个接口呢?我们发现这个invoke()方法其实实现了下边这个接口,如下图:
在这里插入图片描述
可以看到,其实实现的是MethodInterceptor接口的invoke()方法,从MethodInterceptor接口的名字上看,是方法拦截器的意思,那它和我们拦截器链有没有什么关系的?其实拦截器就是MethodInterceptor接口类型的一个实例,MethodInterceptor其实就是拦截器,而拦截器链就是一个一个的MethodInterceptor,就是这个意思。那我们来看下最后剩下的这块代码,如下图:
在这里插入图片描述
这里主要就是为springAdvice设置一些属性,比如切面名称aspectName等。这里设置完属性后就将springAdvice作为结果返回了,其实就是将Advice实例给返回了。
在这里插入图片描述
我们现在拿到了一个advice,那么接下来,我们接着getInterceptors()方法继续往下分析,此时我们会看到下边这块代码:
在这里插入图片描述
我们可以看到,如果这个advice是MethodInterceptor接口实现类的话,那么就直接将advice强转为MethodInterceptor类型并放入到拦截器interceptors中。其实Advice实例其实是MethodInterceptor接口的实现类,比如AspectJAfterAdvice,如下图:
在这里插入图片描述
我们看到这个AspectJAfterAdvice就实现了MethodInterceptor接口,其中invoke()方法就是MethodInterceptor接口中定义的。所以AspectJAfterAdvice就会被直接放到拦截器interceptors中,代码如下:
在这里插入图片描述
说白了就是如果advice是MethodInterceptor的实现类,那么就将advice强转后直接放入到拦截器interceptors中,那么上面构建的advice中,都有哪些advice实现了MethodInterceptor接口,而又有哪些没有实现MethodInterceptor接口呢?我们来看下MethodInterceptor接口的继承关系就知道了,如下图:
在这里插入图片描述
通过上图,我们可以看到,AspectJAfterAdvice、AspectJAroundAdvice、AspectJAfterThrowingAdvice都实现了MethodInterceptor接口,因此这三种Advice本身就是拦截器,而这三种Advice分别对应了@After、@Around和@AfterThrowing这三种增强。所以这三种增强可以通过下边的代码,直接添加到拦截器集合interceptors中。
在这里插入图片描述
所以上面代码的作用,其实就是将实现了MethodInterceptor接口的增强添加到拦截器中。我们现在知道了@After、@Around和@AfterThrowing三种增强,会被添加到拦截器interceptors中。我们知道AspectJ中一共是有五种增强的,那剩下没有实现MethodInterceptor接口的增强又该怎么处理呢?我们知道getInterceptors()方法中最终要返回的是拦截器集合interceptors,而interceptors的定义则是MethodInterceptor类型的List集合。那么此时我们就需要将AspectJ中的五种增强都放到interceptors中返回,但是其中有两种增强,因为没有实现MethodInterceptor接口,所以不能直接放入到interceptors中,那这个时候怎么办呢?我们需要将没有实现MethodInterceptor接口的增强包装一下。说白了就是将它们包装为MethodInterceptor类型的实例。我们继续往下看,于没有实现MethodInterceptor接口的增强,会有单独的逻辑进行处理,我们继续往下看,就会看到这样一块代码,如下:
在这里插入图片描述
通过上边的代码,可以看到,这里主要是对this.adapters进行了遍历处理。那么这个this.adapters是什么呢?我们来找下它的定义,此时会发现这些代码:
在这里插入图片描述
我们可以看到,这个adapters其实就是一个List集合,默认大小为3,是通过构造方法进行初始化的。而构造方法通过调用registerAdvisorAdapter()方法,向adapters中添加了3个Adapter,分别是MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter和ThrowsAdviceAdapter,看名字就是适配器的意思。现在我们知道了adapters中,其实就是MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter和ThrowsAdviceAdapter这三个Adapter,我们继续往下分析,我们现在要分析的代码如下:
在这里插入图片描述
上面的代码中,会遍历adapters中的三个Adapter,然后会调用Adapter的supportsAdvice()方法,通过名字来猜测,这个supportsAdvice()方法应该是来判断是否支持增强的。现在我们已经知道了adapters中的三个Adapter都是什么了,那么我们就干脆来看下这三个Adapter中的supportsAdvice()方法都是怎么实现的吧,此时代码如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到,这三个Adapter的supportsAdvice()方法,主要是来看一下这个advice是不是指定的类型,比如MethodBeforeAdviceAdapter会看一下advice是不是MethodBeforeAdvice类型,而AfterReturningAdviceAdapter则是看一下advice是不是AfterReturningAdvice类型。那剩下的这两种增强,也就是@Before和@AfterReturning,到底是哪种类型呢?我们来看下这两种增强的类继承关系就知道了,首先我们来看下@Before增强的类继承图,也就是AspectJMethodBeforeAdvice的类继承图,如下:
在这里插入图片描述
我们可以看到,AspectJMethodBeforeAdvice实现了MethodBeforeAdvice接口。其实就是当advice为AspectJMethodBeforeAdvice时,由于AspectJMethodBeforeAdvice实现了MethodBeforeAdvice接口,所以此时适配器MethodBeforeAdviceAdapter的supportsAdvice()方法就会返回true。我们接着来看下@AfterReturning的类继承图,也就是AfterReturningAdvice的类继承图,如下:
在这里插入图片描述
上图中AspectJAfterReturningAdvice实现了AfterReturningAdvice接口。那就是当advice为AspectJAfterReturningAdvice时,由于AspectJAfterReturningAdvice实现了AfterReturningAdvice接口,所以适配器AfterReturningAdviceAdapter的supportsAdvice()方法会返回true。一旦supportsAdvice()方法返回true,那么就会执行下边这行代码:
在这里插入图片描述
这里其实就是会调用适配器Adapter的getInterceptor()方法。我们将supportsAdvice()方法和getInterceptor()方法结合起来,来看下这块for循环的代码到底什么意思。
1、当advice为AspectJMethodBeforeAdvice时,遍历到适配器MethodBeforeAdviceAdapter时,supportsAdvice()方法会返回true,那么这个时候就调用适配器MethodBeforeAdviceAdapter的getInterceptor()方法开始处理AspectJMethodBeforeAdvice了,最后将处理结果放到拦截器interceptors中。
2、当advice为AspectJAfterReturningAdvice时,此时遍历到适配器AfterReturningAdviceAdapter,然后发现supportsAdvice()方法的执行结果为true,那么就会调用适配器AfterReturningAdviceAdapter的getInterceptor()方法来处理AspectJAfterReturningAdvice,最后将处理结果放入拦截器interceptors中。

其实这个for循环遍历适配器的代码,无非就是为了让合适的适配器来处理这个advice,比如适配器MethodBeforeAdviceAdapter就是专门来处理AspectJMethodBeforeAdvice的;而适配器AfterReturningAdviceAdapter就是专门来处理AspectJAfterReturningAdvice的。

我们先来看下适配器MethodBeforeAdviceAdapter的代码,我们看这里:
在这里插入图片描述
通过上边的代码,我们可以看到,这里其实就是将advice包装为了一个MethodBeforeAdviceInterceptor类的实例。而MethodBeforeAdviceInterceptor类的构造方法如下:
在这里插入图片描述
通过上边的代码,我们可以看到,这个构造方法非常简单,主要就是传递了这个advice,而且比较重要的是这个MethodBeforeAdviceInterceptor实现了MethodInterceptor接口,这里其实就是将一个advice包装为了一个拦截器MethodInterceptor。我们再来看一下适配器AfterReturningAdviceAdapter的处理,代码如下:
在这里插入图片描述
在这里插入图片描述
这里是将advice封装到了AfterReturningAdviceInterceptor中,而这个AfterReturningAdviceInterceptor也实现了MethodInterceptor接口,所以这里其实也是将advice包装为一个拦截器MethodInterceptor。所以我们知道,对于没有实现MethodInterceptor接口的advice,会有专门的处理逻辑,将这些advice包装为MethodInterceptor类型,说白了就是包装为了拦截器。而这块专门的处理逻辑,就是下面的代码:
在这里插入图片描述
通过上边的代码,我们可以看到,将advice包装为拦截器后,接着就将拦截器放入了拦截器集合interceptors中,最后会将拦截器集合interceptors作为结果返回。那就是Advice和拦截器到底有什么关系?首先我们需要知道一个前提,那就是拦截器说白了就是MethodInterceptor接口的实现类。我们知道,这个Advice可以分为有两大类,一类是实现了MethodInterceptor接口的,另外一类是没有实现MethodInterceptor接口的。对于实现了MethodInterceptor接口的这些Advice来说,Advice本身就是一个拦截器,此时Advice和拦截器就是同一个东西。而对于没有实现MethodInterceptor接口的Advice来说,Advice和拦截器MethodInterceptor没有直接关系,但是Spring会将Advice作为一个属性,给封装到MethodInterceptor的实现类中,所以此时Advice其实就是拦截器中的一个属性。

一张图来梳理下AOP代理的执行流程:
在这里插入图片描述

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

youngerone123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值