深度解析 Spring 源码:解密AOP切点和通知的实现机制

在这里插入图片描述

文章目录

  • 深度解析 Spring 源码:解密AOP切点和通知的实现机制
    • 一、Spring AOP的基础知识
      • 1.1 AOP的核心概念:切点、通知、切面等
      • 1.2 Spring AOP与传统AOP的区别和优势
    • 二、深入分析切点和通知的实现
      • 2.1 研究 Pointcut 接口及其实现类
        • 2.1.1 Pointcut 接口
        • 2.1.2 AspectJExpressionPointcut类
        • 2.1.3 NameMatchMethodPointcut类
      • 2.2 探讨 Advice 接口及其实现类
        • 2.2.1 通知类型
        • 2.2.2 MethodBeforeAdvice接口
        • 2.2.3 AspectJMethodBeforeAdvice类
    • 三、实际与运用
      • 3.1 代码展示Spring AOP的用法和配置方式
      • 3.2 结合实例说明切点和通知如何在实际项目中应用

深度解析 Spring 源码:解密AOP切点和通知的实现机制

一、Spring AOP的基础知识

1.1 AOP的核心概念:切点、通知、切面等

使用AOP可以将那些与核心业务逻辑无关但又分散在各处的横切关注点(如日志记录、性能监控、事务管理等)抽离出来,通过切面的方式进行统一管理和维护,从而提高了代码的模块化程度、可维护性和可扩展性。

  1. 切点:切点是在应用程序中定义的一组条件,用于确定何处插入横切关注点。在Java中,切点通常是由表达式来定义的,这些表达式可以匹配到程序中的特定方法调用或者其他程序执行的位置。例如,一个切点可以定义为匹配所有service包下的方法调用。切点实际上是AOP在代码中的具体位置。
  2. 通知:通知是在切点上执行的代码,它定义了在何时、何地以及如何执行横切逻辑。通知可以是在切点之前执行(Before advice)、在切点之后执行(After advice)、在方法返回值后执行(After-returning advice)、在方法抛出异常后执行(After-throwing advice)以及环绕执行(Around advice)等不同类型。
  3. 切面:切面是横切关注点的模块化实现,它将通知和切点组合在一起。一个切面是一个类,它包含了多个通知和切点的定义。在实际应用中,切面可以被看作是一种特殊的类,它提供了一种方式来定义横切关注点,并将其与主要业务逻辑分离开来。

关系图

在这里插入图片描述

1.2 Spring AOP与传统AOP的区别和优势

Spring AOP相对于传统AOP来说更加轻量级和易用,适合于大部分应用场景下的AOP需求。传统AOP则提供了更丰富的功能和更灵活的配置选项,适用于对AOP功能有更高要求的特定场景。

实现与扩展方面的区别和优势

  1. 实现方式
    • 传统AOP:传统的AOP实现通常是通过静态代理或者动态代理来实现的。静态代理要求在编译时就确定代理对象,而动态代理则是在运行时生成代理对象。传统AOP的实现需要程序员手动编写代理类或使用代码生成工具,相对比较繁琐。
    • Spring AOP:Spring AOP是基于动态代理实现的,它利用了JDK动态代理和CGLIB动态代理来在运行时生成代理对象。Spring AOP通过配置来定义切点和通知,而无需手动编写代理类,简化了AOP的实现。
  2. 依赖关系
    • 传统AOP:传统的AOP实现通常依赖于特定的AOP框架,如AspectJ。使用传统AOP需要引入独立的AOP框架,并学习其专门的语法和配置方式。
    • Spring AOP:Spring AOP是Spring框架的一部分,与Spring IoC容器紧密集成。因此,使用Spring AOP无需引入额外的依赖,而是直接利用Spring的核心功能实现AOP,简化了项目的依赖管理和配置。
  3. 功能扩展
    • 传统AOP:传统AOP通常提供了更丰富的功能和更灵活的配置选项,如支持更多类型的通知(如引入通知)、更细粒度的切点定义等。
    • Spring AOP:Spring AOP相对于传统AOP来说功能较为简单,只支持方法级别的切面,通知类型也相对较少。但Spring AOP提供了与Spring框架无缝集成的优势,能够与Spring的IoC容器和其他功能(如事务管理、异常处理等)无缝配合,使得AOP的应用更加方便和统一。

