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

Spring Boot配置AOP打印日志的全過(guò)程

 更新時(shí)間:2019年08月25日 09:55:11   作者:風(fēng)塵博客  
這篇文章主要給大家介紹了關(guān)于Spring Boot配置AOP打印日志的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring Boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

在項(xiàng)目開(kāi)發(fā)中,日志系統(tǒng)是必不可少的,用AOP在Web的請(qǐng)求做入?yún)⒑统鰠⒌膮?shù)打印,同時(shí)對(duì)異常進(jìn)行日志打印,避免重復(fù)的手寫(xiě)日志,完整案例見(jiàn)文末源碼。

一、Spring AOP

AOP(Aspect-Oriented Programming,面向切面編程),它利用一種"橫切"的技術(shù),將那些多個(gè)類的共同行為封裝到一個(gè)可重用的模塊。便于減少系統(tǒng)的重復(fù)代碼,降低模塊之間的耦合度,并有利于未來(lái)的可操作性和可維護(hù)性。

AOP中有以下概念:

  • Aspect(切面):聲明類似于Java中的類聲明,在Aspect中會(huì)包含一些Pointcut及相應(yīng)的Advice。
  • Joint point(連接點(diǎn)):表示在程序中明確定義的點(diǎn)。包括方法的調(diào)用、對(duì)類成員的訪問(wèn)等。
  • Pointcut(切入點(diǎn)):表示一個(gè)組Joint point,如方法名、參數(shù)類型、返回類型等等。
  • Advice(通知):Advice定義了在Pointcut里面定義的程序點(diǎn)具體要做的操作,它通過(guò)(before、around、after(return、throw)、finally來(lái)區(qū)別實(shí)在每個(gè)Joint point之前、之后還是執(zhí)行 前后要調(diào)用的代碼。
  • Before:在執(zhí)行方法前調(diào)用Advice,比如請(qǐng)求接口之前的登錄驗(yàn)證。
  • Around:在執(zhí)行方法前后調(diào)用Advice,這是最常用的方法。
  • After:在執(zhí)行方法后調(diào)用Advice,after、return是方法正常返回后調(diào)用,after\throw是方法拋出異常后調(diào)用。
  • Finally:方法調(diào)用后執(zhí)行Advice,無(wú)論是否拋出異常還是正常返回。
  • AOP proxy:AOP proxy也是Java對(duì)象,是由AOP框架創(chuàng)建,用來(lái)完成上述動(dòng)作,AOP對(duì)象通??梢酝ㄟ^(guò)JDK dynamic proxy完成,或者使用CGLIb完成。
  • Weaving:實(shí)現(xiàn)上述切面編程的代碼織入,可以在編譯時(shí)刻,也可以在運(yùn)行時(shí)刻,Spring和其它大多數(shù)Java框架都是在運(yùn)行時(shí)刻生成代理。

二、項(xiàng)目示例

當(dāng)然,在使用該案例之前,如果需要了解日志配置相關(guān),可參考 SpringBoot 異步輸出 Logback 日志, 本文就不再概述了。

2.1 在pom引入依賴

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

 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-aop</artifactId>
 </dependency>
 <!-- 分析客戶端信息的工具類-->
 <dependency>
 <groupId>eu.bitwalker</groupId>
 <artifactId>UserAgentUtils</artifactId>
 <version>1.20</version>
 </dependency>
 <!-- lombok -->
 <dependency>
 <groupId>org.projectlombok</groupId>
 <artifactId>lombok</artifactId>
 <scope>1.8.4</scope>
 </dependency>
</dependencies>

2.2 Controller 切面:WebLogAspect

@Aspect
@Component
@Slf4j
public class WebLogAspect {

 /**
 * 進(jìn)入方法時(shí)間戳
 */
 private Long startTime;
 /**
 * 方法結(jié)束時(shí)間戳(計(jì)時(shí))
 */
 private Long endTime;

 public WebLogAspect() {
 }


 /**
 * 定義請(qǐng)求日志切入點(diǎn),其切入點(diǎn)表達(dá)式有多種匹配方式,這里是指定路徑
 */
 @Pointcut("execution(public * cn.van.log.aop.controller.*.*(..))")
 public void webLogPointcut() {
 }

 /**
 * 前置通知:
 * 1. 在執(zhí)行目標(biāo)方法之前執(zhí)行,比如請(qǐng)求接口之前的登錄驗(yàn)證;
 * 2. 在前置通知中設(shè)置請(qǐng)求日志信息,如開(kāi)始時(shí)間,請(qǐng)求參數(shù),注解內(nèi)容等
 *
 * @param joinPoint
 * @throws Throwable
 */
 @Before("webLogPointcut()")
 public void doBefore(JoinPoint joinPoint) {

 // 接收到請(qǐng)求,記錄請(qǐng)求內(nèi)容
 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
 HttpServletRequest request = attributes.getRequest();
 //獲取請(qǐng)求頭中的User-Agent
 UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
 //打印請(qǐng)求的內(nèi)容
 startTime = System.currentTimeMillis();
 log.info("請(qǐng)求開(kāi)始時(shí)間:{}" + LocalDateTime.now());
 log.info("請(qǐng)求Url : {}" + request.getRequestURL().toString());
 log.info("請(qǐng)求方式 : {}" + request.getMethod());
 log.info("請(qǐng)求ip : {}" + request.getRemoteAddr());
 log.info("請(qǐng)求方法 : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
 log.info("請(qǐng)求參數(shù) : {}" + Arrays.toString(joinPoint.getArgs()));
 // 系統(tǒng)信息
 log.info("瀏覽器:{}", userAgent.getBrowser().toString());
 log.info("瀏覽器版本:{}", userAgent.getBrowserVersion());
 log.info("操作系統(tǒng): {}", userAgent.getOperatingSystem().toString());
 }

 /**
 * 返回通知:
 * 1. 在目標(biāo)方法正常結(jié)束之后執(zhí)行
 * 1. 在返回通知中補(bǔ)充請(qǐng)求日志信息,如返回時(shí)間,方法耗時(shí),返回值,并且保存日志信息
 *
 * @param ret
 * @throws Throwable
 */
 @AfterReturning(returning = "ret", pointcut = "webLogPointcut()")
 public void doAfterReturning(Object ret) throws Throwable {
 endTime = System.currentTimeMillis();
 log.info("請(qǐng)求結(jié)束時(shí)間:{}" + LocalDateTime.now());
 log.info("請(qǐng)求耗時(shí):{}" + (endTime - startTime));
 // 處理完請(qǐng)求,返回內(nèi)容
 log.info("請(qǐng)求返回 : {}" + ret);
 }

 /**
 * 異常通知:
 * 1. 在目標(biāo)方法非正常結(jié)束,發(fā)生異?;蛘邟伋霎惓r(shí)執(zhí)行
 * 1. 在異常通知中設(shè)置異常信息,并將其保存
 *
 * @param throwable
 */
 @AfterThrowing(value = "webLogPointcut()", throwing = "throwable")
 public void doAfterThrowing(Throwable throwable) {
 // 保存異常日志記錄
 log.error("發(fā)生異常時(shí)間:{}" + LocalDateTime.now());
 log.error("拋出異常:{}" + throwable.getMessage());
 }
}

2.3 編寫(xiě)測(cè)試

@RestController
@RequestMapping("/log")
public class LogbackController {

 /**
 * 測(cè)試正常請(qǐng)求
 * @param msg
 * @return
 */
 @GetMapping("/{msg}")
 public String getMsg(@PathVariable String msg) {
 return "request msg : " + msg;
 }

 /**
 * 測(cè)試拋異常
 * @return
 */
 @GetMapping("/test")
 public String getException(){
 // 故意造出一個(gè)異常
 Integer.parseInt("abc123");
 return "success";
 }
}

2.4 @Before和@AfterReturning部分也可使用以下代碼替代

 /**
 * 在執(zhí)行方法前后調(diào)用Advice,這是最常用的方法,相當(dāng)于@Before和@AfterReturning全部做的事兒
 * @param pjp
 * @return
 * @throws Throwable
 */
 @Around("webLogPointcut()")
 public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
 // 接收到請(qǐng)求,記錄請(qǐng)求內(nèi)容
 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
 HttpServletRequest request = attributes.getRequest();
 //獲取請(qǐng)求頭中的User-Agent
 UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
 //打印請(qǐng)求的內(nèi)容
 startTime = System.currentTimeMillis();
 log.info("請(qǐng)求Url : {}" , request.getRequestURL().toString());
 log.info("請(qǐng)求方式 : {}" , request.getMethod());
 log.info("請(qǐng)求ip : {}" , request.getRemoteAddr());
 log.info("請(qǐng)求方法 : " , pjp.getSignature().getDeclaringTypeName() , "." , pjp.getSignature().getName());
 log.info("請(qǐng)求參數(shù) : {}" , Arrays.toString(pjp.getArgs()));
 // 系統(tǒng)信息
 log.info("瀏覽器:{}", userAgent.getBrowser().toString());
 log.info("瀏覽器版本:{}",userAgent.getBrowserVersion());
 log.info("操作系統(tǒng): {}", userAgent.getOperatingSystem().toString());
 // pjp.proceed():當(dāng)我們執(zhí)行完切面代碼之后,還有繼續(xù)處理業(yè)務(wù)相關(guān)的代碼。proceed()方法會(huì)繼續(xù)執(zhí)行業(yè)務(wù)代碼,并且其返回值,就是業(yè)務(wù)處理完成之后的返回值。
 Object ret = pjp.proceed();
 log.info("請(qǐng)求結(jié)束時(shí)間:"+ LocalDateTime.now());
 log.info("請(qǐng)求耗時(shí):{}" , (System.currentTimeMillis() - startTime));
 // 處理完請(qǐng)求,返回內(nèi)容
 log.info("請(qǐng)求返回 : " , ret);
 return ret;
 }

三、 測(cè)試

3.1 請(qǐng)求入口LogbackController.java

@RestController
@RequestMapping("/log")
public class LogbackController {

 /**
 * 測(cè)試正常請(qǐng)求
 * @param msg
 * @return
 */
 @GetMapping("/normal/{msg}")
 public String getMsg(@PathVariable String msg) {
 return msg;
 }

 /**
 * 測(cè)試拋異常
 * @return
 */
 @GetMapping("/exception/{msg}")
 public String getException(@PathVariable String msg){
 // 故意造出一個(gè)異常
 Integer.parseInt("abc123");
 return msg;
 }
}

3.2 測(cè)試正常請(qǐng)求

打開(kāi)瀏覽器,訪問(wèn)http://localhost:8082/log/normal/hello

日志打印如下:

[2019-02-24 22:37:50.050] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-1] [65] [INFO ] 請(qǐng)求開(kāi)始時(shí)間:2019-02-24T22:37:50.892
[2019-02-24 22:37:50.050] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-1] [66] [INFO ] 請(qǐng)求Url : http://localhost:8082/log/normal/hello
[2019-02-24 22:37:50.050] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-1] [67] [INFO ] 請(qǐng)求方式 : GET
[2019-02-24 22:37:50.050] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-1] [68] [INFO ] 請(qǐng)求ip : 0:0:0:0:0:0:0:1
[2019-02-24 22:37:50.050] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-1] [69] [INFO ] 請(qǐng)求方法 :
[2019-02-24 22:37:50.050] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-1] [70] [INFO ] 請(qǐng)求參數(shù) : [hello]
[2019-02-24 22:37:50.050] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-1] [72] [INFO ] 瀏覽器:CHROME
[2019-02-24 22:37:50.050] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-1] [73] [INFO ] 瀏覽器版本:76.0.3809.100
[2019-02-24 22:37:50.050] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-1] [74] [INFO ] 操作系統(tǒng): MAC_OS_X
[2019-02-24 22:37:50.050] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-1] [88] [INFO ] 請(qǐng)求結(jié)束時(shí)間:2019-02-24T22:37:50.901
[2019-02-24 22:37:50.050] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-1] [89] [INFO ] 請(qǐng)求耗時(shí):14
[2019-02-24 22:37:50.050] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-1] [91] [INFO ] 請(qǐng)求返回 : hello

