Spring面向切面编程-AOP

2023-11-18

前言

在软件开发中,面向切面编程(Aspect Oriented Programming, AOP)是一个非常重要的编程范式。Spring AOP是Spring框架提供的AOP实现,在Spring中使用AOP实现企业应用开发已经非常普遍。本文将介绍Spring AOP的基本概念、使用方法和一些注意事项。

AOP的基本概念

AOP试图将与核心业务逻辑无关的内容从对象中分离出来,比如错误处理、安全控制、事务管理等等。通过这种方式,开发者可以将这些方面的关注点集中在一起,在一个地方维护这些功能,简化了代码结构和维护难度。AOP的核心思想是基于切面(Aspect)去编写代码。

在AOP中,我们有以下几个角色:

  • 切面(Aspect):切面是横切关注点的模块化。
  • 连接点(Join point):在程序执行过程中能够插入切面的所有点。
  • 切入点(Pointcut):一个切入点定义了一组连接点,或者是按类型、方法和实例。
  • 通知(Advice):在切面的某个连接点处执行的动作。
  • 切点(Join point):一个切点是一个类中可以被增强的方法集合。

Spring AOP的实现

Spring AOP的实现是基于代理模式来实现的,它为应用程序中的对象生成代理对象,从而创建了切面对象。Spring AOP中切面和切入点的定义使用了一个切面语言,即AspectJ的语言。

Spring AOP提供了以下几种通知类型:

  • Before:在连接点之前执行。
  • After Returning:在连接点正常完成后执行。
  • After Throwing:在连接点抛出异常后执行。
  • After:在连接点执行完成后执行,无论发生什么。
  • Around:在连接点周围执行,将连接点包裹起来。

在Spring AOP中,我们可以使用注解或XML来定义切面、切入点和通知。下面是一个使用注解的例子:

@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.example.service..*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Entering " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
    }

    @AfterReturning("execution(* com.example.service..*(..))")
    public void logAfterReturning(JoinPoint joinPoint) {
        System.out.println("Exiting " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
    }

    @AfterThrowing("execution(* com.example.service..*(..))")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
        System.out.println("Exception thrown from " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName() + " with message " + e.getMessage());
    }

    @After("execution(* com.example.service..*(..))")
    public void logAfter(JoinPoint joinPoint) {
        System.out.println("Method execution completed for " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
    }

    @Around("execution(* com.example.service..*(..))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Entering " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        Object result = joinPoint.proceed();
        System.out.println("Exiting " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        return result;
    }
}

这个例子使用了注解定义了一个切面,其中切入点定义了在com.example.service包中的所有方法上执行通知。通知分别是@Before、@AfterReturning、@AfterThrowing、@After和@Around,分别实现了对方法运行前、运行后、抛出异常时、任何情况下和方法运行时的增强处理。

使用示例

下面,我们通过一个简单的示例来演示Spring AOP的使用:

在这个示例中,我们使用Spring来实现一个简单的图书管理系统。包含一个Book实体类、一个BookRepository数据访问类和一个BookService业务逻辑类。我们希望在BookRepository类中插入日志记录的功能。这里我们使用的是注解的方式来定义 Spring AOP。

首先需要在pom.xml文件中增加以下依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>${aspectj.version}</version>
</dependency>

其中,spring.version和aspectj.version是需要指定的Spring版本和AspectJ版本。

然后,我们定义一个Logger切面,来实现对BookRepository类中的所有方法进行日志记录:

@Aspect
@Component
public class Logger {

    private static final Logger LOGGER = LoggerFactory.getLogger(Logger.class);

    @Pointcut("execution(* com.example.bookstore.repository.BookRepository.*(..))")
    public void repositoryMethods() {}

    @Before("repositoryMethods()")
    public void beforeRepository(JoinPoint joinPoint) {
        LOGGER.info("Method execution started: {}", joinPoint.getSignature().getName());
    }

    @AfterReturning("repositoryMethods()")
    public void afterRepository(JoinPoint joinPoint) {
        LOGGER.info("Method execution completed: {}", joinPoint.getSignature().getName());
    }

    @AfterThrowing(value = "repositoryMethods()", throwing = "ex")
    public void afterThrowingRepository(JoinPoint joinPoint, Throwable ex) {
        LOGGER.error("Exception occurred in method: {} with message: {}", joinPoint.getSignature().getName(), ex.getMessage());
    }
}

在这个切面中,我们定义了一个切入点repositoryMethods(),它表示所有满足执行com.example.bookstore.repository.BookRepository的方法将被增强。具体地,我们使用@Before、@AfterReturning和@AfterThrowing来实现对方法执行前、执行后和抛出异常时的增强处理。这里我们仅记录日志信息。

最后,我们在我们的业务逻辑类中调用BookRepository的方法来测试这个切面的效果:

@Service
public class BookService {

    @Autowired
    private BookRepository bookRepository;

    public List<Book> findAll() {
        return bookRepository.findAll();
    }

    public Book save(Book book) {
        return bookRepository.save(book);
    }

    public void deleteAll() {
        bookRepository.deleteAll();
    }
}

在使用Spring AOP时,我们不需要手动创建切面对象,Spring会自动为我们生成代理对象并注入到需要增强的类中。因此,我们只需要在@Configuration类中指定组件扫描的路径,然后在需要增强的Bean类上添加@Aspect注解即可。

@Configuration
@ComponentScan(basePackages = {"com.example.bookstore"})
@EnableAspectJAutoProxy
public class AppConfig {

}

在这个类中,我们使用@ComponentScan来指定需要扫描的组件路径,使用@EnableAspectJAutoProxy来启用自动代理。这样,就可以直接在BookRepository类中调用findAll()方法并查看日志输出结果。

注意事项

  1. 字段或静态方法不能被切入。
  2. 当定义一个切面时,应该把它放在单独的一个文件中,而不是混杂在应用程序逻辑中。
  3. AOP可以降低代码的复杂性,但同时也会带来一些性能消耗。因此,在使用时应该避免滥用。

结语

本文介绍了Spring AOP的基本概念、实现方式和使用方法。通过一个简单的示例,我们演示了如何在Spring应用程序中使用AOP,并实现了一个简单的日志记录功能。当然,Spring AOP的应用远不止于此,它可以帮助我们实现更多的关注点分离,提高代码的可读性和可维护性,从而在企业应用开发中发挥重要作用。希望这篇文章能对你了解和使用Spring AOP有所帮助。

参考文献

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring面向切面编程-AOP 的相关文章

随机推荐

  • 关于GRE over IPsec及IPsec over GRE

    GRE over IPsec IPsec over GRE IPSec Over GRE是先ipsec后gre 这种我没用过 GRE Over IPSec 是先gre后ipsec 也就是说ipsec是最后的承载方式 一般常用的就是这种 解决
  • 最详细的Python安装教程

    最详细的Python安装教程 一 进入Python官网首页 下载最新的Python版本 https www python org downloads 选择最新的Python3 10 5 下载64位的版本 二 下载完成后 进行安装 1 双击P
  • 数字图像处理(入门篇)六 图像数据预处理之坐标变化

    目录 1 平移 2 镜像 3 旋转 4 缩放 图像的坐标变换又称为图像的几何计算 常见的基本变换包括 平移 旋转 镜像和缩放等等 1 平移 1 代码 使用OpenCV仿射变换函数 cv2 warpAffine 实现平移操作 import n
  • 前端vue可以左右滚动的切换的tabs tabs选项卡 滑动动画效果 自动宽度

    随着技术的发展 开发的复杂度也越来越高 传统开发方式将一个系统做成了整块应用 经常出现的情况就是一个小小的改动或者一个小功能的增加可能会引起整体逻辑的修改 造成牵一发而动全身 通过组件化开发 可以有效实现单独开发 单独维护 而且他们之间可以
  • Feign原理 (图解)

    1 1 简介 Feign远程调用的 Feign远程调用 核心就是通过一系列的封装和处理 将以JAVA注解的方式定义的远程调用API接口 最终转换成HTTP的请求形式 然后将HTTP的请求的响应结果 解码成JAVA Bean 放回给调用者 F
  • namespace命令空间

    目录 1 解决什么问题 2 基本介绍 2 1 定义 2 2 应用场景 3 使用案例 4 资源配额 5 标签 5 1 定义 5 2 pod资源打标签 5 3 查看标签 1 解决什么问题 命令空间类似于C 中的命名空间 当用户数量较多的集群 才
  • 使用docker搭建jupyter notebook/jupyterlab

    说明 由于官方镜像实在是不怎么好用 所以我自己做了一个优化过的jupyter notebook的镜像 notebook hub 使用我这个镜像搭建容器非常简单 下面就基于这个notebook hub来进行搭建 关于notebook hub
  • hive 报system:java.io.tmpdir错误解决

    Exception in thread main java lang IllegalArgumentException java net URISyntaxException Relative path in absolute URI sy
  • 2. IDEA + maven + protobuf配置(on mac)

    1 絮絮叨叨 都说懒惰是人类进步的源泉 有时候想想还真就那么回事 学习了如何使用protoc命令编译 重度依赖IDEA且已经习惯了maven的我 就在想是否能在IDEA中一键编译 proto文件 2 vscode配置protobuf编辑环境
  • pyecharts实现电影数据分析可视化

    根据电影数据 使用pyecharts进行可视化分析 数据介绍 import pandas as pd data pd read csv 电影 csv data head 前5行数据如下 需要安装的python库 pip install pa
  • 2.晶晨A311D-编译Ubuntu/Debian固件

    上面是我的微信和QQ群 欢迎新朋友的加入 参考 https docs khadas com zh cn vim3 FenixScript html 编译环境 我重新安装了ubuntu20 安装软件包 配置环境 sudo apt get in
  • 【数据结构】排序(直接插入、折半插入、希尔、冒泡、快速、直接选择、堆、归并、基数排序)

    一 什么是排序 排序 将一组杂乱无章的数据按一定规律顺次排列起来 即 将无序序列的数据节点包含多个数据域 那么排序往往是针对其中某个域而言 二 排序方法的分类 1 按数据存储介质可分为 内部排序 数据量不大 数据在内存 无需内外存交换数据
  • SQL抽取数据脚本

    sp OutputData IF EXISTS SELECT 1 FROM sys objects o WHERE object id object id N sp OutputData AND OBJECTPROPERTY object
  • vue数据劫持 ajax,Vue视图更新原理 - 数据劫持,最小量更新和DIFF算法

    什么是数据劫持 加入有一个js文件内容如下 var obj x 100 y 200 Object defineProperties obj x set console log You gonna update x the vision wi
  • python smtp发送邮件 附件 中文名乱码 问题

    重点 mime add header Content Disposition attachment filename make header file name UTF 8 encode UTF 8 完整代码可以发送多个附件 import
  • 20220801:强改jar包的一下经历

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 改jar包内容 二 使用步骤 1 首先是修改的class文件 2 如何替换jar包中的class文件 总结 前言 目标是一个dubbo的服务 我们的工程引
  • VS2008错误Error spawning 'cmd.exe'的解决方法

    解决方法 In the Options go into Projects and Solutions gt VC Directories page and place this rows SystemRoot System32 System
  • Redisson配置类

    学习记录 Redisson配置类 Bean public RedissonClient redissonClient throws IOException ResourceLoader loader new DefaultResourceL
  • Dell台式机重装win 10系统之后开机报错

    电脑品牌 戴尔 报错信息 Hard disk dirve failure 硬盘驱动器故障 trick the F1 key to continue F2 to run the setup utility 报错原因 电脑一开机出现黑屏并出现H
  • Spring面向切面编程-AOP

    前言 在软件开发中 面向切面编程 Aspect Oriented Programming AOP 是一个非常重要的编程范式 Spring AOP是Spring框架提供的AOP实现 在Spring中使用AOP实现企业应用开发已经非常普遍 本文