【Spring Framework】Spring AOP 面相切面编程

Spring AOP(Aspect-Oriented Programming,面向切面编程)是 Spring 框架的重要组成部分之一,它通过在不修改业务逻辑代码的情况下提供横切关注点的处理能力,使得代码更加简洁、模块化和易于维护。AOP 可以用来处理常见的功能,如日志记录、事务管理、权限控制等。

一、Spring AOP 的基本概念

在 Spring AOP 中,以下是一些关键概念:

  • 切面(Aspect):模块化的横切关注点,例如日志记录、事务管理等。切面可以用类来实现,并使用 @Aspect 注解标记。

  • 通知(Advice):切面在特定连接点执行的动作(方法)。Spring AOP 支持以下几种类型的通知:

    • 前置通知(Before Advice):在目标方法执行之前执行。
    • 后置通知(After Advice):在目标方法执行之后执行。
    • 返回通知(After Returning Advice):在目标方法正常返回后执行。
    • 异常通知(After Throwing Advice):在目标方法抛出异常时执行。
    • 环绕通知(Around Advice):在目标方法执行之前和之后都执行,可以控制方法的执行。
  • 连接点(Joinpoint):程序执行的某个特定点,如方法调用或异常抛出。Spring AOP 只支持方法连接点。

  • 切点(Pointcut):一组连接点的集合,通过表达式来定义这些连接点。切点定义了通知应该在何时何地执行。

  • 目标对象(Target Object):被通知的对象,也就是实际的业务逻辑类。

  • 代理(Proxy):AOP 框架创建的对象,包含目标对象的功能和增强的功能。Spring AOP 使用 JDK 动态代理或 CGLIB 代理来实现。

  • 织入(Weaving):将切面与目标对象连接的过程。Spring AOP 是在运行时织入的。

Spring AOP 的优点

  1. 解耦业务逻辑和横切关注点:通过 AOP,将日志、事务等横切关注点从业务逻辑中分离出来,提高代码的可读性和可维护性。

  2. 提高代码复用性:将通用的逻辑提取到切面中,避免在多个地方重复相同的代码。

  3. 降低代码耦合度:业务逻辑和切面是相互独立的,修改切面不会影响业务逻辑。

二、Spring AOP 注解

Spring AOP 提供了一组注解用于定义切面、切点和通知:

  • @Aspect:用于定义一个类为切面类。
  • @Before:用于定义前置通知。
  • @After:用于定义后置通知。
  • @AfterReturning:用于定义返回通知。
  • @AfterThrowing:用于定义异常通知。
  • @Around:用于定义环绕通知。
  • @Pointcut:用于定义切点表达式。

切点表达式的语法

切点表达式用于匹配连接点,以下是常用的切点表达式语法:

  • execution(* com.example.service.*.*(..)):匹配 com.example.service 包下的所有方法。
  • within(com.example.service..*):匹配 com.example.service 包及其子包下的所有方法。
  • @annotation(org.springframework.transaction.annotation.Transactional):匹配所有被 @Transactional 注解的方法。
  • this(com.example.service.UserService):匹配当前代理对象是 UserService 的所有方法。
  • target(com.example.service.UserService):匹配目标对象是 UserService 的所有方法。

三、Spring AOP 的使用

下面是一个使用 Spring AOP 注解的完整示例。

3.1 项目结构

src└── main├── java│   └── com│       └── example│           ├── aspect│           │   └── LoggingAspect.java│           ├── service│           │   ├── UserService.java│           │   └── UserServiceImpl.java│           └── MainApp.java└── resources└── applicationContext.xml

3.2 添加依赖

pom.xml 中添加 Spring AOP 依赖:

<dependencies><!-- Spring Core --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>5.3.9</version></dependency><!-- Spring AOP --><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.3.9</version></dependency><!-- AspectJ --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version></dependency><!-- Spring Context --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.9</version></dependency><!-- Spring Context Support --><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>5.3.9</version></dependency><!-- Log4j for logging --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.17.1</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.17.1</version></dependency>
</dependencies>

3.3 定义业务逻辑类

UserService 接口

定义一个简单的用户服务接口 UserService