二、深入分析切点和通知的实现

2.1 研究 Pointcut 接口及其实现类

2.1.1 Pointcut 接口

接口 Pointcut 表示一个切点,可以确定哪些类和方法应该被包含在一个切面中。通过提供类过滤器方法匹配器,允许开发者定义更加精确的切点条件。

在这里插入图片描述

2.1.2 AspectJExpressionPointcut类

本文仅仅分析用于确定给定方法是否匹配切点条件的matches方法,对于实现类的其它方法,读者感兴趣可自行解读,亦可以期待后续的博文。

第一个 matches 方法位于 ShadowMatch 对象上,用于判断连接点是否匹配切点条件。这个方法是由 ShadowMatch 类提供的,用于执行切点表达式与目标方法的匹配逻辑。

在这里插入图片描述

第二个 matches 方法位于 JoinPointMatch 对象上,用于判断连接点的匹配状态。这个方法是由 JoinPointMatch 类提供的,用于判断连接点是否成功匹配了切点表达式。

在这里插入图片描述

2.1.3 NameMatchMethodPointcut类

检查给定的方法名是否与列表中的任何一个方法名匹配。

在这里插入图片描述

用于判断一个字符串是否符合给定的模式,源码结合切面表达式看易于理解。

/*** execution(): 这是最常用的切入点函数,在方法执行时触发切入点* 切入点函数参数: 包括方法的访问修饰符、返回类型、类名、方法名和参数列表等* 通配符: 例如*用于匹配任意字符,..用于匹配任意数量的参数等* 逻辑运算符: 例如&&表示与,||表示或,!表示非*/
@Pointcut("execution(* com.example.service.*.*(..))")
private void serviceMethods() {}

在这里插入图片描述

2.2 探讨 Advice 接口及其实现类

Advice 接口有多个子接口,如 MethodBeforeAdviceAfterReturningAdviceThrowsAdvice 等。

本文解读前置通知,其它通知读者感兴趣可以自行去了解。

2.2.1 通知类型

通知类型可以分为以下几种

  1. 前置通知(Before Advice)
    • 在目标方法执行之前执行的逻辑。
    • 实现了 org.springframework.aop.MethodBeforeAdvice 接口的通知称为前置通知。
    • 通常用于执行一些准备工作,比如权限检查、日志记录等。
  2. 后置通知(After Returning Advice)
    • 在目标方法成功执行之后执行的逻辑。
    • 实现了 org.springframework.aop.AfterReturningAdvice 接口的通知称为后置通知。
    • 通常用于处理方法的返回值或清理工作。
  3. 环绕通知(Around Advice)
    • 在目标方法执行前后都能执行的逻辑,可以控制目标方法的执行。
    • 实现了 org.aopalliance.intercept.MethodInterceptor 接口的通知称为环绕通知。
    • 通常用于包装目标方法的调用,实现额外的逻辑,比如性能监控、事务管理等。
  4. 抛出异常通知(After Throwing Advice)
    • 在目标方法抛出异常后执行的逻辑。
    • 实现了 org.springframework.aop.ThrowsAdvice 接口的通知称为抛出异常通知。
    • 通常用于异常处理、日志记录等。
  5. 引介通知(Introduction Advice)
    • 在不修改目标类的前提下,为目标类添加新的方法或字段。
    • 实现了 org.springframework.aop.IntroductionInterceptor 接口的通知称为引介通知。
    • 通常用于向现有类添加新的行为。
2.2.2 MethodBeforeAdvice接口

用于在目标方法执行之前执行某些操作。

在这里插入图片描述

