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

SpringBoot中使用AOP打印接口日志的方法

 更新時間:2018年05月28日 10:25:23   作者:高超楊  
本篇文章主要介紹了SpringBoot中使用AOP打印接口日志的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

前言

AOP 是 Aspect Oriented Program (面向切面)的編程的縮寫。他是和面向?qū)ο缶幊滔鄬Φ囊粋€概念。在面向?qū)ο蟮木幊讨?,我們傾向于采用封裝、繼承、多態(tài)等概念,將一個個的功能在對象中來實現(xiàn)。但是,我們在實際情況中也發(fā)現(xiàn),會有另外一種需求就是一類功能在很多對象的很多方法中都有需要。例如有一些對數(shù)據(jù)庫訪問的方法有事務(wù)管理的需求,有很多方法中要求打印日志。按照面向?qū)ο蟮姆绞?,那么這些相同的功能要在很多地方來實現(xiàn)或者在很多地方來調(diào)用。這就非常繁瑣并且和這些和業(yè)務(wù)不相關(guān)的需求耦合太緊密了。所以后來就出現(xiàn)了面向切面的編程來解決這一類問題,并對面向?qū)ο蟮木幊套隽撕芎玫难a充

概念

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

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

SprinBoot AOP 實現(xiàn)

前面我們已經(jīng)用好幾章講述了 SpringBoot 的基本使用。那么這里我們就用 SpringBoot 和 AOP 結(jié)合來實現(xiàn)一個輸出所有 Rest 接口輸入?yún)?shù)和返回參數(shù)的日志的功能。

實現(xiàn) rest 服務(wù)功能。

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

demo 工程

SpringBoot 項目配置

我們對 SpringBoot 項目配置如下

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 相關(guān)配置是為了將對象輸出成 json 字符串后能夠格式化輸出

實現(xiàn)一個 rest 接口的 Controller 類

在這里,我們實現(xiàn)兩個 rest 接口。一個是返回 hello 信息。一個是根據(jù)輸入返回登錄信息。

package com.yanggch.demo.aop.web;

import com.yanggch.demo.aop.domain.LoginEntity;
import com.yanggch.demo.aop.domain.SecurityEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

/**
 * 安全相關(guān) rest 服務(wù)
 *
 * @author : 楊高超
 * @since : 2018-05-27
 */
@RestController
@RequestMapping("/api/v1/security")
public class SecurityApi {
  @RequestMapping(value = "/login/{shopId}", method = RequestMethod.POST)
  public SecurityEntity login(@RequestBody LoginEntity loginEntity, @PathVariable Long shopId) {
    SecurityEntity securityEntity = new SecurityEntity();
    securityEntity.setShopId(shopId);
    securityEntity.setAccount(loginEntity.getAccount());
    securityEntity.setPwd(loginEntity.getPwd());
    securityEntity.setLoginTime(new Date());
    return securityEntity;
  }

  @RequestMapping(value = "/echo/{name}", method = RequestMethod.GET)
  public String login(@PathVariable String name) {
    return "hello," + name;
  }
}

先在我們要通過 AOP 功能將所有 Rest 接口的輸入?yún)?shù)和返回結(jié)果輸出到日志中。

實現(xiàn) Web Aop 功能。

package com.yanggch.demo.aop.comment;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * web 接口日志
 *
 * @author : 楊高超
 * @since : 2018-05-27
 */
@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.isDebugEnabled()) {
          log.debug(
            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.debug("response parameter : " + mapper.writeValueAsString(response));
    }
  }
}

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

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

測試

在前臺通過 postman 發(fā)起請求,后臺日志輸入結(jié)果如下

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 入口方法中添加上輸出入口參數(shù)和返回參數(shù)的代碼并正確執(zhí)行。

其他說明

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

Advice 類型

  1. before advice 在方法執(zhí)行前執(zhí)行。
  2. after returning advice 在方法執(zhí)行后返回一個結(jié)果后執(zhí)行。
  3. after throwing advice 在方法執(zhí)行過程中拋出異常的時候執(zhí)行。
  4. Around advice 在方法執(zhí)行前后和拋出異常時執(zhí)行,相當(dāng)于綜合了以上三種通知。

AOP 表達式語言

