首页 > 其他分享 >深入理解 SpringAOP(一):AOP 组件概述

深入理解 SpringAOP(一):AOP 组件概述

时间:2024-03-20 23:55:49浏览次数:28  
标签:通知 Advisor 切点 组件 AOP SpringAOP 注解

概述

spring-aop 模块是 Spring 框架中最重要的组件之一,它为我们提供了强大的 AOP 功能,并为其他扩展功能(如声明式事务、声明式异步处理等)提供了支持。在本文中,我们将深入探讨 SpringAOP 的源码,从代理对象的创建开始,揭示 SpringAOP 的运行机制。

首先,在阅读这篇文章前,请先确保对 Spring 中 Bean 创建流程有基本的了解,因为实际上这个流程也是 SpringAOP 生效的关键。在这个基础上,我们将聚焦于 SpringAOP 中的后处理器,以及与 AOP 功能密切相关的通知器、通知和切点等组件或概念,通过对这些组件的代码结构深入认知,我们将更好地理解 SpringAOP 的内部工作原理。

当我们描述 AOP 的时候,它通常包含下述概念/组件:

  • 通知 Advice :是切面逻辑的具体实现,它决定了在切点处执行什么操作;
  • 切点 Pointcut:程序执行过程中的一个特定点,例如方法的调用或异常的抛出,它是通知的触发点;
  • 通知器 Advisor :它代表了要对哪些对象、在哪里、应用哪些通知,它通常是且不限于是通知和切点的组合体;
  • 连接点 Joinpoint :它代表了程序中的某一处位置,通常包含切点切入位置的一些信息,比如 MethodInvocationConstructorInvocation
  • 切面 Aspect:它是 AspectJ 的概念,在 Spring 中可以认为是一个同时包含多种 Advisor 的聚合体,实际使用时,我们通过 @Aspect 注解声明的切面中的方法会被转为多个 Advisor

接下来,我们将围绕着上述内容,展开研究。

本专题共三篇文章,这是第一篇:

  • 深入理解 SpringAOP(一):AOP 组件概述;
  • 深入理解 SpringAOP(二):AOP的执行流程;
  • 深入理解 SpringAOP(三):AspectJ支持;

一、通知器

因此,某种程度上来说,Advisor 就是某个具体切入规则的最小单位。

1、实现体系

image.png
通知器 Advisor 本身的方法异常简单,它只规定“要在哪里应用哪些通知”,而“对哪些类使用”则交由子类来实现:

public interface Advisor {
	
	// 获取通知操作,即具体的操作逻辑
	Advice getAdvice();

	// 每个切入目标是否都需要一个新的通知器
	boolean isPerInstance();

}

因此一般 Advisor 不会直接使用,而是转为具体的 PointcutAdvisorIntroductionAdvisor 使用。

2、切点通知器

PointcutAdvisor ,直译即切点通知器,允许通知器提供一个切点类 Pointcut ,用于匹配特定的方法或者类:

public interface PointcutAdvisor extends Advisor {

	// 获取切点,即类或方法匹配器
	Pointcut getPointcut();

}

它也是最常见的通知器,Spring 中大部分我们熟知的功能都基于它实现,比如用于处理 @Async 注解的 AsyncAnnotationAdvisor ,与用于处理 @Transcational 注解的 TransactionAttributeSourceAdvisor (严格来说这么说并不准确,因为实际上注解是由 TransactionAnnotationParser 处理的,不过这里我们认为它们相关)。

3、引介入通知器

IntroductionAdvisor ,直译即为引介通知器,比较少用到的通知器,用于实现接口引入——即让一个 bean 无中生有的获得特定某些接口的方法,有点类似于 kotlin 的扩展函数:

public interface IntroductionInfo {

	// 需要引入的接口,即被切入的类等于变相的实现了这些接口
	Class<?>[] getInterfaces();

}

它比较常用的实现应该是 DeclareParentsAdvisor ,用于配合 AspectJ@DeclareParents 做接口引入,不过确实不太常见,因此我们了解即可。

二、通知

