• Java异步记录日志-2022新项目


    一、业务场景

      web项目开发中,经常会有的一个操作是记录请求日志,比如记录请求的IP地址,记录请求的路径,记录请求的参数等等。

    每个系统都会根据自己的需要来记录一些请求相关的日志。一般会将记录的日志信息保存到数据库中,以便于查看,如出现异常

    高频率的访问请求,或者是遇到其他一些问题都可以查看记录的日志来进行排查问题。如果系统的请求比较少的话,直接记录日志

    则没什么问题,可是如果请求量比较大的时候,如何来优化日志记录的操作呢?

    二、需求分析

      本篇文章所说的这种方式是使用异步的方式来记录日志。Java代码一般都是同步执行,所谓同步执行,简单理解

    就是从上往下执行,必须要等待上一行代码执行完之后,才会执行下一行代码。了解前端的同学应该对异步操作并不

    陌生,页面中的很多ajaxx请求大多都是异步执行的,并不一定要等前面一行的代码执行完,后面一行的代码也可以执

    行。可是在Java中如何来进行异步操作呢?

    三、解决方案

      从当前项目中学习到的方式如下:

      大致的思路是,在web项目中使用拦截器来拦截需要记录日志的请求,在这个拦截器的拦截方法中,获取一个记录日志的任务对象,

    对象是多实例的。然后使用这个对象设置一些指定的值,比如请求路径,请求IP,请求求时间信息等等。将这些值设置好之后,在使用

    一个工具类来调用方法,传入的参数为这个任务处理类。之后就可以使用异步线程的方式来记录请求的日志数据。自己模仿项目中的方

    式写的代码如下:

    拦截器中的代码:

    @Slf4j
    public class LogRecordInterceptor implements HandlerInterceptor{

        @Autowired
        private LogRecordRunnableTask logRecordRunnableTask;

        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            try{
                String requestURL = request.getRequestURL().toString();
                logRecordRunnableTask.setUrl(requestURL);
                logRecordRunnableTask.setRequestTime(CommonUtil.getCurrentDateTime());
                RecordLogRunnableUtils.submit(logRecordRunnableTask);
            } catch (Exception ex) {
                log.error("日志记录异常--->{}", ex);
            }
            return true;
        }
    }

     

    注册拦截器bean对象的代码:

     

    @Configuration
    public class WebMvcConfig extends WebMvcConfigurerAdapter {

        /**
         *  Function:  addInterceptors
         *  Author :  kaye0110,
        *  Version : 1.0
         *  Description : 注册拦截器                            
         *  Param and Description :  
         *  @param registry
         */
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(logRecordInterceptor()).addPathPatterns("/**");
            super.addInterceptors(registry);
        }

       @Bean
       public LogRecordInterceptor logRecordInterceptor(){
          return  new LogRecordInterceptor();
       }

    }

     

    日志任务处理类的代码

    @Data
    @Component
    @Scope("prototype")
    public class LogRecordRunnableTask implements Runnable{

        @Autowired
        private LogRecordService logRecordService;

        /*
         * 请求地址
         */
        private String url;

        /*
         * 请求时间
         */
        private String requestTime;

        @Override
        public void run() {
            logRecordService.createLogRecord(url, requestTime);
        }
    }

    注意:这个类是多实例的,类中实现Runnable接口,重写Run方法,就在这个方法中执行记录日志的操作。

     

    Service接口实现类的代码.

    @Slf4j
    @Service
    public class LogRecordServiceImpl implements LogRecordService {

        @Override
        public void createLogRecord(String url, String recordTime) {
            log.info("url-->{}, recordTime--->{}", url, recordTime);
        }

    }

    日志记录工具类的代码

    @Slf4j
    public class RecordLogRunnableUtils {

        private RecordLogRunnableUtils(){}

        private static ExecutorService executor = Executors.newFixedThreadPool(20);

         /* @Description: 执行日志记录操作
          * @author: yilang
          * @date: 2022/7/27 13:03
          * @param: runnable
          * @return: void
          */
        public static void submit(Runnable runnable) {
            try{
                executor.submit(runnable);
            } catch (Exception ex) {
                log.error("执行日志操作异常:{}", ex);
            }
        }
    }

     

    简单测试了一下,使用postman一次性发30个请求.

     

    测试结果如下结果符合预期,程序正常执行,后台记录日志的时候是使用多线程的方式来进行处理的。

     

    以后有需要的同学完全可以采用这种方式,来优化日志记录的操作,当访问量越来越大时,这种方式的优点也会提现得更加明显。

    以前也有同事使用过其他方式来优化日志记录,首先将请求的日志信息保存在的redis中,然后另外跑一个定时任务定时去取

    这些日志信息,如果日志信息大于100条则将其存储在数据库中,并且删除已保存的数据。这样在一定程度上也可以提高日志

    记录的效率,如果各位小伙伴还有更好的办法,欢迎留言讨论。

  • 相关阅读:
    从JavaScript到Rust的三年时间小结
    现在性价比高的运动耳机有哪些、性价比最高的蓝牙耳机排行榜
    【21天学习挑战】经典算法之【折半查找】
    从 1.5 开始搭建一个微服务框架——日志追踪 traceId
    一周净赚一套房,“羊了个羊”爆火的产品逻辑可复制吗?
    Java流程控制09:练习题:打印三角形
    什么是分布式锁?几种分布式锁分别是怎么实现的?
    matlab奇技淫巧——绘制三维地图
    csp初赛总结 & 那些年编程走过的坑 & 初高中信竞常考语法算法点
    使用 Spring Boot 构建 RESTful API 的最佳实践
  • 原文地址:https://www.cnblogs.com/yilangcode/p/16530404.html