最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot基于AOP的Controller實現(xiàn)統(tǒng)一日志打印的完整方案

 更新時間:2026年04月03日 08:43:18   作者:謝正元  
本文基于Spring?AOP實現(xiàn)一套無侵入、可配置、靈活擴展的Controller層統(tǒng)一日志打印方案,自動記錄接口全量信息,同時支持慢接口監(jiān)控告警,完全滿足開發(fā)排查問題的核心需求

在日常后端開發(fā)中,接口問題排查效率低是最常見的痛點之一:很多項目沒有統(tǒng)一的日志規(guī)范,Controller接口缺少請求URL、入?yún)ⅰ㈨憫Y(jié)果、執(zhí)行耗時等核心日志,導致線上報錯、接口異常時無法快速定位問題;如果手動在每個接口中打印日志,又會造成代碼冗余、維護成本高,還容易遺漏。

為了解決這個問題,本文基于Spring AOP實現(xiàn)一套無侵入、可配置、靈活擴展的Controller層統(tǒng)一日志打印方案,自動記錄接口全量信息,同時支持慢接口監(jiān)控告警,完全滿足開發(fā)排查問題的核心需求。

一、方案核心優(yōu)勢

  • 無侵入性:無需修改任何Controller業(yè)務代碼,通過切面統(tǒng)一處理日志邏輯
  • 全量信息:自動打印接口URL、請求方法、入?yún)?、響應結(jié)果、執(zhí)行耗時
  • 安全可靠:過濾Web核心對象,避免序列化異常
  • 靈活配置:慢接口閾值可動態(tài)調(diào)整,支持按需開關(guān)/裁剪日志
  • 慢接口監(jiān)控:自動識別超時接口,以WARN級別告警,助力性能優(yōu)化
  • 統(tǒng)一規(guī)范:所有接口日志格式一致,便于日志檢索和問題排查

二、環(huán)境依賴

項目基于Spring Boot開發(fā),只需引入3個核心依賴(Maven):

<!-- Spring AOP 核心依賴 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- FastJSON 用于參數(shù)序列化 -->
<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2</artifactId>
    <version>2.0.32</version>
</dependency>
<!-- Lombok 簡化日志開發(fā) -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

三、核心實現(xiàn)代碼

直接創(chuàng)建AOP日志切面類,復制即用,適配絕大多數(shù)Spring Boot項目:

package com.xm.kite.ztc.common.aspect;

import com.alibaba.fastjson2.JSONObject;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;

/**
 * AOP統(tǒng)一日志處理切面
 * 自動打印Controller層接口:URL、方法名、入?yún)?、響應結(jié)果、執(zhí)行耗時
 * 支持慢接口告警配置
 */
@Slf4j
@Aspect
@Component
public class LoggerHandler {

    /**
     * 慢接口閾值(單位:毫秒)
     * 從配置文件讀取,默認2000ms(2秒)
     */
    @Value("${method-logger.elapsed-time:2000}")
    private Long loggerHandlerElapsedTimeMs;

    /**
     * 切點:匹配指定包下所有Controller的所有方法
     * 可根據(jù)項目包路徑靈活修改?。。?
     */
    @Pointcut("execution(* com.xm.kite.ztc..controller..*.*(..))")
    public void allControllerMethods() {
    }

    /**
     * 環(huán)繞通知:包裹目標接口,執(zhí)行前后統(tǒng)一處理日志
     */
    @Around("allControllerMethods()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 1. 記錄接口開始時間
        long startTime = System.currentTimeMillis();

        // 2. 獲取Http請求對象,解析請求URL
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String requestUrl = request.getRequestURL().toString();

        // 3. 獲取當前接口的類、方法名
        Logger currentLogger = LoggerFactory.getLogger(joinPoint.getSignature().getDeclaringType());
        String methodName = joinPoint.getSignature().getName();

        // 4. 安全處理入?yún)ⅲ哼^濾HttpServletRequest/Response,避免序列化異常
        List<Object> safeArgs = new ArrayList<>();
        for (Object arg : joinPoint.getArgs()) {
            if (arg instanceof HttpServletRequest || arg instanceof HttpServletResponse) {
                safeArgs.add("[" + arg.getClass().getSimpleName() + "]");
            } else {
                safeArgs.add(arg);
            }
        }
        // 入?yún)⑿蛄谢癁镴SON
        String requestArgs = JSONObject.toJSONString(safeArgs);

        // 5. 打印【請求入?yún)ⅰ咳罩?
        currentLogger.info("請求開始 >>> url: {}, method: {}, args: {}", requestUrl, methodName, requestArgs);

        // 6. 執(zhí)行目標接口方法
        Object result = joinPoint.proceed();

        // 7. 計算接口耗時
        long elapsedTime = System.currentTimeMillis() - startTime;
        String responseResult = JSONObject.toJSONString(result);

        // 8. 分級打印【響應結(jié)果】日志:慢接口WARN告警,正常接口INFO打印
        if (elapsedTime > loggerHandlerElapsedTimeMs) {
            currentLogger.warn("請求結(jié)束【慢接口告警】>>> 閾值:{}ms, url: {}, method: {}, args: {}, result: {}, 耗時:{}ms",
                    loggerHandlerElapsedTimeMs, requestUrl, methodName, requestArgs, responseResult, elapsedTime);
        } else {
            currentLogger.info("請求結(jié)束 >>> url: {}, method: {}, args: {}, result: {}, 耗時:{}ms",
                    requestUrl, methodName, requestArgs, responseResult, elapsedTime);
        }

        return result;
    }
}

