Spring @Around注解使用及说明

 更新时间:2025年12月26日 08:36:00   作者:百***5588  
@Around是SpringAOP中的一个注解,用于定义环绕通知,可以在方法执行前后执行自定义逻辑,并控制方法的执行或修改返回值, SpringAOP通过代理对象实现环绕通知,匹配切入点,创建代理并执行环绕通知,@Around注解的应用场景广泛

@Around是 Spring AOP(面向切面编程)中的一个注解,它用于定义一个环绕通知(Around Advice)。

环绕通知是 AOP 中最强大的一种通知类型,因为它能够在方法执行之前和之后都执行自定义的逻辑,并且可以控制方法是否继续执行或改变其返回值。

@Around注解的基本用法

要使用@Around注解,你需要先定义一个切面(Aspect),然后在该切面中使用@Around注解来标注一个方法,该方法将作为环绕通知。环绕通知方法必须接受一个ProceedingJoinPoint类型的参数,这个参数提供了对正在执行的方法的访问。

以下是一个简单的例子:

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 MyAroundAdvice {

    @Around("execution(* com.example.service.*.*(..))")
    public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
        // 在方法执行之前的逻辑
        System.out.println("Before method execution");

        try {
            Object result = pjp.proceed(); // 执行目标方法
            // 在方法执行之后的逻辑
            System.out.println("After method execution");
            return result; // 返回目标方法的执行结果
        } catch (Throwable throwable) {
            // 处理异常
            System.out.println("Exception occurred: " + throwable.getMessage());
            throw throwable; // 重新抛出异常
        }
    }
}

@Around注解的工作机制

  1. 匹配切入点@Around注解的值是一个切入点表达式(Pointcut Expression),它指定了哪些方法将被这个环绕通知拦截。在上面的例子中,切入点表达式"execution(* com.example.service.*.*(..))"匹配了com.example.service包下所有类的所有方法。

  2. 创建代理:Spring AOP 会在运行时为匹配到的方法创建代理对象。当这些方法被调用时,实际上调用的是代理对象的方法。

  3. 执行环绕通知:当代理对象的方法被调用时,Spring AOP 会先执行环绕通知中的逻辑。在环绕通知中,你可以通过调用**ProceedingJoinPointproceed**方法来执行目标方法。你也可以选择不调用proceed方法,从而阻止目标方法的执行。

  4. 处理返回值和异常:环绕通知可以获取目标方法的返回值,并在必要时进行修改。同时,它也可以捕获目标方法抛出的异常,并进行相应的处理。

以下是一些常见的@Around注解应用场景:

  1. 日志记录:在目标方法执行之前和之后记录日志,可以帮助开发者了解方法的执行流程、输入参数、返回值以及执行时间等信息。这对于调试和监控应用程序的状态非常有帮助。

  2. 性能监控:通过在目标方法执行前后记录时间戳,可以计算出方法的执行时间。这对于性能优化和瓶颈识别非常重要,可以帮助开发者找出需要优化的代码段。

  3. 事务管理:在目标方法执行之前开启一个事务,并在方法执行成功后提交事务;如果方法执行失败,则回滚事务。这样可以确保数据的一致性和完整性。

  4. 缓存管理:在目标方法执行之前检查缓存中是否存在所需的数据;如果存在,则直接返回缓存中的数据,避免重复执行耗时的方法;如果不存在,则执行方法并将结果存入缓存中。

  5. 权限检查:在目标方法执行之前检查当前用户是否具有执行该方法的权限;如果没有权限,则抛出异常或返回错误提示,从而保护系统的安全性。

  6. 异常处理:捕获目标方法抛出的异常,并进行统一处理,如记录异常日志、发送报警通知或返回友好的错误提示给用户。这可以提高系统的健壮性和用户体验。

  7. 输入参数校验:在目标方法执行之前对输入参数进行校验,确保参数的有效性和合法性。如果参数无效或不合法,则抛出异常或返回错误提示,避免执行无效的操作。

  8. 结果后处理:在目标方法执行之后对返回结果进行后处理,如格式化数据、转换数据类型或添加额外的信息。这可以满足不同的业务需求和数据展示要求。

综上所述,@Around注解在Spring AOP中具有广泛的应用场景,它能够帮助开发者在不修改目标方法代码的情况下实现各种复杂的功能和逻辑。通过合理地使用@Around注解,可以提高代码的可读性、可维护性和可扩展性。

@Around 注解常用场景实例

权限校验

以下是一个使用@Around注解进行权限校验的示例代码:

@Around("@annotation(authCheck)")
public Object doInterceptor(ProceedingJoinPoint joinPoint, AuthCheck authCheck) throws Throwable {
    String mustRole = authCheck.mustRole();
    RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
    HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
    User loginUser = userService.getLoginUser(request);
    if (!loginUser.hasRole(mustRole)) {
        throw new AccessDeniedException("用户没有权限执行此操作");
    }
    return joinPoint.proceed(); // 继续执行目标方法
}

在这个示例中,doInterceptor方法会在被@AuthCheck注解标记的方法执行前后运行。首先检查用户是否有足够的权限,如果没有权限则抛出异常,否则继续执行目标方法。

日志记录和性能监控

以下是一个使用@Around注解的具体实例,该实例展示了如何在Spring AOP中实现日志记录和性能监控的功能。

