Spring AOP源码分析八

在上一篇文章的中,我们知道了invoke()方法的核心处理流程,其实就是先对特定方法进行处理,然后再获取目标方法的拦截器链,最后执行拦截器链并返回结果。但是具体是怎么获取目标方法对应拦截器链的?又是怎么执行拦截器链的?这些我们目前都不清楚,我们今天主要就是来分析一下拦截器链的获取过程,分析入口就是下边这行代码:
在这里插入图片描述
通过上边的代码,我们可以看到,这个获取拦截器链的核心逻辑都封装在这个getInterceptorsAndDynamicInterceptionAdvice()方法中。那我们直接点进来看下,此时就会看到下边这块代码:
在这里插入图片描述
在这个方法中,首先将method作为入参,构建出来了一个缓存key对象MethodCacheKey,然后使用这个缓存key从缓存methodCache中获取拦截器链。那这个methodCache是什么数据结构呢?目前为止看起来应该是一个Map,这个时候我们翻代码找了一下,发现methodCache确实是一个Map,定义如下:
在这里插入图片描述
在上边的代码中,缓存methodCache的key是一个MethodCacheKey对象,而value则是一个List集合,其实就是专门放拦截器使用的,这个value就是我们要获取的拦截器链,既然现在已经确定缓存methodCache是一个Map了,那么再从Map中获取拦截器链时,一定会使用到key,那么这个key是怎么构造出来的呢?说白了就是MethodCacheKey对象是怎么构造出来的呢?这个时候我们来看下MethodCacheKey的构造方法,如下图:
在这里插入图片描述
可以看到,MethodCacheKey的构造方法其实很简单,其实就是将入参method本身和method的hashCode值分别赋值给了自己内部的成员变量method和hashCode了。现在知道了MethodCacheKey构造方法和methodCache的数据结构后,我们再回到主线上来,如下图:
在这里插入图片描述
通过上边的代码,我们可以看到,其实就是先通过传进来的method构建出来一个缓存key,然后使用这个缓存key从methodCache中获取拦截器链cached,methodCache本质就是一个Map。如果缓存中存在拦截器链的话,即cached不为null,就直接将拦截器链cached作为结果返回。如果缓存中不存在拦截器链的话,即cached为null,那么此时就调用AdvisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice()方法获取拦截器链,并且将最后获取的拦截器链put到缓存methodCache中,这样当下一次获取拦截器链时,就可以直接走缓存了。获取拦截器链的核心逻辑,其实是在AdvisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice()方法中的。我们来看一下getInterceptorsAndDynamicInterceptionAdvice()方法,此时就会看到下边这块代码:

	@Override
	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, @Nullable Class<?> targetClass) {

		// This is somewhat tricky... We have to process introductions first,
		// but we need to preserve order in the ultimate list.
		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

		// 获取当时ProxyFactory中添加的逻辑,也就是拦截器,一般这个config就是ProxyFactory对象
		Advisor[] advisors = config.getAdvisors();
		// 拦截器集合
		List<Object> interceptorList = new ArrayList<>(advisors.length);

		// actualClass 其实就是com.younger.aop.service.ProductServiceImpl
		Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
		Boolean hasIntroductions = null;

		// 遍历所有的增强,匹配出目标方法可以使用的增强,也就是拦截器
		for (Advisor advisor : advisors) {
			if (advisor instanceof PointcutAdvisor) {
				// Add it conditionally.
				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
				// 在类级别判断目标类是否匹配当前增强的Advisor,与之前AopUtils.canApply()匹配切面的逻辑一样。
				if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
					boolean match;
					// 在方法级别判断目标类方法是否匹配当前增强的Advisor,与之前AopUtils.canApply()匹配切面的逻辑一样。
					if (mm instanceof IntroductionAwareMethodMatcher) {
						if (hasIntroductions == null) {
							hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
						}
						match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
					}
					else {
						match = mm.matches(method, actualClass);
					}
					// 匹配成功
					if (match) {
						// 从advisor中获取所有的拦截器
						MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
						if (mm.isRuntime()) {
							// Creating a new object instance in the getInterceptors() method
							// isn't a problem as we normally cache created chains.
							for (MethodInterceptor interceptor : interceptors) {
								// 添加动态拦截器
								interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
							}
						}
						else {
							// 添加普通拦截器
							interceptorList.addAll(Arrays.asList(interceptors));
						}
					}
				}
			}
			// 引介增强的处理
			else if (advisor instanceof IntroductionAdvisor) {
				IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
				if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
					Interceptor[] interceptors = registry.getInterceptors(advisor);
					interceptorList.addAll(Arrays.asList(interceptors));
				}
			}
			else {
				// 其他增强处理
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}

		return interceptorList;
	}

