Spring 核心技术解析【纯干货版】- IV:Spring 切面编程模块 Spring-Aop 模块精讲

随着软件开发技术的不断进步,面向切面编程(AOP)作为一种重要的编程思想,已经在现代开发中占据了重要地位。它通过将横切逻辑从业务逻辑中分离出来,使得代码更加清晰、易于维护。Spring AOP 作为 Spring 框架的核心模块之一,为开发者提供了简单且强大的 AOP 支持,使我们能够以更加优雅的方式处理日志记录、安全控制、事务管理等常见的横切逻辑。本篇内容将引导您深入理解 Spring AOP 的基本概念、核心原理以及实战操作,帮助您在实际项目中更加得心应手地运用这一强大工具。


文章目录

      • 1、Spring-Aop 模块介绍
        • 1.1、Spring-Aop 模块概述
        • 1.2、Spring-Aop 模块依赖
        • 1.3、Spring-Aop 模块作用
      • 2、Spring-Aop 模块补充
        • 2.1、AOP 前置概念
        • 2.2、Spring AOP的实现
        • 2.3、通知类型
          • 2.3.1、前置通知(Before Advice)
          • 2.3.2、后置通知(After Returning Advice)
          • 2.3.3、后置异常通知(After Throwing Advice)
          • 2.3.4、最终通知(After Advice)
          • 2.3.5、环绕通知(Around Advice)
      • 3、基于注解的 Spring AOP 开发
        • 3.1、依赖引入
        • 3.2、Spring 业务类
        • 3.3、Spring 切面类
        • 3.4、Spring 配置类
        • 3.5、Spring 主函数
      • X、后记


1、Spring-Aop 模块介绍

1.1、Spring-Aop 模块概述

Spring AOP 模块,是 Spring 提供的一个面向切面编程(Aspect Oriented Programming,AOP)的模块。

Spring AOP 通过灵活的配置和强大的功能,可以轻松地将横切关注点从业务逻辑中分离出来,提高代码的可维护性和可扩展性。

1.2、Spring-Aop 模块依赖

Spring-AOP 模块的依赖有两个,分别是 Spring-Beans 模块和 Spring-Core 模块。

其中 Spring Beans 模块是对 Spring Bean 进行定义,实现 IOC 基础功能的模块。而 Spring-Core 是 Spring 中的基础模块,它提供了框架运行所必需的核心功能。

1.3、Spring-Aop 模块作用

Spring AOP 模块本身不具备完整的 AOP 能力,需要依赖其他模块和工具(例如 AspectJ 或代理机制)来实现 AOP 功能。这是因为 Spring AOP 本质上是一个基于代理的 AOP 实现框架,它利用 Spring 容器和其他技术来实现横切逻辑。Spring AOP 模块本身不具备完整的 AOP 能力,需要依赖其他模块和工具(例如 AspectJ 或代理机制)来实现 AOP 功能。这是因为 Spring AOP 本质上是一个基于代理的 AOP 实现框架,它利用 Spring 容器和其他技术来实现横切逻辑。


2、Spring-Aop 模块补充

2.1、AOP 前置概念

首先,我们来确认一些 Spring 使用核心的 AOP 概念和术语。Spring 官网的原话是:这些术语并非 Spring 独有,遗憾的是,AOP 术语并不是特别直观。但是,如果 Spring 使用自己的术语,那就更加令人困惑了。

核心术语(逻辑层面,些概念描述的是 AOP 的基本组成部分):

  • 横切(Cross-cutting Concern):横切是指在程序的多个模块中反复出现的功能或逻辑,通常与业务逻辑无直接关系,但又不可或缺。这些功能通常是 “横向” 作用于程序的各个模块,而不是某个模块的核心业务逻辑的一部分,因此被称为横切关注点。
  • 切面(Aspect):切面是 AOP 处理横切关注点的核心单元,它是对 横切逻辑的模块化封装,它包含切点和通知(切面 = 切点 + 通知)。切面的本质是一个包含横切逻辑的类,定义了横切逻辑执行的时机(通知)和适用的位置(切点)。其目的是让横切逻辑独立于业务代码,提高代码模块化程度。换句话说横切是问题,切面是解决方案。
  • 连接点(Join Point):连接点就是程序中可以插入切面逻辑的具体点。例如,一个类中的有多个方法,那么每个方法都是潜在的连接点。
  • 通知(Advice): 通知是在特定连接点处执行的动作。有多种类型的通知,如前置通知、后置通知、环绕通知等。
  • 切点(Pointcut):切点从所有切入点中筛选出需要增强的具体点的过滤条件。通过定义一套过滤条件,决定哪些连接点将会被增强(即在这些连接点执行通知)。这些连接点是程序中可以插入横切逻辑的位置(例如方法调用)。

