解锁Spring AOP的神秘面纱

简介: 解锁Spring AOP的神秘面纱

Spring AOP作为Spring框架的核心模块,为我们提供了一种优雅的方式来处理横切关注点。本篇博客将从组成、实现和实现原理三个方面深入剖析Spring AOP,并结合具体的例子进行说明。

Spring AOP的组成

组成部分与常用注解

  • 切面(Aspect):切面是横切关注点的具体实现,它定义了在何处、何时执行横切逻辑。我们可以通过切点和通知来定义一个切面。
  • 连接点(Join Point):连接点是方法在程序执行过程中能够被拦截的特定点(这个点可以是⽅法调⽤时,抛出异常时,甚⾄修改字段
    时)。在Spring AOP中,连接点通常表示方法的执行。
  • 切点(Pointcut):切点指定了在哪些方法上应该应用切面逻辑。可以使用表达式或注解等方式来定义切点,精确定位到目标方法。
  • 通知(Advice):通知定义了在切点上执行的横切逻辑,可以在方法执行前、后或抛出异常时被触发。

在Spring 切⾯类中,可以在⽅法上使⽤以下注解,会设置⽅法为通知⽅法,在满⾜条件后会通知本⽅法进⾏调⽤:

  • 前置通知使⽤ @Before:通知⽅法会在⽬标⽅法调⽤之前执⾏。
  • 后置通知使⽤ @After:通知⽅法会在⽬标⽅法返回或者抛出异常后调⽤。
  • 返回之后通知使⽤ @AfterReturning:通知⽅法会在⽬标⽅法返回后调⽤。
  • 抛异常后通知使⽤ @AfterThrowing:通知⽅法会在⽬标⽅法抛出异常后调⽤。
  • 环绕通知使⽤ @Around:通知包裹了被通知的⽅法,在被通知的⽅法通知之前和调⽤之后执⾏⾃定义的⾏为。

举例理解

下面通过一个生活中的例子,我们可以更直观地理解Spring AOP的组成部分及其运作方式。

在这个例子中,我们可以将Spring AOP的组成部分与咖啡馆的场景联系起来:

  1. 切面(Aspect):切面就好像是咖啡馆提供的不同附加服务,比如打包、送货等。每种附加服务都是一个切面,它定义了一个特定的横切逻辑。
  2. 切点(Pointcut):切点就像是决定在哪些情况下应该提供附加服务。例如,每次有人点了咖啡,那就是一个切点,表示一个可以应用附加服务的地方。
  3. 通知(Advice):通知就是具体的附加服务的实现。在咖啡馆中,这可以是将咖啡打包的过程,或者是送货员将咖啡送到指定地点的过程。
  4. 连接点(Join Point):连接点就像是咖啡的准备过程,比如磨咖啡豆、冲泡咖啡等。这些过程都是咖啡制作的特定点,也就是连接点。

当你在咖啡馆点一杯咖啡时,Spring AOP的运作方式如下:

  1. 切面定义了附加服务,比如打包和送货。
  2. 切点决定了在哪些情况下应该提供附加服务,比如在每次点咖啡时。
  3. 通知实现了附加服务的具体逻辑,比如将咖啡打包或送到指定地点。
  4. 连接点是咖啡的制作过程,每个步骤都是一个连接点,而在某些连接点上(即切点匹配的地方),会触发附加服务的通知。

这样,当你点了一杯咖啡时,Spring AOP就会在制作咖啡的过程中,根据切点的匹配情况触发相应的附加服务通知,比如将咖啡打包好或送到指定地点。

Spring AOP的实现

Spring AOP的实现主要依赖于JDK动态代理和CGLIB动态代理两种方式。默认情况下,Spring AOP使用JDK动态代理,但也可以通过配置切换到CGLIB动态代理。

添加 Spring AOP 框架⽀持

在 pom.xml 中添加如下配置:

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-bo
ot-starter-aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

定义切⾯和切点

切点指的是具体要处理的某⼀类问题,Spring AOP 切点的定义如下,在切点中我们要定义拦截的规则,具体实现如下:

@Aspect    //表明这个类为一个切面
@Component
public class UserAspect {
  //定义切点,使⽤ AspectJ 表达式语法
    @Pointcut("execution(* com.example.springaop.Controller.UserController.* (..))")
    public void pointcut(){ }  
}

@Pointcut 注解标注的方法是一个空方法,它不需要具体的方法体。它的作用是为下面的通知方法提供一个标识,用来指定具体指向哪个切点。

定义通知

通知定义的是被拦截的⽅法具体要执⾏的业务,比如统一异常处理等待。

依旧是在刚才的切面类UserAspect中书写代码:

