Spring AOP實踐:如何通過aop記錄日志?

目錄

一、依賴

二、自定義注解

三、切面


一、依賴

以SpringBoot工程為例,導入aop的依賴。

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

二、自定義注解

我們自定義一個注解。這里叫LogAnnotation,屬性也可以自定義。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAnnotation {String module() default "";String operation() default "";}

注解有了,我們就可以將這個注解作用到任何方法上面了。

但是僅僅有這個注解還不行,它不能發揮任何功能,起不了什么作用,也僅僅是標記了一個方法。

因此,我們就要為這個注解建立切面。

三、切面

解釋如下代碼含義:

只要標記了@LogAnnotation注解的方法都會執行環繞通知。

通知中做如下處理:方法調用前記錄時間、執行方法、方法執行后記錄時間,最后保存日志。

日志顯示@LogAnnotation的屬性(不寫就是空值默認值)、請求參數、方法名、請求者的ip地址、方法執行耗時等信息。

@Aspect
@Component
@Slf4j
public class LogAspect {@Pointcut("@annotation(com.pps.aop.LogAnnotation)")public void logPointCut() {}@Around("logPointCut()")public Object around(ProceedingJoinPoint point) throws Throwable {long beginTime = System.currentTimeMillis();//執行方法Object result = point.proceed();//執行時長(毫秒)long time = System.currentTimeMillis() - beginTime;//保存日志recordLog(point, time);return result;}private void recordLog(ProceedingJoinPoint joinPoint, long time) {MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);log.info("=====================log start================================");log.info("module:{}",logAnnotation.module());log.info("operation:{}",logAnnotation.operation());//請求的方法名String className = joinPoint.getTarget().getClass().getName();String methodName = signature.getName();log.info("request method:{}",className + "." + methodName + "()");//請求的參數Object[] args = joinPoint.getArgs();if (args.length > 0 ){// 調用的該方法必須有形參才會進入,按順序記錄實參。for (Object param : args) {log.info("params:{}",JSON.toJSONString(param));}}//獲取request 設置IP地址HttpServletRequest request = HttpServletUtils.getHttpServletRequest();log.info("ip:{}", IpUtils.getIpAddr(request));log.info("execute time: {} ms",time);log.info("=====================log end=================================");}
}

IP工具類

/*** 從http請求中獲取ip地址<br>* @author hssy* @version 1.0*/
@Slf4j
public class IpUtils {/*** 獲取IP地址<br/>* 使用Nginx等反向代理軟件, 則不能通過request.getRemoteAddr()獲取IP地址<br/>* 如果使用了多級反向代理的話,X-Forwarded-For的值并不止一個,<br/>* 而是一串IP地址,X-Forwarded-For中第一個非unknown的有效IP字符串,則為真實IP地址<br/>*/public static String getIpAddr(HttpServletRequest request) {String ip = null;try {ip = request.getHeader("x-forwarded-for");if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("HTTP_CLIENT_IP");}if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("HTTP_X_FORWARDED_FOR");}if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}} catch (Exception e) {log.error("IPUtils ERROR ", e);}// 使用代理,則獲取第一個IP地址if (StringUtils.isEmpty(ip) && ip.length() > 15) {if (ip.indexOf(",") > 0) {ip = ip.substring(0, ip.indexOf(","));}}return ip;}
}

獲取HttpServletRequest工具類

public class HttpServletUtils {public static HttpServletRequest getHttpServletRequest(){return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();}
}

演示效果

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/37640.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/37640.shtml
英文地址,請注明出處:http://en.pswp.cn/news/37640.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

為什么要自動化Web測試?

Web自動化是更快地實現所需結果的較佳方式。自動化測試在市場上引起了巨大的轟動。此軟件測試過程可以讓您使用正確的自動化測試工具和技術集自動執行測試過程。我們執行它是為了檢查軟件應用程序是否具有完全按照我們希望它執行的方式執行的勇氣。 比以往更快地獲得反饋 自動化…