package com.example.service;public interface UserService {void addUser(String name);void deleteUser(String name);String findUser(String name);
}
UserServiceImpl 实现类

实现接口的具体类 UserServiceImpl

package com.example.service;import org.springframework.stereotype.Service;@Service
public class UserServiceImpl implements UserService {@Overridepublic void addUser(String name) {System.out.println("Adding user: " + name);}@Overridepublic void deleteUser(String name) {System.out.println("Deleting user: " + name);}@Overridepublic String findUser(String name) {return "User found: " + name;}
}

3.4 定义切面类

LoggingAspect 切面

定义一个切面类 LoggingAspect,用于在方法执行之前和之后记录日志:

package com.example.aspect;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;@Aspect
@Component
public class LoggingAspect {// 定义切点,匹配com.example.service包及其子包下的所有方法@Pointcut("execution(* com.example.service..*(..))")public void serviceLayer() {}// 前置通知,在目标方法执行之前执行@Before("serviceLayer()")public void beforeAdvice(JoinPoint joinPoint) {System.out.println("Before method: " + joinPoint.getSignature().toShortString());}// 后置通知,在目标方法执行之后执行@After("serviceLayer()")public void afterAdvice(JoinPoint joinPoint) {System.out.println("After method: " + joinPoint.getSignature().toShortString());}// 返回通知,在目标方法正常返回后执行@AfterReturning(pointcut = "serviceLayer()", returning = "result")public void afterReturningAdvice(JoinPoint joinPoint, Object result) {System.out.println("After returning method: " + joinPoint.getSignature().toShortString() + " with result: " + result);}// 异常通知,在目标方法抛出异常时执行@AfterThrowing(pointcut = "serviceLayer()", throwing = "exception")public void afterThrowingAdvice(JoinPoint joinPoint, Throwable exception) {System.out.println("After throwing method: " + joinPoint.getSignature().toShortString() + " with exception: " + exception);}// 环绕通知,在目标方法执行之前和之后执行@Around("serviceLayer()")public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {System.out.println("Around before method: " + proceedingJoinPoint.getSignature().toShortString());Object result = proceedingJoinPoint.proceed();  // 调用目标方法System.out.println("Around after method: " + proceedingJoinPoint.getSignature().toShortString());return result;}
}

3.5 Spring 配置

Java 配置类

使用 Java 配置类启用 AOP 功能:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;@Configuration
@ComponentScan(basePackages = "com.example")
@EnableAspectJAutoProxy
public class AppConfig {// 可以选择在这里定义Bean
}
XML 配置

也可以通过 XML 配置启用 AOP 功能:

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 开启AOP支持 --><aop:aspectj-autoproxy/><!-- 扫描包,自动注册Bean --><context:component-scan base-package="com.example"/><!-- 注册切面Bean --><bean id="loggingAspect" class="com.example.aspect.LoggingAspect"/>
</beans>

3.6 测试 AOP

MainApp 类

创建一个测试类 MainApp 来测试 AOP 功能:

package com.example;import com.example.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class MainApp {public static void main(String[] args) {ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);UserService userService = context.getBean(UserService.class);userService.addUser("Alice");userService.deleteUser("Bob");System.out.println(userService.findUser("Charlie"));}
}
输出结果
Before method: UserService.addUser(..)
Adding user: Alice
After method: UserService.addUser(..)
Around before method: UserService.deleteUser(..)
Deleting user: Bob
Around after method: UserService.deleteUser(..)
Before method: UserService.findUser(..)
After returning method: UserService.findUser(..) with result: User found: Charlie
User found: Charlie

四、总结

通过上述示例,我们可以看到 Spring AOP 的强大之处:

  • 灵活性:通过注解和切点表达式,我们可以灵活地定义切面的应用范围。
  • 解耦性:将横切关注点从业务逻辑中分离出来,减少代码的耦合度。
  • 可扩展性:切面可以轻松扩展和修改,不需要改变业务逻辑代码。
  • 易用性:Spring AOP 的注解使得使用 AOP 变得简单直观。

在实际应用中,Spring AOP 常用于日志记录、事务管理、安全性、性能监控等领域,帮助开发者构建更加模块化、可维护的应用程序。

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

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