核心术语(实现层面,这些概念描述的是 AOP 的技术实现方式和执行过程):

  • 引入(Introduction): 动态地为目标类添加新的接口或功能,是一种特殊的增强方式。例如,为一个类增加性能监控的能力,不改变原始代码。
  • 织入(Weaving):将切面逻辑(通知、引入)和目标类的代码结合的过程,生成增强后的类对象。织入可以在编译时、类加载时或运行时进行。
2.2、Spring AOP的实现

Spring AOP 基于代理实现,主要有两种方式:

  1. JDK 动态代理:适用于接口代理。
  2. CGLIB 代理:适用于类代理。

JDK 动态代理:基于 Java 的内置动态代理机制。代理目标对象的接口,而不是类本身。当目标对象实现了一个或多个接口时,Spring 会默认选择 JDK 动态代理。

  • 实现方式:创建一个实现了目标接口的代理类,并在方法调用前后插入增强逻辑。使用 java.lang.reflect.ProxyInvocationHandler
  • 优点:无需引入额外的库(纯 JDK 实现)。代理生成速度较快。
  • 局限性:目标类必须有接口。

CGLIB 代理:基于字节码生成技术,由 CGLIB(Code Generation Library)库支持。通过继承目标类生成代理类,覆盖目标类中的方法来实现增强。当目标类没有实现任何接口时,Spring 会使用 CGLIB 代理。

  • 实现方式:通过字节码操作生成一个目标类的子类,并对其方法进行拦截。
  • 优点:可以代理没有实现接口的类。代理范围更广(包括普通类)。
  • 局限性:目标类或方法不能声明为 final,否则无法被继承和代理。需要引入额外的 CGLIB 库。代理生成速度较慢,但运行时性能较好。
2.3、通知类型

Spring AOP 提供了以下几种通知类型,每种通知用于在不同的时间点插入增强逻辑。

通知类型执行时机注解
前置通知在目标方法执行前@Before
后置通知在目标方法成功返回后@AfterReturning
后置异常通知在目标方法抛出异常后@AfterThrowing
最终通知在目标方法执行后(无论成功与否)@After
环绕通知在目标方法前后都执行,可控制目标方法的执行@Around
2.3.1、前置通知(Before Advice)

在目标方法执行之前执行。

@Aspect
public class LoggingAspect {@Before("execution(* com.example.service.*.*(..))")public void logBefore(JoinPoint joinPoint) {System.out.println("Before method: " + joinPoint.getSignature().getName());}
}
2.3.2、后置通知(After Returning Advice)

在目标方法成功执行之后执行。

@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {System.out.println("After returning: " + joinPoint.getSignature().getName());System.out.println("Result: " + result);
}
2.3.3、后置异常通知(After Throwing Advice)

在目标方法抛出异常后执行。

@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "error")
public void logAfterThrowing(JoinPoint joinPoint, Throwable error) {System.out.println("Exception in method: " + joinPoint.getSignature().getName());System.out.println("Exception: " + error);
}
2.3.4、最终通知(After Advice)

在目标方法执行之后执行,无论方法是否成功执行。

@After("execution(* com.example.service.*.*(..))")
public void logAfter(JoinPoint joinPoint) {System.out.println("After method: " + joinPoint.getSignature().getName());
}
2.3.5、环绕通知(Around Advice)

在目标方法执行前后都执行,可以完全控制目标方法的执行。

@Around("execution(* com.example.service.*.*(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("Before method: " + joinPoint.getSignature().getName());Object result = joinPoint.proceed(); // 执行目标方法System.out.println("After method: " + joinPoint.getSignature().getName());return result;
}

3、基于注解的 Spring AOP 开发

3.1、依赖引入

虽然 Spring AOP 是一个模块,但它需要依赖以下组件来完整实现 AOP 功能:

  • Spring 核心模块:必须依赖 Spring 的核心模块(如 spring-contextspring-beans),用于 Bean 的创建和管理。如果没有容器,Spring AOP 只能手动配置,使用起来非常受限。
  • 代理机制:依赖 JDK 动态代理或 CGLIB 来生成代理对象。
  • AspectJ(可选):Spring AOP 支持 AspectJ 注解,但必须引入 aspectjweaver 库。不依赖 AspectJ 的编译时或加载时织入器。
    <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.39</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.3.39</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.22.1</version></dependency></dependencies>
3.2、Spring 业务类
package com.lizhengi.example;import org.springframework.stereotype.Component;/*** 用户业务类*/
@Component // 标记为 Spring 管理的 Bean
public class UserService {public void createUser(String name) {System.out.println("User " + name + " created.");}public void deleteUser(String name) {System.out.println("User " + name + " deleted.");}
}
3.3、Spring 切面类
package com.lizhengi.example;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;import org.springframework.stereotype.Component;@Aspect // 声明这是一个切面
@Component // 标记为 Spring 管理的 Bean
public class LoggingAspect {@Before("execution(* com.lizhengi.example.UserService.*(..))") // 定义切点public void logBefore() {System.out.println("Logging before method execution");}
}

