首页 > 编程语言 >【spring原理】AOP面向切面编程

【spring原理】AOP面向切面编程

时间:2025-01-22 14:56:26浏览次数:3  
标签:优先级 spring AOP 通知 Spring public 切面

Spring 中的 AOP(Aspect-Oriented Programming,面向切面编程)是一种通过分离关注点来增强代码模块化的编程范式。在 Spring 中,AOP 允许开发者定义通用的行为(如日志记录、安全性验证、事务管理等),然后以非侵入的方式将这些行为应用到应用程序的特定部分(例如方法或类)上,从而避免代码重复并提高代码的可维护性和可读性。

以下是 Spring AOP 的核心概念和工作原理:

核心概念

  1. 切面(Aspect)

    • 切面是功能模块化的横切关注点,例如日志记录或事务管理。
    • 由一个类实现,里面包含横切逻辑代码。
    • 通常通过 @Aspect 注解标识。
  2. 连接点(Join Point)

    • 连接点是程序执行的一个特定点,比如方法调用、对象实例化等。
    • 在 Spring AOP 中,连接点主要指方法的执行。
  3. 通知(Advice)

    • 通知是切面中定义的具体动作,即在连接点上执行的代码。
    • Spring 支持以下几种通知类型:
      • 前置通知(Before Advice):在目标方法执行之前运行。
      • 后置通知(After Advice):在目标方法执行之后运行。
      • 返回通知(After Returning Advice):在目标方法正常返回后运行。
      • 异常通知(After Throwing Advice):在目标方法抛出异常后运行。
      • 环绕通知(Around Advice):包裹目标方法的执行,在方法执行前后均可运行。
  4. 切入点(Pointcut)

    • 切入点是定义某些连接点的表达式,用于指定通知应用的位置。
    • 通常使用 AspectJ 表达式(如 execution(* com.example.service.*.*(..)))定义。
  5. 目标对象(Target Object)

    • 被 AOP 增强的对象。Spring AOP 使用动态代理来创建目标对象的代理对象。
  6. 织入(Weaving)

    • 织入是将切面应用到目标对象并创建代理对象的过程。
    • Spring AOP 在运行时通过动态代理实现织入。

Spring AOP 的实现方式

Spring AOP 的底层实现主要基于以下两种技术:

  1. JDK 动态代理

    • 如果目标类实现了接口,Spring AOP 会使用 JDK 动态代理来创建代理对象。
  2. CGLIB 动态代理

    • 如果目标类没有实现接口,Spring AOP 会使用 CGLIB(Code Generation Library)来生成子类代理。

AOP 的使用步骤

  1. 引入依赖
    在 Spring 项目中启用 AOP 通常需要引入 spring-aop 模块,或在 Spring Boot 项目中通过添加 spring-boot-starter-aop 依赖。

  2. 配置 AOP

    • 开启 AOP 支持:通过 @EnableAspectJAutoProxy 注解启用 AOP。
    • 定义切面类:使用 @Aspect 注解声明一个类为切面。
  3. 定义通知

    • 在切面类中定义通知方法,并通过注解(如 @Before@After 等)绑定到具体的切入点。

在pom.xml⽂件中添加配置

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

示例代码

以下是一个简单的 Spring AOP 示例,记录方法执行的日志:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    // 定义一个切入点,匹配指定包中所有方法
    @Before("execution(* com.example.service.*.*(..))")
    public void logBeforeMethod() {
        System.out.println("方法执行前记录日志...");
    }
}

配置类:

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}

目标类:

import org.springframework.stereotype.Service;

@Service
public class UserService {
    public void performTask() {
        System.out.println("执行业务逻辑...");
    }
}

输出结果:

方法执行前记录日志...
执行业务逻辑...

 通知(Advice)

定义

通知是切面中的具体动作,指在某个连接点上执行的代码逻辑。
Spring 提供了多种类型的通知,分别对应在连接点的不同时间点执行的操作。

通知类型

前置通知(@Before)
在目标方法执行前运行。适用于验证输入参数、初始化资源等操作。

@Before("execution(* com.example.service.*.*(..))")
public void beforeAdvice() {
    System.out.println("方法执行前的通知");
}

后置通知(@After)
在目标方法执行后运行,无论方法是否抛出异常。

@After("execution(* com.example.service.*.*(..))")
public void afterAdvice() {
    System.out.println("方法执行后的通知");
}

返回通知(@AfterReturning)
在目标方法成功返回后运行,适用于获取返回值并进行后续处理。