相关文章

ChatGPT的原理和成本

ChatGPT就是人机交互的一个底层系统&#xff0c;某种程度上可以类比于操作系统。在这个操作系统上&#xff0c;人与AI之间的交互用的是人的语言&#xff0c;不再是冷冰冰的机器语言&#xff0c;或者高级机器语言&#xff0c;当然&#xff0c;在未来的十来年内&#xff0c;机器语…

如何解决XSS攻击

跨站脚本攻击&#xff08;Cross-Site Scripting, XSS&#xff09;是一种常见的网络安全威胁&#xff0c;它允许攻击者将恶意脚本注入到看似可信的网站中。这些脚本可以窃取用户数据、破坏网站功能&#xff0c;甚至冒充用户执行操作。本文将详细介绍XSS攻击的不同类型及其防御策…

K8S 部署peometheus + grafana 监控

安装说明 如果有下载不下来的docker镜像可以私信我免费下载。 系统版本为 Centos7.9 内核版本为 6.3.5-1.el7 K8S版本为 v1.26.14 动态存储&#xff1a;部署文档 GitHub地址 下载yaml 文件 ## 因为我的K8S 版本比较新&#xff0c;我下载的是当前的最新版本&#xff0c;你的要…

go语言day18 reflect反射

Golang-100-Days/Day16-20(Go语言基础进阶)/day19_Go语言反射.md at master rubyhan1314/Golang-100-Days (github.com) 7-19 接口&#xff1a;底层实现_哔哩哔哩_bilibili 一、interface接口 接口类型内部存储了一对pair(value,Type) type interface { type *Type // 类型信…

Linux:传输层(2) -- TCP协议(2)

目录 1. 流量控制 2. 滑动窗口 3. 拥塞控制 4. 延迟应答 5. 捎带应答 6. 面向字节流 7. 粘包问题 8. TCP异常情况 1. 流量控制 接收端处理数据的速度是有限的. 如果发送端发的太快 , 导致接收端的缓冲区被打满 , 这个时候如果发送端继续发送 , 就会造成丢包, 继而引…

7月24日JavaSE学习笔记

序列化版本控制 序列化&#xff1a;将内存对象转换成序列&#xff08;流&#xff09;的过程 反序列化&#xff1a;将对象序列读入程序&#xff0c;转换成对象的方式&#xff1b;反序列化的对象是一个新的对象。 serialVersionUID 是一个类的序列化版本号 private static fin…

oracle 性能指标查询

