本文编写于 998 天前,最后修改于 997 天前,其中某些信息可能已经过时。
JDK代理
- 调用代理类
$Proxy
的方法时,会调用super.h.invoke
方法,该方法实际调用的是JdkDynamicAopProxy#invoke
方法; - 判断当前方法是
equals
方法且实现类未对equals
方法进行重新,如果是,就调用JdkDynamicAopProxy#equals
方法,返回执行结果; - 判断当前方法是
hashCode
方法且实现类未对hashCode
方法进行重新,如果是,就调用JdkDynamicAopProxy#hashCode
方法,返回执行结果;
- 调用代理类
cglib代理
- 实际调用的是
DynamicAdvisedInterceptor#intercept
方法;
- 实际调用的是
调用
AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice
方法获取拦截器链chain
;- 从
methodCache
缓存中查找是否存在目标方法对应的拦截器链; - 如果没有从
methodCache
缓存中找到对应的拦截器链,从ProxyFactory
中获取目标类对应的类级别增强advisors
; 依次遍历所有的增强
advsiors
是否与目标方法匹配,该过程与AOP创建过程中的匹配类似;- 如果是
advisor
是IntroductionAdvisor
引介增强的实现类,那么就进行类级别进行匹配(不常用); - 默认的
InstantiationModelAwarePointcutAdvisorImpl
实现的是普通增强PointcutAdvisor
接口,使用切点Pointcut
进行方法级别的匹配; - 先使用切点表达式和目标类进行匹配,确保类级别满足切点表达式;
遍历当前bean中的所有方法,使用
aspectj
提供的方法(SignaturePattern#matchesExactlyMethod
),依次对切点表达式对方法进行精确匹配;- 判断方法参数是否匹配;
- 判断方法名称是否匹配;
- 判断方法抛出异常是否匹配;
- 判断方法返回值是否匹配;
- 调用
DefaultAdvisorAdapterRegistry#getInterceptors
方法获取advisor
中的拦截器; - 调用
InstantiationModelAwarePointcutAdvisorImpl#findAspectJAnnotationMethod
方法扫描增强方法上的aspectJ
注解; 根据
apectJ
注解的类型创建不同的Advice
;@Around
->AspectJAroundAdvice
;@Before
->AspectJMethodBeforeAdvice
;@After
->AspectJAfterAdvice
;@AfterReturning
->AspectJAfterReturningAdvice
;@AfterThrowing
->AspectJAfterThrowingAdvice
;- 其中
AspectJAfterAdvice
、AspectJAroundAdvice
、AspectJAfterThrowingAdvice
三种Advice
都实现了MethodInterceptor
接口,因此这三种Advice
本身就是拦截器;
- 判断
advice
是否实现MethodInterceptor
接口,如果advice
接口MethodInterceptor
接口,就将advice
添加到interceptors
中,此处会处理@Around
、@After
、@AfterThrowing
三种注解; - 从默认配置的适配器
AdvisorAdapter
:MethodBeforeAdviceAdapter
、AfterReturningAdviceAdapter
、ThrowsAdviceAdapter
中循环判断是否支持当前的Advice
,如果支持,就将advice
包装为拦截器并放入interceptors
中,此处会处理@Before
、@AfterReturning
两种注解; - 最终将匹配的
Advisor
收集到interceptorList
,并放到methodCache
缓存中,以便下一次从缓存获取;
- 如果是
- 从
- 如果拦截器链
chain
为空,则通过反射调用目标方法,将结果返回; - 如果拦截器链
chain
不为空,就将拦截器链chain
统一封装为MethodInvocation
; 调用
ReflectiveMethodInvocation#proceed
,执行拦截器链;- 执行拦截器
ExposeInvocationInterceptor#invoke
方法,将拦截器链暴露到ThreadLocal
中,同一个线程可以通过ThreadLocal
获取当前的拦截器链,继续执行下一个拦截器的invoke
方法; - 执行拦截器
AspectJAfterThrowingAdvice#invoke
方法,该方法继续执行下一个拦截器的invoke
方法,并对invoke
方法进行try...catch
代码块包裹; - 执行拦截器
AfterReturningAdviceInterceptor#invoke
方法,该方法继续执行下一个拦截器的invoke
方法,并在invoke
方法后执行AfterReturning
增强; - 执行拦截器
AspectJAfterAdvice#invoke
方法,该方法继续执行下一个拦截器的invoke
方法,并finally语句块中执行After
增强; - 执行拦截器
AspectJAroundAdvice#invoke
方法,该方法会先执行Around
前置增强,接着继续执行下一个拦截器的invoke
方法,并在方法后执行Around
后置增强; - 执行拦截器
MethodBeforeAdviceInterceptor#invoke
方法,该方法会先执行Before
增强; - 执行目标方法;
- 拦截器
AspectJAroundAdvice
执行Around
后置增强; - 拦截器
AspectJAfterAdvice
在finally语句块中执行
After增强
; - 拦截器
AfterReturningAdviceInterceptor
,如果没有异常发生,就执行AfterReturning
增强,并跳过步骤11执行步骤12; - 拦截器
AspectJAfterThrowingAdvice
的try...catch
代码块如果捕捉到异常并且和@AfterThrowing
注解中指定的异常类型一致则执行AfterThrowing
增强; - 拦截器
ExposeInvocationInterceptor
还原ThreadLocal,停止暴露拦截器链;
- 执行拦截器
- 返回执行结果。