热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SpringBoot利用自定义注解记录请求或方法执行日志

2019独角兽企业重金招聘Python工程师标准SpringBoot利用自定义注解记录请求或方法执行日志首先,定义日志注解,注解字段可自行扩展Do

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

Spring Boot利用自定义注解记录请求或方法执行日志

首先,定义日志注解,注解字段可自行扩展

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Log {/**操作名称*/String value() default "";/**模块名*/String moduleName() default "";}

主要思路是:

利用AOP拦截被注解标注的方法,进行相关参数获取。为了防止日志保存影响正常的业务执行,因此利用Spring的事件机制,发送事件给监听器,监听器收到事件后,异步保存日志。

注:在本示例中,使用Lombok注解,请自行了解Lombok注解作用。

下面是Aop的实现类,拿到拦截参数后,关键的一步是通过spring 的事件机制,将事件广播出去。

LogAop.java

@Slf4j
@Aspect
@Component
public class LogAop {@Pointcut(value = "@annotation(com.chillax.boot.core.common.annotation.Log)")public void cutService() {}@Around("cutService()")public Object recordSysLog(ProceedingJoinPoint point) throws Throwable {long startTime = System.currentTimeMillis();//先执行业务Object result = point.proceed();long endTime = System.currentTimeMillis();try {handle(point, endTime - startTime, null);} catch (Exception e) {log.error("日志记录出错!", e);}return result;}@AfterThrowing(pointcut = "cutService()", throwing = "e")public void doAfterThrowing(JoinPoint point, Throwable e) {try {handle(point, null, e);} catch (Exception ex) {log.error("日志记录出错!", ex);}}private void handle(JoinPoint point, Long methodProcessTime, Throwable e) throws Exception {//获取拦截的方法名Signature sig = point.getSignature();MethodSignature msig = null;if (!(sig instanceof MethodSignature)) {throw new IllegalArgumentException("该注解只能用于方法");}msig = (MethodSignature) sig;Object target = point.getTarget();Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());String methodName = currentMethod.getName();//获取拦截方法的参数Object[] params = point.getArgs();//获取操作名称Log annotation = currentMethod.getAnnotation(Log.class);String moduleName = annotation.moduleName();String operationName = annotation.value();//这里根据自己的业务需求,封装自己的业务类SysLog sysLog = new SysLog();SpringContextUtil.publishEvent(new SysLogEvent(sysLog));}}

日志事件类,用于事件间的传递。可以扩展此类用做其他用途。

SysLogEvent.java

public class SysLogEvent extends ApplicationEvent {public SysLogEvent(Object source) {super(source);}}

Spring容器工具类,在项目启动时,注入Spring上下文,然后封装一下事件发送方法及其他常用方法。

SpringContextUtil.java

@Slf4j
@Service
@Lazy(false)
public class SpringContextUtil implements ApplicationContextAware, DisposableBean {private static ApplicationContext applicationContext;public static Object getBean(String name) {return applicationContext.getBean(name);}public static T getBean(String name, Class requiredType) {return applicationContext.getBean(name, requiredType);}public static boolean containsBean(String name) {return applicationContext.containsBean(name);}public static boolean isSingleton(String name) {return applicationContext.isSingleton(name);}public static Class getType(String name) {return applicationContext.getType(name);}public static void publishEvent(ApplicationEvent event) {if (applicationContext != null) {applicationContext.publishEvent(event);}}public static void clearHolder() {if (log.isDebugEnabled()) {log.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);}applicationContext = null;}@Overridepublic void setApplicationContext(ApplicationContext applicationContext)throws BeansException {SpringContextUtil.applicationContext = applicationContext;}@Overridepublic void destroy() throws Exception {SpringContextUtil.clearHolder();}
}

最后,编写事件监听器。

@Async 标注此方法执行为异步,需要使用**@EnableAsync**注解开启此功能

@Order标记此监听器为最低级别加载

@EventListener(SysLogEvent.class) 标注监听的事件

比较重要的是,监听器需要将它加入到Spring容器中。通过event.getSource() 获取到发送事件时,传递的对象。

SysLogListener.java

@AllArgsConstructor
@Slf4j
@Component
public class SysLogListener {private final ISysLogService sysLogService;@Async@Order@EventListener(SysLogEvent.class)public void saveSysLog(SysLogEvent event) {SysLog sysLog = (SysLog) event.getSource();sysLogService.save(sysLog);}
}


转:https://my.oschina.net/u/3226414/blog/3001771



推荐阅读
  • 本文将带你快速了解 SpringMVC 框架的基本使用方法,通过实现一个简单的 Controller 并在浏览器中访问,展示 SpringMVC 的强大与简便。 ... [详细]
  • 原文网址:https:www.cnblogs.comysoceanp7476379.html目录1、AOP什么?2、需求3、解决办法1:使用静态代理4 ... [详细]
  • com.hazelcast.config.MapConfig.isStatisticsEnabled()方法的使用及代码示例 ... [详细]
  • Java高并发与多线程(二):线程的实现方式详解
    本文将深入探讨Java中线程的三种主要实现方式,包括继承Thread类、实现Runnable接口和实现Callable接口,并分析它们之间的异同及其应用场景。 ... [详细]
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • Java中不同类型的常量池(字符串常量池、Class常量池和运行时常量池)的对比与关联分析
    在研究Java虚拟机的过程中,笔者发现存在多种类型的常量池,包括字符串常量池、Class常量池和运行时常量池。通过查阅CSDN、博客园等相关资料,对这些常量池的特性、用途及其相互关系进行了详细探讨。本文将深入分析这三种常量池的差异与联系,帮助读者更好地理解Java虚拟机的内部机制。 ... [详细]
  • 为什么多数程序员难以成为架构师?
    探讨80%的程序员为何难以晋升为架构师,涉及技术深度、经验积累和综合能力等方面。本文将详细解析Tomcat的配置和服务组件,帮助读者理解其内部机制。 ... [详细]
  • 本文节选自《NLTK基础教程——用NLTK和Python库构建机器学习应用》一书的第1章第1.2节,作者Nitin Hardeniya。本文将带领读者快速了解Python的基础知识,为后续的机器学习应用打下坚实的基础。 ... [详细]
  • JVM钩子函数的应用场景详解
    本文详细介绍了JVM钩子函数的多种应用场景,包括正常关闭、异常关闭和强制关闭。通过具体示例和代码演示,帮助读者更好地理解和应用这一机制。适合对Java编程和JVM有一定基础的开发者阅读。 ... [详细]
  • Hadoop的文件操作位于包org.apache.hadoop.fs里面,能够进行新建、删除、修改等操作。比较重要的几个类:(1)Configurati ... [详细]
  • 本文详细介绍了Java反射机制的基本概念、获取Class对象的方法、反射的主要功能及其在实际开发中的应用。通过具体示例,帮助读者更好地理解和使用Java反射。 ... [详细]
  • Flutter 2.* 路由管理详解
    本文详细介绍了 Flutter 2.* 中的路由管理机制,包括路由的基本概念、MaterialPageRoute 的使用、Navigator 的操作方法、路由传值、命名路由及其注册、路由钩子等。 ... [详细]
  • MySQL 5.7 学习指南:SQLyog 中的主键、列属性和数据类型
    本文介绍了 MySQL 5.7 中主键(Primary Key)和自增(Auto-Increment)的概念,以及如何在 SQLyog 中设置这些属性。同时,还探讨了数据类型的分类和选择,以及列属性的设置方法。 ... [详细]
  • 本文主要探讨了Java中处理ActionEvent事件的接口,以及一些常见的编程问题和解决方案,包括方法重载、成员变量访问、镜片质量检测等。 ... [详细]
  • AIX编程挑战赛:AIX正方形问题的算法解析与Java代码实现
    在昨晚的阅读中,我注意到了CSDN博主西部阿呆-小草屋发表的一篇文章《AIX程序设计大赛——AIX正方形问题》。该文详细阐述了AIX正方形问题的背景,并提供了一种基于Java语言的解决方案。本文将深入解析这一算法的核心思想,并展示具体的Java代码实现,旨在为参赛者和编程爱好者提供有价值的参考。 ... [详细]
author-avatar
贾春雨-cherry
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有