彻底搞懂Spring AOP:概念与实战

一、什么是AOP?

AOP(面向切面编程)是一种编程范式,用于将横切关注点(如日志、事务、安全等)与核心业务逻辑分离的技术。

核心思想:

  • 关注点分离:将系统的通用功能(横切关注点)从业务逻辑中抽离
  • 模块化:通过切面将这些通用功能模块化,便于复用和维护
  • 解耦:避免业务代码中混入大量重复的通用代码

二、AOP的核心概念

概念

说明

类比

Aspect(切面)

横切关注点的模块化,如日志切面、事务切面

一个专门的“功能模块”

Join Point(连接点)

程序执行过程中的某个点,如方法调用、异常抛出

可以被增强的“时机点”

Pointcut(切点)

匹配连接点的表达式,定义在哪些地方应用切面

“筛选器”,选择哪些连接点要增强

Advice(通知)

在特定连接点执行的动作

增强的具体“行为”

Weaving(织入)

将切面应用到目标对象创建代理对象的过程

“植入”增强逻辑的过程

三、Advice的类型

java

// 1. Before:方法执行前 @Before("execution(* com.example.service.*.*(..))") public void beforeAdvice() { System.out.println("方法执行前"); } // 2. AfterReturning:方法正常返回后 @AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result") public void afterReturning(Object result) { System.out.println("方法返回: " + result); } // 3. AfterThrowing:方法抛出异常后 @AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "ex") public void afterThrowing(Exception ex) { System.out.println("方法异常: " + ex.getMessage()); } // 4. After(Finally):方法执行后(无论成功还是异常) @After("execution(* com.example.service.*.*(..))") public void afterAdvice() { System.out.println("方法执行结束"); } // 5. Around:环绕通知(最强大) @Around("execution(* com.example.service.*.*(..))") public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable { // 方法执行前 System.out.println("开始执行: " + joinPoint.getSignature()); long start = System.currentTimeMillis(); Object result = joinPoint.proceed(); // 执行目标方法 // 方法执行后 long end = System.currentTimeMillis(); System.out.println("执行耗时: " + (end - start) + "ms"); return result; }

四、具体例子:日志切面

场景:为所有Service方法添加执行日志和耗时统计

java

@Component @Aspect public class LoggingAspect { private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class); // 定义切点:匹配所有Service包下的方法 @Pointcut("execution(* com.example.service..*.*(..))") public void serviceLayer() {} // 环绕通知:记录方法执行耗时 @Around("serviceLayer()") public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); String className = signature.getDeclaringType().getSimpleName(); String methodName = signature.getName(); long start = System.currentTimeMillis(); try { logger.info("[开始执行] {}.{}() 参数: {}", className, methodName, Arrays.toString(joinPoint.getArgs())); Object result = joinPoint.proceed(); long end = System.currentTimeMillis(); logger.info("[执行成功] {}.{}() 耗时: {}ms 结果: {}", className, methodName, (end - start), result); return result; } catch (Exception e) { long end = System.currentTimeMillis(); logger.error("[执行异常] {}.{}() 耗时: {}ms 异常: {}", className, methodName, (end - start), e.getMessage(), e); throw e; } } // 方法执行前的通知 @Before("serviceLayer() && @annotation(org.springframework.transaction.annotation.Transactional)") public void logBeforeTransactionalMethod(JoinPoint joinPoint) { logger.debug("准备执行事务方法: {}", joinPoint.getSignature()); } }

五、实际应用场景

1.事务管理(Spring最经典的AOP应用)

java

@Service public class OrderService { @Transactional public void createOrder(Order order) { // 业务逻辑 orderDao.save(order); inventoryService.reduceStock(order); // 如果出现异常,整个事务会回滚 } }

2.权限控制

java

@Aspect @Component public class SecurityAspect { @Before("@annotation(RequiresPermission)") public void checkPermission(JoinPoint joinPoint) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); RequiresPermission annotation = signature.getMethod() .getAnnotation(RequiresPermission.class); String permission = annotation.value(); if (!SecurityContext.hasPermission(permission)) { throw new UnauthorizedException("缺少权限: " + permission); } } } // 使用 @RequiresPermission("order:create") public void createOrder(Order order) { // 需要权限的业务逻辑 }

3.缓存切面

java

@Aspect @Component public class CacheAspect { @Around("@annotation(cacheable)") public Object cacheResult(ProceedingJoinPoint joinPoint, Cacheable cacheable) throws Throwable { String key = generateCacheKey(joinPoint); Object cachedValue = cache.get(key); if (cachedValue != null) { return cachedValue; } Object result = joinPoint.proceed(); cache.put(key, result, cacheable.ttl()); return result; } }

六、Spring AOP的实现原理

底层技术:

  1. JDK动态代理(默认,针对接口)
  2. CGLIB动态代理(针对类,当目标对象没有实现接口时)

织入时机:

  1. 编译时织入(AspectJ)
  2. 类加载时织入(AspectJ)
  3. 运行时织入(Spring AOP采用的方式)

七、使用建议

优点:

减少重复代码:横切关注点只需编写一次 ✅ 提高可维护性:业务逻辑更清晰 ✅ 灵活配置:通过注解或XML配置切面 ✅ 易于测试:切面可以独立测试

注意事项:

⚠️ 性能开销:代理调用比直接调用稍慢 ⚠️ 仅方法拦截:Spring AOP只能拦截方法,不能拦截字段访问 ⚠️ 自调用问题:同一类内方法互相调用,AOP可能失效 ⚠️ 理解复杂度:需要理解代理机制和AOP概念

总结

Spring AOP通过动态代理技术,在不修改原有代码的情况下,为程序添加额外的功能。它特别适合处理横切关注点,如日志、事务、安全、缓存等。理解AOP的核心概念(切面、切点、通知)和实际应用场景,能帮助我们编写更清晰、更易维护的代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值