贷款网站怎么做建站工作室网站源码

当前位置: 首页 > news >正文

贷款网站怎么做,建站工作室网站源码,网站建设的个人条件,贵阳建设网站文章目录 一、介绍二、运行环境三、演示项目1. 接口2. 日志配置文件3. 效果演示4. 异步输出验证 四、异步输出原理五、其他参数配置六、源码分析1. 同步输出2. 异步输出 七、总结 一、介绍 对于每一个开发人员来说#xff0c;在业务代码中添加日志是至关重要的#xff0c;尤… 文章目录 一、介绍二、运行环境三、演示项目1. 接口2. 日志配置文件3. 效果演示4. 异步输出验证 四、异步输出原理五、其他参数配置六、源码分析1. 同步输出2. 异步输出 七、总结 一、介绍 对于每一个开发人员来说在业务代码中添加日志是至关重要的尤其是后端开发如果不打印日志在接口出现bug的时候将无法定位bug有了日志即使接口出现bug也可以通过查询日志很快的定位到bug的位置。 使用springboot开发的朋友使用最多的日志框架想必都是logback了吧毕竟它是springboot官方推荐的日志框架与springboot天然整合。再结合第三方工具lombok当我们需要打印日志时只需要通过log.info(第一条日志);、log.error(日志信息:{}, arg1);简单的代码即可完成打印。 如果接口中出现大量日志且日志是直接输出到日志文件或通过网络发送到其他服务器呢这种场景下将会出现较为耗时的磁盘IO或网络IO从而导致接口响应时间变长。 有没有办法通过异步的形式将日志打印出来呢答案是肯定的logback早就想到这一点了。请往下看。 二、运行环境 springboot2.4.3logback1.2.3。logback是springboot自带的默认日志框架 该版本的springboot中自带该版本的logback因此不必单独引入logback的依赖。 三、演示项目 本项目仅用于logback日志的异步打印因此较为简单仅包含一个接口和logback日志配置文件。

  1. 接口 Slf4j RestController RequestMapping(/student) public class StudentController {GetMapping(/insert)public String insert() {log.info(第一条日志);log.info(第二条日志);log.info(第三条日志);log.info(第四条日志);log.info(第五条日志);return 成功;} }2. 日志配置文件 logback提供了大量的Appender将日志输出到指定的位置。如ConsoleAppender用于同步地将日志输出到控制台FileAppender用于同步地将日志输出到指定日志文件SocketAppender用于同步地将日志通过套接字发送到指定服务器。他们都有一个共同点同步。 那么如何修改日志配置文件将日志输出改为异步呢logback提供了一个Appender的异步实现类AsyncAppender。使用方法也非常简单同样也是通过在配置文件中添加appender标签声明AsyncAppender然后通过引用属性引用一个同步Appender即可如下所示 ?xml version1.0 encodingutf-8 ? configuration!– 日志输出格式 –property namelog.patternvalue%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}) - %gray(%msg%n)/!– 同步输出到控制台 –appender nameconsole classch.qos.logback.core.ConsoleAppenderencoderpattern${log.pattern}/pattern/encoder/appender!– 异步输出 –appender nameasync-console classch.qos.logback.classic.AsyncAppender!– 引用同步将其包装为异步 –appender-ref refconsole //appender!– 采用异步输出 –root levelINFOappender-ref refasync-console //root/configuration3. 效果演示 我们使用postman调用接口得到返回结果如下图所示 查看控制台打印的日志如下图所示 可这如何看出该日志打印和接口业务代码为异步的呢
  2. 异步输出验证 我们在AppenderAttachableImpl类的appendLoopOnAppenders()方法上添加断点且要将该端点设置为多线程模式如下图所示 此时再次调用接口得到相同的结果如下图所示 虽然接口已经正常响应了但是我们发现代码却进入了断点从该方法参数可以看出在将要打印第一条日志时进入断点。如下图所示 且控制台上没有输出任何日志 当我们逐次放开断点使代码继续执行时日志才逐行打印出来。因此我们可以断定接口业务代码与日志的打印为异步执行。 四、异步输出原理 为什么给同步Appender包装一层AsyncAppender就可以实现异步输出呢 AsyncAppender内部维护了一个阻塞队列ArrayBlockingQueuelogback将我们打印日志的代码log.info(第一条日志)封装为一个事件Event每当我们需要打印一行日志时logback会将该事件放在阻塞队列中然后再通过多线程的形式从该阻塞队列中获取一个事件执行。 阻塞队列可以保证日志的输出是有序的多线程保证日志的输出是异步的。 五、其他参数配置 AsyncAppender能实现异步输出日志的关键因素是阻塞队列和多线程既然说到阻塞队列那么必然少不了相关的参数。 参数类型说明queueSizeint阻塞队列的最大容量默认为256。discardingThresholdint默认地当阻塞队列剩余容量达到20%时logback将丢弃trace, debug和info三个级别的日志而只输出warn和error级别的日志。如果需要全部输出则将该值设置为0。includeCallerDataboolean如果为truelogback对日志封装的事件中将包含更多调用者和父线程的信息将降低性能。默认为false。maxFlushTimeint当服务停止时logback将会等待一段时间在这段时间内将正在输出的日志完成。neverBlockboolean当阻塞队列已满时如果为truelogback将丢失日志时间。默认为false。 配置文件如下所示 ?xml version1.0 encodingutf-8 ? configuration!– 日志输出格式 –property namelog.patternvalue%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}) - %gray(%msg%n)/!– 同步输出到控制台 –appender nameconsole classch.qos.logback.core.ConsoleAppenderencoderpattern${log.pattern}/pattern/encoder/appender!– 异步输出 –appender nameasync-console classch.qos.logback.classic.AsyncAppender!– 阻塞队列的参数配置 –queueSize256/queueSizediscardingThreshold20/discardingThresholdincludeCallerDatafalse/includeCallerDatamaxFlushTime1000/maxFlushTimeneverBlockfalse/neverBlock!– 引用同步将其包装为异步 –appender-ref refconsole //appender!– 采用异步输出 –root levelINFOappender-ref refasync-console //root/configuration六、源码分析 在logback中任何日志的输出去都是通过start()方法完成的接下来我们以ConsoleAppender同步输出 和 AsyncAppender异步输出为例从源码层面分析。
  3. 同步输出 进入ConsoleAppender源码查看其start()方法。 可以看到其中第一行代码中通过target.getStream()获取输出目标的流而target属性的声明如下所示从该声明中我们看到通过target.getStream()获取输出目标的流就是System.out.print()了。这下我们就明白ConsoleAppender是如何将日志输出到控制台了。 再进入setOutputStream()方法查看其具体实现从中可以看到是通过lock.lock() 和 lock.unlock()来保证其同步执行的其中lock所是一个非公平的可重入同步锁这是多线程中同步锁AQS体系的概念这里不详细展开我们只需要知道通过该锁实现同步即可。 2. 异步输出 进入AsyncAppender源码查看其start()方法该方法定义在其父类AsyncAppenderBase中。 在该方法中我们看到第102行代码使用queueSize参数声明一个指定容量的阻塞队列默认的discardingThreshold参数为阻塞队列容量的1/5即20%然后就是对worker属性进行设置然后调用其start()方法。worker实际上是Thread类的子类Worker对象调用其start()方法就是通过一个新线程调用该对象的run()方法。 从该方法中我们发现无论是直接调用take()方法获取阻塞队列中的元素还是通过遍历阻塞队列获取其中的元素都会调用appendLoopOnAppenders()方法而该方法就是logback真正输出日志的方法也是我们在验证其异步输出是打断点的地方。 七、总结 logback通过AyncAppender实现日志的异步输出。AyncAppender异步输出的原理是通过阻塞队列和多线程实现的。 纸上得来终觉浅绝知此事要躬行。 ————————我是万万岁我们下期再见————————