日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

SpringBoot中使用AOP打印接口日志的方法(转载)

發布時間:2025/3/20 javascript 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringBoot中使用AOP打印接口日志的方法(转载) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

AOP 是 Aspect Oriented Program (面向切面)的編程的縮寫。他是和面向對象編程相對的一個概念。在面向對象的編程中,我們傾向于采用封裝、繼承、多態等概念,將一個個的功能在對象中來實現。但是,我們在實際情況中也發現,會有另外一種需求就是一類功能在很多對象的很多方法中都有需要。例如有一些對數據庫訪問的方法有事務管理的需求,有很多方法中要求打印日志。按照面向對象的方式,那么這些相同的功能要在很多地方來實現或者在很多地方來調用。這就非常繁瑣并且和這些和業務不相關的需求耦合太緊密了。所以后來就出現了面向切面的編程來解決這一類問題,并對面向對象的編程做了很好的補充

概念

要很好的理解面向切面的編程,先要理解 AOP 的一些概念。在 Java 中 AspectJ 比較完整的實現了 AOP 的功能,但是使用起來也比較復,所以這里主要是討論 Spring 的 AOP 。Spring AOP 采用簡單夠用的原則,實現了 AOP 的核心功能。下面先說說 AOP 中的具體概念

  • Aspect:方面。一個可以切入多個類的關注點。這個關注點實現了我們前面說的具體的業務功能。例如打印日志,進行數據庫的事務管理等。
  • Joint point:被切入點。是指具體要實現前面所說的例如打印日志,數據庫事務管理的被切入的點。也就是通過 AOP 將切面功能動態加入進去的程序位置。在 Spring AOP 里面這個指的都是某個方法
  • Pointcut:切點。用來指明如何通過規則匹配 Joint point。這個規則是一個表達式。在 Spring 中,默認使用的是 AspectJ 的 pointcut 表達式語言
  • Advice:指明在一個切入點的不同位置上采取的動作。例如對于一個數據庫訪問事務管理來說,在進入方法后要開啟事務,在方法結束前要提交事務,在發生錯誤的時候要回滾事務。這屬于三個不同的 Advice,要分別進行實現。Advice 通常和具體的 Pointcut 關聯在一起。
  • AOP proxy:AOP 代理。用來實現將 Advice 功能動態加入到 Pointcut 的方法。在 Spring 的 AOP 中采用動態代理和 CGLIB 代理的方式來實現。而 AspectJ 則采用了特定編譯器侵入字節碼的方式來實現。
  • SprinBoot AOP 實現

    前面我們已經用好幾章講述了 SpringBoot 的基本使用。那么這里我們就用 SpringBoot 和 AOP 結合來實現一個輸出所有 Rest 接口輸入參數和返回參數的日志的功能。

    實現 rest 服務功能。

    根據前面的文章,我們先建立一個 SpingBoot 的工程如下圖所示

    demo 工程

    SpringBoot 項目配置

    我們對 SpringBoot 項目配置如下

    ?
    1 2 3 4 5 6 7 8 9 10 11 12 server: ?port: 3030 ?servlet: ??context-path: /aop-demo spring: ?jackson: ??date-format: yyyy-MM-dd HH:mm:ss ??serialization: ???indent-output: true logging: ?level: ??com.yanggch: debug

    其中 jackson 相關配置是為了將對象輸出成 json 字符串后能夠格式化輸出

    先在我們要通過 AOP 功能將所有 Rest 接口的輸入參數和返回結果輸出到日志中。

    實現 Web Aop 功能。

    @Aspect
    @Component
    public class WebLogAspect {
    private static Logger log = LoggerFactory.getLogger(WebLogAspect.class);

    private final ObjectMapper mapper;

    @Autowired
    public WebLogAspect(ObjectMapper mapper) {
    this.mapper = mapper;
    }

    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public void webLog() {
    }

    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) {
    for (Object object : joinPoint.getArgs()) {
    if (
    object instanceof MultipartFile
    || object instanceof HttpServletRequest
    || object instanceof HttpServletResponse
    ) {
    continue;
    }
    try {
    if (log.isInfoEnabled()) {
    log.info(
    joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName()
    + " : request parameter : " + mapper.writeValueAsString(object)
    );
    }
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }

    @AfterReturning(returning = "response", pointcut = "webLog()")
    public void doAfterReturning(Object response) throws Throwable {
    if (response != null) {
    log.info("response parameter : " + mapper.writeValueAsString(response));
    }
    }
    }

    這里有幾個需要注意的地方,

  • 需要在類上聲明 org.aspectj.lang.annotation.Aspect 注解。
  • 需要通過方法上的 org.aspectj.lang.annotation.Pointcut 注解聲明一個 Pointcut ,用來指明要在哪些方法切入。我們的 rest 接口都有 org.springframework.web.bind.annotation.RequestMapping 注解,所以我們這里就用了 "@annotation(org.springframework.web.bind.annotation.RequestMapping)" 表達式來指明。
  • 通過 Advice 相關注解來說明在切入方法的什么位置做什么事。這里用 org.aspectj.lang.annotation.Before
  • 這個實現是指明在所有具備 org.springframework.web.bind.annotation.RequestMapping 注解的方法上,方法進入后打印入口參數。方法返回后,打印返回參數。
  • 測試

    在前臺通過 postman 發起請求,后臺日志輸入結果如下

    2018-05-27 19:58:42.941 DEBUG 86072 --- [nio-3030-exec-4] c.yanggch.demo.aop.comment.WebLogAspect? : com.yanggch.demo.aop.web.SecurityApi.login : request parameter : {
    ? "account" : "yanggch",
    ? "pwd" : "123456"
    }
    2018-05-27 19:58:42.941 DEBUG 86072 --- [nio-3030-exec-4] c.yanggch.demo.aop.comment.WebLogAspect? : com.yanggch.demo.aop.web.SecurityApi.login : request parameter : 2001
    2018-05-27 19:58:42.942 DEBUG 86072 --- [nio-3030-exec-4] c.yanggch.demo.aop.comment.WebLogAspect? : response parameter : {
    ? "shopId" : 2001,
    ? "account" : "yanggch",
    ? "pwd" : "123456",
    ? "loginTime" : "2018-05-27 11:58:42"
    }
    2018-05-27 19:58:45.796 DEBUG 86072 --- [nio-3030-exec-5] c.yanggch.demo.aop.comment.WebLogAspect? : com.yanggch.demo.aop.web.SecurityApi.echo : request parameter : "yanggch"
    2018-05-27 19:58:45.796 DEBUG 86072 --- [nio-3030-exec-5] c.yanggch.demo.aop.comment.WebLogAspect? : response parameter : "hello,yanggch"

    由此可見,我們雖然沒有在 rest 接口方法中寫輸出日志的代碼,但是通過 AOP 的方式可以自動的給各個 rest 入口方法中添加上輸出入口參數和返回參數的代碼并正確執行。

    其他說明

    前面提到了 Advice 的類型和 Pointcut 的 AOP 表達式語言。具體參考如下。

    Advice 類型

  • before advice 在方法執行前執行。
  • after returning advice 在方法執行后返回一個結果后執行。
  • after throwing advice 在方法執行過程中拋出異常的時候執行。
  • Around advice 在方法執行前后和拋出異常時執行,相當于綜合了以上三種通知。
  • AOP 表達式語言

    1、方法參數匹配
    @args()

    2、方法描述匹配
    execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
    其中 returning type pattern,name pattern, and parameters pattern是必須的.
    . ret-type-pattern:可以為表示任何返回值,全路徑的類名等.
    *. name-pattern:指定方法名, *代表所有
    .set代表以set開頭的所有方法.
    . parameters pattern:指定方法參數(聲明的類型),(..)代表所有參數,()代表一個參數
    . (,String)代表第一個參數為任何值,第二個為String類型.

    3、當前AOP代理對象類型匹配

    4、目標類匹配
    @target()
    @within()

    5、標有此注解的方法匹配
    @annotation()

    ps:沒有打印出來的看看自己設置的日志級別

    轉載于:https://www.cnblogs.com/liukunjava/p/9566965.html

    總結

    以上是生活随笔為你收集整理的SpringBoot中使用AOP打印接口日志的方法(转载)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。