news 2026/4/17 20:22:43

如何使用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/4/18 8:16:35

可解释集成模型如何提升商品搜索效果

可解释集成模型改进商品检索 机器学习领域正飞速发展&#xff0c;新模型层出不穷&#xff0c;均承诺超越前代。然而&#xff0c;为特定用例评估新模型是一个耗时且消耗资源的过程。这对于像某中心的商店这样承诺为客户提供最先进技术、同时又全天候高负载运营的在线服务而言&am…

作者头像 李华
网站建设 2026/4/18 8:06:01

Java版LeetCode热题100之验证二叉搜索树:从递归边界到中序遍历的深度解析

Java版LeetCode热题100之验证二叉搜索树&#xff1a;从递归边界到中序遍历的深度解析本文将全面、深入地剖析 LeetCode 第98题「验证二叉搜索树」&#xff0c;不仅提供递归和中序遍历两种主流解法&#xff0c;还涵盖算法原理、复杂度分析、面试技巧、工程应用及关联题目拓展。全…

作者头像 李华
网站建设 2026/4/18 7:55:07

文件清理神器,绝了

在日常电脑使用中清理C盘垃圾是没有办法回避的&#xff0c;因为电脑用的时间久了&#xff0c;C盘肯定会越来越拥挤。今天给大家推荐的这款神器可以帮助清理C盘的重复文件&#xff0c;并且查找出空文件夹。 czkawka 重复文件清理神器 czkawka软件是一款重复文件&#xff0c;大文…

作者头像 李华