请你谈谈:spring AOP的浅显认识?

在Java面向对象编程中,解决代码重复是一个重要的目标,旨在提高代码的可维护性、可读性和复用性。你提到的两个步骤——抽取成方法和抽取类,是常见的重构手段。然而,正如你所指出的,即使抽取成类,有时仍然会面临代码重复的问题,尤其是当某些逻辑(如事务管理、日志记录等)需要跨多个业务类和方法时。

在这里插入图片描述
AOP(面向切面编程)的核心理念就是将那些散布在多个业务逻辑代码中的相同或相似(即横切关注点,cross-cutting concerns)的代码,通过横向切割(即非传统的纵向继承或组合方式)的方式抽取到一个独立的模块(称为切面,Aspect)中。这种方式使得这些横切关注点与业务逻辑代码分离,从而提高了代码的模块性、可维护性和复用性。

AOP使得开发者能够更专注于业务逻辑的实现,而不必在每个业务逻辑代码中重复编写那些与业务逻辑不直接相关的代码(如日志记录、事务管理、安全控制等)。同时,它也提供了一种灵活的方式来动态地添加或修改这些横切关注点,而无需修改业务逻辑代码本身。
在这里插入图片描述

AOP的首要解决问题不仅仅是将重复性的逻辑代码横切出来封装成一个类,更重要的是将这些横切关注点(cross-cutting concerns)以非侵入式的方式融合到业务逻辑代码中,而不需要修改业务逻辑代码本身。

AOP(面向切面编程)确实是对OOP(面向对象编程)的一种重要补充,特别是在处理那些与业务逻辑不直接相关但又必须跨越多个业务模块的横切关注点时。AOP通过提供一种非侵入式的方式来增强业务逻辑,使得开发者能够专注于业务逻辑的实现,而无需关心那些横切关注点的处理。

正如您所提到的,AOP在日志记录、性能统计、安全控制等场景中非常有用。这些功能通常是跨越多个业务模块的,如果直接在每个业务逻辑代码中添加这些功能的代码,不仅会导致代码冗余和难以维护,还会增加业务逻辑代码与这些非业务功能的耦合度。通过使用AOP,我们可以将这些功能封装成独立的切面,并通过声明式的方式在需要的地方应用这些切面,从而实现横切关注点的非侵入式融合。

AOP(面向切面编程)的实际应用案例非常广泛,包括但不限于事务管理、日志记录、安全控制、性能监控等。下面我将以日志记录为例,详细介绍一个基于注解的AOP实现方式。

AOP日志记录案例

1. 项目环境准备

首先,确保你的项目中已经包含了Spring框架和AspectJ的相关依赖。对于Maven项目,你可以在pom.xml文件中添加如下依赖(注意替换为适合你项目的版本):

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>
</dependencies>
    <dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.3.24</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.7</version></dependency>
2. 定义业务逻辑类

假设你有一个业务逻辑类UserService,里面包含了一些用户操作的方法,如addUserdeleteUser等。

