欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot中日志切面實(shí)現(xiàn)小結(jié)

 更新時(shí)間:2024年11月18日 10:06:33   作者:這個(gè)名字應(yīng)該沒人用吧  
本文介紹了SpringBoot中日志切面實(shí)現(xiàn)小結(jié),通過定義一個(gè)自定義注解和創(chuàng)建一個(gè)日志切面類,為方法添加日志記錄功能,感興趣的可以了解一下

在應(yīng)用開發(fā)中,日志記錄對于監(jiān)控、調(diào)試和追蹤用戶行為至關(guān)重要。Spring Boot 雖然內(nèi)置了強(qiáng)大的日志框架,但在某些情況下,我們可能需要更細(xì)粒度的日志管理。Spring AOP 提供了一種靈活的方式來實(shí)現(xiàn)方法級別的日志記錄,而無需侵入業(yè)務(wù)代碼。本文將介紹如何通過 Spring AOP 切面來實(shí)現(xiàn)這一功能。

什么是Spring AOP?

Spring AOP 是一個(gè)面向切面的編程(AOP)框架,它允許開發(fā)者將橫切關(guān)注點(diǎn)(如日志記錄、事務(wù)管理等)與業(yè)務(wù)邏輯分離。通過使用 Spring AOP,我們可以在不修改業(yè)務(wù)代碼的情況下,為應(yīng)用程序添加日志記錄功能。

Spring AOP 詳細(xì)可以看這篇文章  Spring AOP入門

日志切面的設(shè)計(jì)

在我們的示例中,我們定義了一個(gè) SysLog 注解,用于標(biāo)記需要記錄日志的方法。接著,我們創(chuàng)建了一個(gè)日志切面 LogAspect,它會(huì)攔截所有帶有 SysLog 注解的方法,并記錄日志信息。

SysLog 注解

首先,我們定義了一個(gè) SysLog 注解,它可以用來標(biāo)記需要記錄日志的方法:

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

這個(gè)注解非常簡單,它只有一個(gè) value 屬性,用于存儲(chǔ)日志的描述信息。

日志切面 LogAspect

接下來,我們創(chuàng)建了 LogAspect 切面類,它會(huì)攔截所有帶有 SysLog 注解的方法:

@Aspect
@Component
public class LogAspect {
    // 省略其他成員變量和方法

    @Around("@annotation(sysLog)")
    public Object logAround(ProceedingJoinPoint joinPoint, SysLog sysLog) throws Throwable {
        // 日志記錄邏輯
    }
}

在這個(gè)切面中,我們使用了 @Around 注解來定義一個(gè)環(huán)繞通知,它會(huì)在目標(biāo)方法執(zhí)行前后記錄日志信息。

日志記錄的實(shí)現(xiàn)

在 LogAspect 切面類中,我們實(shí)現(xiàn)了 logAround 方法,它會(huì)在目標(biāo)方法執(zhí)行前后記錄日志信息:

@Around("@annotation(sysLog)")
public Object logAround(ProceedingJoinPoint joinPoint, SysLog sysLog) throws Throwable {
    Log log = new Log();
    log.setTimestamp(new Date());
    log.setDescription(sysLog.value());
    log.setMethodName(joinPoint.getSignature().getName());
    log.setParameters(Arrays.toString(joinPoint.getArgs()));

    try {
        Object result = joinPoint.proceed();
        log.setLevel("INFO");
        log.setMessage("方法 " + joinPoint.getSignature().getName() + " 執(zhí)行成功。");
        return result;
    } catch (Exception e) {
        log.setLevel("ERROR");
        log.setMessage("方法 " + joinPoint.getSignature().getName() + " 執(zhí)行過程中發(fā)生異常。");
        log.setException(e.toString());
        throw e;
    } finally {
        logService.save(log);
    }
}

在這個(gè)環(huán)繞通知中,我們首先創(chuàng)建了一個(gè) Log 對象,并設(shè)置了日志的基本信息,如時(shí)間戳、描述、方法名和參數(shù)。然后,我們執(zhí)行目標(biāo)方法,并根據(jù)執(zhí)行結(jié)果記錄日志信息。如果目標(biāo)方法執(zhí)行過程中發(fā)生異常,我們會(huì)記錄異常信息。

測試

完整代碼

Maven依賴

在 pom.xml 文件中添加依賴:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

SQL腳本

創(chuàng)建日志表的 SQL 腳本:

