运用Spring Aop,一个注解实现日志记录
运用Spring Aop,一个注解实现日志记录
1. 介绍
我们都知道Spring框架的两大特性分别是 IOC (控制反转)和 AOP (面向切面),这个是每一个Spring学习视频里面一开始都会提到的。在日常项目中,我们也会经常使用IOC控制反转,但是却感觉AOP很少会运用到。其实AOP大有用处,甚至可以让你偷偷懒。
举一个例子,假如现在要让你记录每一个请求的请求IP,请求的方法,请求路径,请求的参数,返回参数,你会怎么做?你会想,那简单啊,我直接 log.info("xxxx") 输出日志不行吗,简单!可是你要想清楚,每个请求请求的方法不一定是同一个,有一些请求可能请求编辑方法,另外一些请求可能请求登录方法,这么多方法,你每一个方法下面都重复写了差不多6,7行重复代码,你觉得这好吗?
这里,如果我们使用Aop来记录日志,那是再好不过了。我们可以看看一个方法的执行过程来理解AOP。

下面再来看使用AOP后的执行过程。

AOP是面向切面编程,面向切面思想就是让我们把程序想象成一条一条管道连接起来的大管道,而AOP就是在管道和管道之间的过滤网,能够在不影响管道的情况下对管道中传输的数据进行记录,修改。
使用AOP我们可以很方便地进行操作日志记录,性能日志记录,请求日志记录,事务操作,安全管理等。这么说可能很抽象,再详细点说就是各种日志记录我们可以利用AOP来进行记录,而不用在业务逻辑代码中插入,安全管理就是我们可以在请求进来前对请求中的数据进行解密,在请求返回的时候对数据进行加密。这么说AOP很像Java里面的拦截器,过滤器和监听器的结合。
具体AOP的原理就不细讲了,那是另外一篇文章了,有关于动态代理。
2. 实践
说了这么多,大白话就是AOP能让我们在不影响原代码的基础上,对代码功能进行添加,修改
在实现日志记录功能前,我们要先复习一下 Spring Aop 里面的通知顺序(连接点,通知还不知道是什么的,先去B站看一下Spring初级教程)。