@Service
public class UserService {public void addUser(User user) {// 业务逻辑代码...System.out.println("Adding user: " + user.getName());}public void deleteUser(Long userId) {// 业务逻辑代码...System.out.println("Deleting user with ID: " + userId);}// 其他方法...
}
3. 定义日志切面类

接下来,定义一个日志切面类LogAspect,用于在业务方法执行前后记录日志。

@Aspect
@Component
public class LogAspect {// 定义切点,匹配UserService类中的所有方法@Pointcut("execution(* com.yourpackage.UserService.*(..))")public void userServiceMethods() {}// 前置通知,在目标方法执行前运行@Before("userServiceMethods()")public void logBefore(JoinPoint joinPoint) {System.out.println("Before method: " + joinPoint.getSignature().getName());}// 后置通知,在目标方法执行后运行(无论是否抛出异常)@After("userServiceMethods()")public void logAfter(JoinPoint joinPoint) {System.out.println("After method: " + joinPoint.getSignature().getName());}// 返回通知,在目标方法正常返回后运行@AfterReturning(value = "userServiceMethods()", returning = "result")public void logAfterReturning(JoinPoint joinPoint, Object result) {System.out.println("Returning from method: " + joinPoint.getSignature().getName() + " with result: " + result);}// 异常通知,在目标方法抛出异常后运行@AfterThrowing(value = "userServiceMethods()", throwing = "ex")public void logAfterThrowing(JoinPoint joinPoint, Throwable ex) {System.out.println("Exception in method: " + joinPoint.getSignature().getName() + " - " + ex.getMessage());}// 环绕通知,可以在目标方法执行前后自定义行为@Around("userServiceMethods()")public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("Around before method: " + joinPoint.getSignature().getName());Object result = joinPoint.proceed(); // 执行目标方法System.out.println("Around after method: " + joinPoint.getSignature().getName());return result;}
}
4. 开启AOP自动代理

在你的Spring配置类中,或者通过XML配置,确保开启了AOP自动代理。如果使用Java配置,可以添加@EnableAspectJAutoProxy注解到你的配置类上。

@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = "com.yourpackage")
public class AppConfig {// 配置类内容...
}
5. 测试

现在,当你调用UserService中的任何:

    @Testvoid test() {User user = new User();user.setId(1L);user.setUserName("zhaoshuai-lc");userService.addUser(user);}
Around before method: addUser
Before method: addUser
Adding user: zhaoshuai-lc
Returning from method: addUser with result: null
After method: addUser
Around after method: addUser

execute表达式,在AOP(面向切面编程)的上下文中,通常指的是execution表达式,它是用于定义切点(Pointcut)的一种表达式,用于指定哪些方法会被AOP增强(即应用通知)。execution表达式是Spring AOP中最重要的Pointcut表达式之一,它允许你精确地指定哪些类的哪些方法应该被拦截。

execution表达式的基本语法

execution表达式的基本语法如下:

execution(修饰符 返回值类型 声明类型? 方法名(参数类型列表) throws 异常类型列表?)
  • 修饰符:方法的访问修饰符,如publicprivate等,通常可以省略。
  • 返回值类型:方法的返回类型,不能省略,可以使用*表示任意类型。
  • 声明类型:方法的声明类,可以省略,也可以使用*表示任意类。
  • 方法名:方法的名称,不能省略,可以使用*进行通配。
  • 参数类型列表:方法的参数类型列表,括号内的..表示任意数量的参数,参数类型之间用逗号分隔,可以使用*表示任意类型。
  • 异常类型列表:方法声明抛出的异常类型列表,通常省略。

execution表达式的使用示例

  1. 拦截所有public方法
    在这里插入图片描述

    execution(public * *(..))
    

    这个表达式会匹配所有public方法的执行。

  2. 拦截以set开头的任意方法

    execution(* set*(..))
    

    这个表达式会匹配所有以set开头的方法的执行。

  3. 拦截指定类中的方法

    execution(* com.example.service.UserService.*(..))
    

    这个表达式会匹配com.example.service.UserService类中所有方法的执行。

  4. 拦截指定包及其子包中所有类的所有方法

    execution(* com.example.service..*.*(..))
    

    这个表达式会匹配com.example.service包及其所有子包中所有类的所有方法的执行。

注意事项

  • 在使用execution表达式时,需要确保表达式的语法正确,特别是参数类型列表和异常类型列表部分,因为它们是可选的,但如果不写,需要使用括号()来占位。
  • execution表达式是Spring AOP中用于定义切点的主要方式之一,但它并不是唯一的方式。Spring AOP还支持其他类型的Pointcut表达式,如withinthistarget等,这些表达式可以根据不同的需求进行组合使用。
  • 在定义切点时,可以根据需要选择是否包含修饰符、异常类型列表等部分,但返回值类型、声明类型(或省略)、方法名和参数类型列表是必需的。

