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

news2024/9/21 22:58:50

在这里插入图片描述

文章目录

  • 深度解析 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 {
    @Override
    public 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.coloradmin.cn/o/1678910.html

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

相关文章

提升用户体验:Xinstall免邀请码功能详解

在移动互联网时代&#xff0c;App的推广和运营显得尤为重要。然而&#xff0c;传统的App推广方式往往需要用户填写繁琐的邀请码&#xff0c;这不仅降低了用户体验&#xff0c;还影响了推广效果。幸运的是&#xff0c;Xinstall作为国内专业的App全渠道统计服务商&#xff0c;推出…

GPT4 是如何将文本 token 化的?

本文给出一个 GPT4 模型可视化token的工具网站&#xff0c;大家可以去上面测试一下效果。 网址&#xff1a; https://platform.openai.com/tokenizer 使用说明 通过该网站工具&#xff0c;你可以了解一段文本如何被GPT-4模型token化的&#xff0c;以及文本的被token化之后的…

图文教程 | 2024年IDEA安装使用、破解教程,JDK简易下载方法

前言 &#x1f4e2;博客主页&#xff1a;程序源⠀-CSDN博客 &#x1f4e2;欢迎点赞&#x1f44d;收藏⭐留言&#x1f4dd;如有错误敬请指正&#xff01; 目录 一、IDEA安装 二、激活 三、JDK安装 四、JDK环境配置 五、验证 一、IDEA安装 进入官网下载&#xff1a; Other…

丑萌的黏土滤镜爆火,这款APP冲到了排行榜第一

你最近是否在社交软件上看到过黏土风格图片呢&#xff1f;突出的面部线条&#xff0c;宛如橡皮一样富有弹性的质感&#xff0c;不少人都用自己的照片或者一些出名表情包进行了恶搞。而掀起这股风潮的&#xff0c;就是一款Remini的AI修图软件。 聊起AI作图&#xff0c;相信不少人…

使用TerraScan静态扫描KubernetsIaC文件

terrascan https://github.com/tenable/terrascan Terrascan 是基础架构即代码的静态代码分析器。Terrascan 允许&#xff1a; 将基础架构作为代码无缝扫描&#xff0c;以查找错误配置。监控已配置的云基础架构&#xff0c;以查找引入终端安全评估漂移的配置更改&#xff0…

IP-GUARD如何制作授权软件

1、进入控制台 -> 找到文档安全管理 -> 点击授权软件管理 -> 导出授权软件(名称自定义) 2、打开这个蓝宝石工具,并将导出的文件进行打开 选择你要操作的软件进行编辑,然后一直下一步 3、选择要操作的软件进行编辑

【全开源】JAVA语聊大厅+陪玩系统语音聊天APP系统源码

打造全新社交娱乐体验 在数字化社交的浪潮中&#xff0c;人们渴望找到一种既能畅聊又能共享娱乐的新方式。为了满足这一需求&#xff0c;我们推出了“语聊大厅陪玩系统源码”&#xff0c;这是一款集合了语音聊天与陪玩功能的综合性社交娱乐解决方案。 核心功能 语音聊天大厅…

图文成片剪辑软件,分享3个专业的工具!

在数字化时代&#xff0c;图文成片剪辑软件成为了我们创作与表达的重要工具。无论是想要制作一段引人入胜的短视频&#xff0c;还是打造一幅精美的图文海报&#xff0c;这些软件都能助你一臂之力。那么&#xff0c;图文成片剪辑软件的方法有哪些&#xff1f;又有哪些值得一试的…

DBeaver配置离线驱动

因为部署的服务器为无网环境&#xff0c;所以在服务器上使用DBeaver需要配置离线驱动 我们在有网的环境下&#xff0c;安装DBeaver。把驱动下载下来&#xff0c;然后再拷贝到没网的设备上 一、下载驱动 1.在有网的设备上&#xff0c;打开DBeaver 2.找到窗口&#xff0c;选择…

[论文阅读]FINE-TUNE THE PRETRAINED ATST MODEL FOR SOUND EVENT DETECTION

摘要 本研究提出了一种微调预训练模型ATST&#xff08;音频师生转换模型&#xff09;的方法&#xff0c;用于声音事件检测&#xff08;SED&#xff09;。通过引入ATST-Frame模型&#xff0c;该方法在DCASE挑战任务4数据集上取得了新的SOTA结果&#xff0c;有效解决了预训练模型…

STM32学习-1 新建工程

教学资料来自【STM32入门教程-2023版 细致讲解 中文字幕】 https://www.bilibili.com/video/BV1th411z7sn/?p5&share_sourcecopy_web&vd_sourcec6cfedd1c739ca8502f041514e158616 在keil中&#xff0c;每个代码最后一行必须是空的&#xff0c;不然运行会报错 配置库函…

2024自学网络安全的三个必经阶段(含路线图)_网络安全自学路线

一、为什么选择网络安全&#xff1f; 这几年随着我国《国家网络空间安全战略》《网络安全法》《网络安全等级保护2.0》等一系列政策/法规/标准的持续落地&#xff0c;网络安全行业地位、薪资随之水涨船高。 未来3-5年&#xff0c;是安全行业的黄金发展期&#xff0c;提前踏入…

C++类与对象基础探秘系列(三)

目录 再谈构造函数 构造函数体赋值 初始化列表 explicit关键字 static成员 概念 特性 友元 友元函数 友元类 内部类 概念 特性 匿名对象 再次理解类和对象 再谈构造函数 构造函数体赋值 在创建对象时&#xff0c;编译器会通过调用构造函数&#xff0c;给对象中的各个成员…

【数据分析面试】44.分析零售客户群体(Python 集合Set的用法)

题目 假设你是一家在线零售商的数据库管理员&#xff0c;需要分析两类客户的数据。一个集合 purchased_customers 包含在最近一次促销活动中购买了商品的客户ID&#xff0c;另一个集合 newsletter_subscribers 包含订阅了新闻通讯的客户ID。编写一个函数 analyze_customers&am…

2024一站式解决 python打包代码,发布到pypi

2024一站式解决 python打包代码&#xff0c;发布到pypi 文章目录 2024一站式解决 python打包代码&#xff0c;发布到pypi一、前言二、pypi账户注册与配置2.1 账户注册2.2 双因素认证2.3 API token生成 三、代码打包3.1 准备代码3.2 编写setup.py文件3.3 LICENSE3.3.1 常见的开源…

生信人写程序1. Perl语言模板及配置

生物信息领域常用语言 个人认为&#xff1a;是否能熟悉使用Shell(项目流程搭建)R(数据统计与可视化)Perl/Python/Java…(胶水语言&#xff0c;数据格式转换&#xff0c;软件间衔接)三门语言是一位合格生物信息工程师的标准。 生物信息常用语言非常广泛&#xff0c;我常用的有…

IT行业的现状和未来发展趋势:技术创新、市场需求、人才培养、政策法规和社会影响

&#x1f3a9; 欢迎来到技术探索的奇幻世界&#x1f468;‍&#x1f4bb; &#x1f4dc; 个人主页&#xff1a;一伦明悦-CSDN博客 ✍&#x1f3fb; 作者简介&#xff1a; C软件开发、Python机器学习爱好者 &#x1f5e3;️ 互动与支持&#xff1a;&#x1f4ac;评论 &…

SOLIDWORKS 2024云服务新功能

一、简单的分享一下&#xff0c;在线观看&#xff0c;轻松标记 在达索系统SOLIDWORKS 2024云服务中&#xff0c;您只需在达索系统SOLIDWORKS中点击按钮&#xff0c;就可以将当前的设计分享给其他人&#xff0c;无论是客户、供应商还是团队内部成员。共享的用户只要打开浏览器里…

volatile能保证原子性吗?为什么?

一、问题解析 volatile通常被比喻成”轻量级的synchronized“&#xff0c;也是Java并发编程中比较重要的一个关键字。和synchronized不同&#xff0c;volatile是一个变量修饰符&#xff0c;只能用来修饰变量。无法修饰方法及代码块等。 volatile的用法比较简单&#xff0c;只需…

intel三年来首次大更新竟然倒吸牙膏,线程数砍掉25%!

每年科技圈最热闹的几个话题&#xff0c;无非是几大科技公司发布新的产品&#xff0c;那这其中必然有核心巨头 intel 的身影。 据外媒 Benchlife 披露&#xff0c;英特尔计划在其 Arrow Lake-S 架构 Core Ultra 200 台式机 CPU 系列中推出共计 21 款 CPU。 这是 intel 首次在桌…