【小家Spring】Spring AOP之Advisor、PointcutAdvisor、IntroductionAdvisor、IntroductionInterceptor(引介增强)(上)

本文涉及的产品
云解析DNS-重点域名监控,免费拨测 20万次(价值200元)
简介: 【小家Spring】Spring AOP之Advisor、PointcutAdvisor、IntroductionAdvisor、IntroductionInterceptor(引介增强)(上)

前言


上篇文章:【小家Spring】Spring AOP核心类Pointcut解析,对PointcutExpression切点表达式解析原理分析(以AspectJExpressionPointcut为例)

讲到了很多的Pointcut,以及各自的使用场景。


而Advisor是Pointcut以及Advice的一个结合,有着非常深的联系,因此本文主要扫盲一下Advisor


Advisor介绍


Advisor是Spring AOP的顶层抽象,用来管理Advice和Pointcut(PointcutAdvisor和切点有关,但IntroductionAdvisor和切点无关)


注意:Advice是aopalliance对通知(增强器)的顶层抽象,请注意区分~~

Pointcut是Spring AOP对切点的抽象。切点的实现方式有多种,其中一种就是AspectJ

public interface Advisor {
  //@since 5.0 Spring5以后才有的  空通知  一般当作默认值
  Advice EMPTY_ADVICE = new Advice() {};
  // 该Advisor 持有的通知器
  Advice getAdvice();
  // 这个有点意思:Spring所有的实现类都是return true(官方说暂时还没有应用到)
  // 注意:生成的Advisor是单例还是多例不由isPerInstance()的返回结果决定,而由自己在定义bean的时候控制
  // 理解:和类共享(per-class)或基于实例(per-instance)相关  类共享:类比静态变量   实例共享:类比实例变量
  boolean isPerInstance();
}


它的继承体系主要有如下两个:PointcutAdvisor和IntroductionAdvisor


image.png


IntroductionAdvisor与PointcutAdvisor最本质上的区别就是,IntroductionAdvisor只能应用于类级别的拦截,只能使用Introduction型的Advice。

而不能像PointcutAdvisor那样,可以使用任何类型的Pointcut,以及几乎任何类型的Advice。


PointcutAdvisor:和切点有关的Advisor


顾名思义,它和Pointcu有关。在上一篇博文:【小家Spring】Spring AOP核心类Pointcut解析,对PointcutExpression切点表达式解析原理分析(以AspectJExpressionPointcut为例)

其实我们已经介绍了好几个PointcutAdvisor。比如:RegexpMethodPointcutAdvisor和NameMatchMethodPointcutAdvisor,它哥俩都位于org.springframework.aop.support此包。当然还要介绍过AspectJExpressionPointcutAdvisor…


PointcutAdvisor它的实现类非常的多:


public interface PointcutAdvisor extends Advisor {
  Pointcut getPointcut();
}


image.png


AbstractPointcutAdvisor:抽象实现



// 实现了 Ordered接口
public abstract class AbstractPointcutAdvisor implements PointcutAdvisor, Ordered, Serializable {
  // 调用者可以手动来指定Order
  public void setOrder(int order) {
    this.order = order;
  }
  @Override
  public int getOrder() {
    if (this.order != null) {
      return this.order;
    }
    // 若调用者没有指定Order,那就拿advice的order为准(若有),否则LOWEST_PRECEDENCE表示最后执行
    Advice advice = getAdvice();
    if (advice instanceof Ordered) {
      return ((Ordered) advice).getOrder();
    }
    return Ordered.LOWEST_PRECEDENCE;
  }
  // Spring还没有使用该属性 永远返回true了
  @Override
  public boolean isPerInstance() {
    return true;
  }
  ...
}


AbstractGenericPointcutAdvisor 一般的、通用的PointcutAdvisor


public abstract class AbstractGenericPointcutAdvisor extends AbstractPointcutAdvisor {
  private Advice advice = EMPTY_ADVICE;
  public void setAdvice(Advice advice) {
    this.advice = advice;
  }
  @Override
  public Advice getAdvice() {
    return this.advice;
  }
  ...
}


DefaultPointcutAdvisor 通用的,最强大的Advisor


它是Spring提供的通用的,也被认为是最强大的Advisor。它可以把任意的两个Advice和Pointcut放在一起:


public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable {
  private Pointcut pointcut = Pointcut.TRUE;
  public DefaultPointcutAdvisor() {
  }
  // 若没有指定advice,默认Pointcut.TRUE,也就是说会匹配所有的方法的执行
  public DefaultPointcutAdvisor(Advice advice) {
    this(Pointcut.TRUE, advice);
  }
  // 显然,这个构造函数式非常强大的~~
  public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {
    this.pointcut = pointcut;
    setAdvice(advice);
  }
}


AbstractBeanFactoryPointcutAdvisor:和bean工厂有关的PointcutAdvisor


从命名也能看出来,它和BeanFactory有关。