四、靈活配置(核心!支持自定義調(diào)整)

1. 配置慢接口閾值

application.yml/application.properties動態(tài)調(diào)整慢接口標準,無需修改代碼:

# 日志配置:慢接口閾值(單位:毫秒)
method-logger:
  elapsed-time: 1500  # 調(diào)整為1.5秒,根據(jù)項目需求修改

2. 靈活調(diào)整打印內(nèi)容(按需改造)

針對不同開發(fā)場景,可快速裁剪/擴展日志打印內(nèi)容,以下是常用擴展方案:

(1)添加請求IP、請求方式

// 獲取請求方式
String requestMethod = request.getMethod();
// 獲取客戶端IP
String clientIp = request.getRemoteAddr();
// 日志中新增打印
currentLogger.info("url: {}, ip: {}, requestType: {}, method: {}, args: {}", 
        requestUrl, clientIp, requestMethod, methodName, requestArgs);

(2)過濾敏感參數(shù)(密碼、手機號等)

// 改造入?yún)⑦^濾邏輯,隱藏敏感字段
for (Object arg : safeArgs) {
    if (arg instanceof UserDTO) {
        UserDTO user = (UserDTO) arg;
        user.setPassword("***"); // 密碼脫敏
    }
}

(3)日志總開關(guān)(按需開啟/關(guān)閉)

// 新增配置開關(guān)
@Value("${method-logger.enabled:true}")
private boolean loggerEnabled;

// 環(huán)繞通知中判斷
@Around("allControllerMethods()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
    if (!loggerEnabled) {
        return joinPoint.proceed(); // 關(guān)閉日志,直接執(zhí)行接口
    }
    // 原有日志邏輯...
}

(4)修改切點范圍

// 示例1:只打印指定包下的接口
@Pointcut("execution(* com.xm.kite.ztc.user.controller..*.*(..))")
// 示例2:只打印帶有@GetMapping注解的方法
@Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")

(5)關(guān)閉響應結(jié)果打?。ê喕罩荆?/p>

如果接口返回數(shù)據(jù)過大,可取消響應結(jié)果打?。?/p>

// 直接刪除result參數(shù),簡化日志
currentLogger.info("請求結(jié)束 >>> url: {}, 耗時:{}ms", requestUrl, elapsedTime);

五、代碼核心解析

  • 切點定義@Pointcut精準匹配項目中所有Controller接口,是AOP日志的生效范圍
  • 環(huán)繞通知@Around是核心,在接口執(zhí)行前后分別記錄請求、響應信息
  • 參數(shù)安全處理:過濾HttpServletRequest/Response對象,避免JSON序列化失敗
  • 日志分級:正常接口用INFO級別,慢接口用WARN級別告警,便于日志篩選
  • 動態(tài)配置:通過@Value注入配置參數(shù),支持環(huán)境差異化配置

六、日志效果展示

啟動項目后,調(diào)用任意Controller接口,控制臺會打印標準化日志:

# 正常接口
INFO  c.x.k.z.t.controller.UserController - 請求開始 >>> url: http://localhost:8080/user/get, method: getUser, args: {"id":1}
INFO  c.x.k.z.t.controller.UserController - 請求結(jié)束 >>> url: http://localhost:8080/user/get, method: getUser, args: {"id":1}, result: {"code":200,"data":{"name":"張三"}}, 耗時:12ms

# 慢接口告警
WARN  c.x.k.z.t.controller.OrderController - 請求結(jié)束【慢接口告警】>>> 閾值:2000ms, url: http://localhost:8080/order/list, method: getOrderList, args: {"page":1}, result: {...}, 耗時:2560ms

示例:

七、注意事項

  • AOP生效:Spring Boot 2.x+引入spring-boot-starter-aop后,無需額外配置 @EnableAspectJAutoProxy,自動開啟AOP
  • 序列化問題:如果實體類存在循環(huán)引用,F(xiàn)astJSON會自動忽略,無需擔心報錯
  • 性能影響:日志打印為輕量級操作,對接口性能無明顯損耗
  • 包路徑修改:必須將切點中的包路徑com.xm.kite.ztc改為自己項目的實際包路徑,否則日志不生效

總結(jié)

這套基于Spring AOP的統(tǒng)一日志方案,徹底解決了接口排查無日志、手動打印日志冗余的問題,同時具備極高的靈活性:開發(fā)人員可根據(jù)需求自由調(diào)整打印內(nèi)容、開關(guān)日志、配置慢接口閾值。

方案無侵入、易擴展、標準化,完全適配企業(yè)級Spring Boot項目,大幅提升線上問題排查效率和接口性能監(jiān)控能力。

到此這篇關(guān)于SpringBoot基于AOP的Controller實現(xiàn)統(tǒng)一日志打印的完整方案的文章就介紹到這了,更多相關(guān)SpringBoot AOP打印日志內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

遂川县| 洛阳市| 太仆寺旗| 东丽区| 光泽县| 屯门区| 剑川县| 池州市| 武宁县| 读书| 康乐县| 马山县| 合肥市| 甘孜县| 安阳市| 迁安市| 栖霞市| 内丘县| 石门县| 新宁县| 绩溪县| 丰台区| 迁西县| 陈巴尔虎旗| 福清市| 清河县| 钟祥市| 万安县| 当涂县| 嘉鱼县| 体育| 中山市| 邮箱| 嘉祥县| 锦州市| 明溪县| 宿松县| 芜湖市| 盘锦市| 芜湖市| 西盟|