Spring AOP 教程总结
1. AOP 简介
AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,用于将横切关注点(如日志记录、事务管理、安全检查)从业务逻辑中分离,提高代码的可维护性和复用性。Spring AOP 是 Spring 框架的核心模块之一,通过动态代理(JDK 或 CGLIB)实现,与 IoC 容器无缝集成,支持注解和 XML 配置。
核心优势:
- 非侵入式:无需修改原有业务代码。
- 解耦:将公共逻辑抽取为独立模块。
- 适用场景:日志、性能监控、异常处理等。
2. AOP 核心概念
- 切面(Aspect):模块化横切关注点,包含通知和切点(如一个日志类)。
- 切点(Pointcut):定义何时触发切面(如匹配特定方法)。
- 通知(Advice):切面的具体行为,包括:
@Before:方法执行前。@After:方法执行后(无论成功或异常)。@AfterReturning:方法正常返回后。@AfterThrowing:方法抛异常后。@Around:环绕通知,可控制方法执行(最强大)。
- 连接点(Join Point):程序执行中的具体点(如方法调用)。
- 织入(Weaving):将切面应用到目标对象的过程(Spring 通过代理实现)。
3. Spring AOP 配置
3.1 依赖引入(Maven)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.23</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.9.1</version>
</dependency>
3.2 XML 配置(spring-config.xml)
<beans xmlns:aop="http://www.springframework.org/schema/aop">
<aop:aspectj-autoproxy />
<bean id="loggingAspect" class="com.example.LoggingAspect" />
<aop:config>
<aop:aspect ref="loggingAspect">
<aop:pointcut id="controllerMethods" expression="execution(* com.example.controller.*.*(..))" />
<aop:before method="logBefore" pointcut-ref="controllerMethods" />
<aop:after method="logAfter" pointcut-ref="controllerMethods" />
</aop:aspect>
</aop:config>
</beans>
3.3 注解配置(推荐)
在配置类中启用:
@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
@Bean
public LoggingAspect loggingAspect() {
return new LoggingAspect();
}
}
4. 注解实现示例
4.1 切面类(LoggingAspect.java)
@Aspect
@Component // 交给 Spring 管理
public class LoggingAspect {
// 切点表达式:匹配 controller 包下所有公共方法
@Pointcut("execution(* com.example.controller.*.*(..))")
public void controllerMethods() {}
@Before("controllerMethods()")
public void logBefore(JoinPoint joinPoint) {
System.out.println("【Before】方法执行前: " + joinPoint.getSignature().getName());
}
@After("controllerMethods()")
public void logAfter(JoinPoint joinPoint) {
System.out.println("【After】方法执行后: " + joinPoint.getSignature().getName());
}
@Around("controllerMethods()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed(); // 执行目标方法
long end = System.currentTimeMillis();
System.out.println("【Around】执行时长: " + (end - start) + "ms");
return result;
}
}
4.2 目标类(TestController.java)
@Controller
public class TestController {
@RequestMapping("/test")
public String test() {
// 业务逻辑
return "success";
}
}
5. 运行与测试
- 启动 Spring 应用,调用
/test接口。 - 控制台输出:
【Before】方法执行前: test 【Around】执行时长: 5ms 【After】方法执行后: test
注意:
@Around可获取返回值或抛异常处理。- 切点表达式支持
execution、within、args等。 - JDK 代理需接口,CGLIB 支持无接口类(默认)。
6. 常见问题与扩展
- 代理模式:接口类用 JDK,无接口用 CGLIB(配置
proxy-target-class="true")。 - 性能:代理有轻微开销,适合非高并发场景。
- 扩展:结合 AspectJ(更强大,但复杂);用于事务
@Transactional底层即 AOP。 - 最佳实践:切面优先注解,保持简单;测试时 mock 代理。
此总结基于 Spring 5.x 版本,适合初学者快速上手。实际项目中,推荐结合官方文档实践。