在这里插入图片描述
我们可以看到,首先从config中获取到了增强advisors,这个config其实就是最开始时构造的ProxyFactory对象,当时在构造ProxyFactory对象时,就为ProxyFactory设置了增强advisors。我们再回头看一眼构造ProxyFactory的代码,我们看下边这块代码:
在这里插入图片描述可以看到,在给ProxyFactory设置属性的时候,其中有一行代码就是proxyFactory.addAdvisors(advisors),说白了就是通过这行代码将增强advisors设置给了ProxyFactory。所以再回头看下我们这里要分析的代码,如下图:
在这里插入图片描述
这行代码Advisor[] advisors = config.getAdvisors(),就是从ProxyFactory中获取当时设置的增强advisors,而且我们要知道的是这个增强advisors,是当时分别通过类级别和方法级别匹配出来的。并且需要注意的是:这个增强advisors是目标类维度对应的增强,为什么这样说呢?因为当时为目标类匹配增强的时候,Spring的处理逻辑是:只要目标类中任意一个方法匹配上增强的切点表达式,那么就会直接将这个增强放入到目标类对应的“合格增强”集合中。我们接着往下看,此时我们看到了interceptorList变量和actualClass变量的声明,如下图:
在这里插入图片描述
这个interceptorList就是一个拦截器集合,它的大小被设置为了增强advisors的大小,而actualClass代表的则是被调用方法的声明类,声明类是通过getDeclaringClass()方法获取的,在我们这个场景中,这个声明类其实就是ProductServiceImpl。那么到这里为止,做的事情无非就是声明了几个变量而已,分别是当前bean适用的增强advisors、拦截器集合interceptorList以及目标类actualClass这三个变量,而目标类actualClass其实就是ProductServiceImpl这个类。我们需要继续往下看代码,这个时候我们会看到这样一块代码:
在这里插入图片描述
在这里插入图片描述
通过上边的代码,可以看到,这里主要是一个for循环,并且这个for循环是对增强advisors做的遍历处理,其中advisor instanceof PointcutAdvisor和advisor instanceof IntroductionAdvisor,就是判断当前增强到底是不是PointcutAdvisor类型和IntroductionAdvisor类型。这个PointcutAdvisor和IntroductionAdvisor是不是有点熟悉?在前边的文章中我们已经分析过的,这个PointcutAdvisor代表的是普通增强,而IntroductionAdvisor代表的是引介增强,引介增强的控制粒度是类级别的,一般不常用,我们常用的还是控制粒度为方法级别的普通增强,所以接下来我们主要会分析一下普通增强的处理。那接下来该做什么处理了呢?现在我们已经获取到了目标类在类级别对应的增强advisors,其实就是当时设置在ProxyFactory中的增强advisors。但是,我们在真正执行目标方法时,肯定不能将类级别的增强advisors全部执行一遍吧?这样肯定是不合理的,因为有的增强是不适用于当前方法(也就是目标方法)的,所以接下来就要为目标方法匹配出适用的增强,那么具体怎么进行匹配呢?那接下来我们就进入普通增强的if分支来看下吧,首先我们就会看到这个if条件,我们看这里:
在这里插入图片描述
可以看到,只有满足这个if条件,才会正常往下进行处理,我们可以看到这个if条件有两个条件,只要满足其中一个条件,就可以正常往下进行处理了,其中一个条件就是config.isPreFiltered(),说白了就是看下ProxyFactory中的preFiltered标识是否为true,而这个preFiltered标识通过名字猜测,大概表示的意思是“是否为预过滤”,如果是预过滤,那么就正常往下执行。其实这个preFiltered标识,当时我们在ProxyFactory构造那节就讲过,这个preFiltered属性通常会被设置为true,所以这个if条件通常是满足的。那万一这个preFiltered属性为false呢?这个时候该怎么办?
如果preFiltered为false,那么这个时候就要来判断第二个条件了,也就是pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)这个条件,那这行代码是什么意思呢?
我们简单来分析下,首先这个pointcutAdvisor代表的是增强,然后从这个增强pointcutAdvisor中获取到了一个切点Pointcut,接着从切点Pointcut中获取到了一个ClassFilter,而这个ClassFilter看名字是类过滤器的意思,最后通过ClassFilter的matches()方法完成了判断。而且在调用ClassFilter的matches()方法时,我们注意到将目标类actualClass作为入参传递到了matches()方法中,其实到这里,我们大概可以判断出这行代码的作用了,其实就是在类级别判断目标类actualClass是否匹配当前增强pointcutAdvisor,说白了就是看一下目标类actualClass,也就是ProductServiceImpl,是否满足增强中配置的切点表达式,如果满足的话,再进行进一步的处理。这个时候我们继续往下分析,如果当前增强匹配上了目标类,那么就继续往下处理,此时我们就会看到这行代码:
在这里插入图片描述
我们可以看到这行代码MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(),其实和刚才获取类过滤器ClassFilter一样,通过这行代码获取到了当前增强的方法匹配器MethodMatcher,并且将方法匹配器MethodMatcher赋值给了mm变量。那么这个方法匹配器MethodMatcher有啥用呢?这个方法匹配器MethodMatcher,应该是用来判断当前增强是否匹配目标方法的。我们继续往下看,此时我们就会看到下边这块代码:
在这里插入图片描述
这里会根据方法匹配器mm的类型不同,做不同的处理,但是核心都是一样的,最后都会调用方法匹配器mm的matches()方法完成判断,而这个matches()方法的其中一个入参就是目标方法method。这个就是在方法级别,来判断一下目标方法和增强中的切点表达式是否匹配。也就是说这里匹配的时候,会先在类级别判断是否匹配,如果类级别匹配成功,那么就在方法级别进一步判断是否匹配。这里其实就是在进行类级别和方法级别的匹配,说白了就是通过类级别和方法级别的匹配,来看下这个增强advisor是否可以适用于当前要调用的目标方法,如果适用,说白了就是匹配上的话,那么就会将match变量赋值为true。将match变量赋值为true之后,接下来做什么呢?我们继续往下看,此时会看到这块代码:
在这里插入图片描述
当match为true的时候,首先会执行registry.getInterceptors(advisor)这行代码来获取增强advisor中的拦截器,并将获取到的拦截器赋值给interceptors数组,最终将interceptors数组添加到拦截器集合interceptorList中。这里就是先找到适用于当前方法对应的增强advisor,然后再获取到增强advisor对应的拦截器interceptors,最终将拦截器interceptors收集起来,也就是最后给放到了拦截器集合interceptorList中。到这里为止,普通增强就处理完了,我们来看下剩下的代码:
在这里插入图片描述
可以看到,其实处理都是大同小异的。刚才我们分析的是普通增强的处理,而这里则是引介增强和其他类型增强的处理,过程都差不多,比如引介增强这里在目标类级别进行了判断,如果匹配成功的话,就将增强对应的拦截器放入到拦截器集合interceptorList中。最后当for循环执行完毕时,也就是目标类级别对应的所有增强advisor都处理完毕了,那么就会将拦截器集合interceptorList作为结果进行返回。需要注意的是,最后返回的这个拦截器集合interceptorList是目标方法级别对应要执行的增强,也就是在执行目标方法时,这个拦截器集合interceptorList中的拦截器都是需要执行的!接着就会将返回的拦截器集合,也就是拦截器链放入到缓存中,这样可以便于下一次直接从缓存中获取拦截器链,最后将拦截器链返回,如下图:
在这里插入图片描述
最后在JdkDynamicAopProxy的invoke()方法中,就可以获取到拦截器链chain了,如下图:
在这里插入图片描述
到这里为止,就成功获取到目标方法适用的拦截器链了,当目标方法执行的时候,拦截器链chain中的拦截器都需要被执行。
一张图来梳理下AOP代理的执行流程:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

youngerone123

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

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

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

打赏作者

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

抵扣说明:

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

余额充值