一、AOP的作用

二、AOP 术语解释

https://www.processon.com/view/link/5ecca5ebe0b34d5f262eae3a
image.png
image.png

三、Spring Aop与AspectJ

Spring Aop:

  • 它基于动态代理来实现。默认地,如果使用接口的,用 JDK 提供的动态代理实现,如果没有接口,使用 CGLIB 实现。大家一定要明白背后的意思,包括什么时候会不用 JDK 提供的动态代理,而用 CGLIB 实现。
  • Spring 3.2 以后,spring-core 直接就把 CGLIB 和 ASM 的源码包括进来了,这也是为什么我们不需要显式引入这两个依赖
  • Spring 的 IOC 容器和 AOP 都很重要,Spring AOP 需要依赖于 IOC 容器来管理。
  • Spring AOP 只能作用于 Spring 容器中的 Bean,它是使用纯粹的 Java 代码实现的,只能作用于 bean 的方法。
  • Spring 提供了 AspectJ 的支持,但只用到的AspectJ的切点解析和匹配。
  • 很多人会对比 Spring AOP 和 AspectJ 的性能,Spring AOP 是基于代理实现的,在容器启动的时候需要生成代理实例,在方法调用上也会增加栈的深度,使得 Spring AOP 的性能不如 AspectJ 那么好。

