拿到代理对象,如何调用增强方法

步骤1

前面已经创建了MathCal的代理对象了,我们在调用方法时加一个断点

这里返回的确实是代理对象,这个对象中保存了详细信息(增强器,原始对象等),我们进入bean.add(2, 10) 中,来到


org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor.intercept(Object, Method, Object[], MethodProxy)方法,


拦截目标方法的执行

根据ProxyFactory获得目标方法的拦截器链,如果没有拦截器链,就直接执行目标方法

如果有拦截器链,将需要执行的目标对象,目标方法,连接器链传入,创建一个CglibMethodInvocation对象并调用proceed()方法

那么拦截器链如何获取呢?我们进入this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)方法中

通过advisorChainFactory获得目标方法的拦截器链,进入this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass)

先创建一个list保存所有拦截器,可以看到,list创建时,已经初始化长度,这个长度就是通知方法的个数+一个默认通知,对于本案例就是5个。


之后又在循环遍历所有增强器,调用registry.getInterceptors(advisor);将其增强器包装为Interceptor[]拦截器,那么是如何包装的呢?

进入到其中查看,其实很简单,首先判断增强器是不是MethodInterceptor,如果是就直接加入到list中,


如果不是就使用增强器的适配器AdvisorAdapter将增强器转为MethodInterceptor,之后转为数组返回。


foreach循环完后就获得了拦截器链(每一个通知方法又被包装为拦截器,利用MethodInterceptor机制)


步骤2

获得了拦截器链,拦截器链是如何执行的呢?获得拦截器链后有new了一个CglibMethodInvocation并调用了proceed()方法

我们进入到proceed()方法

this.currentInterceptorIndex 表示执行的拦截器索引默认等于-1,首先判断是否有拦截器执行目标方法,


或者拦截器索引等于拦截器数组大小减一相等(也就是执行到最后一个拦截器)都会执行目标方法。下面我们debug调试,查看拦截器的执行


首先来到第一个拦截器

拦截器索引等于-1,拦截器数组等于4,通过this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);


获得到第一个拦截器,拦截器索引+1,执行interceptorOrInterceptionAdvice).invoke(this)方法,传入的this为ChlibProxy

进入其中

其中invocation是当前线程共享的MethodInvocation,先从其中获得MethodInvocation,再将ChlibProxy加入到当前线程公享数据中,


调用ChlibProxy的procees()方法,进入mi.proceed()中,又来到我们之前的proceed()方发,初始的拦截器索引+1了

然后又重this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);获得第二个拦截器

之后又会调用((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);来到AspectJAfterThrowingAdvice的invoke()方法中

又是调用mi.proceed()方法,又来到proceed()方法,拦截器索引+1,又获的一个拦截器

AfterReturningAdviceInterceptor这个拦截器还是调用((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)方法,进入其中

又调用mi.proceed()方法,来到proceed(),拦截器索引+1,获得一个拦截器

又调用((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)方法,进入其中

又调用mi.proceed()来到proceed()方法,拦截器索引+1,获得一个拦截器

又调用((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)方法,进入其中

这里就调用了前置通知,之后又调用mi.proceed()来到proceed()方法

此时拦截器索引为4,等于拦截器数组大小4,就调用invokeJoinpoint()方法,执行目标方法并返回,之后就调用后置通知

后置通知调用完毕如果有异常就将异常向上抛,执行异常通知

如果没有异常,就执行返回通知

返回通知执行完毕,程序也就跑完了。拦截器链就是链式或去拦截器,调用拦截器的invoke()方法,


每一个拦截器都等待下一个拦截器执行完毕返回以后,在执行。通过拦截器链的机制,保证通知方法与目标方法的执行顺序。


步骤3,拦截器链调用过程


总结

我们使用@EnableAspectJAutoProxy 开启AOP功能,主要是 @EnableAspectJAutoProxy 会给容器中注册一个 AnnotationAwareAspectJAutoProxyCreator 后置处理器的定义信息 beanDefinition


通过 registerBeanPostProcessors(beanFactory) 创建 AnnotationAwareAspectJAutoProxyCreator 后置处理器对象并向容器注册,


然后通过finishBeanFactoryInitialization(beanFactory),初始化剩下的单实例bean,我们自己的类就会创建出来,AnnotationAwareAspectJAutoProxyCreator也会拦截组件的创建过程,


在组件创建后,AnnotationAwareAspectJAutoProxyCreator会通过postProcessAfterInstantiation()判断主键是否需要包装,如果需要,就会将切面中的通知方法包装为增强器(Advisor),


然后给目标对象创建一个代理对象,接下来就是通过代理对象执行目标方法。代理对象执行目标方法前会被CglibProxy.intercept()拦截,


拦截中,先得到目标方法的拦截器链(增强器包装为拦截器),通过拦截器链机制,依次进入每一个拦截器进行执行


执行方式一(目标方法没有出现异常):前置通知->目标方法->后置通知->返回通知


执行方式二(目标方法出现异常):前置通知->目标方法->后置通知->异常通知

posted @ 2025-03-26 03:44  jock_javaEE  阅读(69)  评论(0)    收藏  举报