一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|JavaScript|易語言|

服務器之家 - 編程語言 - Java教程 - SpringBoot中使用AOP打印接口日志的方法

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

2021-05-06 11:14高超楊 Java教程

本篇文章主要介紹了SpringBoot中使用AOP打印接口日志的方法,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

前言

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

概念

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

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

sprinboot aop 實現

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

實現 rest 服務功能。

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

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

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 字符串后能夠格式化輸出

實現一個 rest 接口的 controller 類

在這里,我們實現兩個 rest 接口。一個是返回 hello 信息。一個是根據輸入返回登錄信息。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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;
 
/**
 * 安全相關 rest 服務
 *
 * @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 接口的輸入參數和返回結果輸出到日志中。

實現 web aop 功能。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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 相關注解來說明在切入方法的什么位置做什么事。這里用 org.aspectj.lang.annotation.before
  4. 這個實現是指明在所有具備 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 類型

  1. before advice 在方法執行前執行。
  2. after returning advice 在方法執行后返回一個結果后執行。
  3. after throwing advice 在方法執行過程中拋出異常的時候執行。
  4. 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()

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:https://www.jianshu.com/p/946c654f02c1

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 91制片厂制作果冻传媒破解 | 亚洲欧美一 | 日本在线你懂的 | 四虎影在线永久免费观看 | 国产成人精品免费午夜 | 亚洲成人免费 | 成年视频在线观看免费 | 99精品久久精品一区二区小说 | ts人妖系列在线专区 | 99re在线视频免费观看 | 国产福利视频一区二区微拍 | 四虎永久在线精品国产馆v视影院 | 日本大片网 | 男女刺激高清视频在线观看 | 国产精品免费小视频 | 3d动漫被吸乳羞羞 | 九色PORNY丨视频入口 | 久久婷婷五月综合色精品首页 | 动漫肉在线观看 | 插得好爽 | 美国一级大黄大色毛片 | 2012手机在线中文字幕 | 亚洲午夜久久久 | 亚洲成年网站在线观看 | 美女被扣逼 | 精品一区二区三区色花堂 | chinese456老年gay| 国产自拍视频一区 | 欧美老骚 | 毛片应用| 甜性涩爱 | 国产精品林美惠子在线观看 | 丝袜高跟小说 | 亚洲日韩男人网在线 | 91大神在线精品视频一区 | 四虎影院久久 | 色综合亚洲天天综合网站 | 国产日韩欧美综合在线 | 无码一区国产欧美在线资源 | 亚洲一区二区三区深夜天堂 | 91影视永久福利免费观看 |