3.3 測(cè)試異常情況

訪問(wèn):http://localhost:8082/log/exception/hello

[2019-02-24 22:39:57.057] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-9] [65] [INFO ] 請(qǐng)求開(kāi)始時(shí)間:2019-02-24T22:39:57.728
[2019-02-24 22:39:57.057] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-9] [66] [INFO ] 請(qǐng)求Url : http://localhost:8082/log/exception/hello
[2019-02-24 22:39:57.057] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-9] [67] [INFO ] 請(qǐng)求方式 : GET
[2019-02-24 22:39:57.057] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-9] [68] [INFO ] 請(qǐng)求ip : 0:0:0:0:0:0:0:1
[2019-02-24 22:39:57.057] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-9] [69] [INFO ] 請(qǐng)求方法 :
[2019-02-24 22:39:57.057] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-9] [70] [INFO ] 請(qǐng)求參數(shù) : [hello]
[2019-02-24 22:39:57.057] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-9] [72] [INFO ] 瀏覽器:CHROME
[2019-02-24 22:39:57.057] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-9] [73] [INFO ] 瀏覽器版本:76.0.3809.100
[2019-02-24 22:39:57.057] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-9] [74] [INFO ] 操作系統(tǒng): MAC_OS_X
[2019-02-24 22:39:57.057] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-9] [104] [ERROR] 發(fā)生異常時(shí)間:2019-02-24T22:39:57.731
[2019-02-24 22:39:57.057] [cn.van.log.aop.aspect.WebLogAspect] [http-nio-8082-exec-9] [105] [ERROR] 拋出異常:For input string: "abc123"
[2019-02-24 22:39:57.057] [org.apache.juli.logging.DirectJDKLog] [http-nio-8082-exec-9] [175] [ERROR] Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NumberFormatException: For input string: "abc123"] with root cause
java.lang.NumberFormatException: For input string: "abc123"