说明:

  1. @Aspect:标记为切面。
  2. @Before:定义一个前置通知,在方法执行前触发。
  3. 切点表达式:execution(* com.example.service.UserService.*(..)) 表示匹配 UserService 中的所有方法。
3.4、Spring 配置类
package com.lizhengi.example;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;@Configuration // 声明为配置类
@ComponentScan(basePackages = "com.lizhengi") // 自动扫描指定包
@EnableAspectJAutoProxy // 启用 AOP
public class AppConfig {}

说明:

  1. @Configuration:标记这是一个 Spring 配置类。
  2. @ComponentScan:指定要扫描的包,加载所有带有 @Component 的类。
  3. @EnableAspectJAutoProxy:启用 AOP 的自动代理。
3.5、Spring 主函数
package com.lizhengi;import com.lizhengi.example.AppConfig;
import com.lizhengi.example.UserService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class Main {public static void main(String[] args) {// 加载 Spring 应用上下文AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);// 获取 UserService 的代理对象UserService userService = context.getBean(UserService.class);// 调用方法,触发 AOP 增强userService.createUser("Alice");userService.deleteUser("Bob");// 关闭上下文context.close();}
}

运行结果:

Logging before method execution
User Alice created.
Logging before method execution
User Bob deleted.

X、后记

在学习和实践 Spring AOP 的过程中,我们不仅能深入了解其实现机制,还能感受到面向切面编程对开发效率和代码质量的提升作用。从初识 AOP 的基础概念到动手实现切面逻辑,每一步都在为我们构建更加清晰、健壮的应用体系奠定基础。希望本篇内容能为您打开通往 AOP 世界的大门,也期待您在实际工作中灵活运用所学,将代码的复杂度隐藏于优雅的设计之中,为团队和项目带来更大的价值。如果您有任何疑问或见解,欢迎随时交流与探讨!

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

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

相关文章

计算机网络期末复习(含选择题、判断题、简答题、判断题)

&#x1f4e2;&#x1f4e2;&#x1f4e2;传送门 一、选择题二、判断题三、简答题目1.问&#xff1a;常用的信道复用技术包括哪几种?简述它们的基本工作原理2.问&#xff1a;请分别列举OSI参考模型和TCP/IP参考模型的层次结构3.问&#xff1a;请描述交换机的基本功能。用它怎样…

MySQL - 函数

一 . 函数定义&#xff1a; 函数 是指一段可以直接被另一段程序调用的程序或代码。 ---> 说明这些函数已经被mysql内置了 MySQL中的函数主要分为以下四类&#xff1a; 字符串函数、数值函数、日期函数、流程函数。 二 . 字符串函数 MySQL中内置了很多字符串函数&#xff0c…

UniApp 原生插件开发指南

一、UniApp 原生插件开发引言 在当今的移动应用开发领域&#xff0c;跨平台开发已成为主流趋势&#xff0c;而 UniApp 作为一款强大的跨平台开发框架&#xff0c;备受开发者青睐。它凭借 “一套代码&#xff0c;多端运行” 的特性&#xff0c;极大地提高了开发效率&#xff0c…

Java高频面试之SE-08

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本牛马baby今天又来了&#xff01;哈哈哈哈哈嗝&#x1f436; 成员变量和局部变量的区别有哪些&#xff1f; 在 Java 中&#xff0c;成员变量和局部变量是两种不同类型的变量&#xff0c;它们在作用域…

计算机网络 (15)宽带接入技术

前言 计算机网络宽带接入技术是指通过高速、大容量的通信信道或网络&#xff0c;实现用户与互联网或其他通信网络之间的高速连接。 一、宽带接入技术的定义与特点 定义&#xff1a;宽带接入技术是指能够传输大量数据的通信信道或网络&#xff0c;其传输速度通常较高&#xff0c…

2453.学习周刊-2024年53周

封面 不要站在问题一边打败孩子&#xff0c;而是站在孩子一边打败问题&#xff0c;多从孩子的角度思考问题&#xff0c;帮助孩子一起解决问题 ✍优秀博文 SQL中历史数据处理实践指南新领导上任了&#xff0c;老员工该如何适应&#xff1f;主动接纳还是我行我素&#xff1f; ✍…

回归预测 | MATLAB实现CNN-SVM多输入单输出回归预测

回归预测 | MATLAB实现CNN-SVM多输入单输出回归预测 目录 回归预测 | MATLAB实现CNN-SVM多输入单输出回归预测预测效果基本介绍模型架构程序设计参考资料 预测效果 基本介绍 CNN-SVM多输入单输出回归预测是一种结合卷积神经网络&#xff08;CNN&#xff09;和支持向量机&#…

python学opencv|读取图像(二十四)使用cv2.putText()绘制文字进阶-倾斜文字

【1】引言 前述学习进程中&#xff0c;我们已经掌握了pythonopencv绘制文字的基本技能&#xff0c;相关链接为&#xff1a; python学opencv|读取图像&#xff08;二十三&#xff09;使用cv2.putText()绘制文字-CSDN博客 在这里&#xff0c;我们使用不同的字体、线条颜色和线…

【Unity3D】UGUI Canvas画布渲染流程

参考文档&#xff1a;画布 - Unity 手册 Canvas组件&#xff1a;画布组件是进行 UI 布局和渲染的抽象空间。所有 UI 元素都必须是附加了画布组件的游戏对象的子对象。 参数&#xff1a; Render Mode 渲染模式&#xff1a;Screen Space - Overlay、Screen Spa…

热备份路由HSRP及配置案例

✍作者&#xff1a;柒烨带你飞 &#x1f4aa;格言&#xff1a;生活的情况越艰难&#xff0c;我越感到自己更坚强&#xff1b;我这个人走得很慢&#xff0c;但我从不后退。 &#x1f4dc;系列专栏&#xff1a;网路安全入门系列 目录 一&#xff0c;HSRP的相关概念二&#xff0c;…

牛客网刷题 ——C语言初阶——JZ15 二进制中1的个数

1.题目描述 题目OJ链接 描述 输入一个整数 n &#xff0c;输出该数32位二进制表示中1的个数。其中负数用补码表示。 2.思路 求2进制中1的个数&#xff0c;可以转换为求每一位&#xff0c;1的个数&#xff0c;1&1还是1 所以判断如果该数值&1为真&#xff0c;我们就co…

机器学习笔记 - 单幅图像深度估计的最新技术

1、深度估计简述 单眼深度估计是一项计算机视觉任务,AI 模型从单个图像中预测场景的深度信息。模型估计场景中对象从一个照相机视点的距离。单目深度估计已广泛用于自动驾驶、机器人等领域。深度估计被认为是最困难的计算机视觉任务之一,因为它要求模型理解对象及其深度信息之…

Spring AOP 扫盲

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

RocketMQ面试题:基础部分

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

【VUE】使用create-vue快速创建一个vue + vite +vue-route 等其他查看的工程

create-vue 简介 GitHub:https://github.com/vuejs/create-vue 创建的选项有多个,具体的可以看下方截图,当创建完成的时候可以发现工程中是自带vite的。 下面对其中的各种内容进行简单的说明 JSX (可以选择,但是我感觉没什么必要) 全称:JavaScript XML 允许你在 Java…

pikachu靶场--目录遍历和敏感信息泄露

pikachu靶场—目录遍历和敏感信息泄露 目录遍历 概述 在web功能设计中,很多时候我们会要将需要访问的文件定义成变量&#xff0c;从而让前端的功能便的更加灵活。 当用户发起一个前端的请求时&#xff0c;便会将请求的这个文件的值(比如文件名称)传递到后台&#xff0c;后台再…

使用WebSocket 获取实时数据

回车发送数据&#xff0c;模拟服务器发送数据 效果图&#xff1a; 源码&#xff1a; <template><div><h1>WebSocket 实时数据</h1><input type"text" v-model"ipt" keyup.enter"sendMessage(ipt)"><div v-if…

Onedrive精神分裂怎么办(有变更却不同步)

Onedrive有时候会分裂&#xff0c;你在本地删除文件&#xff0c;并没有同步到云端&#xff0c;但是本地却显示同步成功。 比如删掉了一个目录&#xff0c;在本地看已经删掉&#xff0c;onedrive显示已同步&#xff0c;但是别的电脑并不会同步到这个删除操作&#xff0c;在网页版…

虚拟电厂搭建指南:绿虫仿真设计软件的助力

在虚拟电厂的搭建中&#xff0c;绿虫仿真设计软件起着重要作用。 绿虫光伏仿真软件是一款综合性辅助工具&#xff0c;能为虚拟电厂中的光伏项目提供精准数据支持。它所提供的项目选址地气象数据&#xff0c;涵盖海拔、辐照、风速、温度等&#xff0c;数据源为 Meteonorm &…

PHP框架+gatewayworker实现在线1对1聊天--聊天界面布局+创建websocket连接(5)

文章目录 聊天界面布局html代码 创建websocket连接为什么要绑定&#xff1f; 聊天界面布局 在View/Index目录下创建index.html html代码 <div id"chat"><div id"nbar"><div class"pull-left">与牛德胜正在聊天...</div…