基于Promise.resolve實現Koa請求隊列中間件

本文作者為360奇舞團前端工程師 前言 最近在做一個 AIGC 項目&#xff0c;后端基于 Koa2 實現。其中有一個需求就是調用兄弟業務線服務端 AIGC 能力生成圖片。但由于目前兄弟業務線的 AIGC 項目也是處于測試階段&#xff0c;能夠提供的服務器資源有限&#xff0c;當并發請求資源…

kafka和rabbitmq之間的區別以及適用場景

Kafka 和 RabbitMQ 都是流行的消息傳遞系統&#xff0c;用于實現分布式系統中的消息傳遞、事件處理和數據流。它們在設計和適用場景上有一些不同&#xff0c;下面詳細介紹它們之間的區別和適用場景。 Kafka 特點和優勢&#xff1a; 高吞吐量&#xff1a; Kafka 的設計目標是實…

【Java】數據交換 Json 和 異步請求 Ajax

&#x1f384;歡迎來到邊境矢夢的csdn博文&#xff0c;本文主要講解Java 中 數據交換和異步請求 Json&Ajax 的相關知識&#x1f384; &#x1f308;我是邊境矢夢&#xff0c;一個正在為秋招和算法競賽做準備的學生&#x1f308; &#x1f386;喜歡的朋友可以關注一下&#…

go mod 添加私有庫GOPRIVATE

私有地址 形式倉庫域名/組織名形式倉庫域名形式*倉庫域名 示例私有地址&#xff1a; gitee.com/takujo_admin 或者igitlab.com 多個私有地址,分割&#xff0c;示例&#xff1a; gitee.com,igitlab.com 修改env go env -w GOPRIVATE"私有地址" go env -w …

conda創建虛擬環境

創建虛擬環境是在計算機上設置一個獨立的空間&#xff0c;用于安裝和運行特定版本的軟件和依賴項&#xff0c;以避免與系統其他部分的沖突。 創建虛擬環境&#xff1a; conda create --name myenv python3.8 這將創建一個名為myenv的虛擬環境&#xff0c;并安裝Python 3.8版本。…

pwm接喇叭搞整點報時[keyestudio的8002模塊]

雖然現在查看時間很方便&#xff0c;但是其實好像我的時間觀念卻越來越差。于是決定搞一個整點報時&#xff0c;時常提醒自己時光飛逝&#xff0c;不要老是瞎墨跡。 這篇主要講一下拼裝方式和配置&#xff0c;就差不多了。不涉及什么代碼。3針的元器件&#xff0c;去掉正負接線…

day3 STM32 GPIO口介紹

GPIO接口簡介 通用輸入輸出接口GPIO是嵌入式系統、單片機開發過程最常用的接口&#xff0c;用戶可以通過編程靈活的對接口進行控制&#xff0c;實現對電路板上LED、數碼管、按鍵等常用設備控制驅動&#xff0c;也可以作為串口的數據收發管腳&#xff0c;或AD的接口等復用功能使…

網絡安全--iptables(待更新,累了)

總結&#xff1a; iptables 的關鍵概念和功能&#xff1a; 規則&#xff08;Rules&#xff09;&#xff1a; iptables 使用規則來定義特定的操作&#xff0c;例如允許或拒絕特定類型的網絡流量。每條規則都由條件和操作組成。條件可以是源 IP 地址、目標 IP 地址、端口號等&a…

thinkphp:對數據庫減少增加某個字段的值(dec、inc的用法)

例子&#xff1a;當字段po_num的值等于數組list_info中的po_num的值時修改數據庫表po_rcv_receipt_line中某些信息&#xff1a; 1、數據庫delivery_quantity字段的值 數據庫中delivery_quantity的值變量$list_info[write_quantity] ->inc(delivery_quantity, $list_info[…

【設計模式——學習筆記】23種設計模式——狀態模式State(原理講解+應用場景介紹+案例介紹+Java代碼實現)