AspectJ:

  • AspectJ 出身也是名门,来自于 Eclipse 基金会,link:https://www.eclipse.org/aspectj
  • 属于静态织入,它是通过修改代码来实现的,它的织入时机可以是:
    • Compile-time weaving:编译期织入,如类 A 使用 AspectJ 添加了一个属性,类 B 引用了它,这个场景就需要编译期的时候就进行织入,否则没法编译类 B。
    • Post-compile weaving:编译后织入,也就是已经生成了 .class 文件,或已经打成 jar 包了,这种情况我们需要增强处理的话,就要用到编译后织入。
    • Load-time weaving:指的是在加载类的时候进行织入,要实现这个时期的织入,有几种常见的方法。1、自定义类加载器来干这个,这个应该是最容易想到的办法,在被织入类加载到 JVM 前去对它进行加载,这样就可以在加载的时候定义行为了。2、在 JVM 启动的时候指定 AspectJ 提供的 agent:-javaagent:xxx/xxx/aspectjweaver.jar。
  • AspectJ 能干很多 Spring AOP 干不了的事情,它是 AOP 编程的完全解决方案。Spring AOP 致力于解决的是企业级开发中最普遍的 AOP 需求(方法织入),而不是力求成为一个像 AspectJ 一样的 AOP 编程完全解决方案。
  • 因为 AspectJ 在实际代码运行前完成了织入,所以大家会说它生成的类是没有额外运行时开销的。

    四、用两个demo快速理解AOP到底能做些什么

    我们有一个简单的计算器demo,目前只有最简单的加减乘除功能,代码如下:

    1.接口类

    1. public interface Calculate {
    2. /*** 加法*/
    3. int add(int numA, int numB);
    4. /*** 减法*/
    5. int sub(int numA, int numB);
    6. /*** 乘法*/
    7. int multi(int numA, int numB);
    8. /*** 除法*/
    9. int div(int numA, int numB);
    10. }

    2.接口实现类

    1. import org.springframework.aop.framework.AopContext;
    2. import org.springframework.stereotype.Component;
    3. @Component
    4. public class CalculateImpl implements Calculate {
    5. /*** 加法*/
    6. public int add(int numA, int numB) {
    7. return numA+numB;
    8. }
    9. /*** 减法*/
    10. public int sub(int numA, int numB) {
    11. return numA-numB;
    12. }
    13. /*** 乘法*/
    14. public int multi(int numA, int numB) {
    15. return numA*numB;
    16. }
    17. /*** 除法*/
    18. public int div(int numA, int numB) {
    19. return numA/numB;
    20. //((Calculate) AopContext.currentProxy()).add(numA,numB);
    21. }
    22. }

    假设我现在我想在项目功能上加一个函数调用日志打印的功能,但我又不想去改动CalculateImpl代码了,我们都知道一些基础的类尽量是不要做过多的功能改动的除非是bug要修正。下面我们来看看用AOP是如何实现的:

    1.定义一个切面类

    1. import org.aspectj.lang.JoinPoint;
    2. import org.aspectj.lang.annotation.*;
    3. import org.springframework.core.annotation.Order;
    4. import org.springframework.stereotype.Component;
    5. @Aspect
    6. @Order
    7. @Component
    8. /***
    9. * 定义一个切面类,用来增强加减乘除时做日志打印功能
    10. */
    11. public class CalculateLogAspect {
    12. //定义切点,定义那些方法需要增强
    13. @Pointcut("execution(* com.bean.aop.CalculateImpl.*(..))")
    14. public void pointCut(){};
    15. @Before(value = "pointCut()")
    16. public void before(JoinPoint joinpoint) throws Throwable {
    17. String methodName = joinpoint.getSignature().getName();
    18. System.out.println("--------before--------");
    19. System.out.println("执行目标方法:"+methodName);
    20. }
    21. @After(value = "pointCut()")
    22. public void after(JoinPoint joinpoint) throws Throwable {
    23. String methodName = joinpoint.getSignature().getName();
    24. System.out.println("--------after--------");
    25. System.out.println("执行目标方法:"+methodName);
    26. }
    27. @AfterReturning(value = "pointCut()")
    28. public void afterReturning(JoinPoint joinpoint) throws Throwable {
    29. String methodName = joinpoint.getSignature().getName();
    30. System.out.println("--------afterReturning--------");
    31. System.out.println("执行目标方法:"+methodName);
    32. }
    33. @AfterThrowing(value = "pointCut()")
    34. public void afterThrowing(JoinPoint joinpoint) throws Throwable {
    35. String methodName = joinpoint.getSignature().getName();
    36. System.out.println("--------afterThrowing--------");
    37. System.out.println("执行目标方法:"+methodName);
    38. }
    39. }

    2.调用测试:

    1. import org.springframework.context.ApplicationContext;
    2. import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    3. import org.springframework.context.annotation.ComponentScan;
    4. import org.springframework.context.annotation.Configuration;
    5. import org.springframework.context.annotation.EnableAspectJAutoProxy;
    6. @Configuration
    7. @EnableAspectJAutoProxy(proxyTargetClass = true) /*<aop:aspectj-autoproxy/> <aop:config proxy-target-class="true"/>*/
    8. @ComponentScan("com.bean.aop")
    9. public class AopApplication {
    10. public static void main(String[] args) {
    11. ApplicationContext context = new AnnotationConfigApplicationContext(AopApplication.class);
    12. CalculateImpl calculate = context.getBean(CalculateImpl.class);
    13. calculate.add(1,2);
    14. }
    15. }

    3.运行结果:

    可以看出,我们并没有对原有的接口实现类CalculateImpl做任何的代码修改,通过Pointcut的方式就实现了日志打印的功能
    image.png

    我们还是继续上面的例子,假如我现在不是在原有功能上做增强,我是想增加新的功能,如我想给程序加一个取模的计算功能,还是不想修改到CalculateLogAspect类,用AOP又如何实现呢?

    1.我们先添加一个取模的接口和接口实现

    1. public interface CalculateQM {
    2. /*** 取模*/
    3. int mod(int numA, int numB);
    4. }
    5. public class CalculateQMImpl implements CalculateQM {
    6. /*** 取模*/
    7. public int mod(int numA,int numB){
    8. return numA%numB;
    9. }
    10. }

    2.我们再添加一个Aspect切面类来引入新增加的取模功能

    1. @Aspect
    2. @Order
    3. @Component
    4. /***
    5. * 定义一个切面类,用来新增取模计算功能
    6. */
    7. public class CalculateQMAspect {
    8. /*引入:*/
    9. @DeclareParents(value="com.bean.aop.CalculateImpl", // 动态实现的类,即指定要给那一个类引入新功能
    10. defaultImpl = CalculateQMImpl.class) // 引入的接口的默认实现,即指定新增加的功能接口的实现类
    11. public static CalculateQM calculateQM; // 引入的接口,即指定新增加的功能接口
    12. }

    3.测试

    1. @Configuration
    2. @EnableAspectJAutoProxy(proxyTargetClass = true) /*<aop:aspectj-autoproxy/> <aop:config proxy-target-class="true"/>*/
    3. @ComponentScan("com.bean.aop")
    4. public class AopApplication {
    5. public static void main(String[] args) {
    6. ApplicationContext context = new AnnotationConfigApplicationContext(AopApplication.class);
    7. CalculateImpl calculate = context.getBean(CalculateImpl.class);
    8. calculate.add(1,2);
    9. //CalculateQM接口功能已经引入到了calculateImpl,这里已经可以直接从calculateImpl这个bean中拿到CalculateQM对象并使用取模功能了。
    10. CalculateQM pcalculate = (CalculateQM) context.getBean("calculateImpl");
    11. System.out.println(pcalculate.mod(100,200));
    12. }
    13. }

    4.运行结果

    从下图可以看出,在没有修改任何一行calculateImpl代码的前提下,我们给calculateImpl引入了新的取模计算功能。
    image.png

    五、spring aop源码解析

    上面做了作用、原理以及案例的演示,原理和使用还是很简单的。
    我们知道,spring中的aop是通过动态代理实现的,那么他底层具体是如何实现的呢?
    spring通过一个切面类,在他的类上加入@Aspect注解,定义一个Pointcut方法,最后定义一系列的增强方法。这样就完成一个对象的切面操作。
    通过上面的例子,我们可以思考一下,要实现我们的aop,大致有以下思路:
    1.找到所有的切面类
    2.解析出所有的advice并保存
    3.创建一个动态代理类
    4.调用被代理类的方法时,找到他的所有增强器,并增强当前的方法
    那么下面通过源码验证一下我们的猜测:
    image.png

    5.1、切面类的解析

    spring通过@EnableAspectJAutoProxy开启aop切面,在注解类上面发现@Import(AspectJAutoProxyRegistrar.class),AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar,所以他会通过registerBeanDefinitions方法为我们容器导入beanDefinition。
    image.png
    进入解析切面的过程:
    image.png
    postProcessBeforeInstantiation是在任意bean创建的时候就调用了
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInstantiation
    org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
    org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation
    详细流程图:
    https://www.processon.com/view/link/5f1958a35653bb7fd24d0aad
    追踪一下源码可以看到最终导入AnnotationAwareAspectJAutoProxyCreator,我们看一下他的类继承关系图,发现它实现了两个重要的接口,BeanPostProcessor和InstantiationAwareBeanPostProcessor
    首先看InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法
    Object postProcessBeforeInstantiation(Class beanClass, String beanName)(InstantiationAwareBeanPostProcessor)
    org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation
    org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#shouldSkip
    org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
    org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors

    1. public List<Advisor> buildAspectJAdvisors() {
    2. //获取缓存中的aspectBeanNames
    3. List<String> aspectNames = this.aspectBeanNames;
    4. if (aspectNames == null) {
    5. synchronized (this) {
    6. aspectNames = this.aspectBeanNames;
    7. if (aspectNames == null) {
    8. List<Advisor> advisors = new ArrayList<>();
    9. aspectNames = new ArrayList<>();
    10. //获取beanFactory中所有的beanNames
    11. String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
    12. this.beanFactory, Object.class, true, false);
    13. for (String beanName : beanNames) {
    14. if (!isEligibleBean(beanName)) {
    15. continue;
    16. }
    17. // We must be careful not to instantiate beans eagerly as in this case they
    18. // would be cached by the Spring container but would not have been weaved.
    19. Class<?> beanType = this.beanFactory.getType(beanName);
    20. if (beanType == null) {
    21. continue;
    22. }
    23. //找出所有类上面含@Aspect注解的beanName
    24. if (this.advisorFactory.isAspect(beanType)) {
    25. //将找到的beanName放入aspectNames集合
    26. aspectNames.add(beanName);
    27. AspectMetadata amd = new AspectMetadata(beanType, beanName);
    28. if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
    29. MetadataAwareAspectInstanceFactory factory =
    30. new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
    31. //1.找到切面类的所有但是不包括@Pointcut注解的方法
    32. //2.筛选出来包含@Around, @Before, @After,@ AfterReturning, @AfterThrowing注解的方法
    33. //3.封装为List<Advisor>返回
    34. List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
    35. if (this.beanFactory.isSingleton(beanName)) {
    36. //将上面找出来的Advisor按照key为beanName,value为List<Advisor>的形式存入advisorsCache
    37. this.advisorsCache.put(beanName, classAdvisors);
    38. }
    39. else {
    40. this.aspectFactoryCache.put(beanName, factory);
    41. }
    42. advisors.addAll(classAdvisors);
    43. }
    44. else {
    45. // Per target or per this.
    46. if (this.beanFactory.isSingleton(beanName)) {
    47. throw new IllegalArgumentException("Bean with name '" + beanName +
    48. "' is a singleton, but aspect instantiation model is not singleton");
    49. }
    50. MetadataAwareAspectInstanceFactory factory =
    51. new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
    52. this.aspectFactoryCache.put(beanName, factory);
    53. advisors.addAll(this.advisorFactory.getAdvisors(factory));
    54. }
    55. }
    56. }
    57. this.aspectBeanNames = aspectNames;
    58. return advisors;
    59. }
    60. }
    61. }
    62. if (aspectNames.isEmpty()) {
    63. return Collections.emptyList();
    64. }
    65. List<Advisor> advisors = new ArrayList<>();
    66. for (String aspectName : aspectNames) {
    67. //当再次进入该方法,会直接从advisorsCache缓存中获取
    68. List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
    69. if (cachedAdvisors != null) {
    70. advisors.addAll(cachedAdvisors);
    71. }
    72. else {
    73. MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
    74. advisors.addAll(this.advisorFactory.getAdvisors(factory));
    75. }
    76. }
    77. return advisors;
    78. }

    流程图:
    image.png
    解析的步骤:
    image.png
    最终将解析出来的advisor放入缓存,这里思考清楚 advisor和advise的区别
    image.png
    其实就是我们切面中的通知方法:
    image.png

    5.2、创建代理

    进入创建代理的过程:
    image.png
    postProcessAfterInitialization是在bean创建完成之后执行的
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
    org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization
    org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
    image.png
    详细流程图:
    https://www.processon.com/view/link/5f1e93f25653bb7fd2549b7c
    1.获取advisors:创建代理之前首先要判断当前bean是否满足被代理, 所以需要将advisor从之前的缓存中拿出来和当前bean 根据表达式进行匹配:
    Object postProcessAfterInitialization(@Nullable Object bean, String beanName)(BeanPostProcessor)
    org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
    org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
    org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
    org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
    上述代码的链路最终到了findCandidateAdvisors,我们发现在postProcessBeforeInstantiation方法中对查找到的Advisors做了缓存,所以这里只需要从缓存中取就好了
    最后创建代理类,并将Advisors赋予代理类,缓存当前的代理类
    2.匹配:根据advisors和当前的bean根据切点表达式进行匹配,看是否符合。
    image.png
    org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply
    org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply
    org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Advisor, java.lang.Class, boolean) 拿到PointCut
    org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class, boolean)
    org.springframework.aop.ClassFilter#matches 粗筛
    org.springframework.aop.IntroductionAwareMethodMatcher#matches 精筛

