详解SpringBoot AOP 拦截器(Aspect注解方式)

下面是详解 SpringBoot AOP 拦截器(Aspect 注解方式)的完整攻略,并附带两条示例。

什么是 AOP

AOP(Aspect Oriented Programming,面向切面编程)是一种面向对象编程的编程思想,AOP 的思想是将系统分解为多个功能单元,称之为“切面”(Aspect),然后编写代码来定义这些切面。这些切面可以跨越多个类,不仅仅是某个类的某个方法。AOP 主要用于解决系统中的横切关注点(Crosscutting Concerns)问题,比如日志记录、性能统计、安全控制、事务处理等。

什么是 SpringBoot AOP 拦截器(Aspect 注解方式)

SpringBoot AOP 在 AOP 基础上,采用了拦截器的方式来实现对方法的切面编程。SpringBoot AOP 拦截器可以根据注解设置来实现不同的切面,常见的切面有:

  • @Before:在方法之前执行。
  • @After:在方法之后执行。
  • @AfterReturning:在方法正常返回之后执行。
  • @AfterThrowing:在方法抛出异常之后执行。

SpringBoot AOP 拦截器(Aspect 注解方式)的实现步骤

下面是 SpringBoot AOP 拦截器(Aspect 注解方式)的实现步骤:

步骤一:创建一个自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
    String value() default "";
}

步骤二:编写 AOP 切面代码

@Aspect
@Component
@Slf4j
public class LogAspect {
    @Around("@annotation(com.example.demo.annotation.Log)")
    public Object logRecord(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object result = null;
        try {
            // 方法执行前
            String className = proceedingJoinPoint.getTarget().getClass().getName();
            String methodName = proceedingJoinPoint.getSignature().getName();
            log.info("Class Name: {}, Method Name:{}", className, methodName);
            Object[] args = proceedingJoinPoint.getArgs();
            for (Object arg : args) {
                log.info("Args: {}", arg);
            }
            result = proceedingJoinPoint.proceed(args);
            // 方法正常返回
            log.info("Result:{}", result);
        } catch (Throwable throwable) {
            // 方法执行异常
            log.error("Method Execution Error:{}", throwable.getMessage());
            throw throwable;
        }
        return result;
    }
}

步骤三:在需要切面的方法上添加自定义注解

@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @Log(value = "查询用户信息")
    @GetMapping("/user/get/{id}")
    public UserVO getUserById(@PathVariable("id") Long id) {
        return userService.getUserById(id);
    }
}

示例一:记录用户操作日志

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserOperateLog {
    String value() default "";
}

@Aspect
@Component
@Slf4j
public class UserOperateLogAspect {
    @Autowired
    private UserOperateLogService userOperateLogService;

    @Around("@annotation(com.example.demo.annotation.UserOperateLog)")
    public Object userOperateLogRecord(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object result = null;
        try {
            // 方法执行前
            MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
            UserOperateLog userOperateLogAnn = signature.getMethod().getAnnotation(UserOperateLog.class);
            String operation = userOperateLogAnn.value();
            String className = proceedingJoinPoint.getTarget().getClass().getName();
            String methodName = proceedingJoinPoint.getSignature().getName();
            log.info("Class Name: {}, Method Name:{}, Operation: {}", className, methodName, operation);

            // 记录用户操作日志
            User user = SessionUtils.getCurrentUser();
            if (user != null) {
                UserOperateLog userOperateLog = new UserOperateLog();
                userOperateLog.setUserId(user.getId());
                userOperateLog.setUserName(user.getName());
                userOperateLog.setOperation(operation);
                userOperateLog.setOperateTime(new Date());
                userOperateLogService.saveUserOperateLog(userOperateLog);
            }

            Object[] args = proceedingJoinPoint.getArgs();
            result = proceedingJoinPoint.proceed(args);
            // 方法正常返回
            log.info("Result:{}", result);
        } catch (Throwable throwable) {
            // 方法执行异常
            log.error("Method Execution Error:{}", throwable.getMessage());
            throw throwable;
        }
        return result;
    }
}

@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @UserOperateLog(value = "查询用户信息")
    @GetMapping("/user/get/{id}")
    public UserVO getUserById(@PathVariable("id") Long id) {
        return userService.getUserById(id);
    }
}

示例二:时间统计

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TimeCount {
    String value() default "";
}

@Aspect
@Component
@Slf4j
public class TimeCountAspect {

    @Around("@annotation(com.example.demo.annotation.TimeCount)")
    public Object timeCount(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object result = null;
        try {
            // 方法执行前
            MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
            TimeCount timeCountAnn = signature.getMethod().getAnnotation(TimeCount.class);
            String operation = timeCountAnn.value();
            long startTime = System.currentTimeMillis();
            result = proceedingJoinPoint.proceed();
            long endTime = System.currentTimeMillis();
            log.info("Operation: {},TimeCost: {}ms", operation, endTime - startTime);
        } catch (Throwable throwable) {
            // 方法执行异常
            log.error("Method Execution Error:{}", throwable.getMessage());
            throw throwable;
        }
        return result;
    }
}