@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
public void afterReturningAdvice(Object result) {
    System.out.println("方法返回值: " + result);
}

异常通知(@AfterThrowing)
在目标方法抛出异常时运行,用于记录错误日志或进行回滚操作。

@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "exception")
public void afterThrowingAdvice(Exception exception) {
    System.out.println("方法抛出异常: " + exception.getMessage());
}

环绕通知(@Around)
包裹目标方法的执行,能在方法执行前后都插入逻辑代码。

@Around("execution(* com.example.service.*.*(..))")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("方法执行前的环绕通知");
    Object result = joinPoint.proceed(); // 调用目标方法
    System.out.println("方法执行后的环绕通知");
    return result;
}
通知的核心点
  • 通知必须绑定到一个切入点。
  • 通知中可以获取目标方法的上下文信息,比如方法名、参数、返回值等。

切入点(Pointcut)

定义

切入点是一个表达式,定义在哪些连接点上应用通知。
它的作用是筛选出一组匹配的连接点,从而指定通知的作用范围。

表达式

切入点通常使用 AspectJ 表达式定义,主要包含以下部分:

方法签名匹配
使用 execution 表达式,匹配目标方法的访问修饰符、返回类型、类路径、方法名、参数等。
示例:

execution(<修饰符>? <返回类型> <类路径>.<方法名>(<参数列表>))

例如:

// 匹配 com.example.service 包下所有类的所有方法
execution(* com.example.service.*.*(..))

// 匹配返回类型为 String 的所有方法
execution(String *.*(..))

类注解匹配
使用 @within@target 表达式,匹配带有特定注解的类。
示例:

@within(org.springframework.stereotype.Service)

方法注解匹配
使用 @annotation 表达式,匹配带有特定注解的方法。
示例:

@annotation(org.springframework.transaction.annotation.Transactional)

参数匹配
使用 args 表达式,匹配方法的参数类型或具体值。
示例:

args(java.lang.String)

切入点定义示例

@Aspect
@Component
public class LoggingAspect {
    // 定义切入点表达式
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethods() {}

    // 使用切入点
    @Before("serviceMethods()")
    public void logBefore() {
        System.out.println("在服务方法之前执行日志记录");
    }
}

总结

  • 连接点是程序执行中的某个具体点,Spring AOP 只支持方法级别的连接点。
  • 通知是在连接点上执行的具体代码逻辑,可以选择在方法前、后或异常时执行。
  • 切入点通过表达式定义了哪些连接点会被增强,是通知的作用范围的核心筛选条件。

切面优先级 

在 Spring AOP 中,多个切面可以作用于同一个目标方法。如果这些切面包含不同的通知(如 @Before@After 等),Spring 提供了优先级机制来控制切面执行的顺序。这个优先级可以通过 @Order 注解来定义。


@Order 注解

@Order 是 Spring 提供的注解,用于指定切面的优先级。

  • 数值越小,优先级越高,切面会更早执行。
  • 数值越大,优先级越低,切面会更晚执行。

适用范围

@Order 注解应用在切面类(标注了 @Aspect 的类)上。