首先,我们需要定义一个切面类,并在其中使用@Around注解来标注环绕通知方法。

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 LoggingAndPerformanceAspect {

    @Around("execution(* com.example.service.*.*(..))")
    public Object logAndMeasureExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        // 记录方法开始执行的时间
        long startTime = System.currentTimeMillis();

        // 记录日志:方法开始执行
        System.out.println("Method " + joinPoint.getSignature().getName() + " is starting with arguments: " + Arrays.toString(joinPoint.getArgs()));

        try {
            // 执行目标方法
            Object result = joinPoint.proceed();

            // 记录方法执行结束的时间
            long endTime = System.currentTimeMillis();

            // 记录日志:方法执行结束,并输出执行时间
            System.out.println("Method " + joinPoint.getSignature().getName() + " executed in " + (endTime - startTime) + " milliseconds with result: " + result);

            // 返回目标方法的执行结果
            return result;
        } catch (Throwable throwable) {
            // 记录异常日志
            System.out.println("Exception occurred in method " + joinPoint.getSignature().getName() + ": " + throwable.getMessage());

            // 重新抛出异常,以便上层调用者处理
            throw throwable;
        }
    }
}

在这个例子中,LoggingAndPerformanceAspect是一个切面类,它包含了一个使用@Around注解标注的环绕通知方法logAndMeasureExecutionTime。这个方法会在匹配到的方法执行之前和之后分别记录日志,并测量方法的执行时间。

接下来,我们需要确保Spring容器能够识别这个切面类,并将其应用到相应的目标方法上。通常,这可以通过在Spring配置文件中启用AOP自动代理或者通过@EnableAspectJAutoProxy注解来实现。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {

    // 其他Bean定义...

    // 确保LoggingAndPerformanceAspect被Spring容器管理
    @Bean
    public LoggingAndPerformanceAspect loggingAndPerformanceAspect() {
        return new LoggingAndPerformanceAspect();
    }
}

现在,当Spring容器中的任何匹配到切入点表达式"execution(* com.example.service.*.*(..))"的方法被执行时,logAndMeasureExecutionTime环绕通知都会被触发,从而记录日志和测量执行时间。

例如,如果你有一个服务类MyService,其中有一个方法doSomething,那么当这个方法被调用时,你会在控制台看到类似以下的输出:

Method doSomething is starting with arguments: [...]
Method doSomething executed in XXX milliseconds with result: ...

这样,你就成功地使用@Around注解实现了日志记录和性能监控的功能。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 解析Spring中面向切面编程

    解析Spring中面向切面编程

    如果说 IoC 是 Spring 的核心,那么面向切面编程就是 Spring 最为重要的功能之一了,在数据库事务中切面编程被广泛使用
    2021-06-06
  • java中有关构造方法中的输出

    java中有关构造方法中的输出

    这篇文章主要介绍了java中有关构造方法中的输出,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • Mybatis-plus配置之日期时间自动填充实践

    Mybatis-plus配置之日期时间自动填充实践

    本文介绍如何使用MyBatis-Plus的MetaObjectHandler接口实现新增和更新时间的自动填充,通过继承抽象类、添加注解及处理版本兼容性,简化开发流程并减少手动操作
    2025-08-08
  • 关于SpringBoot单元测试(cobertura生成覆盖率报告)

    关于SpringBoot单元测试(cobertura生成覆盖率报告)

    这篇文章主要介绍了关于SpringBoot单元测试(cobertura生成覆盖率报告),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • MyBatis批量插入(insert)数据操作

    MyBatis批量插入(insert)数据操作

    本文给大家分享MyBatis批量插入(insert)数据操作知识,非常不错,具有参考借鉴价值,感兴趣的朋友一起学习吧
    2016-06-06
  • Mybatis 返回值类型和参数传递的配置方法

    Mybatis 返回值类型和参数传递的配置方法

    在 MyBatis 中,返回值类型和参数传递是 Mapper 接口中至关重要的两个方面,正确理解和使用它们可以帮助我们高效、准确地进行数据库操作,接下来通过本文给大家介绍Mybatis 返回值类型和参数传递的配置方法,感兴趣的朋友跟随小编一起看看吧
    2024-08-08
  • 在SpringBoot项目中整合拦截器的详细步骤

    在SpringBoot项目中整合拦截器的详细步骤

    在系统中经常需要在处理用户请求之前和之后执行一些行为,例如检测用户的权限,或者将请求的信息记录到日志中,即平时所说的"权限检测"及"日志记录",下面这篇文章主要给大家介绍了关于在SpringBoot项目中整合拦截器的相关资料,需要的朋友可以参考下
    2022-09-09
  • java+vue3+el-tree实现树形结构操作代码

    java+vue3+el-tree实现树形结构操作代码

    基于springboot + vue3 elementPlus实现树形结构数据的添加、删除和页面展示,本文通过示例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2024-06-06
  • java 高并发中volatile的实现原理

    java 高并发中volatile的实现原理

    这篇文章主要介绍了java 高并发中volatile的实现原理的相关资料,在多线程并发编程中synchronized和Volatile都扮演着重要的角色,Volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的“可见性”,需要的朋友可以参考下
    2017-03-03
  • 详解Java并发编程之原子类

    详解Java并发编程之原子类

    这篇文章主要为大家介绍了Java并发编程之原子类介绍,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04

最新评论