Spring AOP 核心概念与实战入门
AOP(Aspect Oriented Programming,面向切面编程)是 Spring 框架的两大核心之一,另一个是 IoC。简单来说,AOP 是一种思想,旨在将那些与业务无关、却为业务模块所共同调用的逻辑(如事务管理、日志记录、性能监控等)封装起来,减少系统的重复代码,降低模块间的耦合度。
为什么需要 AOP?
在实际开发中,我们往往面临这样的场景:项目中有大量业务功能,某些接口执行效率较低,需要优化。第一步通常是定位耗时较长的方法,而统计每个方法的运行时间是一个典型需求。
如果不使用 AOP,我们需要在每个业务方法的前后手动添加记录开始和结束时间的代码。随着业务模块增多,这种重复工作会显著增加维护成本。AOP 的优势在于,它允许我们在不修改源代码的前提下,针对特定方法进行功能增强。这种非侵入式的解耦方式,正是 AOP 的核心价值所在。
实战:引入依赖与编写程序
1. 引入 AOP 依赖
在 pom.xml 中添加 Spring Boot 的 AOP 启动器依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2. 编写切面类 (Aspect)
接下来定义一个切面类,用于拦截目标方法并记录耗时。这里使用 @Around 环绕通知,它可以包裹目标方法的执行过程。
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Slf4j
@Component
@Aspect
public class AspectTest {
/**
* 记录方法耗时
*/
@Around("execution(* com.wmh.springaop.controller.*.*(..))")
public Object recordTime(ProceedingJoinPoint pjp) throws Throwable {
// 记录方法执行开始时间
long begin = System.currentTimeMillis();
// 执行原始方法,这是关键步骤,必须调用 proceed() 才能继续后续逻辑
Object result = pjp.proceed();
// 记录方法执行结束时间
long end = System.currentTimeMillis();
// 输出耗时信息
log.info(pjp.getSignature() + "执行耗时:{}ms", end - begin);
return result;
}
}
注意: 这里的切入点表达式 execution(* com.wmh.springaop.controller.*.*(..)) 表示拦截该包下所有 Controller 的所有方法。实际项目中应根据具体需求调整路径。
3. 目标控制器 (Controller)
为了验证效果,我们需要一个被拦截的目标类。
package com.wmh.springaop.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RequestMapping("/test")
@RestController
public class TestController {
@RequestMapping("/t1")
public String t1() {
log.info("执行 t1 方法...");
try {
Thread.sleep(100); // 模拟耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
return "t1";
}
}
4. 运行结果
当访问 /test/t1 接口时,控制台会同时打印业务日志和切面记录的耗时日志。这证明了在不修改 TestController 源码的情况下,我们已经成功增强了其功能。

关键注解解析
在上述代码中,有几个核心注解起到了决定性作用:
- @Aspect: 标识该类为一个切面类,告诉 Spring 容器这是一个 AOP 组件。
- @Around: 环绕通知,意味着通知逻辑会在目标方法执行前后都被触发。这是最强大的通知类型,可以控制是否执行目标方法以及修改返回值。
- ProceedingJoinPoint.proceed(): 这是执行原始方法的关键。如果不调用此方法,目标方法将不会执行,相当于直接拦截了请求。
整个流程可以概括为三部分:方法执行前逻辑 -> 原始方法执行 -> 方法执行后逻辑。通过这种结构,我们可以灵活地插入各种横切关注点。
AOP 的主要优势
理解了基本用法后,我们再来看看 AOP 带来的核心价值:
-
关注点分离 将日志、安全、事务等非核心逻辑从业务代码中剥离,使业务逻辑更清晰,专注于核心功能实现。
-
代码重用 将通用的辅助功能封装为可重用的切面,避免在多个模块中重复编写相同代码,减少冗余。
-
系统可维护性增强 横切关注点集中在切面中管理,修改这些功能只需改动一处,降低了维护成本和引入新错误的风险。
-
灵活性提高 基于动态代理技术,可以在运行时动态地将切面应用到目标对象上。新增或移除切面无需修改现有业务逻辑。
-
易于测试 单元测试可以更聚焦于业务功能本身,因为非核心代码已被隔离。部分切面甚至可以在测试环境中被禁用或替换。
-
支持事务管理 Spring 的事务管理底层就是基于 AOP 实现的。通过声明式事务,开发者可以轻松定义哪些方法需要事务支持,无需在代码中混入复杂的事务处理逻辑。
通过上述示例,我们可以看到 Spring AOP 如何以简洁的方式解决复杂的横切问题。掌握这一机制,对于构建高质量、易维护的企业级应用至关重要。