查看表空间大小以及数据文件大小 select dt.TABLESPACE_NAME, concat(dt.MAX_SIZE,(MB)) total, concat(ddf.total_space,(MB)) used from dba_tablespaces dt,(SELECT tablespace_name,sum(bytes) / (1024 * 1024) total_spaceFROM dba_data_fileswhere TABLESPACE_NAME like…

dsp c6657 SYS/BIOS学习笔记

1 SYS/BIOS简介 SYS/BIOS是一种用于TI的DSP平台的嵌入式操作系统&#xff08;RTOS&#xff09;。 2 任务 2.1 任务调度 SYS/BIOS任务线程有0-31个优先级&#xff08;默认0-15&#xff0c;优先级0被空闲线程使用&#xff0c;任务最低优先级为1&#xff0c;最高优先级为15&am…

使用 EJS 模板引擎的示例

使用 EJS 模板引擎的示例 EJS&#xff08;Embedded JavaScript&#xff09;是一种简单的模板引擎&#xff0c;允许你在 HTML 中嵌入 JavaScript 代码。以下是一个使用 EJS 模板引擎的完整示例&#xff0c;包括设置 Express.js 项目、配置 EJS 视图引擎和创建 EJS 模板文件。 …

Java | Leetcode Java题解之第264题丑数II

题目&#xff1a; 题解&#xff1a; class Solution {public int nthUglyNumber(int n) {int[] dp new int[n 1];dp[1] 1;int p2 1, p3 1, p5 1;for (int i 2; i < n; i) {int num2 dp[p2] * 2, num3 dp[p3] * 3, num5 dp[p5] * 5;dp[i] Math.min(Math.min(num2…

2024年网络安全焦点:新兴威胁与防御技术创新

概述 2024年&#xff0c;随着网络技术的发展&#xff0c;网络安全面临的威胁也在不断演变。本文将深入探讨2024年网络安全领域的最新威胁与防御技术创新&#xff0c;并分析它们对企业及个人安全的影响。 新兴威胁分析 云集中风险 随着越来越多的企业将数据和服务迁移至云端…

鸿蒙笔记--存储

这一节了解一下鸿蒙中常用存储API&#xff0c;主要有LocalStorage &#xff0c;AppStorage&#xff0c;PersistentStorage&#xff0c;LocalStorage 是一种页面级UI状态存储机制&#xff0c;主要用于在UIAbility内和页面间共享状态数据。通过使用特定的装饰器&#xff0c;Local…

昇思25天学习打卡营第20天|CV-ResNet50图像分类

打卡 目录 打卡 图像分类 ResNet网络介绍 数据集准备与加载 可视化部分数据集 残差网络构建 Building Block 结构 代码实现 Bottleneck结构 代码实现 构建ResNet50网络 代码定义 模型训练与评估 可视化模型预测 重点&#xff1a;通过网络层数加深&#xff0c;感知…

数据输入输出的概念

文章目录 数据输入输出的概念及在C语言中的实现简单的格式输入与输出用简单的printf函数输出数据用简单的scanf函数输入数据较复杂的输入输出格式控制输出数据格式控制 数据输入输出的概念及在C语言中的实现 数据的输入与输出是相对于计算机而言的。其中&#xff1a; 从计算机…

Linux的shell的date命令

用于生成备份文件的例子 fp"/etc/samba/smb.conf" ; cp -a ${fp} ${fp}.$(date %0y%0m%0d%0H%0M%0S).bak带纳秒ns fp/etc/samba/smb.conf ; cp -a $fp $fp.$(date %0y%0m%0d%0H%0M%0Sns%0N).bakfp/etc/samba/smb.conf ; cp -a $fp $fp.$(date %0y%0m%0d%0…

昇思25天学习打卡营第33天|共赴算力时代

文章目录 一、平台简介二、深度学习模型2.1 处理数据集2.2 模型训练2.3 加载模型 三、共赴算力时代 一、平台简介 昇思大模型平台&#xff0c;就像是AI学习者和开发者的超级基地&#xff0c;这里不仅提供丰富的项目、模型和大模型体验&#xff0c;还有一大堆经典数据集任你挑。…

BM58 字符串的排列

1.题目描述 输入一个长度为 n 字符串&#xff0c;打印出该字符串中字符的所有排列&#xff0c;你可以以任意顺序返回这个字符串数组。 例如输入字符串ABC,则输出由字符A,B,C所能排列出来的所有字符串ABC,ACB,BAC,BCA,CBA和CAB。 数据范围&#xff1a;n<10n<10 要求&#…

本地搭建rtmp拉流

本地搭建rtmp拉流 可按照步骤来 关注公众号&#xff1a;城羽海 更多有趣实用教程 下载地址: 从微信公众号发送关键词 rtmp可获取下载地址 文章目录 本地搭建rtmp拉流 可按照步骤来 关注公众号&#xff1a;城羽海 更多有趣实用教程 拿到之后如图所下&#xff1f;二、配置obs文…

Spark_Oracle_I_通过jdbc读取oracle程序报错invalid character

问题背景&#xff1a; 我原先是通过我么api直接读取的oracle,现在由于要并行读取这个oracle数据库表数据&#xff0c;因此采用jdbc的方式&#xff0c;一开始我把sql变成query直接查&#xff0c;所以报上面的问题。部分样例代码如下 val date "2024/07/01" val quer…

华为网络模拟器eNSP安装部署教程

eNSP是图形化网络仿真平台&#xff0c;该平台通过对真实网络设备的仿真模拟&#xff0c;帮助广大ICT从业者和客户快速熟悉华为数通系列产品&#xff0c;了解并掌握相关产品的操作和配置、提升对企业ICT网络的规划、建设、运维能力&#xff0c;从而帮助企业构建更高效&#xff0…