前言

在SpringBoot中使用自定义注解、aop切面打印web请求日志。主要是想把controller的每个request请求日志收集起来,调用接口、执行时间、返回值这几个重要的信息存储到数据库里,然后可以使用火焰图统计接口调用时长,平均响应时长,以便于我们对接口的调用和执行情况及时掌握。

添加依赖

  <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>

 

自定义注解

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface WebLogger { String value() default "";
}

  

AOP定义切面、切点

在实现切面之前先要了解几个aop的注解:

  • @Aspect、
  • @Pointcut 定义切点,后面跟随一个表达式,表达式可以是一个注解,也可以具体到方法级别。
  • @Before
  • @After
  • @Around

实现切面,在before方法里统计request请求相关参数,在around方法里计算接口调用时间。这里统计请求的参数时有个bug,joinpoint.getArgs返回值是一个Object数组,但是数组里只有参数值,没有参数名。还没找到解决办法。

@Aspect
@Component
public class WebLoggerAspect { @Pointcut("@annotation(com.zhangfei.anno.WebLogger)"
public void log() {} @Around("log()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime=System.currentTimeMillis(); Object result=joinPoint.proceed();
System.out.println("Response:"+new Gson().toJson(result));
System.out.println("耗时:"+(System.currentTimeMillis()-startTime)); return result;
} @Before("log()")
public void doBefore(JoinPoint joinPoint) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest(); System.out.println("==================Start=================");
System.out.println("URL:" + request.getRequestURL().toString());
System.out.println("Description:" + getLogValue(joinPoint));
System.out.println("Method:" + request.getMethod().toString()); //打印controller全路径及method
System.out.println("Class Method:" + joinPoint.getSignature().getDeclaringTypeName() + "," + joinPoint.getSignature().getName());
System.out.println("客户端IP:" + request.getRemoteAddr()); System.out.println("请求参数:" + new Gson().toJson(joinPoint.getArgs())); } private String getLogValue(JoinPoint joinPoint) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod(); WebLogger webLogger = method.getAnnotation(WebLogger.class); return webLogger.value();
} @After("log()")
public void doAfter() {
System.out.println("==================End=================");
}
} 

怎么使用注解?

这里就直接在你的web请求方法上直接添加WebLogger注解

@Controller
@RequestMapping("/student")
public class StudentController { private final Logger logger= LoggerFactory.getLogger(StudentController.class); @GetMapping("/list")
@WebLogger("学生列表")
public @ResponseBody List<Student> list(){
ArrayList<Student> list=new ArrayList<>();
Student student0=new Student(1,"kobe",30);
Student student1=new Student(2,"james",30);
Student student2=new Student(3,"rose",30); list.add(student0);
list.add(student1);
list.add(student2); return list;
} @WebLogger("学生实体")
@RequestMapping("/detail")
public @ResponseBody Student student(int id){
return new Student(1,"kobe",30);
} }

切面日志输出效果

总结

从头条上一位朋友文章评论上看到有人提出,在分布式部署的环境中,出现高并发时日志打印会出现错乱的情况,这里还需要把线程id或者声明一个guid, 存入ThreadLoal中统计使用。当然更多的人简历还是使用ELK等分布式日志解决方法,好吧,这些还有待于自己部署环境去尝试。

