侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

Spring AOP 中如何定义一个简单的日志切面?

2025-12-13 / 0 评论 / 4 阅读

题目

Spring AOP 中如何定义一个简单的日志切面?

信息

  • 类型:问答
  • 难度:⭐

考点

切面定义,前置通知,切入点表达式

快速回答

在 Spring AOP 中定义一个简单日志切面的步骤如下:

  1. 创建带有 @Aspect 注解的切面类
  2. 使用 @Before 注解定义前置通知
  3. 通过切入点表达式指定目标方法(如 @Before("execution(* com.example.service.*.*(..))")
  4. 在通知方法中实现日志逻辑
  5. 启用 Spring AOP 自动代理(通过 @EnableAspectJAutoProxy
## 解析

原理说明

Spring AOP 基于代理模式实现,在方法调用前后插入横切逻辑(通知)。核心组件:

  • 切面(Aspect):封装横切关注点的模块(使用 @Aspect 注解的类)
  • 通知(Advice):切面中的具体逻辑(如前置通知 @Before
  • 切入点(Pointcut):定义通知的应用位置(通过表达式匹配方法)

代码示例

// 1. 启用AOP自动代理
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {}

// 2. 定义切面
@Aspect
@Component
public class LoggingAspect {

    // 3. 前置通知:在com.example.service包下所有方法执行前触发
    @Before("execution(* com.example.service.*.*(..))")
    public void logMethodCall(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("[LOG] 调用方法: " + methodName);
    }
}

// 4. 目标服务类
@Service
public class UserService {
    public void createUser(String name) {
        // 业务逻辑
    }
}

最佳实践

  • 切入点表达式:优先使用精确包路径避免意外匹配(如 com.example.service.*
  • 组件扫描:确保切面类在 Spring 容器中(添加 @Component
  • 日志内容:通过 JoinPoint 获取方法名、参数等上下文信息
  • 通知类型:根据场景选择合适通知(前置/后置/环绕等)

常见错误

  • 未启用自动代理:忘记添加 @EnableAspectJAutoProxy 导致切面不生效
  • 表达式错误:错误的包路径或方法签名匹配(如 *.*(..) 匹配所有方法)
  • 作用域问题:目标类必须是 Spring 管理的 Bean(非 new 创建的对象)
  • 循环依赖:切面中注入的 Bean 与目标 Bean 相互引用导致启动失败

扩展知识

  • 其他通知类型
    • @After:最终通知(无论是否异常都执行)
    • @AfterReturning:返回后通知
    • @AfterThrowing:异常通知
    • @Around:环绕通知(可控制方法执行)
  • 切入点复用:使用 @Pointcut 定义可重用的表达式
  • 代理机制:Spring AOP 默认使用 JDK 动态代理(接口)或 CGLIB(类)
  • 性能影响:过多的切面会增加调用栈深度,避免在高频方法使用