首页 > 其他分享 >Srping AOP的学习(三):AOP的执行过程

Srping AOP的学习(三):AOP的执行过程

时间:2022-11-12 20:45:04浏览次数:35  
标签:Srping 拦截器 target 代理 学习 AOP targetClass 方法 method

1. 说明

前面学习了spring AOP的简单使用以及代理的一些知识,我们知道AOP的原理主要是使用了动态代理,那么它的具体执行流程又是怎样的呢?下面来使用Spring AOP的学习(一)中的demo来进行看一下。

2. 分析

  • 2.1 首先我们先在环绕通知的位置打个断点,然后进行debug
    image
  • 2.2 通过debug我们可以看出使用代理首先会走到下面的拦截器方法CglibAopProxy$DynamicAdvisedInterceptor#intercept
    image
    注意:这个是使用cglib代理走的方法,如果是使用jdk代理走的应该是JdkDynamicAopProxy#invoke方法。这边由于使用的demo代理是没有实现接口的方法,所以是由cglib代理的,因此这边以cglib动态代理进行介绍,不过cglib代理与jdk代理二者的内容是基本相同的。
  • 2.3 下面接着分析CglibAopProxy$DynamicAdvisedInterceptor#intercept这个方法:
    @Override
    @Nullable
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    	// 旧代理
    	Object oldProxy = null;
    	boolean setProxyContext = false;
    	Object target = null;
    	// 获取目标对象
    	TargetSource targetSource = this.advised.getTargetSource();
    	try {
    		// exposeProxy是通过@EnableAspectJAutoProxy(exposeProxy = true)设置的,其默认值为false,如果设置为true的话则可以通过AopContext.currentProxy()获取该代理了
    		if (this.advised.exposeProxy) {
    			// Make invocation available if necessary.
    			// 将代理对象暴露到ThreadLocal中
    			oldProxy = AopContext.setCurrentProxy(proxy);
    			setProxyContext = true;
    		}
    		// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
    		// 获取目标对象实例,这边经过debug发现获取的好像是生成的代理
    		target = targetSource.getTarget();
    		// 获取目标对象的类
    		Class<?> targetClass = (target != null ? target.getClass() : null);
    		// 获取目标方法的拦截器链
    		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    		Object retVal;
    		// Check whether we only have one InvokerInterceptor: that is,
    		// no real advice, but just reflective invocation of the target.
    		// 这里主要就是看是否有拦截器链,如果没有拦截器链则表示不需要增强,直接调用原方法就行,CglibMethodInvocation.isMethodProxyCompatible()这个方法是用来检查是否实现了equals(),hashcode()方法,如果没有也不需要进行代理。jdk代理则是将这一步放在了前面
    		if (chain.isEmpty() && CglibMethodInvocation.isMethodProxyCompatible(method)) {
    			// We can skip creating a MethodInvocation: just invoke the target directly.
    			// Note that the final invoker must be an InvokerInterceptor, so we know
    			// it does nothing but a reflective operation on the target, and no hot
    			// swapping or fancy proxying.
    			// 跳过创建 MethodInvocation:直接调用目标,不需要增强
    			Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
    			retVal = invokeMethod(target, method, argsToUse, methodProxy);
    		}
    		else {
    			// We need to create a method invocation...
    			// 如果拦截器链不为空,则创建一个MethodInvocation,并调用其proceed()方法,也就是开始执行拦截器链
    			retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
    		}
    		// 处理返回值
    		retVal = processReturnType(proxy, target, method, retVal);
    		return retVal;
    	}
    	finally {
    		if (target != null && !targetSource.isStatic()) {
    			// 释放资源
    			targetSource.releaseTarget(target);
    		}
    		if (setProxyContext) {
    			// Restore old proxy.
    			// 恢复旧代理
    			AopContext.setCurrentProxy(oldProxy);
    		}
    	}
    }
    
    • getInterceptorsAndDynamicInterceptionAdvice方法
      public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
      	MethodCacheKey cacheKey = new MethodCacheKey(method);
      	// 从缓存中获取拦截器链
      	List<Object> cached = this.methodCache.get(cacheKey);
      	if (cached == null) {
      		// 如果缓存中没有则通过getInterceptorsAndDynamicInterceptionAdvice获取
      		cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
      				this, method, targetClass);
      		// 将获取的连接器链放入缓存
      		this.methodCache.put(cacheKey, cached);
      	}
      	// 返回拦截器链
      	return cached;
      }
      
      • 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();
        	// 从config中获取所有的advisiors(增强器)
        	Advisor[] advisors = config.getAdvisors();
        	// 拦截器列表,也就是拦截器链
        	List<Object> interceptorList = new ArrayList<>(advisors.length);
        	// 设置目标类
        	Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
        	// 是否有IntroductionAdvisor类型的增强器
        	Boolean hasIntroductions = null;
        	// 遍历advisors
        	for (Advisor advisor : advisors) {
        		// advisor是PointcutAdvisor
        		if (advisor instanceof PointcutAdvisor) {
        			// Add it conditionally.
        			PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
        			// 判断与目标类是否匹配
        			if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
        				MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
        				boolean match;
        				if (mm instanceof IntroductionAwareMethodMatcher) {
        					if (hasIntroductions == null) {
        						hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
        					}
        					match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
        				}
        				else {
        					match = mm.matches(method, actualClass);
        				}
        				// 如果匹配则将advisor转换为方法拦截器对象
        				if (match) {
        					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) {
        			// 如果advisor是IntroductionAdvisor
        			IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
        			if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
        				// 其与目标类匹配,直接将其转化为interceptor加入到拦截器列表中
        				Interceptor[] interceptors = registry.getInterceptors(advisor);
        				interceptorList.addAll(Arrays.asList(interceptors));
        			}
        		}
        		else {
        			// 其它的情况则将其直接转化为interceptor加入拦截器列表中
        			Interceptor[] interceptors = registry.getInterceptors(advisor);
        			interceptorList.addAll(Arrays.asList(interceptors));
        		}
        	}
        	// 返回拦截器列表
        	return interceptorList;
        }
        
        上面的getInterceptors()方法,则会判断是否属于MethodInterceptor,是的话,则直接加入列表,不是的话在调用适配器进行处理,具体的如下:
        image
    • new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed()方法
      首先这个方法分为两部分,第一部分new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)就是创建一个MethodInvocation对象,重要的proceed()方法部分,这个才是主要的拦截器链调用过程。这边通过一路点下来可以发现最后到了ReflectiveMethodInvocation#proceed方法
      image
      • ReflectiveMethodInvocation#proceed方法
      @Override
      @Nullable
      public Object proceed() throws Throwable {
      	// We start with an index of -1 and increment early.
      	// 当前拦截器的下表与拦截器链的长度减一进行比较,就是看是否到了拦截器链中的最后一个拦截器,currentInterceptorIndex初始值为-1
      	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
      		// 调用目标方法
      		return invokeJoinpoint();
      	}
      	// 获取当前拦截器
      	Object interceptorOrInterceptionAdvice =
      			this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
      	// 动态方法匹配拦截器
      	if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
      		// Evaluate dynamic method matcher here: static part will already have
      		// been evaluated and found to match.
      		InterceptorAndDynamicMethodMatcher dm =
      				(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
      		Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
      		// 动态匹配目标方法参数
      		if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
      			// 匹配成功,执行当前拦截器的逻辑
      			return dm.interceptor.invoke(this);
      		}
      		else {
      			// Dynamic matching failed.
      			// Skip this interceptor and invoke the next in the chain.
      			// 匹配失败,跳过这个拦截器
      			return proceed();
      		}
      	}
      	else {
      		// It's an interceptor, so we just invoke it: The pointcut will have
      		// been evaluated statically before this object was constructed.
      		// 一个普通拦截器,调用它的逻辑
      		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
      	}
      }
      
    通过上面的分析可以得知CglibAopProxy$DynamicAdvisedInterceptor#intercept方法的主要过程为:
    image

