【Spring 篇】注解之舞:Spring AOP的优雅表演

在这里插入图片描述

欢迎来到Spring的代码舞台,在这里,我们将沉浸在一场注解之舞的盛宴中。今天我们将探讨如何使用注解方式实现Spring AOP,一种优雅而富有表现力的编程技术。

AOP的魅力

在编程的舞台上,AOP(Aspect-Oriented Programming)是一种让代码更具模块性和可维护性的编程范式。它通过将横切关注点(Cross-cutting Concerns)从主要业务逻辑中抽离出来,形成一个独立的模块——切面(Aspect)。而今我们将学会如何在Spring中使用注解方式实现AOP,为我们的代码世界增添一抹优雅的色彩。

注解的舞台布景

在Spring中,注解是一种优雅的表达方式,它将AOP的配置融入到代码中,让我们不再依赖XML文件。让我们先了解几个关键的注解,它们将在AOP的舞台上大放异彩。

切面(@Aspect)

在注解方式中,我们使用@Aspect注解来定义切面。切面包含了通知(Advice)和切点(Pointcut),是AOP的主角之一。

@Aspect
@Component
public class LoggingAspect {@Before("execution(* com.example.service.*.*(..))")public void logBefore(JoinPoint joinPoint) {// 前置通知的逻辑System.out.println("Before method: " + joinPoint.getSignature().getName());}@After("execution(* com.example.service.*.*(..))")public void logAfter(JoinPoint joinPoint) {// 后置通知的逻辑System.out.println("After method: " + joinPoint.getSignature().getName());}
}

在这个例子中,我们使用@Aspect注解定义了一个名为LoggingAspect的切面,并通过@Component注解将其交给Spring进行管理。在切面内部,我们使用@Before注解定义了前置通知,它将在com.example.service包下所有方法执行前执行;使用@After注解定义了后置通知,它将在这些方法执行后执行。

通知类型注解

在注解方式中,通知的类型由特定的注解表示,让我们分别了解一下。

1. 前置通知(@Before)

前置通知在连接点之前执行,用于预处理操作。

@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {// 前置通知的逻辑System.out.println("Before method: " + joinPoint.getSignature().getName());
}

在这个例子中,@Before注解表示这是一个前置通知,而括号中的参数是切点表达式,指定了在com.example.service包下所有方法执行前执行。

2. 后置通知(@After)

后置通知在连接点之后执行,用于后处理操作。

@After("execution(* com.example.service.*.*(..))")
public void logAfter(JoinPoint joinPoint) {// 后置通知的逻辑System.out.println("After method: " + joinPoint.getSignature().getName());
}

在这个例子中,@After注解表示这是一个后置通知,同样指定了在com.example.service包下所有方法执行后执行。

3. 返回通知(@AfterReturning)

返回通知在连接点正常执行并返回结果后执行,用于处理返回结果。

@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {// 返回通知的逻辑System.out.println("After returning from method: " + joinPoint.getSignature().getName());System.out.println("Result: " + result);
}

在这个例子中,@AfterReturning注解表示这是一个返回通知,pointcut属性指定了切点表达式,returning属性指定了返回结果的参数名。

4. 异常通知(@AfterThrowing)

异常通知在连接点抛出异常时执行,用于处理异常情况。

@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "exception")
public void logAfterThrowing(JoinPoint joinPoint, Throwable exception) {// 异常通知的逻辑System.out.println("After throwing exception from method: " + joinPoint.getSignature().getName());System.out.println("Exception: " + exception.getMessage());
}

在这个例子中,@AfterThrowing注解表示这是一个异常通知,pointcut属性和throwing属性的用法同上。

5. 环绕通知(@Around)

环绕通知是最灵活的通知类型,可以在连接点前后执行额外的代码,并控制连接点的执行。

@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;
}

在这个例子中,@Around注解表示这是一个环绕通知,方法参数ProceedingJoinPoint用于执行连接点。

舞者登场:实际应用示例

让我们通过一个实际的业务场景,演示如何使用注解方式实现AOP。假设我们有一个简单的购物车服务,我们想要在用户购物时记录购物车的处理时间和处理异常。