先把Aop的starter依赖添加进pom文件中。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.1 定义注解
那现在我们来自定义一个注解,目的是标注该注解的方法将会记录调用该方法的请求信息
@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("执行时间 : {} ms", System.currentTimeMillis() - startTime);
log.info("返回参数 : {}", result);
return result;
}
}
通过 @Around 环绕通知我们可以进行简单的性能记录,如果加上 Oshi 我们甚至可以记录执行该方法前后的CPU,内存占用率。
Oshi是Java的免费基于JNA的操作系统和硬件信息库,Github地址是:https://github.com/oshi/oshi
它的优点是不需要安装任何其他本机库,并且旨在提供一种跨平台的实现来检索系统信息,例如操作系统版本,进程,内存和CPU使用率,磁盘和分区,设备,传感器等。
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中的代码,就可以实现对Controller中每个方法请求信息的日志记录功能。
而且我们还能够指定该切面类是在生产环境还是开发环境下生效,只需要在切面类上添加注解。
@Profile({"dev"})
然后在配置文件中定义 spring.profiles.active 的属性即可。
3. 总结
因为学习了Spring后,虽然知道有AOP这个东西,但是却从来没有真正的在实际项目中运用,这几天研究日志记录,却发现AOP在日志记录中的妙用,甚至可以利用AOP在对代码无侵入的情况下,进行参数数据的加密和解密操作。但是,虽然说AOP使用方便,但是不能够滥用,毕竟AOP底层使用动态代理,而动态代理要做到对方法的修改就肯定要使用到反射,反射会对性能有影响。
4. 参考文章
(7 封私信 / 66 条消息) 在一个完整的项目中,会用AOP技术么,能用简单易懂的方式说明下什么是AOP么? - 知乎 (zhihu.com)
【SpringBoot】AOP应用实例_sysu_lluozh-CSDN博客
(20条消息) Springboot Aop 自定义注解、切面_张同学的博客-CSDN博客_springboot 自定义注解切面
运用Spring Aop,一个注解实现日志记录的更多相关文章
- spring aop通过注解实现日志记录
首先是几个概念:连接点(Joinpoint).切点(Pointcut).增强(Advice).切面(Aspect) 另外也要使用到注解. 需求:通过注解定义LogEnable.然后程序运行能够识别定义 ...
- 利用Spring AOP自定义注解解决日志和签名校验
转载:http://www.cnblogs.com/shipengzhi/articles/2716004.html 一.需解决的问题 部分API有签名参数(signature),Passport首先 ...
- spring AOP自定义注解 实现日志管理
今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接开始!!! 关于配置我还是的再说一遍. 在appli ...
- (转)利用Spring AOP自定义注解解决日志和签名校验
一.需解决的问题 部分API有签名参数(signature),Passport首先对签名进行校验,校验通过才会执行实现方法. 第一种实现方式(Origin):在需要签名校验的接口里写校验的代码,例如: ...
- spring AOP自定义注解方式实现日志管理
今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接开始!!! 关于配置我还是的再说一遍. 在appli ...
- Spring Boot 2.X(八):Spring AOP 实现简单的日志切面
AOP 1.什么是 AOP ? AOP 的全称为 Aspect Oriented Programming,译为面向切面编程,是通过预编译方式和运行期动态代理实现核心业务逻辑之外的横切行为的统一维护的一 ...
- spring aop 使用注解方式总结
spring aop的注解方式:和xml的配置方式略有区别,详细如下: 1.首先还是建立需要的切面类:切面类里面定义好切点配置,以及所有的需要实现的通知方法. /** * */ package com ...
- Spring aop+自定义注解统一记录用户行为日志
写在前面 本文不涉及过多的Spring aop基本概念以及基本用法介绍,以实际场景使用为主. 场景 我们通常有这样一个需求:打印后台接口请求的具体参数,打印接口请求的最终响应结果,以及记录哪个用户在什 ...
- Spring AOP使用注解记录用户操作日志
最后一个方法:核心的日志记录方法 package com.migu.cm.aspect; import com.alibaba.fastjson.JSON; import com.migu.cm.do ...
随机推荐
- Problem 2233 ~APTX4869
Problem 2233 ~APTX4869 Accept: 55 Submit: 176Time Limit: 1000 mSec Memory Limit : 32768 KB Pro ...
- 如何在 Go 中将 []byte 转换为 io.Reader?
原文链接: 如何在 Go 中将 []byte 转换为 io.Reader? 在 stackoverflow 上看到一个问题,题主进行了一个网络请求,接口返回的是 []byte.如果想要将其转换成 io ...
- Entropy, relative entropy and mutual information
目录 Entropy Joint Entropy Conditional Entropy Chain rule Mutual Information Relative Entropy Chain Ru ...
- ZooKeeper基础知识总结
数据模型 ZooKeeper数据模型是一个树状的数据结构,类似于文件系统:和文件系统的区别在于树中的每一个节点(叶子节点与非叶子节点)都可以保存数据,且每个节点的访问都必须从根节点开始,以斜线作为分隔 ...
- vue项目在ie浏览器下报语法错误
错误如下: 1.用vue 写的项目最多可以兼容到IE9 及以上版本 2.使用babel-polyfill做兼容npm install babel-polyfill --save-dev 安装之后如果发 ...
- html+css+JavaScript实现爱恩斯坦棋游戏
title: "html+css+JavaScript实现爱恩斯坦棋游戏" author: Sun-Wind date: December 30, 2021 背景:本贴将基于前端的 ...
- emqx启用redis认证插件
本次测试使用的是免费版的 emqx-windows-4.3.10 版本 1.修改redis插件 emqx_auth_redis.conf 设置用户名密码, auth.redis.passwor ...
- awk 内置变量
awk 内置变量 FS 设置输入域分隔符,等价于命令行 -F选项 OFS 输出域分隔符 NF 浏览记录的域的个数NR 已读的记录数RS 控制记录分隔符 ORS 输出记录分隔符 substr 截取指定的 ...
- hisql ORM 框架研究(国内第一个支持HANA的ORM框架)
HiSql 操作说明文档 V1.0 下一代ORM框架 国内第一个支持HANA的ORM框架 hisql源码下载 git clone https://github.com/tansar/HiSql.git ...
- 分享一篇:sql语句中使用子查询,可能会引起查询的性能问题,查询时间会变长
前段时间,做自动化适配的时候,查找需要的数据的时候,使用到了dblink,跨数据库实例进行访问,整段sql拼接再加上dblink,在plsql查询的时候,性能还不是很长时间,最多2分钟可以查到,前期调 ...