四、源碼

4.1 示例代碼

Github 示例代碼

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • 使用Jacoco獲取 Java 程序的代碼執(zhí)行覆蓋率的步驟詳解

    使用Jacoco獲取 Java 程序的代碼執(zhí)行覆蓋率的步驟詳解

    這篇文章主要介紹了使用Jacoco獲取 Java 程序的代碼執(zhí)行覆蓋率的步驟詳解,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下
    2021-03-03
  • java:找不到符號(hào)報(bào)錯(cuò)的排錯(cuò)方案舉例

    java:找不到符號(hào)報(bào)錯(cuò)的排錯(cuò)方案舉例

    當(dāng)你使用一個(gè)未定義或未導(dǎo)入的類時(shí),編譯器會(huì)報(bào)錯(cuò),下面這篇文章主要給大家介紹了關(guān)于java:找不到符號(hào)報(bào)錯(cuò)的排錯(cuò)方案,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • 簡(jiǎn)談java并發(fā)FutureTask的實(shí)現(xiàn)

    簡(jiǎn)談java并發(fā)FutureTask的實(shí)現(xiàn)

    這篇文章主要介紹了簡(jiǎn)談java并發(fā)FutureTask的實(shí)現(xiàn),FutureTask都是用于獲取線程執(zhí)行的返回結(jié)果。文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,,需要的朋友可以參考下
    2019-06-06
  • 淺談JAVA設(shè)計(jì)模式之享元模式

    淺談JAVA設(shè)計(jì)模式之享元模式

    這篇文章主要介紹了JAVA設(shè)計(jì)模式之享元模式的的相關(guān)資料,文中詳細(xì)的介紹了享元模式的概念以及使用方法,感興趣的朋友可以了解下
    2020-06-06
  • Java8內(nèi)存模型PermGen Metaspace實(shí)例解析

    Java8內(nèi)存模型PermGen Metaspace實(shí)例解析

    這篇文章主要介紹了Java8內(nèi)存模型PermGen Metaspace實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • mybatisPlus使用LocalDateTime轉(zhuǎn)化異常的實(shí)現(xiàn)

    mybatisPlus使用LocalDateTime轉(zhuǎn)化異常的實(shí)現(xiàn)

    本文主要介紹了mybatisPlus使用LocalDateTime轉(zhuǎn)化異常的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-07-07
  • 解決java.util.NoSuchElementException異常正確方法

    解決java.util.NoSuchElementException異常正確方法

    java.util.NoSuchElementException是Java中的一種異常,表示在迭代器或枚舉中找不到元素,這篇文章主要給大家介紹了關(guān)于解決java.util.NoSuchElementException異常的相關(guān)資料,需要的朋友可以參考下
    2023-11-11
  • Java+Mysql學(xué)生管理系統(tǒng)源碼

    Java+Mysql學(xué)生管理系統(tǒng)源碼

    這篇文章主要為大家詳細(xì)介紹了Java+Mysql學(xué)生管理系統(tǒng)源碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-06-06
  • 關(guān)于@CacheEvict無(wú)法解決分頁(yè)緩存清除的解決思路

    關(guān)于@CacheEvict無(wú)法解決分頁(yè)緩存清除的解決思路

    這篇文章主要介紹了關(guān)于@CacheEvict無(wú)法解決分頁(yè)緩存清除的解決思路,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • 高并發(fā)下restTemplate的錯(cuò)誤分析方式

    高并發(fā)下restTemplate的錯(cuò)誤分析方式

    這篇文章主要介紹了高并發(fā)下restTemplate的錯(cuò)誤分析方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10

最新評(píng)論