SpringBoot自定义注解、AOP打印日志的更多相关文章

  1. 自定义注解-aop实现日志记录

    关于注解,平时接触的可不少,像是 @Controller.@Service.@Autowried 等等,不知道你是否有过这种疑惑,使用 @Service 注解的类成为我们的业务类,使用 @Contro ...

  2. java/springboot自定义注解实现AOP

    java注解 即是注释了,百度解释:也叫元数据.一种代码级别的说明. 个人理解:就是内容可以被代码理解的注释,一般是一个类. 元数据 也叫元注解,是放在被定义的一个注解类的前面 ,是对注解一种限制. ...

  3. spring AOP自定义注解方式实现日志管理

    今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接开始!!! 关于配置我还是的再说一遍. 在appli ...

  4. SpringBoot 自定义注解 实现多数据源

    SpringBoot自定义注解实现多数据源 前置学习 需要了解 注解.Aop.SpringBoot整合Mybatis的使用. 数据准备 基础项目代码:https://gitee.com/J_look/ ...

  5. [技术博客] SPRINGBOOT自定义注解

    SPRINGBOOT自定义注解 在springboot中,有各种各样的注解,这些注解能够简化我们的配置,提高开发效率.一般来说,springboot提供的注解已经佷丰富了,但如果我们想针对某个特定情景 ...

  6. SpringCloud微服务实战——搭建企业级开发框架(三十九):使用Redis分布式锁(Redisson)+自定义注解+AOP实现微服务重复请求控制

      通常我们可以在前端通过防抖和节流来解决短时间内请求重复提交的问题,如果因网络问题.Nginx重试机制.微服务Feign重试机制或者用户故意绕过前端防抖和节流设置,直接频繁发起请求,都会导致系统防重 ...

  7. SpringBoot中使用AOP打印接口日志的方法(转载)

    前言 AOP 是 Aspect Oriented Program (面向切面)的编程的缩写.他是和面向对象编程相对的一个概念.在面向对象的编程中,我们倾向于采用封装.继承.多态等概念,将一个个的功能在 ...

  8. Spring AOP 自定义注解实现统一日志管理

    一.AOP的基本概念: AOP,面向切面编程,常用于日志,事务,权限等业务处理.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容(Spring核心之一),是函数式编程 ...

  9. SpringBoot自定义注解

    1.注解的概念 注解是一种能被添加到java代码中的元数据,类.方法.变量.参数和包都可以用注解来修饰.注解对于它所修饰的代码并没有直接的影响. 2.注解的使用范围 1)为编译器提供信息:注解能被编译 ...

随机推荐

  1. 易优CMS:volist的基础应用

      [基础用法] 名称:volist 功能:数据/记录循环输出标签 语法: {eyou:channel type='top'}            {eyou:volist name='$field ...

  2. Kali linux-信息收集-dmitry

    信息收集-dmitry DMitry(Deepmagic Information Gathering Tools 深度信息收集工具)是一个kali linux下用C语言写的工具.主要功能为端口扫描,w ...

  3. Mac遇到挖矿程序的应急方法

    Mac遇到挖矿程序应急的方法 工作笔记:   1.起因:监控发现jsonrpc挖矿报警,询问当事人描述当时情况是安装了sketch软件.   网上可以定位到该IOC   运行后该IOC流量依然可以观测 ...

  4. k8s资产清单(二)

    什么是清单 说白了清单是k8s当中用来定义pod的文件,语法格式遵循yaml语法,在yaml当中可以定义控制器类型,元数据,容器端口号等等等....,也可以针对于清单对pod进行删除等操作 为什么太学 ...

  5. 使用ML.NET进行自定义机器学习

    ML.NET是Microsoft最近发布的用于机器学习的开源,跨平台,代码优先的框架.尽管对我们来说是一个新的框架,但该框架的根源是Microsoft Research,并且在过去十年中已被许多内部团 ...

  6. spark streaming checkpointing windows

    spark streaming的相关概念: spark的核心是创建一个RDD对象,然后对RDD对象进行计算操作等 streaming可以理解为是 一个连续不断的数据流 ,然后将每个固定时间段里的数据构 ...

  7. 浅谈DFS序

    浅谈DFS序 本篇随笔简要讲解一下信息学奥林匹克竞赛中有关树的DFS序的相关内容. DFS序的概念 先来上张图: 树的DFS序,简单来讲就是对树从根开始进行深搜,按搜到的时间顺序把所有节点打上时间戳. ...

  8. nextjs作为koa中间件的使用

    react客户端渲染的缺点:首屏速度慢,对SEO不友好 浏览器请求步骤                                                        客户端跳转 1. ...

  9. 关于一个.2lf和.2f的战争!(貌似书上错了,静待打脸。)

    在山东理工oj上做题,谈到了输入数据... double i: scanf(“%lf”,&i): 谨记呀,lf时,可以输入任何类型的数据,而.2f,只能输入符合其规格的数据. 再谈输出,dou ...

  10. angular6 ngx-echarts 图表数据更新

    最近在用angular写一个echarts图表,初始化赋值数据可以展示,但是重新获取数据以后,图表不会刷新. 后来发现了问题点所在, <div echarts class="demo- ...