spring boot aop简单demo


Spring Boot AOP 的核心概念

AOP(Aspect-Oriented Programming,面向切面编程) 是一种编程范式,用于将横切关注点(如日志、事务、权限校验)与业务逻辑解耦。通过动态代理技术,Spring Boot AOP 可以在不修改源代码的情况下,在方法执行前后插入通用逻辑。


AOP 的五大核心应用场景

场景说明典型实现
日志记录统一记录方法入参、返回值、异常信息@Around 环绕通知
事务管理声明式事务(如 @TransactionalSpring 内置事务切面
权限校验拦截请求,验证用户角色或权限@Before 前置通知 + 自定义注解
性能监控统计方法执行耗时@Around + 计时逻辑
缓存处理方法执行前检查缓存,存在则直接返回@Around + Redis 操作
异常统一处理全局捕获异常并返回标准化错误响应@AfterThrowing 异常通知

Spring Boot AOP 实现步骤

1. 添加依赖

pom.xml 中引入 AOP 依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2. 创建切面类

使用 @Aspect@Component 定义切面:

package com.example.spring_demo01.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogAspect {

    // 定义切点:拦截所有 Service 层方法
    @Pointcut("execution(* com.example.spring_demo01.service.*.*(..))")
    public void serviceLayer() {}

    // 环绕通知:记录方法耗时
    @Around("serviceLayer()")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = joinPoint.proceed(); // 执行目标方法
        long duration = System.currentTimeMillis() - startTime;
        System.out.printf("方法 %s 执行耗时: %d ms\n", joinPoint.getSignature(), duration);
        return result;
    }
}
3. 定义自定义注解(可选)

创建注解用于标记需要特殊处理的方法:

package com.example.spring_demo01.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AdminOnly {
}
4. 实现权限校验切面
@Aspect
@Component
public class AuthAspect {

    // 拦截所有标记了 @AdminOnly 的方法
    @Before("@annotation(com.example.spring_demo01.annotation.AdminOnly)")
    public void checkAdminPermission() {
        // 模拟权限校验
        if (!CurrentUser.isAdmin()) {
            throw new RuntimeException("无权限访问!");
        }
    }
}
5. 在业务方法上使用注解
@Service
public class UserService {

    @AdminOnly
    public void deleteUser(Long userId) {
        // 删除用户逻辑
    }
}

AOP 核心注解详解

注解说明
@Aspect声明一个切面类
@Pointcut定义切点表达式,确定哪些方法需要被拦截
@Before在目标方法执行前执行
@After在目标方法执行后执行(无论是否抛出异常)
@AfterReturning在目标方法成功返回后执行
@AfterThrowing在目标方法抛出异常后执行
@Around环绕通知,可完全控制目标方法的执行

切点表达式语法

表达式示例说明
execution(* com.example.service.*.*(..))匹配 service 包下所有类的所有方法
@annotation(com.example.AdminOnly)匹配标记了 @AdminOnly 注解的方法
within(com.example.controller..*)匹配 controller 包及其子包下的所有方法
args(java.lang.String, ..)匹配第一个参数为 String 类型的方法

AOP 实现原理

Spring AOP 基于 动态代理 实现:

  • JDK 动态代理:针对实现了接口的类,通过 Proxy 类生成代理对象。
  • CGLIB 代理:针对未实现接口的类,通过继承生成子类代理。

常见问题与解决方案

问题 1:AOP 不生效
  • 原因:同类内部方法调用(如 this.method())无法被代理拦截。
  • 解决:通过依赖注入调用自身方法:
    @Service
    public class UserService {
        @Autowired
        private UserService self; // 注入自身代理对象
    
        public void methodA() {
            self.methodB(); // 通过代理对象调用
        }
    
        @AdminOnly
        public void methodB() {}
    }
    
问题 2:切点表达式错误
  • 调试工具:使用 AopUtils 检查方法是否被代理:
    boolean isProxy = AopUtils.isAopProxy(bean);
    
问题 3:循环依赖
  • 原因:AOP 代理导致 Bean 初始化顺序冲突。
  • 解决:使用 @Lazy 延迟注入:
    @Service
    public class OrderService {
        @Lazy
        @Autowired
        private UserService userService;
    }
    

总结

通过 Spring Boot AOP,你可以高效地实现以下功能:

  1. 统一日志记录
  2. 声明式事务管理
  3. 细粒度权限控制
  4. 接口性能监控
  5. 全局异常处理

合理使用 AOP 能显著提升代码的可维护性和复用性,但需注意代理机制的限制(如内部方法调用问题)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值