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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 【小家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);
  }
  ...
}
相关文章
|
2天前
|
存储 安全 Java
Spring Boot 3 集成Spring AOP实现系统日志记录
本文介绍了如何在Spring Boot 3中集成Spring AOP实现系统日志记录功能。通过定义`SysLog`注解和配置相应的AOP切面,可以在方法执行前后自动记录日志信息,包括操作的开始时间、结束时间、请求参数、返回结果、异常信息等,并将这些信息保存到数据库中。此外,还使用了`ThreadLocal`变量来存储每个线程独立的日志数据,确保线程安全。文中还展示了项目实战中的部分代码片段,以及基于Spring Boot 3 + Vue 3构建的快速开发框架的简介与内置功能列表。此框架结合了当前主流技术栈,提供了用户管理、权限控制、接口文档自动生成等多项实用特性。
23 8
|
2月前
|
XML Java 数据安全/隐私保护
Spring Aop该如何使用
本文介绍了AOP(面向切面编程)的基本概念和术语,并通过具体业务场景演示了如何在Spring框架中使用Spring AOP。文章详细解释了切面、连接点、通知、切点等关键术语,并提供了完整的示例代码,帮助读者轻松理解和应用Spring AOP。
Spring Aop该如何使用
|
2月前
|
监控 安全 Java
什么是AOP?如何与Spring Boot一起使用?
什么是AOP?如何与Spring Boot一起使用?
76 5
|
2月前
|
Java 开发者 Spring
深入解析:Spring AOP的底层实现机制
在现代软件开发中,Spring框架的AOP(面向切面编程)功能因其能够有效分离横切关注点(如日志记录、事务管理等)而备受青睐。本文将深入探讨Spring AOP的底层原理,揭示其如何通过动态代理技术实现方法的增强。
80 8
|
2月前
|
Java 开发者 Spring
Spring AOP 底层原理技术分享
Spring AOP(面向切面编程)是Spring框架中一个强大的功能,它允许开发者在不修改业务逻辑代码的情况下,增加额外的功能,如日志记录、事务管理等。本文将深入探讨Spring AOP的底层原理,包括其核心概念、实现方式以及如何与Spring框架协同工作。
|
2月前
|
XML 监控 安全
深入调查研究Spring AOP
【11月更文挑战第15天】
50 5
|
2月前
|
Java 开发者 Spring
Spring AOP深度解析:探秘动态代理与增强逻辑
Spring框架中的AOP(Aspect-Oriented Programming,面向切面编程)功能为开发者提供了一种强大的工具,用以将横切关注点(如日志、事务管理等)与业务逻辑分离。本文将深入探讨Spring AOP的底层原理,包括动态代理机制和增强逻辑的实现。
51 4
|
3月前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
57 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
2月前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
47 1
|
2月前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
49 0
下一篇
开通oss服务