Spring AOP详解
什么是AOP
AOP(Aspect-Oriented Programming)面向切面编程,用于分离横切关注点,如日志、事务、安全等。
AOP核心概念
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LogAspect {
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {}
@Before("serviceLayer()")
public void beforeMethod(JoinPoint joinPoint) {
System.out.println("方法执行前: " + joinPoint.getSignature().getName());
}
@After("serviceLayer()")
public void afterMethod(JoinPoint joinPoint) {
System.out.println("方法执行后: " + joinPoint.getSignature().getName());
}
@Around("serviceLayer()")
public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long elapsed = System.currentTimeMillis() - start;
System.out.println("方法耗时: " + elapsed + "ms");
return result;
}
@AfterReturning(pointcut = "serviceLayer()", returning = "result")
public void afterReturning(Object result) {
System.out.println("方法返回: " + result);
}
@AfterThrowing(pointcut = "serviceLayer()", throwing = "ex")
public void afterThrowing(Exception ex) {
System.out.println("方法异常: " + ex.getMessage());
}
}
切入点表达式
import org.aspectj.lang.annotation.*;
@Aspect
public class PointcutDemo {
@Pointcut("execution(* com.example.service.*.*(..))")
public void allServiceMethods() {}
@Pointcut("execution(public * *(..))")
public void allPublicMethods() {}
@Pointcut("within(com.example.service..*)")
public void inServicePackage() {}
@Pointcut("bean(userService)")
public void userServiceBean() {}
@Pointcut("@annotation(com.example.annotation.Loggable)")
public void loggableMethods() {}
}
AOP实战:日志记录
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.controller.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("[" + LocalDateTime.now() + "] 调用: " +
joinPoint.getSignature().toShortString());
}
@AfterReturning(pointcut = "execution(* com.example.controller.*.*(..))",
returning = "result")
public void logAfter(JoinPoint joinPoint, Object result) {
System.out.println("[" + LocalDateTime.now() + "] 返回: " + result);
}
}
AOP实战:性能监控
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class PerformanceAspect {
@Around("@annotation(com.example.annotation.PerformanceMonitor)")
public Object monitorPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().getName();
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long elapsed = System.currentTimeMillis() - start;
System.out.println("性能监控 - " + methodName + " 耗时: " + elapsed + "ms");
return result;
}
}
AOP实战:事务管理
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class TransactionAspect {
@Autowired
private TransactionManager transactionManager;
@Around("execution(* com.example.service.*.*(..))")
public Object manageTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
TransactionStatus status = transactionManager.getTransaction(
new DefaultTransactionDefinition());
try {
Object result = joinPoint.proceed();
transactionManager.commit(status);
return result;
} catch (Exception e) {
transactionManager.rollback(status);
throw e;
}
}
}
AOP实战:安全检查
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class SecurityAspect {
@Before("@annotation(com.example.annotation.RequiresRole)")
public void checkPermission(JoinPoint joinPoint) {
System.out.println("检查用户权限...");
}
@Around("@annotation(com.example.annotation.Secured)")
public Object secureMethod(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("安全验证中...");
Object result = joinPoint.proceed();
System.out.println("安全验证完成");
return result;
}
}
AOP实战:缓存
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import java.util.concurrent.ConcurrentHashMap;
@Aspect
@Component
public class CacheAspect {
private final ConcurrentHashMap<String, Object> cache = new ConcurrentHashMap<>();
@Around("@annotation(com.example.annotation.Cachable)")
public Object cacheResult(ProceedingJoinPoint joinPoint) throws Throwable {
String key = joinPoint.getSignature().getName() +
java.util.Arrays.toString(joinPoint.getArgs());
if (cache.containsKey(key)) {
System.out.println("从缓存返回: " + key);
return cache.get(key);
}
Object result = joinPoint.proceed();
cache.put(key, result);
System.out.println("缓存结果: " + key);
return result;
}
}
启用AOP
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
}
AOP最佳实践
- 使用@Around处理复杂逻辑
- 合理使用切入点表达式
- 避免过度使用AOP影响性能
- AOP通知中避免异常
- 使用@Order控制通知执行顺序
总结
Spring AOP提供了强大的面向切面编程能力。掌握AOP的使用,能帮助你优雅地处理横切关注点。