购物车服务

首先,我们创建一个购物车服务接口和实现类。

public interface ShoppingCartService {void addToCart(String userId, String productId, int quantity);
}@Service
public class ShoppingCartServiceImpl implements ShoppingCartService {@Overridepublic void addToCart(String userId, String productId, int quantity) {// 购物车逻辑System.out.println("Adding " + quantity + " " + productId + "(s) to the cart for user " + userId);if (productId.equals("invalidProduct")) {throw new RuntimeException("Invalid product added to the cart.");}}
}

购物车服务切面

然后,我们创建一个购物车服务切面,用于记录购物车服务的执行时间和处理异常。

@Aspect
@Component
public class ShoppingCartAspect {@Around("execution(* com.example.service.ShoppingCartService.addToCart(..))")public Object logShoppingCart(ProceedingJoinPoint joinPoint) throws Throwable {long startTime = System.currentTimeMillis();// 环绕通知的逻辑System.out.println("Before adding to cart...");try {Object result = joinPoint.proceed(); // 执行连接点System.out.println("After adding to cart...");long endTime = System.currentTimeMillis();System.out.println("Time taken to add to cart: " + (endTime - startTime) + " milliseconds");return result;} catch (Exception e) {System.out.println("Exception while adding to cart: " + e.getMessage());throw e;}}
}

在这个例子中,我们使用@Around注解定义了一个名为logShoppingCart的环绕通知。在通知内部,我们记录了添加购物车前后的信息,并计算了执行时间。如果在添加购物车时发生异常,我们捕获并记录异常信息,然后重新抛出异常。

配置和启用AOP

最后,在Spring Boot应用的主类上添加@EnableAspectJAutoProxy注解,启用AspectJ自动代理。

@SpringBootApplication
@EnableAspectJAutoProxy
public class SpringAopAnnotationApplication {public static void main(String[] args) {SpringApplication.run(SpringAopAnnotationApplication.class, args);}
}

通过以上配置,我们成功地在购物车服务中应用了注解方式实现的AOP。当调用addToCart方法时,AOP会记录购物车处理的执行时间,并在出现异常时记录异常信息。这种方式使得我们能够在不修改购物车服务实现的情况下,增加额外的功能,保持了代码的清晰和可维护性。

舞台绽放:AOP的优势和应用场景

在注解的舞台上,AOP以一种轻盈而灵活的形式为我们呈现。让我们总结一下注解方式实现AOP的优势和适用场景。

优势

  1. 简洁明了: 注解方式让AOP配置更加直观,不再依赖于XML文件,代码更加清晰简洁。

  2. 灵活性: 注解方式使得AOP的配置更加灵活,可以更方便地应对不同场景的需求。

  3. 可读性: 切面和通知直接与业务代码结合,提高了代码的可读性和维护性。

应用场景

  1. 日志记录: 在方法执行前后记录日志信息,以便追踪代码执行流程。

  2. 事务管理: 实现对事务的自动开启、提交或回滚。

  3. 异常处理: 在出现异常时执行额外的逻辑,如记录异常信息、发送通知等。

  4. 性能监控: 监控方法的执行时间,识别性能瓶颈。

  5. 权限控制: 鉴权操作可以被封装在切面中,使得权限控制逻辑独立于业务逻辑。

