好的,我们将系统性地解析 Spring Boot 中的 AOP 切面编程,涵盖核心概念、实现步骤及实战案例。
一、AOP 核心概念
AOP(Aspect-Oriented Programming)是一种横向切割代码逻辑的编程范式,用于解耦与业务无关的通用行为(如日志、事务、权限校验)。其核心组件包括:
封装横切逻辑的模块(如日志切面、事务切面)。
通过表达式定位需要拦截的连接点(如:@Pointcut("execution(* com.example.service.*.*(..))"))。
定义在切点执行的逻辑类型:
- @Before:目标方法执行前
- @AfterReturning:方法成功返回后
- @AfterThrowing:方法抛出异常后
- @After:方法结束后(无论成功或异常)
- @Around:环绕整个方法执行过程
程序执行过程中的特定点(如方法调用、异常抛出)。
二、Spring Boot 集成 AOP 步骤
1. 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2. 定义切面类
@Aspect
@Component
public class LoggingAspect {
// 定义切点:拦截 service 包下所有方法
@Pointcut("execution(* com.example.service.*.*(..))")
public void servicePointcut() {}
// 前置通知:记录方法入参
@Before("servicePointcut()")
public void logBefore(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("Method " + methodName + " called with args: " + Arrays.toString(args));
}
// 环绕通知:计算方法执行耗时
@Around("servicePointcut()")
public Object logTime(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = joinPoint.proceed(); // 执行目标方法
long duration = System.currentTimeMillis() – startTime;
System.out.println("Method execution time: " + duration + "ms");
return result;
}
}
三、实战进阶案例:权限校验切面
场景
拦截带有 @RequiresPermission 注解的方法,校验用户权限。
1. 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiresPermission {
String value(); // 权限标识符,如 "admin:delete"
}
2. 权限校验切面
@Aspect
@Component
public class PermissionAspect {
@Autowired
private PermissionService permissionService; // 权限校验服务
// 切点:拦截所有带 @RequiresPermission 注解的方法
@Pointcut("@annotation(com.example.annotation.RequiresPermission)")
public void permissionCheck() {}
@Before("permissionCheck()")
public void checkPermission(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
RequiresPermission annotation = signature.getMethod().getAnnotation(RequiresPermission.class);
String permission = annotation.value();
// 模拟获取当前用户(实际可从 ThreadLocal 或 SecurityContext 获取)
String currentUser = "user123";
if (!permissionService.hasPermission(currentUser, permission)) {
throw new SecurityException("Permission denied: " + permission);
}
}
}
3. 使用注解
@Service
public class UserService {
@RequiresPermission("user:delete")
public void deleteUser(Long userId) {
// 删除用户逻辑
}
}
四、AOP 最佳实践
使用 within() 缩小拦截范围,避免过度拦截:
@Pointcut("within(com.example.service..*) && execution(* *.*(..))")
通过 @Order 注解控制多个切面的执行优先级:
@Aspect
@Order(1) // 数字越小优先级越高
public class LoggingAspect { … }
切面中注入的 Bean 不要依赖被切面拦截的 Bean(可通过 @Lazy 延迟注入解决)。
五、常见问题排查
- 检查切面类是否被 Spring 扫描(@Component 或显式配置 @EnableAspectJAutoProxy)。
- 确认切点表达式匹配目标方法。
Spring AOP 基于代理机制,同类内部方法调用不会触发切面(可通过 AopContext.currentProxy() 获取代理对象解决)。
通过以上内容,您已掌握 Spring Boot AOP 的核心用法与进阶实践。如有具体场景问题,可进一步深入探讨!
网硕互联帮助中心




评论前必须登录!
注册