优先级的执行规则

  1. 前置通知(@Before

    • 按照优先级从 低到高@Order 值从小到大)依次执行。
  2. 后置通知(@After@AfterReturning

    • 按照优先级从 高到低@Order 值从大到小)依次执行。
  3. 环绕通知(@Around

    • 环绕通知包裹目标方法,其执行顺序遵循前置通知的优先级规则。

示例代码

定义两个切面
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Order(1) // 优先级最高
public class FirstAspect {
    @Before("execution(* com.example.service.*.*(..))")
    public void beforeAdvice() {
        System.out.println("FirstAspect: 前置通知");
    }
}

@Aspect
@Component
@Order(2) // 优先级较低
public class SecondAspect {
    @Before("execution(* com.example.service.*.*(..))")
    public void beforeAdvice() {
        System.out.println("SecondAspect: 前置通知");
    }
}

目标方法

import org.springframework.stereotype.Service;

@Service
public class UserService {
    public void performTask() {
        System.out.println("执行业务逻辑...");
    }
}
执行结果

当调用 UserService.performTask() 时,输出顺序为:

FirstAspect: 前置通知
SecondAspect: 前置通知
执行业务逻辑...

如果是后置通知,顺序会反过来:

SecondAspect: 后置通知
FirstAspect: 后置通知

注意事项

  1. 默认优先级

    • 如果未标注 @Order,默认优先级最低(即 Integer.MAX_VALUE)。
    • 如果多个切面都未标注 @Order,它们的执行顺序是不确定的。
  2. @Order 与切入点无关

    • @Order 仅影响同一个连接点上的切面的优先级,与切入点匹配逻辑无直接关系。
  3. 环绕通知的特殊性

    • 环绕通知会包裹目标方法及其他通知,因此优先级需要特别注意,否则可能导致执行顺序不符合预期。

总结

  • @Order 控制切面之间的优先级,数值越小优先级越高。
  • 不同类型的通知(如前置和后置)执行顺序遵循不同规则:
    • 前置通知按优先级升序执行。
    • 后置通知按优先级降序执行。
  • 合理使用 @Order 可以确保切面按照预期顺序执行。

标签:优先级,spring,AOP,通知,Spring,public,切面
From: https://blog.csdn.net/yican2580/article/details/145302911

相关文章

  • SpringBoot整合minio(实现minio-starter)
    SpringBoot整合minio(实现minio-starter)1)依赖导入<dependencies><!--工具类相关--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></depe......
  • OpenFeign在SpringCloud项目中的搭建
    1、添加依赖首先,在项目中的pom.xml中添加feign和springCloud相关依赖:<dependencies><!--SpringCloudOpenFeign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-ope......
  • SpringBoot(Spring)中为什么不推荐使用@Autowired?
    在Spring框架中,依赖注入是一种常见的设计模式,用于实现对象之间的解耦。Spring提供了多种依赖注入的方式,其中@Autowired注解是最常用的一种。然而,在SpringBoot中,官方并不推荐使用@Autowired注解进行依赖注入,而是推荐使用构造函数注入。本文将详细分析为什么不推荐使用@Autowired......
  • 计算机毕业设计Springboot基于的露营活动装备租凭系统 基于Spring Boot的户外露营装备
    计算机毕业设计Springboot基于的露营活动装备租凭系统6fnmr8bp(配套有源码程序mysql数据库论文)本套源码可以先看具体功能演示视频领取,文末有联xi可分享随着户外露营活动的兴起,越来越多的人开始追求亲近自然的生活方式。然而,高昂的露营装备购置成本、使用后的存放问题以及......
  • 计算机毕业设计Springboot基于大数据的红色旅游景点可视化安全分析系统 基于Spring Bo
    计算机毕业设计Springboot基于大数据的红色旅游景点可视化安全分析系统995q07gh(配套有源码程序mysql数据库论文)本套源码可以先看具体功能演示视频领取,文末有联xi可分享随着信息技术的飞速发展和大数据时代的到来,红色旅游作为中国文化旅游的重要组成部分,承载着丰富的历史......
  • 计算机毕业设计Springboot基于Java的医院床位管理系统 基于Spring Boot的Java医院床位
    计算机毕业设计Springboot基于Java的医院床位管理系统18b553a9(配套有源码程序mysql数据库论文)本套源码可以先看具体功能演示视频领取,文末有联xi可分享随着医疗行业的不断发展,医院床位管理系统的开发成为了提升医疗服务效率的关键环节。传统的人工管理方式不仅效率低下,还......
  • 基于Springboot的大学生二手电子产品交易平台的设计与实现
    ......
  • Spring Boot框架大学生竞赛管理系统(源码+lw+部署文档+讲解等)
    大学生竞赛管理系统摘要随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了大学生竞赛管理系统的开发全过程。通过分析大学生竞赛管理系统管理的不足,创建了一个计算机管理大学生竞赛管理系统的方案。文章介绍了大学生竞赛管理系......
  • 2025毕设springboot 基于的网上招聘系统的设计与实现论文+源码
    系统程序文件列表开题报告内容研究背景随着互联网技术的迅猛发展和普及,网络已经成为人们获取信息、交流互动的重要平台。在人力资源领域,传统的招聘方式逐渐暴露出效率低下、信息不对称等问题。而网上招聘系统作为一种新兴的招聘模式,凭借其便捷性、高效性和广泛性,正逐步取代......
  • 2025毕设springboot 基于的网上订餐系统的设计与实现论文+源码
    系统程序文件列表开题报告内容研究背景随着互联网技术的飞速发展,人们的生活方式正发生着深刻的变化,特别是在餐饮消费领域,网上订餐已成为一种普遍现象。传统的餐饮消费模式往往需要消费者亲自前往餐厅点餐,不仅耗时费力,还受到地理位置和营业时间的限制。而基于互联网的网上订......