3.创建代理:找到了 和当前Bean匹配的advisor说明满足创建动态代理的条件:
image.png

  1. Object proxy = createProxy(
  2. bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
  3. this.proxyTypes.put(cacheKey, proxy.getClass());

image.png
理解了上面两个重要的方法,我们只需要将他与创建bean的流程联系起来就可以知道代理对象创建的整个流程了,在before和after方法分别放置断点,我们可以看到他的整个调用链路

5.3、代理类的调用

https://www.processon.com/view/link/5f4dd513e0b34d1abc735998
前面的分析可知,spring将找到的增强器Advisors赋予了代理类,那么在执行只要将这些增强器应用到被代理的类上面就可以了,那么spring具体是怎么实现的呢,下面我们以jdk代理为例分析一下源码:

  1. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  2. MethodInvocation invocation;
  3. Object oldProxy = null;
  4. boolean setProxyContext = false;
  5. //获取当前被代理类
  6. TargetSource targetSource = this.advised.targetSource;
  7. Object target = null;
  8. // equals,hashcode等方法不做代理,直接调用
  9. try {
  10. if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
  11. // The target does not implement the equals(Object) method itself.
  12. return equals(args[0]);
  13. }
  14. else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
  15. // The target does not implement the hashCode() method itself.
  16. return hashCode();
  17. }
  18. else if (method.getDeclaringClass() == DecoratingProxy.class) {
  19. // There is only getDecoratedClass() declared -> dispatch to proxy config.
  20. return AopProxyUtils.ultimateTargetClass(this.advised);
  21. }
  22. else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
  23. method.getDeclaringClass().isAssignableFrom(Advised.class)) {
  24. // Service invocations on ProxyConfig with the proxy config...
  25. return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
  26. }
  27. Object retVal;
  28. // 将代理对象放到线程本地变量中
  29. if (this.advised.exposeProxy) {
  30. // Make invocation available if necessary.
  31. oldProxy = AopContext.setCurrentProxy(proxy);
  32. setProxyContext = true;
  33. }
  34. // Get as late as possible to minimize the time we "own" the target,
  35. // in case it comes from a pool.
  36. target = targetSource.getTarget();
  37. Class<?> targetClass = (target != null ? target.getClass() : null);
  38. //将增加器装换为方法执行拦截器链
  39. List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
  40. // Check whether we have any advice. If we don't, we can fallback on direct
  41. // reflective invocation of the target, and avoid creating a MethodInvocation.
  42. if (chain.isEmpty()) {
  43. // We can skip creating a MethodInvocation: just invoke the target directly
  44. // Note that the final invoker must be an InvokerInterceptor so we know it does
  45. // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
  46. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
  47. retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
  48. }
  49. else {
  50. //将拦截器链包装为ReflectiveMethodInvocation并执行
  51. invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
  52. retVal = invocation.proceed();
  53. }
  54. // Massage return value if necessary.
  55. Class<?> returnType = method.getReturnType();
  56. if (retVal != null && retVal == target &&
  57. returnType != Object.class && returnType.isInstance(proxy) &&
  58. !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
  59. // Special case: it returned "this" and the return type of the method
  60. // is type-compatible. Note that we can't help if the target sets
  61. // a reference to itself in another returned object.
  62. retVal = proxy;
  63. }
  64. else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
  65. throw new AopInvocationException(
  66. "Null return value from advice does not match primitive return type for: " + method);
  67. }
  68. return retVal;
  69. }
  70. finally {
  71. if (target != null && !targetSource.isStatic()) {
  72. // Must have come from TargetSource.
  73. targetSource.releaseTarget(target);
  74. }
  75. if (setProxyContext) {
  76. // Restore old proxy.
  77. AopContext.setCurrentProxy(oldProxy);
  78. }
  79. }
  80. }