综上所述,execution表达式是Spring AOP中用于定义切点的一种强大工具,它允许你精确地指定哪些方法的执行应该被拦截,并通过AOP技术对这些方法进行增强。

AOP(Aspect Oriented Programming,面向切面编程)是一种编程范式,它旨在通过将关注点(如日志记录、事务管理、权限控制等)分离出来,使其独立于业务逻辑代码,从而提高代码的可维护性和可重用性。AOP的核心概念主要包括以下几个方面:
在这里插入图片描述

1. 切面(Aspect)

切面(Aspect)是面向切面编程(AOP)中的一个核心概念。在AOP中,切面代表了横切关注点的模块化,即将那些与业务逻辑不直接相关,但却会影响到多个业务组件的公共行为(如日志记录、事务管理、安全控制等)封装成一个独立的模块。这个模块就是切面。

切面主要由两部分组成:

  1. 切点(Pointcut):定义了哪些连接点(Join Point)会被切面所增强。连接点是程序执行中的某个点,比如方法调用、字段访问等。在Spring AOP中,连接点通常指的是方法的执行点。切点通过一种表达式(如execution表达式)来指定,它决定了切面中的增强逻辑将会应用到哪些具体的连接点上

  2. 通知(Advice):定义了切面在特定连接点上要执行的动作。通知是切面的具体实现,它包含了要增强的逻辑。根据执行时机和方式的不同,通知可以分为多种类型,如前置通知(Before)、后置通知(After)、返回通知(After Returning)、异常通知(After Throwing)和环绕通知(Around)等。

切面通过切点和通知的组合,实现了对目标对象(Target Object)的增强。在运行时,AOP框架会为目标对象创建一个代理对象(AOP Proxy),这个代理对象会拦截对目标对象的调用,并根据切点的定义,在适当的时机执行通知中的增强逻辑。这样,就可以在不修改目标对象代码的情况下,为其添加额外的行为,实现了横切关注点的模块化。

在Spring AOP中,通知(Advice)是切面(Aspect)中的核心部分,用于定义在连接点(Joinpoint)处应该执行的操作。根据执行时机和方式的不同,Spring AOP支持五种类型的通知:前置通知(Before advice)、正常返回通知(After returning advice)、异常返回通知(After throwing advice)、后置通知(After (finally) advice)和环绕通知(Around advice)。这些通知的执行顺序在Spring AOP中是有明确规定的。

通知的执行顺序

当多个通知作用于同一个连接点时,它们的执行顺序如下(以方法调用为连接点为例):

  1. 环绕通知(Around advice):首先执行环绕通知的“前部分”,即在目标方法执行之前执行的逻辑。然后,它会调用ProceedingJoinPointproceed()方法来执行目标方法。如果目标方法正常执行完成,环绕通知会接着执行其“后部分”,即目标方法执行之后的逻辑。如果目标方法抛出异常,则环绕通知的“后部分”会在捕获异常后执行(如果环绕通知中进行了异常处理)。

  2. 前置通知(Before advice):在环绕通知的“前部分”执行完毕后,紧接着执行前置通知。前置通知在目标方法执行之前执行,但它不能阻止目标方法的执行(除非它抛出了异常)。

  3. 目标方法(Target method):前置通知执行完毕后,执行目标方法本身。

  4. 正常返回通知(After returning advice):如果目标方法正常执行完成并返回结果,则在环绕通知的“后部分”执行完毕后(如果存在环绕通知的话),执行正常返回通知。如果目标方法抛出异常,则不会执行正常返回通知。

  5. 异常返回通知(After throwing advice):如果目标方法执行过程中抛出了异常,则在环绕通知的“后部分”执行完毕后(如果存在环绕通知,并且环绕通知中捕获了异常),执行异常返回通知。

  6. 后置通知(After (finally) advice):无论目标方法是正常返回还是抛出异常,后置通知都会执行。它类似于Java中的finally块,用于执行一些清理工作。

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

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

相关文章