2.2.3 AspectJMethodBeforeAdvice类

主要作用是在目标方法执行前执行一些额外的操作。

在这里插入图片描述

三、实际与运用

3.1 代码展示Spring AOP的用法和配置方式

Spring AOP是 Spring 框架的一个重要特性,允许以声明性方式来定义横切关注点,如日志记录、性能监控、事务管理等,而无需修改业务逻辑代码。

Spring AOP 的使用XML形式的Demo,包括配置方式和用法

  1. 添加依赖
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.9</version> <!-- 版本号可以根据实际情况调整 -->
</dependency>
  1. 创建切面类
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;/*** @Aspect 注解表示这是一个切面类* @Before 注解表示在目标方法执行之前执行通知* 切入点表达式指定了切入点为 com.example.service 包中的所有类的所有方法*/
@Aspect
public class LoggingAspect {@Before("execution(* com.example.service.*.*(..))")public void logBefore() {System.out.println("Logging before method execution...");}
}
  1. 配置 Spring Bean
<!-- Spring 配置文件中声明切面类为一个 Spring Bean -->
<bean id="loggingAspect" class="com.example.aspect.LoggingAspect"/>
  1. 启用 Spring AOP
<!-- 在 Spring 配置文件中启用 Spring AOP -->
<aop:aspectj-autoproxy/>
  1. 创建业务类
package com.example.service;public class MyService {public void doSomething() {System.out.println("Doing something...");}
}
  1. 测试
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.example.service.MyService;public class Main {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");MyService myService = (MyService) context.getBean("myService");myService.doSomething();}
}

3.2 结合实例说明切点和通知如何在实际项目中应用

以订单创建日志记录的Demo:

  1. 定义订单服务接口
public interface OrderService {void createOrder(Order order);
}
  1. 实现订单服务
@Service
public class OrderServiceImpl implements OrderService {@Overridepublic void createOrder(Order order) {// 创建订单的具体逻辑System.out.println("订单已创建:" + order);}
}
  1. 创建订单实体类
public class Order {private Long id;private String customerName;private double amount;// 省略 getter 和 setter 方法
}
  1. 创建日志切面
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;/*** 在LoggingAspect切面类上添加了@Aspect和@Component注解,用于告诉Spring这是一个切面类,并将其纳入Spring容器管理*/
@Aspect
@Component
public class LoggingAspect {/*** 使用了@Before注解来定义了一个前置通知* 执行OrderService接口的createOrder方法之前被触发* 切入点表达式指定切入点为OrderService接口的createOrder方法*/@Before("execution(* com.example.service.OrderService.createOrder(..)) && args(order)")public void logBefore(Order order) {System.out.println("订单已创建,订单ID:" + order.getId() + ",客户姓名:" + order.getCustomerName());System.out.println("记录订单创建日志...");}
}
  1. AppConfig配置类
/*** 使用了@Configuration、@ComponentScan和@EnableAspectJAutoProxy注解来启用Spring AOP和组件扫描*/
@Configuration
@ComponentScan(basePackages = "com.example")
@EnableAspectJAutoProxy
public class AppConfig {
}
  1. 测试
public class Main {public static void main(String[] args) {ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);OrderService orderService = context.getBean(OrderService.class);Order order = new Order();order.setId(1L);order.setCustomerName("Alice");order.setAmount(100.0);orderService.createOrder(order);}
}// 输出结果
订单已创建,订单ID1,客户姓名:Alice
记录订单创建日志...
订单已创建:Order{id=1, customerName='Alice', amount=100.0}

古人学问无遗力,少壮工夫老始成

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/12848.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

powershell 防止休眠或屏幕关闭并定时截屏保存

powershell 防止休眠或屏幕关闭 01 前言 因工作需要&#xff0c;需要在用户的机器上进行操作&#xff0c;有些工作比较耗时、耗CPU&#xff0c;配置也不高&#xff0c;因而就不能用这台机器同时干太多活&#xff0c;又不能干盯着啥也干不了&#xff0c;但是一段时间不操作&am…

