news 2026/2/4 15:54:07

如何使用Spring框架实现AOP?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何使用Spring框架实现AOP?

一、先明确核心概念(快速回顾)

在动手前,先理清 Spring AOP 的核心术语,避免后续代码理解混乱:

  • 切面(Aspect):封装 “横切逻辑” 的类(比如日志、权限校验、事务),是 AOP 的核心载体。
  • 切点(Pointcut):定义 “哪些方法需要被增强”(比如指定包下的所有 Service 方法)。
  • 通知(Advice):定义 “增强的时机和逻辑”,包括:
    • @Before:目标方法执行前执行
    • @After:目标方法执行后执行(无论是否异常)
    • @AfterReturning:目标方法正常返回后执行
    • @AfterThrowing:目标方法抛出异常后执行
    • @Around:环绕通知(最灵活,可控制目标方法的执行时机、参数、返回值)
  • 连接点(JoinPoint):程序执行过程中可被增强的 “点”(比如方法调用、异常抛出),Spring 只支持方法级连接点。

二、Spring AOP 实现步骤(基于注解,最常用)

Spring AOP 有两种实现方式:注解式(推荐)XML 配置式,这里重点讲注解式,步骤如下:

步骤 1:引入依赖(Maven/Gradle)

核心依赖是spring-context(已包含 AOP 基础),如果是 Spring Boot 项目,只需引入spring-boot-starter即可;非 Spring Boot 项目需手动引入:

xml

<!-- Spring核心+AOP依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>6.1.4</version> <!-- 适配Java 17+,按需调整版本 --> </dependency> <!-- Spring AOP增强(可选,简化切点表达式) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>6.1.4</version> </dependency>
步骤 2:开启 AOP 注解支持

在 Spring 配置类上添加@EnableAspectJAutoProxy注解,启用 AOP 自动代理:

java

运行

import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; // 配置类,开启AOP注解支持 @Configuration @ComponentScan("com.example") // 扫描指定包下的Bean @EnableAspectJAutoProxy public class SpringConfig { }
步骤 3:定义目标类(被增强的业务类)

创建普通的 Spring Bean,作为 AOP 的 “目标对象”:

java

运行

import org.springframework.stereotype.Service; // 业务层Bean,作为AOP的目标类 @Service public class UserService { // 待增强的方法1 public void addUser(String username) { System.out.println("执行添加用户逻辑:" + username); // 可手动抛出异常测试@AfterThrowing:throw new RuntimeException("添加用户失败"); } // 待增强的方法2 public String getUserById(Integer id) { System.out.println("执行查询用户逻辑:id=" + id); return "用户-" + id; } }
步骤 4:定义切面类(封装横切逻辑)

创建切面类,用@Aspect标记,同时标注为 Spring Bean(@Component),并定义切点和通知:

java

运行

import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; // 1. 标记为切面类 + Spring Bean @Aspect @Component public class LogAspect { // 2. 定义切点(复用性高,可被多个通知引用) // 切点表达式:匹配com.example.service包下所有类的所有方法 @Pointcut("execution(* com.example.service.*.*(..))") public void servicePointcut() {} // 3. 定义通知(增强逻辑) // 前置通知:目标方法执行前执行 @Before("servicePointcut()") public void beforeAdvice(JoinPoint joinPoint) { // JoinPoint可获取目标方法名、参数等信息 String methodName = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); System.out.println("[前置通知] 方法:" + methodName + ",参数:" + java.util.Arrays.toString(args)); } // 后置返回通知:目标方法正常返回后执行 @AfterReturning(value = "servicePointcut()", returning = "result") public void afterReturningAdvice(JoinPoint joinPoint, Object result) { String methodName = joinPoint.getSignature().getName(); System.out.println("[返回通知] 方法:" + methodName + ",返回值:" + result); } // 异常通知:目标方法抛出异常后执行 @AfterThrowing(value = "servicePointcut()", throwing = "e") public void afterThrowingAdvice(JoinPoint joinPoint, Exception e) { String methodName = joinPoint.getSignature().getName(); System.out.println("[异常通知] 方法:" + methodName + ",异常:" + e.getMessage()); } // 环绕通知(最灵活,可控制目标方法执行) @Around("servicePointcut()") public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable { String methodName = joinPoint.getSignature().getName(); System.out.println("[环绕前置] 开始执行方法:" + methodName); // 执行目标方法(必须调用,否则目标方法不会执行) Object result = joinPoint.proceed(); System.out.println("[环绕后置] 方法:" + methodName + "执行完成"); return result; // 可修改返回值 } }
步骤 5:测试 AOP 效果

编写测试类,启动 Spring 容器并调用目标方法:

java

运行