【Redis宕机啦!】Redis数据恢复策略:RDB vs AOF vs RDB+AOF

文章目录 Redis宕机了&#xff0c;如何恢复数据为什么要做持久化持久化策略RDBredis.conf中配置RDBCopy-On-Write, COW快照的频率如何把握优缺点 AOFAOF日志内容redis.conf中配置AOF写回策略AOF日志重写AOF重写会阻塞吗优缺点 RDB和AOF混合方式总结 Redis宕机了&#xff0c;如何…

Spring Bean - xml 配置文件创建对象

类型&#xff1a; 1、值类型 2、null &#xff08;标签&#xff09; 3、特殊符号 &#xff08;< -> < &#xff09; 4、CDATA <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/bea…

分布式锁的三种实现方式:Redis、基于数据库和Zookeeper

分布式锁的实现 操作共享资源&#xff1a;例如操作数据库中的唯一用户数据、订单系统、优惠券系统、积分系统等&#xff0c;这些系统需要修改用户数据&#xff0c;而多个系统可能同时修改同一份数据&#xff0c;这时就需要使用分布式锁来控制访问&#xff0c;防止数据不一致。…

最新爆火的开源AI项目 | LivePortrait 本地安装教程

LivePortrait 本地部署教程&#xff0c;强大且开源的可控人像AI视频生成 1&#xff0c;准备工作&#xff0c;本地下载代码并准备环境&#xff0c;运行命令前需安装git 以下操作不要安装在C盘和容量较小的硬盘&#xff0c;可以找个大点的硬盘装哟 2&#xff0c;需要安装FFmp…

项目开发实战案例 —— Spring Boot + MyBatis + Hibernate + Spring Cloud

作者简介 我是本书的作者&#xff0c;拥有多年Java Web开发经验&#xff0c;致力于帮助更多开发者快速掌握并运用Java Web技术栈中的关键框架和技术。本书旨在通过实战案例的方式&#xff0c;带领读者深入理解并实践Spring Boot、MyBatis、Hibernate以及Spring Cloud等热门技术…

2-46 基于matlab的声音信号的短时能量、短时过零率、端点检测

基于matlab的声音信号的短时能量、短时过零率、端点检测。通过计算计算短时能量、调整能量门限&#xff0c;然后开始端点检测。输出可视化结果。程序已调通&#xff0c;可直接运行。 2-46 短时能量 短时过零率 端点检测 - 小红书 (xiaohongshu.com)

Vue element ui分页组件示例

https://andi.cn/page/621615.html

Camera Raw:预设

Camera Raw 的预设 Presetss模块能够简化和加速照片编辑过程。预设不仅能大大提升工作效率&#xff0c;还能确保处理结果的一致性和专业性。 快捷键&#xff1a;Shift P 预设 Preset与配置文件、快照有其异同之处&#xff0c;它们都可以快速改变照片的影调和颜色。 不同是&…

SQL labs-SQL注入(三,sqlmap使用)

本文仅作为学习参考使用&#xff0c;本文作者对任何使用本文进行渗透攻击破坏不负任何责任。 引言&#xff1a; 盲注简述&#xff1a;是在没有回显得情况下采用的注入方式&#xff0c;分为布尔盲注和时间盲注。 布尔盲注&#xff1a;布尔仅有两种形式&#xff0c;ture&#…

python-学生排序(赛氪OJ)

[题目描述] 已有 a、b 两个链表&#xff0c;每个链表中的结点包括学号、成绩。要求把两个链表合并&#xff0c;按学号升序排列。输入格式&#xff1a; 输入共 NM1 行。 第一行&#xff0c;输入 a、b 两个链表元素的数量 N、M&#xff0c;中间用空格隔开。下来 N 行&#xff0c;…

全网爆火的AI老照片变视频项目来了,简单易上手,1单69,日入1000+