// 前置通知
  @Before("pointcut()")
  public void doBefore(){
    System.out.println("执⾏ Before ⽅法");
  }

我们在UserController中写一个测试方法:

@RestController
@ResponseBody
@RequestMapping("/con")
public class UserController {
    @RequestMapping("/tsst")
    public Object test() {
        System.out.println("测试方法执行");
        return "测试";
    }
}

我们在浏览器进行访问测试方法:

通过控制台信息发现前置通知方法的实现在测试方法之前,至于其他通知方法我们也补全于切面类当中

// 后置通知
    @After("pointcut()")
    public void doAfter() {
        System.out.println("执⾏ After ⽅法");
    }
    @AfterReturning("pointcut()")
    public void doAfterReturning() {
        System.out.println("执⾏ return 之前通知⽅法");
    }
    @AfterThrowing
    public void doAfterThrowing() {
        System.out.println("执行异常抛出之前的通知方法");
    }
    @Around("pointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint) {
        Object obj = new Object();
        System.out.println("开始执行环绕通知方法");
        try {
            //执行目标方法
            joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("环绕通知方法结束");
        return obj;
    }

可以将环绕通知方法理解为包裹目标方法的一层“包装”,它可以在目标方法执行前后进行一些额外的操作和控制。通过环绕通知,我们可以在不改变目标方法原有逻辑的同时,添加一些横切关注点的功能,例如日志记录、性能监控、事务管理等。

切点表达式说明

AspectJ ⽀持三种通配符

  • *:匹配任意字符,只匹配⼀个元素(包,类,或⽅法,⽅法参数)
  • .. :匹配任意字符,可以匹配多个元素 ,在表示类时,必须和 * 联合使⽤
  • +:表示按照类型匹配指定类的所有类,必须跟在类名后⾯,如com.cad.Car+ ,表示继承该类的所有⼦类包括本身

切点表达式由切点函数组成,其中 execution() 是最常⽤的切点函数,⽤来匹配⽅法,语法为:execution(<修饰符><返回类型><包.类.⽅法(参数)><异常>)

其中修饰符与异常可以省略

示例:

execution(* com.cad.demo.User+.*(..))

匹配该类的⼦类包括该类的所有⽅法。

execution(* addUser(String, int))

匹配 addUser ⽅法,且第⼀个参数类型是 String,第⼆个参数类型是 int。

Spring AOP 实现原理

Spring AOP的实现原理主要依赖于动态代理机制。当使用Spring AOP时,它会在运行时为目标对象生成一个代理对象,并将切面逻辑织入到目标对象的方法调用中。

Spring AOP所使用的代理方式可以分为两种:JDK动态代理和CGLIB动态代理。

JDK动态代理

当目标对象实现了至少一个接口时,Spring AOP会使用JDK动态代理来生成代理对象。JDK动态代理是通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口实现的。

  • 在Spring AOP中,首先会根据目标对象和切面对象,创建一个实现了InvocationHandler接口的代理对象。
  • 当目标对象的方法被调用时,代理对象的invoke()方法会被调用。在invoke()方法内部,可以通过反射机制来执行目标方法,同时在目标方法的执行前后,插入切面逻辑。

CGLIB动态代理

当目标对象没有实现任何接口时,Spring AOP会使用CGLIB动态代理来生成代理对象。CGLIB动态代理是通过继承目标类并重写目标方法的方式实现的。

  • 在Spring AOP中,首先会针对目标对象生成一个继承了目标类的代理类,并在代理类中重写目标方法。
  • 当目标对象的方法被调用时,代理对象的相应重写方法会被调用。在重写方法中,可以在目标方法的执行前后,插入切面逻辑。

总结起来,Spring AOP的实现原理是通过动态代理机制,在运行时为目标对象生成代理对象,并将切面逻辑织入到目标对象的方法中。具体使用JDK动态代理还是CGLIB动态代理取决于目标对象是否实现了接口。


相关文章
|
1月前
|
XML 安全 Java
使用 Spring 的 @Aspect 和 @Pointcut 注解简化面向方面的编程 (AOP)
面向方面编程(AOP)通过分离横切关注点,如日志、安全和事务,提升代码模块化与可维护性。Spring 提供了对 AOP 的强大支持,核心注解 `@Aspect` 和 `@Pointcut` 使得定义切面与切入点变得简洁直观。`@Aspect` 标记切面类,集中处理通用逻辑;`@Pointcut` 则通过表达式定义通知的应用位置,提高代码可读性与复用性。二者结合,使开发者能清晰划分业务逻辑与辅助功能,简化维护并提升系统灵活性。Spring AOP 借助代理机制实现运行时织入,与 Spring 容器无缝集成,支持依赖注入与声明式配置,是构建清晰、高内聚应用的理想选择。
309 0
|
5月前
|
监控 安全 Java
Spring AOP实现原理
本内容主要介绍了Spring AOP的核心概念、实现机制及代理生成流程。涵盖切面(Aspect)、连接点(Join Point)、通知(Advice)、切点(Pointcut)等关键概念,解析了JDK动态代理与CGLIB代理的原理及对比,并深入探讨了通知执行链路和责任链模式的应用。同时,详细分析了AspectJ注解驱动的AOP解析过程,包括切面识别、切点表达式匹配及通知适配为Advice的机制,帮助理解Spring AOP的工作原理与实现细节。
|
2月前
|
人工智能 监控 安全
Spring AOP切面编程颠覆传统!3大核心注解+5种通知类型,让业务代码纯净如初
本文介绍了AOP(面向切面编程)的基本概念、优势及其在Spring Boot中的使用。AOP作为OOP的补充,通过将横切关注点(如日志、安全、事务等)与业务逻辑分离,实现代码解耦,提升模块化程度、可维护性和灵活性。文章详细讲解了Spring AOP的核心概念,包括切面、切点、通知等,并提供了在Spring Boot中实现AOP的具体步骤和代码示例。此外,还列举了AOP在日志记录、性能监控、事务管理和安全控制等场景中的实际应用。通过本文,开发者可以快速掌握AOP编程思想及其实践技巧。
|
2月前
|
人工智能 监控 安全
如何快速上手【Spring AOP】?核心应用实战(上篇)
哈喽大家好吖~欢迎来到Spring AOP系列教程的上篇 - 应用篇。在本篇,我们将专注于Spring AOP的实际应用,通过具体的代码示例和场景分析,帮助大家掌握AOP的使用方法和技巧。而在后续的下篇中,我们将深入探讨Spring AOP的实现原理和底层机制。 AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的核心特性之一,它能够帮助我们解决横切关注点(如日志记录、性能统计、安全控制、事务管理等)的问题,提高代码的模块化程度和复用性。
|
2月前
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。
|
9月前
|
XML Java 开发者
Spring Boot中的AOP实现
Spring AOP(面向切面编程)允许开发者在不修改原有业务逻辑的情况下增强功能,基于代理模式拦截和增强方法调用。Spring Boot通过集成Spring AOP和AspectJ简化了AOP的使用,只需添加依赖并定义切面类。关键概念包括切面、通知和切点。切面类使用`@Aspect`和`@Component`注解标注,通知定义切面行为,切点定义应用位置。Spring Boot自动检测并创建代理对象,支持JDK动态代理和CGLIB代理。通过源码分析可深入了解其实现细节,优化应用功能。
452 6
|
8月前
|
XML Java 测试技术
Spring AOP—通知类型 和 切入点表达式 万字详解(通俗易懂)
Spring 第五节 AOP——切入点表达式 万字详解!
411 25
|
8月前
|
XML 安全 Java
Spring AOP—深入动态代理 万字详解(通俗易懂)
Spring 第四节 AOP——动态代理 万字详解!
322 24
|
7月前
|
Java API 微服务
微服务——SpringBoot使用归纳——Spring Boot中的切面AOP处理——Spring Boot 中的 AOP 处理
本文详细讲解了Spring Boot中的AOP(面向切面编程)处理方法。首先介绍如何引入AOP依赖,通过添加`spring-boot-starter-aop`实现。接着阐述了如何定义和实现AOP切面,包括常用注解如`@Aspect`、`@Pointcut`、`@Before`、`@After`、`@AfterReturning`和`@AfterThrowing`的使用场景与示例代码。通过这些注解,可以分别在方法执行前、后、返回时或抛出异常时插入自定义逻辑,从而实现功能增强或日志记录等操作。最后总结了AOP在实际项目中的重要作用,并提供了课程源码下载链接供进一步学习。
797 0
|
7月前
|
Java 开发者 微服务
微服务——SpringBoot使用归纳——Spring Boot中的切面AOP处理——什么是AOP
本文介绍了Spring Boot中的切面AOP处理。AOP(Aspect Oriented Programming)即面向切面编程,其核心思想是分离关注点。通过AOP,程序可以将与业务逻辑无关的代码(如日志记录、事务管理等)从主要逻辑中抽离,交由专门的“仆人”处理,从而让开发者专注于核心任务。这种机制实现了模块间的灵活组合,使程序结构更加可配置、可扩展。文中以生活化比喻生动阐释了AOP的工作原理及其优势。
407 0