DROP TABLE IF EXISTS `logs`;
CREATE TABLE `logs`  (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '描述',
  `level` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '日志級別',
  `timestamp` datetime NOT NULL COMMENT '時(shí)間戳',
  `message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '日志消息',
  `class_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '類名',
  `method_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '方法名',
  `parameters` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '參數(shù)',
  `user_identifier` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用戶標(biāo)識',
  `exception` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '異常信息',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '日志表' ROW_FORMAT = DYNAMIC;

日志實(shí)體類 Log

我們定義了一個(gè) Log 實(shí)體類,用于存儲(chǔ)日志信息:

/**
 * 日志實(shí)體類
 *
 * @author 王聞薪
 */
@Data
@TableName("logs")
public class Log implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 主鍵ID
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * 描述
     */
    @TableField("description")
    private String description;

    /**
     * 日志級別
     */
    @TableField("level")
    private String level;

    /**
     * 時(shí)間戳
     */
    @TableField("timestamp")
    private Date timestamp;

    /**
     * 日志消息
     */
    @TableField("message")
    private String message;

    /**
     * 類名
     */
    @TableField("class_name")
    private String className;

    /**
     * 方法名
     */
    @TableField("method_name")
    private String methodName;


    /**
     * 參數(shù)
     */
    @TableField("parameters")
    private String parameters;

    /**
     * 用戶標(biāo)識
     */
    @TableField("user_identifier")
    private String userIdentifier;

    /**
     * 異常信息
     */
    @TableField("exception")
    private String exception;

}

這個(gè)實(shí)體類映射到數(shù)據(jù)庫中的 logs 表,用于存儲(chǔ)日志的詳細(xì)信息。

切面代碼

日志切面類 LogAspect

package org.example.demo.aspectj;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.example.demo.annotation.SysLog;
import org.example.demo.entity.Log;
import org.example.demo.service.ILogService;
import org.example.demo.utils.TokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Date;

/**
 * 日志切面類
 * 用于攔截標(biāo)注有@SysLog注解的方法,并記錄日志信息。
 *
 * @author 王聞薪
 */
@Slf4j
@Aspect // 標(biāo)記為切面類
@Component // 將此切面類交給Spring管理
public class LogAspect {

    @Autowired
    private ILogService logService;

    @Autowired
    private TokenService tokenService;

    /**
     * 環(huán)繞通知
     * 攔截帶有@SysLog注解的方法,并在方法執(zhí)行前后進(jìn)行日志記錄。
     *
     * @param joinPoint 連接點(diǎn)對象,包含方法的調(diào)用信息。
     * @param sysLog 注解對象,包含日志描述信息。
     * @return 方法執(zhí)行結(jié)果。
     * @throws Throwable 可能拋出的異常。
     */
    @Around("@annotation(sysLog)")
    public Object logAround(ProceedingJoinPoint joinPoint, SysLog sysLog) throws Throwable {
        // 創(chuàng)建日志對象
        Log log = new Log();
        log.setLevel("INFO");
        log.setTimestamp(new Date());
        log.setUserIdentifier(getUserId().toString());
        log.setDescription(sysLog.value());
        // 記錄方法調(diào)用前的日志
        logBefore(joinPoint, log);

        try {
            // 繼續(xù)執(zhí)行目標(biāo)方法
            Object result = joinPoint.proceed();

            // 記錄方法調(diào)用后的日志
            logAfter(joinPoint, result, log);
            log.setMessage("方法 " + joinPoint.getSignature().getName() + " 執(zhí)行成功。");

            return result;
        } catch (Exception e) {
            // 記錄異常日志
            logException(joinPoint, e, log);
            log.setLevel("ERROR");
            log.setMessage("方法 " + joinPoint.getSignature().getName() + " 執(zhí)行過程中發(fā)生異常。");
            throw e; // 重新拋出異常
        } finally {
            // 保存日志到數(shù)據(jù)庫
            logService.save(log);
        }
    }

    /**
     * 記錄方法調(diào)用前的日志信息。
     *
     * @param joinPoint 連接點(diǎn)對象,包含方法的調(diào)用信息。
     * @param log 日志對象,用于存儲(chǔ)日志信息。
     */
    private void logBefore(ProceedingJoinPoint joinPoint, Log log) {
        log.setClassName(joinPoint.getSignature().getDeclaringTypeName());
        log.setMethodName(joinPoint.getSignature().getName());
        log.setParameters(Arrays.toString(joinPoint.getArgs()));
        log.setTimestamp(new Date()); // 設(shè)置日志時(shí)間
    }

    /**
     * 記錄方法調(diào)用后的日志信息。
     *
     * @param joinPoint 連接點(diǎn)對象,包含方法的調(diào)用信息。
     * @param result 方法執(zhí)行結(jié)果。
     * @param log 日志對象,用于存儲(chǔ)日志信息。
     */
    private void logAfter(ProceedingJoinPoint joinPoint, Object result, Log log) {
        log.setMessage(log.getMessage() + result);
    }

    /**
     * 記錄方法執(zhí)行過程中的異常信息。
     *
     * @param joinPoint 連接點(diǎn)對象,包含方法的調(diào)用信息。
     * @param e 捕獲的異常對象。
     * @param log 日志對象,用于存儲(chǔ)日志信息。
     */
    private void logException(ProceedingJoinPoint joinPoint, Exception e, Log log) {
        log.setException(e.toString());
        log.setMessage(log.getMessage() + " 異常信息:" + e.getMessage());
    }

    /**
     * 獲取當(dāng)前用戶ID。
     *
     * @return 用戶ID。
     */
    private Long getUserId() {
        return tokenService.getUserId();
    }
}

結(jié)論

通過使用 Spring AOP 和注解,我們可以靈活地為 Spring Boot 應(yīng)用程序添加日志記錄功能,而無需修改業(yè)務(wù)邏輯代碼。這不僅提高了代碼的可維護(hù)性,還使得日志記錄變得更加方便和強(qiáng)大。

到此這篇關(guān)于SpringBoot中日志切面實(shí)現(xiàn)小結(jié)的文章就介紹到這了,更多相關(guān)SpringBoot 日志切面內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論