Srping AOP的学习(三):AOP的执行过程
1. 说明
前面学习了spring AOP的简单使用以及代理的一些知识,我们知道AOP的原理主要是使用了动态代理,那么它的具体执行流程又是怎样的呢?下面来使用Spring AOP的学习(一)中的demo来进行看一下。
2. 分析
- 2.1 首先我们先在环绕通知的位置打个断点,然后进行debug
- 2.2 通过debug我们可以看出使用代理首先会走到下面的拦截器方法
CglibAopProxy$DynamicAdvisedInterceptor#intercept
注意:这个是使用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方法
上面的getInterceptors()方法,则会判断是否属于MethodInterceptor,是的话,则直接加入列表,不是的话在调用适配器进行处理,具体的如下:@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; }
- getInterceptorsAndDynamicInterceptionAdvice方法
- new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed()方法
首先这个方法分为两部分,第一部分new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)
就是创建一个MethodInvocation对象,重要的proceed()方法部分,这个才是主要的拦截器链调用过程。这边通过一路点下来可以发现最后到了ReflectiveMethodInvocation#proceed方法
- 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
方法的主要过程为:
- getInterceptorsAndDynamicInterceptionAdvice方法
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):释放资源,恢复旧代理
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?