3. 总结

这里只是对aop的执行流程的简单说明,只是说明了一下大致的流程,其中更具体的则没有往下看。通过这个简单分析可以得知aop的简单执行流程为:
(1):调用连接点
(2):根据使用的代理方式进入CglibAopProxy$DynamicAdvisedInterceptor#intercept方法(cglib动态代理),还是JdkDynamicAopProxy#invoke方法(jdk动态代理)。
(3):获取目标对象
(4):判断exposeProxy是否为true,为true的话则暴露对象到ThreadLocal
(5):获取目标对象和所在的类
(6):获取目标方法的拦截器链。首先会从缓存中获取,如果缓存中没有则通过getInterceptorsAndDynamicInterceptionAdvice方法进行获取
(7):判断拦截器链是否为空,以及是否实现了equals,hashcode等方法,如果为空,则通过反射执行目标方法,不进行增强
(8):如果不为空,则创建MethodInvocation调用proceed()方法执行拦截器链。这边在执行的过程中,是根据currentInterceptorIndex当前拦截器链下标来获取当前执行哪个拦截器的,通过动态匹配的方式,来判断是执行这个拦截器的增强逻辑,还是直接跳过这个拦截器,执行下一个拦截器。直到执行到最后一个。(执行方法中的具体的逻辑就是在7,8这两步的过程中执行的)
(9):对上面的执行得到的结果进行处理
(10):释放资源,恢复旧代理

标签:Srping,拦截器,target,代理,学习,AOP,targetClass,方法,method
From: https://www.cnblogs.com/mcj123/p/16884603.html

相关文章