1、方法參數(shù)匹配
@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:指定方法參數(shù)(聲明的類型),(..)代表所有參數(shù),()代表一個參數(shù)
. (,String)代表第一個參數(shù)為任何值,第二個為String類型.

3、當(dāng)前AOP代理對象類型匹配

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

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

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Springboot整合WebSocket 實現(xiàn)聊天室功能

    Springboot整合WebSocket 實現(xiàn)聊天室功能

    WebSocket是一種在單個TCP連接上進行全雙工通信的協(xié)議,本文主要介紹了Springboot整合WebSocket實現(xiàn)聊天室功能,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-05-05
  • Java中的HashMap為什么會產(chǎn)生死循環(huán)

    Java中的HashMap為什么會產(chǎn)生死循環(huán)

    這篇文章主要介紹了Java中的HashMap為什么會產(chǎn)生死循環(huán),HashMap?死循環(huán)是一個比較常見、比較經(jīng)典的問題,下面文章我們就來徹底理解死循環(huán)的原因。需要的小伙伴可以參考一下
    2022-05-05
  • springboot項目docker分層構(gòu)建的配置方式

    springboot項目docker分層構(gòu)建的配置方式

    在使用dockerfile構(gòu)建springboot項目時,速度較慢,用時比較長,為了加快構(gòu)建docker鏡像的速度,采用分層構(gòu)建的方式,這篇文章主要介紹了springboot項目docker分層構(gòu)建,需要的朋友可以參考下
    2024-03-03
  • java操作mongodb實現(xiàn)CURD功能實例

    java操作mongodb實現(xiàn)CURD功能實例

    mongodb支持多種語言,并且提供了多種語言的驅(qū)動,本文使用java操作mongodb實現(xiàn)CURD功能,大家參考使用吧
    2013-12-12
  • SpringBoot中使用Knife4J的解決方案

    SpringBoot中使用Knife4J的解決方案

    knife4j是為Java?MVC框架集成Swagger生成Api文檔的增強解決方案,這篇文章主要介紹了SpringBoot中使用Knife4J,需要的朋友可以參考下
    2022-10-10
  • Scala求和示例代碼

    Scala求和示例代碼

    這篇文章主要介紹了Scala求和示例代碼,需要的朋友可以參考下
    2019-06-06
  • 基于JPA中的@Basic注解詳解

    基于JPA中的@Basic注解詳解

    這篇文章主要介紹了JPA中的@Basic注解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java代碼實現(xiàn)Map和Object互轉(zhuǎn)及Map和Json互轉(zhuǎn)

    Java代碼實現(xiàn)Map和Object互轉(zhuǎn)及Map和Json互轉(zhuǎn)

    這篇文章主要介紹了Java代碼實現(xiàn)map和Object互轉(zhuǎn)及Map和json互轉(zhuǎn)的相關(guān)資料,需要的朋友可以參考下
    2016-05-05
  • SpringData JPA 如何搭建 xml的配置方式

    SpringData JPA 如何搭建 xml的配置方式

    這篇文章主要介紹了SpringData JPA 如何搭建 xml的配置方式,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2023-12-12
  • Netty中的心跳檢測機制詳解

    Netty中的心跳檢測機制詳解

    這篇文章主要介紹了Netty中的心跳檢測機制詳解,Netty 是 基于 TCP 協(xié)議開發(fā)的,在四層協(xié)議 TCP 協(xié)議的實現(xiàn)中也提供了 keepalive 報文用來探測對端是否可用,TCP 層將在定時時間到后發(fā)送相應(yīng)的 KeepAlive 探針以確定連接可用性,需要的朋友可以參考下
    2023-12-12

最新評論

焦作市| 湘乡市| 泸水县| 浏阳市| 奉新县| 河曲县| 崇礼县| 宁蒗| 天全县| 改则县| 岗巴县| 和顺县| 重庆市| 揭西县| 山东| 山西省| 历史| 来宾市| 巴南区| 丁青县| 陇南市| 闽清县| 噶尔县| 文化| 肥城市| 大埔区| 建宁县| 建始县| 南靖县| 南投县| 大埔县| 罗江县| 河东区| 荣成市| 山丹县| 大渡口区| 定结县| 宁国市| 茶陵县| 张家川| 滦南县|