image.png
Advice 即 “通知”,它表示切入对象后,需要“在什么地方做什么事”。它的子接口非常多,但是按切入位置可以简单分为三类:

  • 执行前通知:BeforeAdvice
  • 环绕通知:InterceptorAdvice
  • 后置通知:AfterAdvice ,这里又分为返回后通知 AfterReturningAdvice 和异常通知 ThrowsAdvice

比较有趣的是,除了 DynamicIntroductionAdvice 外,AdviceInterceptorBeforeAdviceAfterAdvice  这几个顶级接口都是没有抽象方法的标记接口,因此我们可以一般只关注具体的实现接口即可。
方法拦截器与切点
方法拦截器 MethodInterceptor 最常见的 Advice ,我们熟知的绝大部分基于 SpringAOP 提供的功能都依赖它实现——实际上,就算是其他的实现,到最后执行代理方法的时候依然要适配为 MethodInterceptor 去执行。

public interface MethodInterceptor extends Interceptor {

	// 拦截方法调用
	@Nullable
	Object invoke(@Nonnull MethodInvocation invocation) throws Throwable;

}

在这里,我们就会接触到 Joinpoint ,也就是切点的概念,MethodInvocation就是方法切点:
它包含了一次方法调用中的一些已知信息,包括调用的方法、调用的参数等等,最常见的实现是 ReflectiveInvocation ,我们在 AspectJ 中接触的 JoinPoint 跟它基本一样。
image.png

三、切点

切面 Pointcut 是属于 PointcutAdvisor 的一个组件,它用于匹配类或者方法:

public interface PointcutAdvisor extends Advisor {

	/**
	 * Get the Pointcut that drives this advisor.
	 */
	Pointcut getPointcut();
}

切点由类型过滤器 ClassFilter 和方法匹配器 MethodMatcher 两个组件共同组成:

public interface Pointcut {

	/**
	 * Return the ClassFilter for this pointcut.
	 * @return the ClassFilter (never {@code null})
	 */
	ClassFilter getClassFilter();

	/**
	 * Return the MethodMatcher for this pointcut.
	 * @return the MethodMatcher (never {@code null})
	 */
	MethodMatcher getMethodMatcher();

}

当使用时,将仅会拦截 ClassFilter  不过滤的类中与 MethodMatcher 匹配的方法。
比较常用的实现类为支持对类和方法名进行表达式匹配的 NameMatchMethodPointcut ,与支持 Spring 元注解机制,能够按照类和方法上注解进行匹配的 AnnotationMatchingPointcut

四、后处理器

image.png
AOP 发生在 Bean 的创建过程中,它基于特定的后处理器 AbstractAutoProxyCreator 完成,当然,实际上它的背后是一个大家族:
两个关键的抽象类

  • AbstractAutoProxyCreatorAbstractAutoProxyCreator是一个抽象类,实现了BeanPostProcessor接口,用于自动创建代理对象。它的作用是在Spring容器中自动检测符合条件的bean,并对其进行代理。它可以根据一些配置条件(例如bean的名称、类型、注解等)决定是否对目标bean进行代理,并提供了一些钩子方法供子类实现自定义的代理逻辑;
  • AbstractAdvisorAutoProxyCreatorAbstractAdvisorAutoProxyCreatorAbstractAutoProxyCreator 的子类,它进一步扩展了自动代理的功能。除了 AbstractAutoProxyCreator 的功能外,AbstractAdvisorAutoProxyCreator 还能够通过配置Advisor(通知器)来决定代理的行为;

两个关键的实现类

  • AspectJAwareAdvisorAutoProxyCreatorAspectJAwareAdvisorAutoProxyCreator 继承自 AbstractAdvisorAutoProxyCreator,它是Spring AOP的一个关键组件之一,用于实现基于AspectJ注解的自动代理。它支持使用AspectJ注解(如 @Aspect@Pointcut@Before@After 等)来定义切面,然后根据这些切面的定义,在目标 bean 上应用相应的通知;
  • AnnotationAwareAspectJAutoProxyCreatorAnnotationAwareAspectJAutoProxyCreatorAspectJAwareAdvisorAutoProxyCreator 的子类,它进一步扩展了 AspectJ 注解的自动代理功能。与 AspectJAwareAdvisorAutoProxyCreator 相比,AnnotationAwareAspectJAutoProxyCreator 提供了更加灵活的注解驱动的 AOP 配置方式。它支持使用 @Aspect 注解定义切面,并且还支持其他注解如 @Before@After@Around 等,用于在目标 bean 的方法上应用切面逻辑;

