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.rhkb.cn/news/501177.html

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

相关文章

SOLIDWORKS Composer在产品设计、制造与销售中的应用

SOLIDWORKS Composer是一款专为技术团队设计的高效沟通工具&#xff0c;广泛应用于产品设计、制造、销售及售后等领域。它能从复杂的CAD数据中提取关键信息&#xff0c;轻松转化为高质量的产品文档、交互式3D动画及说明视频&#xff0c;显著提升产品沟通效率。 Composer擅长制…

【数据结构Ⅰ复习题】

如有错误欢迎指正&#xff0c;题目根据教材----------严蔚敏数据结构&#xff08;c语言版 第2版&#xff09;人民邮电电子版 数据结构Ⅰ复习题 一、填空题1&#xff0e;算法应该具备的5个重要特性有___有穷性___、确定性、可行性、输入和输出。2&#xff0e;非空单链表L中*p是头…

flutter 专题二十四 Flutter 响应式状态管理框架GetX

一、状态管理框架对比 在Flutter的状态管理框架中&#xff0c;主流的状态管理框架有四个&#xff1a;GetX&#xff08;又称为Get&#xff09;、BLoC、MobX、Provider。 Provider 其中&#xff0c;Provider是Flutter社区提供的一种状态管理工具&#xff0c;本质上是对Inherit…

禁用div的写法(自定义disabled)Vue3

因为div 元素本身没有 disabled 属性&#xff0c;所以需要根据JavaScript中的变量、通过动态绑定 class &#xff08;Vue的:class&#xff09;来改变样式。 需要一个变量 isDivDisabled import { ref } from vue; let isDivDisabled ref(false);当 isDivDisabled true &…

大模型系列——旋转位置编码和长度外推

绝对位置编码 旋转位置编码 论文中有个很直观的图片展示了旋转变换的过程&#xff1a; 对于“我”对应的d维向量&#xff0c; 拆分成d/2组以后&#xff0c;每组对应一个角度&#xff0c;若1对应的向量为(x1,x2)&#xff0c;应用旋转位置编码&#xff0c;相当于这个分量旋转了m…

路径规划 | 基于极光PLO优化算法的三维路径规划Matlab程序

效果一览 基本介绍 研究内容 极光优化算法&#xff08;PLO&#xff09;的深入理解&#xff1a; 研究极光优化算法的基本原理&#xff0c;包括模拟带电粒子在地球磁场中的旋转运动、极光椭圆区域内的行走以及粒子间的碰撞等。 分析PLO算法的全局搜索能力和局部开发能力&#xf…

MATLAB画柱状图

一、代码 clear; clc; figure(position,[150,100,900,550])%确定图片的位置和大小&#xff0c;[x y width height] %准备数据 Y1[0.53,7.9,8.3;0.52,6.8,9.2;0.52,5.9,8.6;2.8,5.8,7.9;3.9,5.2,7.8;1.8,5.8,8.4]; % withoutNHC X11:6; %画出4组柱状图&#xff0c;宽度1 h1…

[实用指南]如何将视频从iPhone传输到iPad

概括 将视频从 iPhone 传输到 iPad 时遇到问题&#xff1f;您可能知道一种方法&#xff0c;但不知道如何操作。此外&#xff0c;您要传输的视频越大&#xff0c;完成任务就越困难。那么如何将视频从 iPhone 传输到 iPad&#xff0c;特别是当您需要发送大视频文件时&#xff1f…

Git命令行的使用

目录 一、什么是Git 1、本地仓库 vs 远端仓库 本地仓库 远端仓库 2、.git vs .gitignore .git .gitignore 二、使用Git命令 1、安装git 2、git首次使用需要配置用户邮箱和用户名 3、上传目录/文件到远端仓库步骤 1&#xff09;创建放置文件的目录 2&#xff09;cd…

黑马JavaWeb开发跟学(十五).Maven高级