文章目錄 案例引入介紹基本介紹登場角色應用場景 案例實現案例一類圖實現 案例二&#xff1a;借貸平臺源碼剖析傳統方式實現分析狀態修改流程類圖實現 案例三&#xff1a;金庫警報系統系統的運行邏輯偽代碼傳統實現方式使用狀態模式 類圖實現分析問題問題一問題二 總結文章說明…

國內芯片廠商創新突破,助力國產替代持續加速

近日&#xff0c;中商產業研究院發布最新研究報告顯示&#xff0c;今年1~5月份中國進口集成電路為1865億件&#xff0c;同比下降19.6%&#xff0c;同比去年5個月累計少進口了455億顆&#xff0c;平均每天少進口3億顆。與此同時&#xff0c;英特爾、AMD、美光、三星、SK海力士等…

OSI七層模型和TCP/IP四層模型

OSI七層模型和TCP/IP四層模型 七層模型(OSI) OSI七層模型&#xff08;Open Systems Interconnection Reference Model&#xff09;是一個用于計算機網絡體系結構的標準化框架&#xff0c;旨在定義網絡通信中不同層次的功能和協議。 各個層次具體如下&#xff1a; 物理層&am…

C語言 冒泡排序

目錄 一、原理 二、代碼演示 三、代碼優化 一、原理 假設&#xff1a; int arr[] { 9,8,7,6,5,4,3,2,1,0 }; 將 arr 內的元素進行升序排列&#xff0c;得到一個新的數組 int arr[] { 0&#xff0c;1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;…

windows docker mysql8.0 掛載配置文件不生效的問題

原因 mysql 8.0 遇到sql_modeonly_full_group_by的問題&#xff0c;于是就自定義my.cnf 去掉only_full_group_by&#xff0c;修改my.cnf 文件后&#xff0c;進行映射啟動 docker run 命令 docker run -p 3306:3306 --privilegedtrue --restartalways -d --name axsc-mysql -…

【0814作業】多線程并發服務器

1) 代碼 #include <stdio.h> #include <sys/socket.h> #include <sys/types.h> #include <arpa/inet.h> #include <string.h> #include <stdlib.h> #include <signal.h> #include <sys/wait.h> #include <netinet/in.h>…

配置文件優先級解讀

目錄 概述 同級目錄application配置文件優先級 application 以及bootstrap 優先級 不同級目錄配置文件優先級 外部配置加載順序 概述 SpringBoot除了支持properties格式的配置文件&#xff0c;還支持另外兩種格式的配置文件。三種配置文件格式分別如下: properties格式…

Python學習筆記_基礎篇(二)_數據類型之字符串

一.基本數據類型 整數&#xff1a;int 字符串&#xff1a;str(注&#xff1a;\t等于一個tab鍵) 布爾值&#xff1a; bool 列表&#xff1a;list 列表用[] 元祖&#xff1a;tuple 元祖用&#xff08;&#xff09; 字典&#xff1a;dict 注&#xff1a;所有的數據類型都存在想對應…

TFTP Server

簡介 TFTP&#xff08;Trivial File Transfer Protocol,簡單文件傳輸協議&#xff09;是TCP/IP協議族中的一個用來在客戶機與服務器之間進行簡單文件傳輸的協議&#xff0c;提供不復雜、開銷不大的文件傳輸服務。端口號為69。 TFTP和FTP的區別 安全性區別 FTP支持登錄安全&…

ATF(TF-A)安全通告 TFV-9 (CVE-2022-23960)

ATF(TF-A)安全通告匯總 目錄 一、ATF(TF-A)安全通告 TFV-9 (CVE-2022-23960) 二、CVE-2022-23960 一、ATF(TF-A)安全通告 TFV-9 (CVE-2022-23960) Title TF-A披露通過分支預測目標重用&#xff08;branch prediction target reuse&#xff09;引發的前瞻執行處理器漏洞 CV…