通过上面代码可知,将增强器装换为方法拦截器链,最终包装为ReflectiveMethodInvocation执行它的proceed方法,那么我们就来看下具体如果执行

  1. public Object proceed() throws Throwable {
  2. // 当执行到最后一个拦截器的时候才会进入
  3. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
  4. return invokeJoinpoint();
  5. }
  6. //获取集合当前需要运行的拦截器
  7. Object interceptorOrInterceptionAdvice =
  8. this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
  9. if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
  10. // Evaluate dynamic method matcher here: static part will already have
  11. // been evaluated and found to match.
  12. InterceptorAndDynamicMethodMatcher dm =
  13. (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
  14. Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
  15. if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
  16. return dm.interceptor.invoke(this);
  17. }
  18. else {
  19. // Dynamic matching failed.
  20. // Skip this interceptor and invoke the next in the chain.
  21. return proceed();
  22. }
  23. }
  24. else {
  25. // 执行拦截器方法
  26. return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
  27. }
  28. }

这样一看会感觉很蒙,其实追踪一下源码就很好理解了
org.springframework.aop.interceptor.ExposeInvocationInterceptor#invoke

  1. public Object invoke(MethodInvocation mi) throws Throwable {
  2. MethodInvocation oldInvocation = invocation.get();
  3. invocation.set(mi);
  4. try {
  5. return mi.proceed();
  6. }
  7. finally {
  8. invocation.set(oldInvocation);
  9. }
  10. }