黑马JavaWeb开发跟学.十五.Maven高级 Maven高级1. 分模块设计与开发1.1 介绍1.2 实践1.2.1 分析1.2.2 实现 1.3 总结 2. 继承与聚合2.1 继承2.1.1 继承关系2.1.1.1 思路分析2.1.1.2 实现 2.1.2 版本锁定2.1.2.1 场景2.1.2.2 介绍2.1.2.3 实现2.1.2.4 属性配置 2.2 聚合2.2.1 介…

十二、Vue 路由

文章目录 一、简介二、安装与基本配置安装 Vue Router创建路由实例在应用中使用路由实例三、路由组件与视图路由组件的定义与使用四、动态路由动态路由参数的定义与获取动态路由的应用场景五、嵌套路由嵌套路由的概念与配置嵌套路由的应用场景六、路由导航<router - link>…

AE RFG 1251 Generator User Manual

AE RFG 1251 Generator User Manual

vue2、element的el-select 选项框的宽度设置、文本过长问题

<el-select v-model"value" placeholder"请选择"><el-optionv-for"item in cities":key"item.value":label"item.label":value"item.value"><el-tooltip class"item" :content"ite…

【Matlab算法】基于改进人工势场法的移动机器人路径规划研究(附MATLAB完整代码)

基于改进人工势场法的移动机器人路径规划研究 结果图摘要1. 引言2. 方法说明2.1 基本原理2.2 改进策略3. 核心函数解释3.1 改进的斥力计算函数3.2 路径规划主函数4. 实验设计4.1 实验环境设置4.2 关键参数选择5. 结果分析5.1 实验结果5.2 性能分析附录:完整代码参考文献结果图…

【MySQL】--- 内置函数

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; MySQL &#x1f3e0; 时间函数 约定&#xff1a;我们在MySQL中说的日期指的是年 月 日&#xff0c;时间指的是时 分 秒。 &#x1f9f7; now() select n…

springboot和vue项目前后端交互

java后端开发常用springboot框架&#xff0c;开发简单不繁琐&#xff0c;容易上手。简简单单配置好一些配置项&#xff0c;整个web项目就能运行起来了。vue前端也是比较流行的前端开发框架&#xff0c;写起来简单&#xff0c;组件也丰富&#xff0c;参考资料多。 这期就应薯薯…

酒店管理系统|Java|SSM|VUE| 前后端分离

【技术栈】 1⃣️&#xff1a;架构: B/S、MVC 2⃣️&#xff1a;系统环境&#xff1a;Windowsh/Mac 3⃣️&#xff1a;开发环境&#xff1a;IDEA、JDK1.8、Maven、Mysql5.7 4⃣️&#xff1a;技术栈&#xff1a;Java、Mysql、SSM、Mybatis-Plus、VUE、jquery,html 5⃣️数据库可…

OkHttp接口自动化测试

文章目录 java环境搭建OkHttp之getOkHttp之POSTPOST发送From表单POST发送jsonPOST上传文件 OkHttp之deleteOkHttp之put java环境搭建 引入依赖 <!--okhttp3--><dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</art…

分数阶傅里叶变换代码 MATLAB实现

function Faf myfrft(f, a) %分数阶傅里叶变换函数 %输入参数&#xff1a; %f&#xff1a;原始信号 %a&#xff1a;阶数 %输出结果&#xff1a; %原始信号的a阶傅里叶变换N length(f);%总采样点数 shft rem((0:N-1)fix(N/2),N)1;%此项等同于fftshift(1:N)&#xff0c;起到翻…

【Rust练习】26.Package and Crate

练习题来自&#xff1a;https://practice-zh.course.rs/crate-module/crate.html 建议在命令行下操作完成本节内容&#xff0c;Windows 11/10 首选 Windows 终端&#xff0c;好看&#xff0c;支持渲染中文字体&#xff0c;缺点是功能太少了&#xff1b;其次推荐 mobaxterm&…