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.mzph.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…