跳转到内容

Spring通知类型

来自代码酷

Spring通知类型[编辑 | 编辑源代码]

Spring AOP(面向切面编程)提供了多种通知(Advice)类型,允许开发者在不修改原有业务逻辑代码的情况下,通过声明式方式在方法执行的不同阶段插入横切关注点(如日志、事务管理等)。本文将详细介绍Spring AOP中的五种通知类型及其应用场景。

通知类型概述[编辑 | 编辑源代码]

通知是AOP的核心概念之一,它定义了“何时”以及“做什么”。Spring AOP支持以下五种通知类型:

1. 前置通知(Before Advice):在目标方法执行前执行。 2. 后置通知(After Returning Advice):在目标方法成功执行后执行(无异常抛出时)。 3. 异常通知(After Throwing Advice):在目标方法抛出异常后执行。 4. 最终通知(After (Finally) Advice):在目标方法执行后执行(无论是否抛出异常)。 5. 环绕通知(Around Advice):包围目标方法的执行,可以控制是否执行目标方法以及修改返回值。

以下是一个通知执行顺序的示意图:

sequenceDiagram participant Client participant Proxy participant Target Client->>Proxy: 调用方法 alt 环绕通知(前置部分) Proxy->>Proxy: 执行环绕通知的前置逻辑 end alt 前置通知 Proxy->>Proxy: 执行前置通知 end Proxy->>Target: 执行目标方法 alt 后置通知(成功时) Target-->>Proxy: 返回结果 Proxy->>Proxy: 执行后置通知 end alt 异常通知(失败时) Target--xProxy: 抛出异常 Proxy->>Proxy: 执行异常通知 end alt 最终通知 Proxy->>Proxy: 执行最终通知 end alt 环绕通知(后置部分) Proxy->>Proxy: 执行环绕通知的后置逻辑 end Proxy-->>Client: 返回结果或异常

详细说明与示例[编辑 | 编辑源代码]

1. 前置通知(Before Advice)[编辑 | 编辑源代码]

在目标方法执行前触发,适用于权限检查、参数验证等场景。

@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.example.service.*.*(..))")
    public void beforeAdvice(JoinPoint joinPoint) {
        System.out.println("前置通知:准备执行 " + joinPoint.getSignature().getName());
    }
}

输出示例:

前置通知:准备执行 getUserById

2. 后置通知(After Returning Advice)[编辑 | 编辑源代码]

仅在目标方法成功执行后触发,可访问返回值。

@AfterReturning(
    pointcut = "execution(* com.example.service.*.*(..))",
    returning = "result"
)
public void afterReturningAdvice(JoinPoint joinPoint, Object result) {
    System.out.println("后置通知:方法 " + joinPoint.getSignature().getName() 
        + " 执行成功,返回值: " + result);
}

输出示例:

后置通知:方法 getUserById 执行成功,返回值: User{id=1, name='John'}

3. 异常通知(After Throwing Advice)[编辑 | 编辑源代码]

当目标方法抛出异常时触发,适合异常日志记录。

@AfterThrowing(
    pointcut = "execution(* com.example.service.*.*(..))",
    throwing = "ex"
)
public void afterThrowingAdvice(JoinPoint joinPoint, Exception ex) {
    System.err.println("异常通知:方法 " + joinPoint.getSignature().getName() 
        + " 抛出异常: " + ex.getMessage());
}

输出示例:

异常通知:方法 updateUser 抛出异常: 用户不存在

4. 最终通知(After (Finally) Advice)[编辑 | 编辑源代码]

无论目标方法是否成功完成都会执行,类似于try-catch-finally中的finally块。

@After("execution(* com.example.service.*.*(..))")
public void afterFinallyAdvice(JoinPoint joinPoint) {
    System.out.println("最终通知:方法 " + joinPoint.getSignature().getName() + " 执行结束");
}

输出示例(成功时):

最终通知:方法 getUserById 执行结束

输出示例(异常时):

最终通知:方法 updateUser 执行结束

5. 环绕通知(Around Advice)[编辑 | 编辑源代码]

功能最强大的通知类型,可以完全控制目标方法的执行。

@Around("execution(* com.example.service.*.*(..))")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("环绕通知-前置:准备执行 " + joinPoint.getSignature().getName());
    
    try {
        Object result = joinPoint.proceed(); // 执行目标方法
        System.out.println("环绕通知-后置:方法执行成功,返回值: " + result);
        return result;
    } catch (Exception ex) {
        System.err.println("环绕通知-异常:捕获异常: " + ex.getMessage());
        throw ex;
    } finally {
        System.out.println("环绕通知-最终:方法执行结束");
    }
}

输出示例:

环绕通知-前置:准备执行 getUserById
环绕通知-后置:方法执行成功,返回值: User{id=1, name='John'}
环绕通知-最终:方法执行结束

实际应用案例[编辑 | 编辑源代码]

性能监控场景[编辑 | 编辑源代码]

通过环绕通知实现方法执行时间统计:

@Around("execution(* com.example.service.*.*(..))")
public Object monitorPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
    long startTime = System.currentTimeMillis();
    Object result = joinPoint.proceed();
    long elapsedTime = System.currentTimeMillis() - startTime;
    
    System.out.println("方法 " + joinPoint.getSignature().getName() 
        + " 执行耗时: " + elapsedTime + "ms");
    return result;
}

事务管理场景[编辑 | 编辑源代码]

结合声明式事务使用环绕通知:

@Around("@annotation(org.springframework.transaction.annotation.Transactional)")
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 ex) {
        transactionManager.rollback(status);
        throw ex;
    }
}

数学表达[编辑 | 编辑源代码]

在AOP中,通知的执行可以形式化表示为: {Before(f)当 f 被调用前执行AfterReturning(f,r)当 f 成功返回 r 后执行AfterThrowing(f,e)当 f 抛出异常 e 后执行After(f)无论 f 如何结束都执行Around(f)完全控制 f 的执行流程

总结[编辑 | 编辑源代码]

Spring AOP的通知类型为开发者提供了灵活的横切关注点处理能力。通过合理组合这些通知,可以实现:

  • 非侵入式的功能增强
  • 清晰的职责分离
  • 可复用的通用逻辑

建议初学者从简单的前置通知后置通知开始实践,逐步掌握更复杂的环绕通知应用。