默认情况下,我们的项目都是基于 AnnotationAwareAspectJAutoProxyCreator 实现的 AOP 功能。
在后文,我们会深入后处理器的源码,从而跟踪 AOP 的运行流程。

总结

image.png

标签:通知,Advisor,切点,组件,AOP,SpringAOP,注解
From: https://www.cnblogs.com/Createsequence/p/18086406

相关文章

  • 深入理解 SpringAOP(二):AOP的执行流程
    概述在之前的文章中,我们已经对SpringAOP的关键组件进行了描述,并且了解了其基本操作和流程。在本文中,我们将进一步深入源码,揭示SpringAOP的内部实现细节,理解其运行机制的每个环节,包括切面的织入方式、代理对象的创建过程、连接点的定位与匹配等。通过对完整运行流程的深入研究......
  • Spring AOP初探
    SpringAOP初探Springaop,翻译成中文就是面向切面编程;笔者的个人理解是当spring框架执行一系列方法的时候,通过某种机制匹配到各个需要添加额外逻辑的方法也就是执行点,这些执行点类似数学概念中的一个个点,然后一个个点连起来就成为一个平面了;所有的执行点都会被匹配规则匹配到,然......
  • Salesforce LWC学习(四十九) RefreshView API实现标准页面更新,自定义组件自动捕捉更新
    本篇参考: https://developer.salesforce.com/docs/platform/lwc/guide/data-refreshview.htmlhttps://developer.salesforce.com/docs/platform/lwc/guide/reference-lightning-refreshview.htmlhttps://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007KX6dA......
  • 在非标准Spring组件中(比如websocket)注入Spring管理bean的方法
    privatestaticUserMapperuserMapper;@AutowiredpublicvoidsetUserMapper(UserMapperuserMapper){WebSocketServer.userMapper=userMapper;}WebSocketServer是通过JavaWebSocketAPI创建的,并且由于@ServerEndpoint不是Spring的标准组件注解,直......
  • 【数据脱敏方案】不使用 AOP + 注解,使用 SpringBoot+YAML 实现
    文章目录引入认识YAML格式规范定义脱敏规则格式脱敏逻辑实现读取YAML配置文件获取脱敏规则通过键路径获取对应字段规则原始优化后对数据进行脱敏处理递归生成字段对应的键路径脱敏测试完整工具类引入在项目中遇到一个需求,需要对交易接口返回结果中的指定字段......
  • AOP
    AOP(AspectOrientedProgramming):动态代理在程序运行期间将某段代码切入到指定方法指定位置进行运行的编程方式。通知方法前置通知:在目标方法运行之前运行后置通知:在目标方法结束之后运行返回通知:在目标方法正常返回之后运行异常通知:在目标方法异常返回之后运行环绕通......
  • VUE3 十种组件通信的方式(附详细代码)
    props用途:可以实现父子组件、子父组件、甚至兄弟组件通信父组件<template><div><Son:money="money"></Son></div></template><scriptsetuplang="ts">importSonfrom'./son.vue'import{re......
  • 使用AOP记录feign调用日志
    文章目录业务场景使用DemoClientFeignDemlFeignFallBack主要代码DockLogAspectDockLogDockLogServiceDockLogAddDTOJacksonUtils业务场景记录请求第三方接口的情况。@DockLog可以用在类上也可以用在方法上使用DemoClientFeignimportorg.springframework.cloud......
  • 【Vue3】组件通信以及各种方式的对比
    方式一:props「父」向「子」组件发送数据父组件:定义需要传递给子组件的数据,并使用v-bind指令将其绑定到子组件的props上。<template><child-component:message="parentMessage"/></template><scriptsetup>importChildComponentfrom'./ChildComponent.......
  • 微信小程序(vantWeapp) UI组件库
     vantWeapp官方文档: https://youzan.github.io/vant-weapp/#/quickstart 根据文档的安装步骤  为什么写这样的变量名就能实现对相关的组件修改自定义颜色呢? 原因如下:根据文档描述,官方提供了相关的变量对应的组件 https://github.com/youzan/vant-weapp/blo......