import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class AopTest { public static void main(String[] args) { // 初始化Spring容器 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); // 获取目标Bean UserService userService = context.getBean(UserService.class); // 调用目标方法,触发AOP增强 userService.addUser("张三"); System.out.println("-----分割线-----"); userService.getUserById(1001); // 关闭容器 context.close(); } }
执行结果(正常情况):

plaintext

[环绕前置] 开始执行方法:addUser [前置通知] 方法:addUser,参数:[张三] 执行添加用户逻辑:张三 [环绕后置] 方法:addUser执行完成 -----分割线----- [环绕前置] 开始执行方法:getUserById [前置通知] 方法:getUserById,参数:[1001] 执行查询用户逻辑:id=1001 [返回通知] 方法:getUserById,返回值:用户-1001 [环绕后置] 方法:getUserById执行完成

三、关键知识点解析

  1. 切点表达式(execution 语法)上面用的execution(* com.example.service.*.*(..))是最常用的切点表达式,拆解如下:

    • *:返回值任意(第一个 *)
    • com.example.service.*:匹配 service 包下的所有类
    • .*:匹配类下的所有方法
    • (..):方法参数任意(数量、类型都不限)其他常用表达式:
    • 匹配指定方法:execution(public String com.example.service.UserService.getUserById(Integer))
    • 匹配注解:@annotation(org.springframework.transaction.annotation.Transactional)(匹配加了 @Transactional 的方法)
  2. 环绕通知的注意事项

    • ProceedingJoinPointJoinPoint的子类,只有环绕通知能使用。
    • 必须调用joinPoint.proceed()才能执行目标方法,否则目标方法不会运行。
    • 可通过proceed(args)修改目标方法的参数,也可修改返回值。
  3. AOP 的实现原理Spring AOP 基于动态代理实现:

    • 如果目标类实现了接口:使用 JDK 动态代理(生成接口的代理类)。
    • 如果目标类未实现接口:使用 CGLIB 动态代理(生成目标类的子类)。
    • @EnableAspectJAutoProxy(proxyTargetClass = true):强制使用 CGLIB 代理。

四、总结

  1. Spring AOP 实现的核心步骤:引入依赖 → 开启 AOP 注解 → 定义目标 Bean → 编写切面类(@Aspect + 切点 + 通知) → 测试。
  2. 注解式 AOP 是主流方式,核心注解包括@EnableAspectJAutoProxy(开启 AOP)、@Aspect(标记切面)、@Pointcut(定义切点)、各类通知注解(@Before/@Around 等)。
  3. 环绕通知(@Around)最灵活,但使用成本稍高;简单场景优先用 @Before/@AfterReturning 等简单通知。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/4 12:58:04

强烈安利8个AI论文软件,专科生搞定毕业论文必备!

强烈安利8个AI论文软件&#xff0c;专科生搞定毕业论文必备&#xff01; AI 工具助力论文写作&#xff0c;专科生也能轻松应对 对于许多专科生来说&#xff0c;毕业论文似乎是一个难以逾越的难关。从选题、查找资料到撰写初稿、反复修改&#xff0c;每一步都充满了挑战。而如今…

作者头像 李华
网站建设 2026/1/30 7:59:37

一文吃透 Spring 事务传播行为:7 种场景#x2B;代码实战

作为后端开发&#xff0c;Spring 事务是日常工作的基础&#xff0c;但不少人只会用 Transactional 注解加个 rollbackFor&#xff0c;对底层的事务传播行为一知半解。直到遇到“嵌套调用事务不回滚”“重复提交导致数据异常”等问题&#xff0c;才发现对传播行为的理解不足会踩…

作者头像 李华
网站建设 2026/2/4 9:12:12

边缘智能革命:让YOLO在FPGA上“飞”起来的软硬协同之道

当目标检测算法遇上边缘计算硬件,一场关于速度、精度与功耗的精妙平衡就此展开。你不是在压缩模型,而是在为算法设计专属的硅基座驾。 在一台无人机上进行实时目标检测,需要多少功耗?传统方案使用高性能GPU需要15-30瓦,而通过算法-硬件协同优化设计的FPGA加速系统,可以将…

作者头像 李华
网站建设 2026/2/4 14:55:05

基于Java的医院急诊系统毕业论文+PPT(附源代码+演示视频)

文章目录基于Java的医院急诊系统一、项目简介&#xff08;源代码在文末&#xff09;1.运行视频2.&#x1f680; 项目技术栈3.✅ 环境要求说明4.包含的文件列表&#xff08;含论文&#xff09;数据库结构与测试用例系统功能结构前端运行截图后端运行截图项目部署源码下载基于Jav…

作者头像 李华
网站建设 2026/2/1 22:41:43

吐血推荐!专科生必用AI论文网站TOP9:开题报告全攻略

吐血推荐&#xff01;专科生必用AI论文网站TOP9&#xff1a;开题报告全攻略 2026年专科生AI论文写作工具测评&#xff1a;精准选型指南 随着人工智能技术的不断进步&#xff0c;AI论文写作工具逐渐成为高校学生&#xff0c;尤其是专科生撰写论文的重要辅助。然而&#xff0c;面…

作者头像 李华