@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @TimeCount(value = "查询用户信息")
    @GetMapping("/user/get/{id}")
    public UserVO getUserById(@PathVariable("id") Long id) {
        return userService.getUserById(id);
    }
}

以上就是详解 SpringBoot AOP 拦截器(Aspect 注解方式)的完整攻略以及两条示例。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解SpringBoot AOP 拦截器(Aspect注解方式) - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • spring boot打包成war包的页面如何存放

    将Spring Boot应用程序打包成WAR包可以让我们将应用程序部署到支持WAR包的应用服务器中。在打包成WAR包时,需要注意如何存放静态页面资源。下面是一个完整的攻略: 1. 修改pom.xml文件 首先需要将pom.xml文件中的打包方式由jar改为war。在pom.xml文件中添加以下代码: <packaging>war</pack…

    Java 2023年6月16日
    00
  • 解决mybatis plus 驼峰式命名规则问题

    当我们使用 MyBatis-Plus 进行开发时,如果数据库中的表和列采用了下划线命名法,则需要搭配驼峰式命名法进行开发,这个过程中就需要解决 MyBatis-Plus 驼峰式命名规则问题。 以下是解决 MyBatis-Plus 驼峰式命名规则问题的完整攻略: 1. 配置文件中开启驼峰命名法 在 MyBatis-Plus 中,我们可以通过在配置文件中开启驼峰…

    Java 2023年5月20日
    00
  • JSP实现带查询条件的通用分页组件

    JSP 实现带查询条件的通用分页组件的完整攻略,主要分以下三个步骤: 在前端页面搭建分页组件的基本框架 在后台编写分页查询的 SQL 语句,实现数据的分页查询 前后端的数据交互和页面渲染 下面我们来详细讲解这三个步骤。 步骤一:前端页面搭建分页组件的基本框架 在前端页面,我们需要搭建一个分页组件的基本框架,包括必要的 HTML 结构和样式,以及 JavaSc…

    Java 2023年6月15日
    00
  • jsp+jdbc实现连接数据库的方法

    下面我将详细讲解使用JSP和JDBC连接数据库的实现方法。 确认需求 首先需要明确自己的需求,比如需要连接的数据库的名称、表格的结构以及需要进行什么样的操作等等。此处以连接MySQL数据库为例,假设需要查询表格中所有用户的信息。 准备工作 在进行连接数据库之前,需要完成以下准备工作: 确认数据库的JDBC驱动版本,下载对应版本的JDBC驱动程序。 将驱动程序…

    Java 2023年6月15日
    00
  • java 数组转list的两种方式

    Java 数组转 List 的方式有两种,分别为使用 Arrays.asList() 和通过遍历数组进行转换。下面将会对这两种方式进行详细讲解。 使用 Arrays.asList() Arrays.asList() 方法可以方便地将数组转换为 List,代码如下所示: String[] array = {"a", "b&quot…

    Java 2023年5月26日
    00
  • Java如何从json字符串中获取某个值详解

    下面是“Java如何从json字符串中获取某个值”的完整攻略: 1. 导入相关包和类库 在Java中,我们可以使用相关的包和类库来操作JSON格式的数据。常用的JSON处理库有: Gson Jackson FastJson 具体使用哪个库可以根据自己的需要和喜好选择。这里以Jackson为例,需要导入以下依赖: <dependency> <…

    Java 2023年5月26日
    00
  • Java实现购物管理系统

    Java实现购物管理系统攻略 1. 确定项目需求和功能 在 Java 实现购物管理系统之前,首先需要确定项目的需求和功能,包括: 用户登录和注册 商品浏览和搜索 商品添加、修改和删除 购物车功能 订单生成和支付 在确定了以上需求和功能之后,我们可以进行后续开发工作。 2. 创建数据库和数据表 为了存储商品信息、用户信息、订单信息等数据,我们需要创建相应的数据…

    Java 2023年5月18日
    00
  • IntelliJ IDEA 2020.3 EAP5:引入 ML 编码,Git Stage 支持

    下面我来为您详细讲解“IntelliJ IDEA 2020.3 EAP5:引入 ML 编码,Git Stage 支持”的完整攻略。 什么是IntelliJ IDEA 2020.3 EAP5 IntelliJ IDEA是一款由JetBrains公司开发的Java集成开发环境。2020.3是其最新版本,而EAP5是该版本的一个预览版,其中包含了一些新的特性和改进…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部