// 实现了BeanFactoryAware接口,若在Bean容器里注册可议注入BeanFactory~~~从而访问里面的实例
public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {
  // 我们发现这两个都是@Nullable,所以他们脱离容器使用也是可以的
  @Nullable
  private String adviceBeanName;
  @Nullable
  private BeanFactory beanFactory;
  @Nullable
  private transient volatile Advice advice;
  public void setAdviceBeanName(@Nullable String adviceBeanName) {
    this.adviceBeanName = adviceBeanName;
  }
  @Override
  public void setBeanFactory(BeanFactory beanFactory) {
    this.beanFactory = beanFactory;
    // 若在Spring环境下,会给AdviceMonitor重新赋值为:getSingletonMutex()
    resetAdviceMonitor();
  }
  // 此处加锁
  public void setAdvice(Advice advice) {
    synchronized (this.adviceMonitor) {
      this.advice = advice;
    }
  }
  // 这是它最重要的方法,获取增强器
  @Override
  public Advice getAdvice() {
    Advice advice = this.advice;
    // 非Spring环境一般手动set进来,所以就直接返回吧
    if (advice != null) {
      return advice;
    }
    // 显然进来Spring容器环境了,bean工厂和beanName都是不能为null的
    Assert.state(this.adviceBeanName != null, "'adviceBeanName' must be specified");
    Assert.state(this.beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");
    // 若bean是单例的  那就没什么好说的  直接去工厂里拿出来就完事了(Advice.class)  有可能返回null哦
    if (this.beanFactory.isSingleton(this.adviceBeanName)) {
      advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
      this.advice = advice;
      return advice;
    }
    // 若是多例的,就加锁  然后调用getBean()给他生成一个新的实例即可
    else {
      synchronized (this.adviceMonitor) {
        //这步赋值和判断不能省~~~确保万无一失
        advice = this.advice;
        if (advice == null) {
          advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
          this.advice = advice;
        }
        return advice;
      }
    }
  }
}


DefaultBeanFactoryPointcutAdvisor:通用的BeanFactory的Advisor


这个是和Bean工厂关联的,通用的PointcutAdvisor


public class DefaultBeanFactoryPointcutAdvisor extends AbstractBeanFactoryPointcutAdvisor {
  private Pointcut pointcut = Pointcut.TRUE;
  // 若传进来为null,还是选择 Pointcut.TRUE 匹配所有
  public void setPointcut(@Nullable Pointcut pointcut) {
    this.pointcut = (pointcut != null ? pointcut : Pointcut.TRUE);
  }
  @Override
  public Pointcut getPointcut() {
    return this.pointcut;
  }
}


在Spring事务相关里,你会看到这个类


位于org.springframework.aop.support包内


BeanFactoryCacheOperationSourceAdvisor:和Cache有关


Spring Cache的@Cachable等注解的拦截,就是采用了它。该类位于:org.springframework.cache.interceptor,显然它和cache相关了。Jar包属于:Spring-context.jar

// @since 3.1  毕竟Spring的整个org.springframework.cache.Cache体系都是从这里开始的。(@Cacheable...等等)
public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
  // 显然它最重要的是持有这个引用(Cache章节详细介绍了它)
  @Nullable
  private CacheOperationSource cacheOperationSource;
  // Pointcut使用的是CacheOperationSourcePointcut
  private final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut() {
    @Override
    @Nullable
    protected CacheOperationSource getCacheOperationSource() {
      return cacheOperationSource;
    }
  };
  public void setCacheOperationSource(CacheOperationSource cacheOperationSource) {
    this.cacheOperationSource = cacheOperationSource;
  }
  public void setClassFilter(ClassFilter classFilter) {
    this.pointcut.setClassFilter(classFilter);
  }
  @Override
  public Pointcut getPointcut() {
    return this.pointcut;
  }
}


AsyncAnnotationAdvisor:和@Async有关


位于包为:org.springframework.scheduling.annotation,所属jar包为spring-context.jar