每天为大家带来一个可实操落地的副业项目&#xff0c;创业思维&#xff0c;只要你认真看完&#xff0c;多少都能够为你带来帮助或启发。 最近在短视频上看到很多怀旧视频流量真的大&#xff0c;同时也看到朋友圈很多人在培训这个项目。 既然有这么多人在做&#xff0c;就证明…

一天搞定React(5)——ReactRouter(下)【已完结】

Hello&#xff01;大家好&#xff0c;今天带来的是React前端JS库的学习&#xff0c;课程来自黑马的往期课程&#xff0c;具体连接地址我也没有找到&#xff0c;大家可以广搜巡查一下&#xff0c;但是总体来说&#xff0c;这套课程教学质量非常高&#xff0c;每个知识点都有一个…

C语言文件操作,文件读写

目录 为什么要使用文件&#xff1f; 文件概念 1. 什么是文件&#xff1f; 2. 程序文件 3. 数据文件 4. 文件名 文件的使用 1. 文件指针 2. 文件的打开与关闭 文件的顺序读写 1. 顺序读写函数 2. scanf系列与printf系列 文件的随机读写 1. fseek 2. ftell 3. …

B端:用弹框还是用抽屉,请说出你的依据。

选择浮层&#xff08;弹出框&#xff09;还是抽屉&#xff08;侧边栏&#xff09;作为B端系统的浮层&#xff0c;需要根据具体情况来决定。以下是一些依据供您参考&#xff1a; 1.功能需求&#xff1a; 浮层的选择应该符合系统的功能需求。如果需要在当前页面上提供一些额外的操…

C++ 基础(类和对象下)

目录 一. 再探构造函数 1.1. 初始化列表&#xff08;尽量使用列表初始化&#xff09; 二. static成员 2.1static成员初始化 三.友元 3.1友元&#xff1a;提供了⼀种 突破类访问限定符封装的方式. 四.内部类 4.1如果⼀个类定义在另⼀个类的内部&#xff0c;这个内部类就叫…

Google Android 2024年7月最新消息汇总

本文首发于公众号“AntDream”&#xff0c;欢迎微信搜索“AntDream”或扫描文章底部二维码关注&#xff0c;和我一起每天进步一点点 Google Android 2024年7月最新消息汇总 2024年7月&#xff0c;Google在Android生态系统中发布了多项更新和政策调整&#xff0c;涵盖了Google …

6万字,让你轻松上手的大模型 LangChain 框架

本文为我学习 LangChain 时对官方文档以及一系列资料进行一些总结&#xff5e;覆盖对Langchain的核心六大模块的理解与核心使用方法&#xff0c;全文篇幅较长&#xff0c;共计50000字&#xff0c;可先码住辅助用于学习Langchain。** 一、Langchain是什么&#xff1f; 如今各类…

开源多协议分布式压力测试工具Tsung详解

目录 1、Tsung简介 2、Tsung安装 3、Tsung的使用流程 4、Tsung配置详解 4.1、客户端配置 4.2、服务端配置 4.3、压力阶段配置 4.4、选项参数配置 4.5、会话动作配置 5、Tsung压测后的结果分析 5.1、统计数据表 5.2、曲线图 6、其他 6.1、record录制 6.2、Plotte…

多区域DNS以及主从DNS的搭建

搭建多域dns服务器&#xff1a; 搭建DNS多区域功能&#xff08;Multi-Zone DNS&#xff09;主要是为了满足复杂网络环境下的多样化需求&#xff0c;提高DNS服务的灵活性、可扩展性和可靠性。 适应不同网络环境&#xff1a; 在大型组织、跨国公司或跨地域服务中&#xff0c;网…

【算法】单向环形链表解决Josephu(约瑟夫)问题

应用场景 n 个小孩标号&#xff0c;逆时针站一圈。从 k 号开始&#xff0c;每一次从当前的小孩逆时针数 m 个&#xff0c;然后让最后这个小孩出列。不断循环上述过程&#xff0c;直到所有小孩出列&#xff0c;由此产生出一个队列编号。 提示 用一个不带头节点的循环链表来处…