運用Spring?Aop+注解實現(xiàn)日志記錄
1. 介紹
我們都知道Spring框架的兩大特性分別是 IOC (控制反轉)和 AOP (面向切面),這個是每一個Spring學習視頻里面一開始都會提到的。在日常項目中,我們也會經常使用IOC控制反轉,但是卻感覺AOP很少會運用到。其實AOP大有用處,甚至可以讓你偷偷懶。
舉一個例子,假如現(xiàn)在要讓你記錄每一個請求的請求IP,請求的方法,請求路徑,請求的參數(shù),返回參數(shù),你會怎么做?你會想,那簡單啊,我直接 log.info("xxxx") 輸出日志不行嗎,簡單!可是你要想清楚,每個請求請求的方法不一定是同一個,有一些請求可能請求編輯方法,另外一些請求可能請求登錄方法,這么多方法,你每一個方法下面都重復寫了差不多6,7行重復代碼,你覺得這好嗎?
這里,如果我們使用Aop來記錄日志,那是再好不過了。我們可以看看一個方法的執(zhí)行過程來理解AOP。

下面再來看使用AOP后的執(zhí)行過程。

AOP是面向切面編程,面向切面思想就是讓我們把程序想象成一條一條管道連接起來的大管道,而AOP就是在管道和管道之間的過濾網,能夠在不影響管道的情況下對管道中傳輸?shù)臄?shù)據(jù)進行記錄,修改。
使用AOP我們可以很方便地進行操作日志記錄,性能日志記錄,請求日志記錄,事務操作,安全管理等。這么說可能很抽象,再詳細點說就是各種日志記錄我們可以利用AOP來進行記錄,而不用在業(yè)務邏輯代碼中插入,安全管理就是我們可以在請求進來前對請求中的數(shù)據(jù)進行解密,在請求返回的時候對數(shù)據(jù)進行加密。這么說AOP很像Java里面的攔截器,過濾器和監(jiān)聽器的結合。
具體AOP的原理就不細講了,那是另外一篇文章了,有關于動態(tài)代理。
2. 實踐
說了這么多,大白話就是AOP能讓我們在不影響原代碼的基礎上,對代碼功能進行添加,修改
在實現(xiàn)日志記錄功能前,我們要先復習一下 Spring Aop 里面的通知順序(連接點,通知還不知道是什么的,先去B站看一下Spring初級教程)。

先把Aop的starter依賴添加進pom文件中。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>2.1 定義注解
那現(xiàn)在我們來自定義一個注解,目的是標注該注解的方法將會記錄調用該方法的請求信息
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface MyLog {
String value() default "";
}注解不是本篇重點,有興趣的童鞋可以搜一下。
2.2 切面類
定義我們的日志記錄切面類,切面類中記錄請求的信息。
@Component
@Aspect
@Slf4j
public class LogAspect {
//切入點為自定義注解
@Pointcut("@annotation(com.example.springaopdemo.demo2.MyLog)")
public void MyLog(){}
@Before("MyLog()")
public void Before(JoinPoint jp){
//獲取HttpServletRequest對象
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
assert requestAttributes != null;
HttpServletRequest request = requestAttributes.getRequest();
log.info("==========請求信息==========");
log.info("請求鏈接 : {}",request.getRequestURL().toString());
log.info("Http Method : {}",request.getMethod());
log.info("Class Method : {}.{}",jp.getSignature().getDeclaringTypeName(),jp.getSignature().getName());
log.info("Ip : {}",request.getRemoteAddr());
log.info("Args : {}", Arrays.asList(jp.getArgs()));
}
@Around("MyLog()")
public Object Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = proceedingJoinPoint.proceed();
log.info("執(zhí)行時間 : {} ms", System.currentTimeMillis() - startTime);
log.info("返回參數(shù) : {}", result);
return result;
}
}通過 @Around 環(huán)繞通知我們可以進行簡單的性能記錄,如果加上 Oshi 我們甚至可以記錄執(zhí)行該方法前后的CPU,內存占用率。
Oshi是Java的免費基于JNA的操作系統(tǒng)和硬件信息庫,Github地址是:https://github.com/oshi/oshi
它的優(yōu)點是不需要安裝任何其他本機庫,并且旨在提供一種跨平臺的實現(xiàn)來檢索系統(tǒng)信息,例如操作系統(tǒng)版本,進程,內存和CPU使用率,磁盤和分區(qū),設備,傳感器等。
2.3 編寫測試方法
編寫一個簡單的請求,請求需要一個User對象的請求體,返回一個Map結果。
@RestController
@Slf4j
public class Controller {
@PostMapping("/test")
@MyLog
public Map<String, Object> testAop(@RequestBody User user){
Map<String,Object> map = new HashMap<>();
map.put("code",200);
map.put("errorMsg","success");
return map;
}
}2.4 運行結果
使用IDEA自帶的Http Client來測試api

結果:

可以看到通過利用AOP,我們沒有修改Controller中的代碼,就可以實現(xiàn)對Controller中每個方法請求信息的日志記錄功能。
而且我們還能夠指定該切面類是在生產環(huán)境還是開發(fā)環(huán)境下生效,只需要在切面類上添加注解。
@Profile({"dev"})
然后在配置文件中定義 spring.profiles.active 的屬性即可。
3. 總結
因為學習了Spring后,雖然知道有AOP這個東西,但是卻從來沒有真正的在實際項目中運用,這幾天研究日志記錄,卻發(fā)現(xiàn)AOP在日志記錄中的妙用,甚至可以利用AOP在對代碼無侵入的情況下,進行參數(shù)數(shù)據(jù)的加密和解密操作。但是,雖然說AOP使用方便,但是不能夠濫用,畢竟AOP底層使用動態(tài)代理,而動態(tài)代理要做到對方法的修改就肯定要使用到反射,反射會對性能有影響。
4. 參考文章
(7 封私信 / 66 條消息) 在一個完整的項目中,會用AOP技術么,能用簡單易懂的方式說明下什么是AOP么? - 知乎 (zhihu.com)
【SpringBoot】AOP應用實例_sysu_lluozh-CSDN博客
(20條消息) Springboot Aop 自定義注解、切面_張同學的博客-CSDN博客_springboot 自定義注解切面
到此這篇關于運用Spring Aop,一個注解實現(xiàn)日志記錄的文章就介紹到這了,更多相關Spring Aop日志記錄內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
IDEA插件之Mybatis Log plugin 破解及安裝方法
這篇文章主要介紹了IDEA插件之Mybatis Log plugin 破解方法及安裝方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09
使用Filter攔截器如何實現(xiàn)請求跨域轉發(fā)
這篇文章主要介紹了使用Filter攔截器如何實現(xiàn)請求跨域轉發(fā),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08
解析XML文件時的嵌套異常SAXParseException問題
這篇文章主要介紹了解析XML文件時的嵌套異常SAXParseException問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-04-04