public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {
  // 处理异步发生的异常的====
  private AsyncUncaughtExceptionHandler exceptionHandler;
  private Advice advice;
  private Pointcut pointcut;
  // 构造函数们
  public AsyncAnnotationAdvisor() {
    this(null, null);
  }
  // executor:可以自己指定异步任务的执行器
  // exceptionHandler:异步异常的处理器
  public AsyncAnnotationAdvisor(@Nullable Executor executor, @Nullable AsyncUncaughtExceptionHandler exceptionHandler) {
    Set<Class<? extends Annotation>> asyncAnnotationTypes = new LinkedHashSet<>(2);
    asyncAnnotationTypes.add(Async.class);
    // 支持EJB的注解:@Asynchronous
    try {
      asyncAnnotationTypes.add((Class<? extends Annotation>)
          ClassUtils.forName("javax.ejb.Asynchronous", AsyncAnnotationAdvisor.class.getClassLoader()));
    } catch (ClassNotFoundException ex) {
      // If EJB 3.1 API not present, simply ignore.
    }
    if (exceptionHandler != null) {
      this.exceptionHandler = exceptionHandler;
    } else {
      // SimpleAsyncUncaughtExceptionHandler:只是一个简单的logger.error的输入打印
      this.exceptionHandler = new SimpleAsyncUncaughtExceptionHandler();
    }
    // buildAdvice: new AnnotationAsyncExecutionInterceptor(executor, exceptionHandler)   它是个MethodInterceptor  环绕通知器
    this.advice = buildAdvice(executor, this.exceptionHandler);
    // 把asyncAnnotationTypes交给buildPointcut,它最终是个ComposablePointcut,会把这两种注解都支持。union起来 或者的关系
    this.pointcut = buildPointcut(asyncAnnotationTypes);
  }
  public void setTaskExecutor(Executor executor) {
    this.advice = buildAdvice(executor, this.exceptionHandler);
  }
  ...
}
相关文章
|
3月前
|
XML 安全 Java
使用 Spring 的 @Aspect 和 @Pointcut 注解简化面向方面的编程 (AOP)
面向方面编程(AOP)通过分离横切关注点,如日志、安全和事务,提升代码模块化与可维护性。Spring 提供了对 AOP 的强大支持,核心注解 `@Aspect` 和 `@Pointcut` 使得定义切面与切入点变得简洁直观。`@Aspect` 标记切面类,集中处理通用逻辑;`@Pointcut` 则通过表达式定义通知的应用位置,提高代码可读性与复用性。二者结合,使开发者能清晰划分业务逻辑与辅助功能,简化维护并提升系统灵活性。Spring AOP 借助代理机制实现运行时织入,与 Spring 容器无缝集成,支持依赖注入与声明式配置,是构建清晰、高内聚应用的理想选择。
437 0
|
2月前
|
XML Java 数据格式
《深入理解Spring》:AOP面向切面编程深度解析
Spring AOP通过代理模式实现面向切面编程,将日志、事务等横切关注点与业务逻辑分离。支持注解、XML和编程式配置,提供五种通知类型及丰富切点表达式,助力构建高内聚、低耦合的可维护系统。
|
7月前
|
监控 安全 Java
Spring AOP实现原理
本内容主要介绍了Spring AOP的核心概念、实现机制及代理生成流程。涵盖切面(Aspect)、连接点(Join Point)、通知(Advice)、切点(Pointcut)等关键概念,解析了JDK动态代理与CGLIB代理的原理及对比,并深入探讨了通知执行链路和责任链模式的应用。同时,详细分析了AspectJ注解驱动的AOP解析过程,包括切面识别、切点表达式匹配及通知适配为Advice的机制,帮助理解Spring AOP的工作原理与实现细节。
1127 13
|
4月前
|
人工智能 监控 安全
如何快速上手【Spring AOP】?核心应用实战(上篇)
哈喽大家好吖~欢迎来到Spring AOP系列教程的上篇 - 应用篇。在本篇,我们将专注于Spring AOP的实际应用,通过具体的代码示例和场景分析,帮助大家掌握AOP的使用方法和技巧。而在后续的下篇中,我们将深入探讨Spring AOP的实现原理和底层机制。 AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的核心特性之一,它能够帮助我们解决横切关注点(如日志记录、性能统计、安全控制、事务管理等)的问题,提高代码的模块化程度和复用性。
|
4月前
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。
|
10月前
|
XML Java 测试技术
Spring AOP—通知类型 和 切入点表达式 万字详解(通俗易懂)
Spring 第五节 AOP——切入点表达式 万字详解!
729 25
|
10月前
|
XML 安全 Java
Spring AOP—深入动态代理 万字详解(通俗易懂)
Spring 第四节 AOP——动态代理 万字详解!
448 24
|
9月前
|
Java API 微服务
微服务——SpringBoot使用归纳——Spring Boot中的切面AOP处理——Spring Boot 中的 AOP 处理
本文详细讲解了Spring Boot中的AOP(面向切面编程)处理方法。首先介绍如何引入AOP依赖,通过添加`spring-boot-starter-aop`实现。接着阐述了如何定义和实现AOP切面,包括常用注解如`@Aspect`、`@Pointcut`、`@Before`、`@After`、`@AfterReturning`和`@AfterThrowing`的使用场景与示例代码。通过这些注解,可以分别在方法执行前、后、返回时或抛出异常时插入自定义逻辑,从而实现功能增强或日志记录等操作。最后总结了AOP在实际项目中的重要作用,并提供了课程源码下载链接供进一步学习。
1095 0
|
9月前
|
Java 开发者 微服务
微服务——SpringBoot使用归纳——Spring Boot中的切面AOP处理——什么是AOP
本文介绍了Spring Boot中的切面AOP处理。AOP(Aspect Oriented Programming)即面向切面编程,其核心思想是分离关注点。通过AOP,程序可以将与业务逻辑无关的代码(如日志记录、事务管理等)从主要逻辑中抽离,交由专门的“仆人”处理,从而让开发者专注于核心任务。这种机制实现了模块间的灵活组合,使程序结构更加可配置、可扩展。文中以生活化比喻生动阐释了AOP的工作原理及其优势。
524 0