巩固学习9

show-me-the-code题目001 #做为 Apple Store App 独立开发者&#xff0c;你要搞限时促销&#xff0c;为你的应用生成激活码&#xff08;或者优惠券&#xff09;&#xff0c;使用 Python 如何生成 200 个激活码&#xff08;或者优惠券&#xff09;&#xff1f; import random a…

延迟队列有哪些

延迟队列 与时间相关场景的应用,经常用于延后多少时间执行什么任务。 java 自带延迟队列 class Solution {public static void main(String[] args) throws InterruptedException {DelayQueue<DelayMealTask> queue = new DelayQueue<>();DelayMealTask task =…

MySQL存储过程练习

DDL CREATE TABLE student (id int(11) NOT NULL AUTO_INCREMENT COMMENT 学号,createDate datetime DEFAULT NULL,userName varchar(20) DEFAULT NULL,pwd varchar(36) DEFAULT NULL,phone varchar(11) DEFAULT NULL,age tinyint(3) unsigned DEFAULT NULL,sex char(2) DEFAU…

数据库审计系统Yearning使用笔记

一、启动 1、初始化MySQL 启动mysql docker run -d --namemysql -p 3306:3306 -e MYSQL_ROOT_PASSWORDroot mysql:5.7创建数据库&#xff0c;链接数据库并执行以下创建库的脚步&#xff0c;注意字符集 create database yearning char set utf8mb42、启动Yeelabs 需要执行…

CDGA|揭秘移动物联网数据治理秘诀,轻松提升数据质量,赋能智慧未来

在数字化浪潮汹涌的今天&#xff0c;移动物联网作为连接物理世界与数字世界的桥梁&#xff0c;其数据治理的重要性日益凸显。高质量的数据不仅是企业决策的基石&#xff0c;更是推动行业智能化、精细化发展的关键。本文将为您揭秘移动物联网数据治理的技巧&#xff0c;助您轻松…

如何设计实用的ITSM自助服务台

在现代IT服务管理&#xff08;ITSM&#xff09;领域中&#xff0c;自助服务台已成为IT运维环境的核心组件。它作为企业内部信息中心与其他部门用户之间的桥梁&#xff0c;一个以用户为中心的平台&#xff0c;更注重用户的自主性和自助能力&#xff0c;使用户能够直接访问所需的…

微软宣布GPT-4o模型,可在 Azure OpenAI上使用

5月14日&#xff0c;微软在官网宣布&#xff0c;OpenAI最新发布的多模态模型GPT-4o&#xff0c;可以在 Azure OpenAI 云服务中使用。 据悉&#xff0c;GPT-4o支持跨文本、视频、音频多模态推理&#xff0c;例如&#xff0c;通过GPT-4o打造一个AI助手&#xff0c;用于辅导孩子解…

halcon学习之形状匹配

算子 create_shape_model&#xff08;&#xff09; 创建一个用于匹配的形状模型 create_shape_model(Template : : NumLevels, AngleStart, AngleExtent, AngleStep, Optimization, Metric, Contrast, MinContrast : ModelID) 参数 Template&#xff1a; NumLevels&#…

基于NIOS-II软核流水灯和串口通信实现

文章目录 一、创建工程二、系统设计1. 在 “component library” 标签栏中找到 “Nios II Processor” 后点击 Add2. 在 ”Component Library” 标签栏中的查找窗口输入 jtag 找到 ”JTAG UART ”&#xff0c;然后点击 Add3. 添加片上存储器 On-Chip Memory(RAM)核4. 查找窗口输…

做简单易用的GIS资源管理软件

在室外资源管理领域&#xff0c;采用基于GIS的解决方案已成为主流趋势&#xff0c;旨在实现资源的高效利用和管理。GIS技术结合资源对象的规划、定位和监控&#xff0c;为企业提供全面的管理方案&#xff0c;从而优化资源使用、提高运营效率和降低成本。 然而&#xff0c;许多资…

龙迅LT8911EX LVDS桥接到EDP,支持4K30HZ分辨率

龙迅LT8911EX描述&#xff1a; Lontium LT8911EX是LVDS到eDP转换器&#xff0c;具有单端口或双端口可配置的LVDS接收器&#xff0c;有1个时钟通道和最多8个数据通道&#xff0c;每个数据通道最大运行1.2Gbps&#xff0c;最大输入带宽为9.6Gbps。转换器将输入LVDS数据去序列化&…

OpenNJet产品体验:探索无限可能

文章目录 前言一、OpenNJet是什么&#xff1f;二、OpenNJet特性和优点三、OpenNJet功能规划四、OpenNJet快速上手五、OpenNJet的使用总结 前言 现代社会网络高速发展&#xff0c;同时也迎来了互联网发展的高峰&#xff0c;OpenNJet作为一个基于NGINX的面向互联网和云原生应用提…

掏心经验分享,软考中项0基础入门篇!

想备考下半年中项&#xff08;系统集成项目管理工程师&#xff09;的朋友&#xff0c;不知道如何了解软考中项&#xff0c;今天给大家整理一篇关于我自己在备考软考时的一些考量和踩过的一些坑。&#xff08;无广&#xff0c;放心看&#xff09; 很多小伙伴总是听大家说软考中…

NGM-SLAM:首创融合神经辐射场子图的3DGS-SLAM,问鼎SOTA!

论文标题&#xff1a; NGM-SLAM: Gaussian Splatting SLAM with Radiance Field Submap 论文作者&#xff1a; Mingrui Li, Jingwei Huang, Lei Sun Aaron, Xuxiang Tian, Tianchen Deng, Hongyu Wang 导读&#xff1a; 3DGS技术因其性能卓越而备受关注&#xff0c;3DGS-SLA…

uniapp微信小程序通过萤石云接入海康摄像机

需求&#xff1a;在uniapp微信小程序上查看海康威视的摄像机监控视频和和操作摄像机拍摄方向 在萤石云接入海康摄像机设备&#xff0c;由于不同品牌设备在不同时间段接入方式可能不一致&#xff0c;具体接入方式查看官方文档或咨询官方客服。 海康摄像机官方客服热线&#xf…

stack、queue、priority_queue以及仿函数

我们上次对std中的list进行实现&#xff0c;今天我们要实现stack、queue、priority_queue以及仿函数。 目录 stack堆堆的框架构造函数push插入pop删除size()大小empty()判断空top()取栈顶的元素 queue队列队列框架问题&#xff1a; 这里我们为什么用deque? 插入删除取头数据取…

AI交互数字人赋能农业数字化、智能化推广营销

2024陵水荔枝文化节上“数字新农人”陵小荔身着黎族服饰、佩戴银器亮相开幕式现场&#xff0c;AI交互数字人生动地以互动式推介和歌舞等形式&#xff0c;带领宾客们了解陵水荔枝的发展历程、产业布局、未来愿景等。如今&#xff0c;越来越多农产品品牌通过3D虚拟数字人定制&…

Redis和数据库能做到强一致吗?

在现代软件系统中&#xff0c;数据一致性是至关重要的&#xff0c;特别是对于需要处理大量并发请求和实时数据的系统。Redis 和数据库都是常见的数据存储解决方案&#xff0c;但它们在保证数据一致性方面有着不同的特点和限制。 本文将深入探讨 Redis 和数据库是否能够做到强一…

最详细的提单知识总结 | 数字贸易综合服务平台 | 箱讯科技

在外贸交易中&#xff0c;国际物流是必不可少的一个步骤。国际物流掌控好&#xff0c;就等于把货物牢牢握在手心&#xff0c;不怕货财两空。 本期将向大家介绍正本提单、电放提单、海运单三种国际海运放货方式以及区分它们的方法。 超实用&#xff01;外贸人赶紧收藏~ 正本提…