  6. 缓存管理: 在方法执行前检查缓存,避免执行昂贵的操作。

舞者告别:结束语

在这个注解的舞台上,我们学会了如何使用注解方式实现Spring AOP。AOP为我们的代码世界增添了一抹优雅的色彩,让代码更加模块化、清晰和可维护。

愿你在编程的旅途中,能够在注解的舞台上舞出属于自己的优美编程之舞。让我们共同期待,注解的魔法继续为我们的代码世界奏响动人的旋律。在这个AOP的舞台上,愿你的代码之舞更加轻盈自如!

作者信息

作者 : 繁依Fanyi
CSDN: https://techfanyi.blog.csdn.net
掘金:https://juejin.cn/user/4154386571867191

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

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

相关文章

CMU15-445-Spring-2023-Project #2 - 前置知识(lec07-010)

Lecture #07_ Hash Tables Data Structures Hash Table 哈希表将键映射到值。它提供平均 O (1) 的操作复杂度(最坏情况下为 O (n))和 O (n) 的存储复杂度。 由两部分组成: Hash Function和Hashing Scheme(发生冲突后的处理&…

[论文阅读]YOLO9000:Better,Faster,Stronger

摘要 我们引入了YOLO9000,一个可以检测超过9000种类别的先进的实时目标检测系统。首先我们提出了多种yolo检测方法的提升方式,既新颖又参考了 之前的工作。改进后的模型,YOLOV2在标准检测任务例如PASCAL VO 和COCO 上都取得了领先。使用一个…

每天学习一点点之 Spring Boot 1.x 升级 2.x 之 allowBeanDefinitionOverriding

最近组内大佬正在进行 Spring Boot 版本的升级,从 1.x 版本升级到 2.x 版本。在查看代码变更时,我注意到我之前编写的一个名为 ShardingRuleStrategy 的类被添加了 Primary 注解。这个类在原来的代码中被标记为 Component,同时也在 API 中被定…

Android开发基础(一)

Android开发基础(一) 本篇主要是从Android系统架构理解Android开发。 Android系统架构 Android系统的架构采用了分层的架构,共分为五层,从高到低分别是Android应用层(System Apps)、Android应用框架层&a…

Python基础知识:整理9 文件的相关操作

1 文件的打开 # open() 函数打开文件 # open(name, mode, encoding) """name: 文件名(可以包含文件所在的具体路径)mode: 文件打开模式encoding: 可选参数,表示读取文件的编码格式 """ 2 文件的读取 文…

Qt During startup program exited with code 0xc0000135

网上试了好多办法没有用,可以试试在pro目录下加入如图所示的.dll 可以下个everything搜索整个电脑查看是否有上述dll,如果没有也可以网上下载或者点击连接

文心大模型融入荣耀MagicOS!打造大模型“端云协同”创新样板

2024年1月10日,在荣耀MagicOS 8.0发布会及开发者大会上,荣耀终端有限公司CEO赵明宣布了“百模生态计划”,并与百度集团执行副总裁、百度智能云事业群总裁沈抖共同宣布,百度智能云成为荣耀大模型生态战略合作伙伴。 沈抖在现场演讲…

【UE Niagara学习笔记】05 - 喷射火焰顶部的蓝色火焰

在上一篇博客(【UE Niagara学习笔记】04 - 火焰喷射时的黑烟效果)的基础上继续实现在火焰喷射的起点位置生成蓝色火焰的效果。 目录 效果 步骤 1. 创建新的发射器 2. 减少粒子生成数量 3. 减小粒子初始大小 4. 减少粒子喷射距离 5. 减少粒子初始…

网络服务DHCP与DNS

一.DHCP 1.DHCP概念 DHCP(Dynamic Host Configuration Protocol,动态主机配置协议) 通常被应用在大型的局域网络环境中,主要作用是集中地管理、分配IP地址,使网络环境中的主机动态的获得IP地址、Gateway地址、DNS服务…

xss-labs(10-16)

level10:欢迎来到level10 尝试注入 <script>alert(欢迎来钓鱼)</script> 寻找注入点 让表单显示出来 随便输入一个字符康康 url出现了变化</

分布式全局id

分布式全局id snowflake 算法是 twitter 开源的分布式 id 生成算法&#xff0c;采用 Scala 语言实现&#xff0c;是把一个 64 位的 long 型的 id&#xff0c;1 个 bit 是不用的&#xff0c;用其中的 41 bits 作为毫秒数&#xff0c;用 10 bits 作为工作机器 id&#xff0c;12 …

职场日常英语口语,成人英语培训学校,柯桥学英语推荐哪里

“玩手机”用英语怎么说&#xff1f;你的第一反应是不是&#xff1a;play the phone&#xff1f; 在英语中&#xff0c;play这个动词通常表示“玩耍、娱乐、操纵”等意思&#xff0c;而手机是一种工具&#xff0c;不是玩耍的对象。 换句话说&#xff0c;我们“玩手机”&#xf…