org.springframework.aop.aspectj.AspectJAfterThrowingAdvice#invoke
异常拦截器,当方法调用异常会被执行

  1. public Object invoke(MethodInvocation mi) throws Throwable {
  2. try {
  3. return mi.proceed();
  4. }
  5. catch (Throwable ex) {
  6. if (shouldInvokeOnThrowing(ex)) {
  7. invokeAdviceMethod(getJoinPointMatch(), null, ex);
  8. }
  9. throw ex;
  10. }
  11. }

org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor#invoke
返回拦截器,方法执行失败,不会调用

  1. public Object invoke(MethodInvocation mi) throws Throwable {
  2. Object retVal = mi.proceed();
  3. this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
  4. return retVal;
  5. }

org.springframework.aop.aspectj.AspectJAfterAdvice#invoke
后置拦截器,总是执行

  1. public Object invoke(MethodInvocation mi) throws Throwable {
  2. try {
  3. return mi.proceed();
  4. }
  5. finally {
  6. invokeAdviceMethod(getJoinPointMatch(), null, null);
  7. }
  8. }

org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor#invoke
前置拦截器

  1. public Object invoke(MethodInvocation mi) throws Throwable {
  2. this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
  3. return mi.proceed();
  4. }

这里用了责任链的设计模式,递归调用排序好的拦截器链