JAVA主流日志框架梳理学习及使用
前言
:目前市面上有挺多JAVA的日志框架,比如JUL(JDK自带的日志框架),Log4j,Logback,Log4j2等,有人可能有疑问说还有slf4j,不过slf4j不是一种日志框架的具体实现,而是一种日志门面(日志门面可以理解为是一种统一的接口,只是为了规范日志,没有具体的实现;可以类比USB接口,对于USB接口有好多个厂商,这多个厂商生产出来的USB头都是一样的,使得我们用起来就很方便,slf4j其实也是一样)。虽然市面上有很多日志框架,但是笔者之前只是能够简单的使用日志框架,而且使用时总感觉似懂非懂,对目前市面上的日志框架并没有一个整体且系统的了解。因此,笔者利用周末这两天系统的学习了一下目前市面上的框架,也就有了这篇文章,希望这篇文章能够帮助大家对JAVA日志框架有个清晰的认识。
笔者这篇文件是对该视频内容的提炼,需要的可以自行观看。如果想快速了解日志的重点内容,那么可以继续往下看。
视频链接
一、市面上主要日志简介
目前市面上主要的日志框架有:JUL(JDK自带的日志框架),Log4j,Logback,Log4j2
。
日志门面:slf4j
,log4j2也是一种日志门面,不过因为其实现了丰富的日志功能,所以不把其当做一种日志门面了
日志框架(门面)出现的先后顺序:JUL,Log4j在slf4j门面技术出现之前,logback,Log4j2在slf4j门面技术出现之后。因为JUL,Log4j在slf4j出现之前就有了,所以这两个日志的实现并没有遵循slf4j的规范(不过可以通过导入适配器的依赖来使用)。因为Log4j2是对Log4j的升级,JUL功能比较弱(不过因为是JDK自带的日志实现,不需要导入依赖,使用起来比较方便),所以本文只介绍Logback和Log4j2。
主流日志使用方式:slf4j+Logback、slf4j+Log4j2
使用方式:配置文件。
在使用各种库时,第一步都是导入对应的依赖,日志框架也是一样。此外,对于记录的日志会有不同的日志级别,日志显示(或写入文件)的条件就是当前日志级别大于所设置的日志级别时才会打印,如果不设置日志级别,系统会有默认的日志级别。
日志级别由高到低: error > warn>info>debug>trace(这个日志级别是针对slf4j门面的日志级别,各种日志框架的日志级别都大同小异)
二、slf4j+Logback使用
2.1 导入依赖
在导入依赖时我们需要导入slf4j
的依赖(slf4j-api)
和logback
的依赖,因为依赖的传递性,logback-classic
的依赖中包含了slf4j-api
的依赖,所以我们在实际的使用中只需要导入logback-classic
的依赖即可:
依赖情况
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version></dependency>
2.2 使用方式
对于日志,我们分别测试下面这几种情况:
2.2.1不使用配置文件
2.2.2使用配置文件2.2.2.1输出到控制台
2.2.2.2输出到文件
2.2.2.3输出到文件(对文件拆分)
2.2.1 不使用配置文件
项目结构
执行右面的test01输出如下:
如上图所示,当不添加配置文件时,默认的输出格式如上所示。只有trace
日志级别的日志没有输出,所以logback
系统默认的日志级别是debug
级别。
日志级别的值
/*** The <code>OFF</code> is used to turn off logging.*/
public static final Level OFF = new Level(OFF_INT, "OFF");/*** The <code>ERROR</code> level designates error events which may or not* be fatal to the application.*/
public static final Level ERROR = new Level(ERROR_INT, "ERROR");/*** The <code>WARN</code> level designates potentially harmful situations.*/
public static final Level WARN = new Level(WARN_INT, "WARN");/*** The <code>INFO</code> level designates informational messages* highlighting overall progress of the application.*/
public static final Level INFO = new Level(INFO_INT, "INFO");/*** The <code>DEBUG</code> level designates informational events of lower* importance.*/
public static final Level DEBUG = new Level(DEBUG_INT, "DEBUG");/*** The <code>TRACE</code> level designates informational events of very low* importance.*/
public static final Level TRACE = new Level(TRACE_INT, "TRACE");/*** The <code>ALL</code> is used to turn on all logging.*/
public static final Level ALL = new Level(ALL_INT, "ALL");//对应的具体值
public static final int OFF_INT = Integer.MAX_VALUE;
public static final int ERROR_INT = 40000;
public static final int WARN_INT = 30000;
public static final int INFO_INT = 20000;
public static final int DEBUG_INT = 10000;
public static final int TRACE_INT = 5000;
public static final int ALL_INT = Integer.MIN_VALUE;
2.2.2 使用配置文件
2.2.1 输出到控制台
配置文件名:logback.xml
内容
<?xml version="1.0" encoding="UTF-8" ?><configuration><!--%-10level 日志级别(设置10个字符,字符不够空格补齐,左对齐)%d{yyyy-MM-dd HH:mm:ss.SSS} 日期%c 当前类全限定名%M 当前执行日志的方法%L 行号%thread 线程名称%m或者%msg 信息%n 换行--><property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %thread %L:%m%n"/><appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender"><target>System.err</target><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder></appender><root level="ALL"><appender-ref ref="consoleAppender"/></root>
</configuration>
看这个配置文件,我们可以看到所有的内容都包含在configuration
标签中,configuration
标签内部定义了property,appender,root
标签,其中property
标签是定义配置文件内的变量,方便我们使用(即在后面直接引用该变量就行)。其中appender
标签和root
标签是需要我们重点关注的内容。
我们知道日志一般可以输出到控制台或者文件中,对于具体输出到控制台还是输出到文件中就是通过appender
来控制的。因此,我们可以通过appender
标签来定义一个变量。其中,appender
标签的name
属性就是变量名,class
属性就是变量的类型。appender
标签内的target
标签不太重要,设置的具体值等同于Java中的System.out
和System.err
。appender
标签内的encoder
标签其实是定义日志的输出格式,我们看到的日志一般都会包括日志级别,线程名称,时间,文件全类名,消息等信息,就是通过该标签控制。所以这些是appender
标签的核心内容。
虽然appender
标签定义了具体的appender变量,但决定是否使用该变量时通过下面的root
标签来控制的,我们可以看到root
标签有个level
属性,我们将该属性值设置为ALL
,则表示所有的日志级别都会显示。root
标签下的appender-ref
属性则是决定具体使用哪个appender
变量。可以看到appender-ref
标签的ref
属性值为consoleAppender
,说明使用了变量名为consoleAppender
的appender
输出器。
执行效果如下:
可以看到,所有的日志信息全都输出了(同样执行的test01()
方法)。此外,日志显示为红色,这其实就是System.err
设置的效果。而且我们可以看到输出的日志具有特定的格式,即[INFO ] 2023-12-18 08:26:32.869 com.xlb.LogBackDemo test01 main 14:info 信息
含义为日志级别 时间 当前类全限定名 当前执行日志的方法 线程名 行号:消息体
。这种输出格式即是我们通过encoder
标签下的pattern
标签定义的。格式化的含义具体如下:
%-10level 日志级别(设置10个字符,字符不够空格补齐,左对齐)
%d{yyyy-MM-dd HH:mm:ss.SSS} 日期
%c 当前类全限定名
%M 当前执行日志的方法
%L 行号
%thread 线程名称
%m或者%msg 信息
%n 换行
2.2.2.2 输出到文件
我们上面是将日志成功输出到了控制台,下面我们将日志输出到文件,大致过程和上面类似。
修改后的配置文件如下:
<?xml version="1.0" encoding="UTF-8" ?><configuration><!--%-10level 日志级别(设置10个字符,字符不够空格补齐,左对齐)%d{yyyy-MM-dd HH:mm:ss.SSS} 日期%c 当前类全限定名%M 当前执行日志的方法%L 行号%thread 线程名称%m或者%msg 信息%n 换行--><property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %thread %L:%m%n"/><property name="logDir" value="F:\\CODE\\JAVA\\LogStudyV2\\LogStudy\\LOGBACK_StudyV2\\log"/><appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender"><target>System.err</target><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder></appender><appender name="fileAppender" class="ch.qos.logback.core.FileAppender"><file>${logDir}\mylog.log</file><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder></appender><root level="ALL"><appender-ref ref="fileAppender"/></root>
</configuration>
实际上我们就只修改了这三个地方
最上面指定了日志文件的输出路径的变量(指定位置为当前项目下的log文件夹),中间添加了一个输出到文件的appender
,增加了file
标签,在其内部定义了日志文件的输出路径,下面在root
标签中指定了我们新添加的appender
。
输出结果如下:
可以看到,控制台没有日志输出,但是文件中有日志输出。
2.2.2.3 输出到控制台和文件
修改后的配置如下
<?xml version="1.0" encoding="UTF-8" ?><configuration><!--%-10level 日志级别(设置10个字符,字符不够空格补齐,左对齐)%d{yyyy-MM-dd HH:mm:ss.SSS} 日期%c 当前类全限定名%M 当前执行日志的方法%L 行号%thread 线程名称%m或者%msg 信息%n 换行--><property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %thread %L:%m%n"/><property name="logDir" value="F:\\CODE\\JAVA\\LogStudyV2\\LogStudy\\LOGBACK_StudyV2\\log"/><appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender"><target>System.err</target><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder></appender><appender name="fileAppender" class="ch.qos.logback.core.FileAppender"><file>${logDir}\mylog.log</file><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder></appender><root level="ALL"><appender-ref ref="fileAppender"/><appender-ref ref="consoleAppender"/></root>
</configuration>
可以看到,对于新的配置文件我们只是增加了上面一行,即在root
标签中同时也使用了控制台的appender
。
输出结果如下
可以看到,日志记录输出到了控制台和文件中,而且文件中的日志是追加的方式记录的(可以查看日志的时间来看当前的日志记录)。
从这个案例我们可以知道,日志可以指定多个appender
,指定多个appender
只需要增加对应的appender
引用即可。
2.2.2.3 输出到文件(对文件拆分)
如果日志文件一直追加,那么日志文件就可能变得非常大,不方便日志管理,或者有时候同类型的日志需要归档,所以我们需要对日志文件进行拆分管理,对文件拆分管理方式如下。
修改配置文件
<?xml version="1.0" encoding="UTF-8" ?><configuration><!--%-10level 日志级别(设置10个字符,字符不够空格补齐,左对齐)%d{yyyy-MM-dd HH:mm:ss.SSS} 日期%c 当前类全限定名%M 当前执行日志的方法%L 行号%thread 线程名称%m或者%msg 信息%n 换行--><property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %thread %L:%m%n"/><property name="logDir" value="F:\\CODE\\JAVA\\LogStudyV2\\LogStudy\\LOGBACK_StudyV2\\log"/><appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender"><target>System.err</target><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder></appender><appender name="fileAppender" class="ch.qos.logback.core.FileAppender"><file>${logDir}\mylog.log</file><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder></appender><appender name="rollAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder><file>${logDir}\roll_logback.log</file><!-- 指定拆分规则--><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><fileNamePattern>${logDir}/roll.%d{yyyy-MM-dd}.log%i.gz</fileNamePattern><maxFileSize>1KB</maxFileSize></rollingPolicy></appender><root level="ALL"><appender-ref ref="rollAppender"/></root>
</configuration>
对于日志规则的拆分,如上所示,同样只需要修改这两处。
因为设置了日志文件的大小为1KB,所以我们使用for循环
来追加操作,达到拆分文件的目的,演示如下:
代码:
@Testpublic void test02(){Logger logger = LoggerFactory.getLogger(LogBackDemo.class);for (int i = 0; i < 200; i++) {logger.trace("trace 信息");logger.debug("debug 信息");logger.info("info 信息");logger.warn("warn 信息");logger.error("error 信息");}}
输出:
可以看到日志文件按照我们设置的格式进行了拆分。
2.2.2.4 输出为html格式
除了上面几种格式,还可以将logback
输出为html
的格式,只需要下面这样设置即可:
<?xml version="1.0" encoding="UTF-8" ?><configuration><!--%-10level 日志级别(设置10个字符,字符不够空格补齐,左对齐)%d{yyyy-MM-dd HH:mm:ss.SSS} 日期%c 当前类全限定名%M 当前执行日志的方法%L 行号%thread 线程名称%m或者%msg 信息%n 换行--><property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %thread %L:%m%n"/><property name="logDir" value="F:\\CODE\\JAVA\\LogStudyV2\\LogStudy\\LOGBACK_StudyV2\\log"/><appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender"><target>System.err</target><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder></appender><appender name="fileAppender" class="ch.qos.logback.core.FileAppender"><file>${logDir}\mylog.log</file><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder></appender><appender name="rollAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder><file>${logDir}\roll_logback.log</file><!-- 指定拆分规则--><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><fileNamePattern>${logDir}/roll.%d{yyyy-MM-dd}.log%i.gz</fileNamePattern><maxFileSize>1KB</maxFileSize></rollingPolicy></appender><!-- html格式--><appender name="htmlAppender" class="ch.qos.logback.core.FileAppender"><file>${logDir}\myHtmllog.html</file><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="ch.qos.logback.classic.html.HTMLLayout"><pattern>${pattern}</pattern></layout></encoder></appender><root level="ALL"><appender-ref ref="htmlAppender"/></root>
</configuration>
同样改动很小,输出如下(使用test01):
可以看到有个html文件。
浏览器打开该html日志文件展示如下:
可以看到自动为我们添加了特定的样式,使得日志以表格的形式展示。
2.2.2.5 过滤器
实际使用时,可能每个appender
我们想设置的日志级别都不同,那么此时我们就需要一个过滤器,该过滤器也是通过设置日志级别来控制是否输出当前appender
的日志。
配置如下
<?xml version="1.0" encoding="UTF-8" ?><configuration><!--%-10level 日志级别(设置10个字符,字符不够空格补齐,左对齐)%d{yyyy-MM-dd HH:mm:ss.SSS} 日期%c 当前类全限定名%M 当前执行日志的方法%L 行号%thread 线程名称%m或者%msg 信息%n 换行--><property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %thread %L:%m%n"/><property name="logDir" value="F:\\CODE\\JAVA\\LogStudyV2\\LogStudy\\LOGBACK_StudyV2\\log"/><appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender"><target>System.err</target><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder></appender><!-- 过滤器--><appender name="consoleFilterAppender" class="ch.qos.logback.core.ConsoleAppender"><target>System.err</target><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder><!-- 配置过滤器(等于配置的级别才会输出)--><filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 设置日志的输出级别--><level>INFO</level><!-- 高于level中设置的级别,则打印日志--><onMatch>ACCEPT</onMatch><!-- 低于level中设置的级别,则不打印--><onMismatch>DENY</onMismatch></filter><!-- <!– 配置临界值过滤器(输出大于等于level的日志)–>-->
<!-- <filter class="ch.qos.logback.classic.filter.ThresholdFilter">-->
<!-- <!– 设置日志的输出级别–>-->
<!-- <level>INFO</level>-->
<!-- </filter>--></appender><appender name="fileAppender" class="ch.qos.logback.core.FileAppender"><file>${logDir}\mylog.log</file><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder></appender><appender name="rollAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder><file>${logDir}\roll_logback.log</file><!-- 指定拆分规则--><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><fileNamePattern>${logDir}/roll.%d{yyyy-MM-dd}.log%i.gz</fileNamePattern><maxFileSize>1KB</maxFileSize></rollingPolicy></appender><!-- html格式--><appender name="htmlAppender" class="ch.qos.logback.core.FileAppender"><file>${logDir}\myHtmllog.html</file><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="ch.qos.logback.classic.html.HTMLLayout"><pattern>${pattern}</pattern></layout></encoder></appender><root level="ALL"><appender-ref ref="consoleFilterAppender"/></root></configuration>
在consoleAppender里设置了INFO级别的日志级别,不过root标签下的日志级别是ALL,我们看下输出:
可以看到只输出了INFO
级别的日志,即我们在日志中配的INFO
级别。下面我们看一下另一种过滤器:
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"><!-- 设置日志的输出级别--><level>INFO</level>
</filter>
将上面的过滤器换成这个(ThresholdFilter
),我们再看下输出:
可以看到大于等于INFO
级别的日志都进行了输出。从上面的输出可以看出这两种过滤器的差别。
2.2.2.6 异步日志
因为日志和业务逻辑无关,日志只是便于我们处理问题。所以在项目中一般都会使用异步日志,来提升业务逻辑的处理速度。异步日志的使用如下:
<?xml version="1.0" encoding="UTF-8" ?><configuration><!--%-10level 日志级别(设置10个字符,字符不够空格补齐,左对齐)%d{yyyy-MM-dd HH:mm:ss.SSS} 日期%c 当前类全限定名%M 当前执行日志的方法%L 行号%thread 线程名称%m或者%msg 信息%n 换行--><property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %thread %L:%m%n"/><property name="logDir" value="F:\\CODE\\JAVA\\LogStudyV2\\LogStudy\\LOGBACK_StudyV2\\log"/><appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender"><target>System.err</target><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder></appender><!-- 过滤器--><appender name="consoleFilterAppender" class="ch.qos.logback.core.ConsoleAppender"><target>System.err</target><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder><!-- 配置过滤器(等于配置的级别才会输出)-->
<!-- <filter class="ch.qos.logback.classic.filter.LevelFilter">-->
<!-- <!– 设置日志的输出级别–>-->
<!-- <level>INFO</level>-->
<!-- <!– 高于level中设置的级别,则打印日志–>-->
<!-- <onMatch>ACCEPT</onMatch>-->
<!-- <!– 低于level中设置的级别,则不打印–>-->
<!-- <onMismatch>DENY</onMismatch>-->
<!-- </filter>--><!-- <!– 配置临界值过滤器(输出大于等于level的日志)–>--><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><!-- 设置日志的输出级别--><level>INFO</level></filter></appender><appender name="fileAppender" class="ch.qos.logback.core.FileAppender"><file>${logDir}\mylog.log</file><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder></appender><appender name="rollAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder><file>${logDir}\roll_logback.log</file><!-- 指定拆分规则--><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><fileNamePattern>${logDir}/roll.%d{yyyy-MM-dd}.log%i.gz</fileNamePattern><maxFileSize>1KB</maxFileSize></rollingPolicy></appender><!-- html格式--><appender name="htmlAppender" class="ch.qos.logback.core.FileAppender"><file>${logDir}\myHtmllog.html</file><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="ch.qos.logback.classic.html.HTMLLayout"><pattern>${pattern}</pattern></layout></encoder></appender><!-- 引入异步日志--><appender name="asyncAppender" class="ch.qos.logback.classic.AsyncAppender"><appender-ref ref="consoleAppender"/></appender><root level="ALL"><appender-ref ref="asyncAppender"/></root></configuration>
可以看到,使用异步日志很简单,我们只需要如上定义,最终日志输出来的就是异步日志,注意异步日志里面引用我们定义好的输出到控制台的consoleAppender
。
下面我们看下输出:
@Testpublic void test03(){Logger logger = LoggerFactory.getLogger(LogBackDemo.class);for (int i = 0; i < 200; i++) {logger.trace("trace 信息");logger.debug("debug 信息");logger.info("info 信息");logger.warn("warn 信息");logger.error("error 信息");}for (int i = 0; i < 200; i++) {System.out.println("======================");}}
我们可以看到输出的日志时穿插执行的,即可以证明日志时异步输出的。
2.2.2.7 自定义日志
我们在上面使用的日志其实都是rootLogger,我们应该记得在XML文件最后定义了root标签,这个定义的其实就是rootLogger,rootLogger是日志框架自带的,是所有日志的父级日志。什么是父级日志?对于市面上的所有日志框架,其实是有父子关系的,不过这种父子关系不是通过继承实现,而是通过包路径来体现的。如果包路径越具体,说明其越是儿子。例如:三个包com.aaa.bbb.ccc,和com.aaa.bbb和com.aaa中,com.aaa是com.aaa.bbb与com.aaa.bbb.ccc的父级日志,com.aaa.bbb是com.aaa.bbb.ccc的父级日志。对于父级日志的设置可以对子级日志生效;所以如果想一次生效多个日志,那么可以对父级进行设置。而rootLogger就是所有包的父级日志。那这个日志包路径什么时候指定的呢?我们可以看下面这一行代码:
Logger logger = LoggerFactory.getLogger(LogBackDemo.class);
可以看到,上面参数列表中我们传入了类,java内部通过反射机制可以获得该类的全路径;因为这个方法进行了重载,所以也可以直接指定全路径名。
想要引入自定义日志,需要下面这样配置
自定义日志引入
<?xml version="1.0" encoding="UTF-8" ?><configuration><!--%-10level 日志级别(设置10个字符,字符不够空格补齐,左对齐)%d{yyyy-MM-dd HH:mm:ss.SSS} 日期%c 当前类全限定名%M 当前执行日志的方法%L 行号%thread 线程名称%m或者%msg 信息%n 换行--><property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %thread %L:%m%n"/><property name="logDir" value="F:\\CODE\\JAVA\\LogStudyV2\\LogStudy\\LOGBACK_StudyV2\\log"/><appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender"><target>System.err</target><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder></appender><!-- 过滤器--><appender name="consoleFilterAppender" class="ch.qos.logback.core.ConsoleAppender"><target>System.err</target><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder><!-- 配置过滤器(等于配置的级别才会输出)-->
<!-- <filter class="ch.qos.logback.classic.filter.LevelFilter">-->
<!-- <!– 设置日志的输出级别–>-->
<!-- <level>INFO</level>-->
<!-- <!– 高于level中设置的级别,则打印日志–>-->
<!-- <onMatch>ACCEPT</onMatch>-->
<!-- <!– 低于level中设置的级别,则不打印–>-->
<!-- <onMismatch>DENY</onMismatch>-->
<!-- </filter>--><!-- <!– 配置临界值过滤器(输出大于等于level的日志)–>--><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><!-- 设置日志的输出级别--><level>INFO</level></filter></appender><appender name="fileAppender" class="ch.qos.logback.core.FileAppender"><file>${logDir}\mylog.log</file><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder></appender><appender name="rollAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${pattern}</pattern></encoder><file>${logDir}\roll_logback.log</file><!-- 指定拆分规则--><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><fileNamePattern>${logDir}/roll.%d{yyyy-MM-dd}.log%i.gz</fileNamePattern><maxFileSize>1KB</maxFileSize></rollingPolicy></appender><!-- html格式--><appender name="htmlAppender" class="ch.qos.logback.core.FileAppender"><file>${logDir}\myHtmllog.html</file><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="ch.qos.logback.classic.html.HTMLLayout"><pattern>${pattern}</pattern></layout></encoder></appender><!-- 引入异步日志--><appender name="asyncAppender" class="ch.qos.logback.classic.AsyncAppender"><appender-ref ref="consoleAppender"/></appender><root level="ALL"><appender-ref ref="consoleAppender"/></root><!-- 自定义日志--><logger name="com.xlb" level="info" additivity="false"><appender-ref ref="consoleAppender"/></logger></configuration>
输出如下(使用test01)
可以看到输出了INFO,WARN,ERROR日志级别的日志。
如果我们既有父级目录,又有子级目录,以子级日志目录设置的日志级别为准,如下我将父级日志设置成INFO
级别,将子级日志设置成ALL
级别,并且去掉additivity=false
属性,显示如下:
可以看到同样的日志输出了两份,下面加上additivity=false
再看下输出:
可以看到日志输出只有一份,并且是以子级日志级别为准的。
三、slf4j+Log4j2使用
slf4j+Log4j2日志的使用和slf4j+logback的使用大同小异
3.1 导入依赖
<dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j2-impl</artifactId><version>2.19.0</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.19.0</version></dependency>
</dependencies>
测试类:
package com.xlb;import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class LOG4J2Demo {@Testpublic void test01(){Logger logger = LoggerFactory.getLogger(LOG4J2Demo.class);logger.trace("trace 信息");logger.debug("debug 信息");logger.info("info 信息");logger.warn("warn 信息");logger.error("error 信息");}
}
3.2.1 不使用配置文件
可以看到只输出了ERROR级别的日志,因此log4j2的日志的默认日志级别为error级别。
3.2.2 使用配置文件
3.2.2.1 输出到控制台
<?xml version="1.0" encoding="UTF-8" ?><Configuration><properties><property name="logDir">F:\\CODE\\JAVA\\LogStudyV2\\LogStudy\\LOG4J2_StudyV2\\log</property><property name="pattern">[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %thread %L:%m%n</property></properties><Appenders>
<!-- 输出到控制台--><Console name="consoleAppender" target="SYSTEM_ERR"></Console></Appenders><Loggers><Root level="trace"><AppenderRef ref="consoleAppender"/></Root></Loggers>
</Configuration>
默认输出
<?xml version="1.0" encoding="UTF-8" ?><Configuration><properties><property name="logDir">F:\\CODE\\JAVA\\LogStudyV2\\LogStudy\\LOG4J2_StudyV2\\log</property><property name="pattern">[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %thread %L:%m%n</property></properties><Appenders>
<!-- 输出到控制台--><Console name="consoleAppender" target="SYSTEM_ERR"><patternLayout pattern="${pattern}"/></Console></Appenders><Loggers><Root level="trace"><AppenderRef ref="consoleAppender"/></Root></Loggers>
</Configuration>
格式化输出
3.2.2.2 输出到文件
我们上面是将日志成功输出到了控制台,下面我们将日志输出到文件,大致过程和上面类似。
修改配置文件如下:
<?xml version="1.0" encoding="UTF-8" ?><Configuration><properties><property name="logDir">F:\\CODE\\JAVA\\LogStudyV2\\LogStudy\\LOG4J2_StudyV2\\log</property><property name="pattern">[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %thread %L:%m%n</property></properties><Appenders>
<!-- 输出到控制台--><Console name="consoleAppender" target="SYSTEM_ERR"><patternLayout pattern="${pattern}"/></Console><!-- 输出到文件--><File name="fileAppender" fileName='${logDir}\\log4j2.log'><!-- 配置日志文件格式--><patternLayout pattern="${pattern}"/></File></Appenders><Loggers><Root level="trace"><AppenderRef ref="fileAppender"/></Root></Loggers>
</Configuration>
3.2.2.3 输出到控制台和文件
<?xml version="1.0" encoding="UTF-8" ?><Configuration><properties><property name="logDir">F:\\CODE\\JAVA\\LogStudyV2\\LogStudy\\LOG4J2_StudyV2\\log</property><property name="pattern">[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %thread %L:%m%n</property></properties><Appenders>
<!-- 输出到控制台--><Console name="consoleAppender" target="SYSTEM_ERR"><patternLayout pattern="${pattern}"/></Console><!-- 输出到文件--><File name="fileAppender" fileName='${logDir}\\log4j2.log'><!-- 配置日志文件格式--><patternLayout pattern="${pattern}"/></File></Appenders><Loggers><Root level="trace"><AppenderRef ref="consoleAppender"/><AppenderRef ref="fileAppender"/></Root></Loggers>
</Configuration>
3.2.2.4 输出到文件(对文件拆分)
<?xml version="1.0" encoding="UTF-8" ?><Configuration><properties><property name="logDir">F:\\CODE\\JAVA\\LogStudyV2\\LogStudy\\LOG4J2_StudyV2\\log</property><property name="pattern">[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %thread %L:%m%n</property></properties><Appenders>
<!-- 输出到控制台--><Console name="consoleAppender" target="SYSTEM_ERR"><patternLayout pattern="${pattern}"/></Console><!-- 输出到文件--><File name="fileAppender" fileName='${logDir}\\log4j2.log'><!-- 配置日志文件格式--><patternLayout pattern="${pattern}"/></File><!--fileName:日志文件名$${date:yyyy-MM-dd}:表示以日期为文件夹对日志文件进行归档
--><RollingFile name="rollingFile" fileName="${logDir}/rollog.log"filePattern="${logDir}/$${date:yyyy-MM-dd}/rollog-%d{yyyy-MM-dd-HH-mm}-%i.log"><Policies><!-- 在系统启动时,触发拆分规则,产生一个日志文件--><OnStartupTriggeringPolicy/><!-- 按照文件的大小进行拆分--><SizeBasedTriggeringPolicy size="10KB"/><!-- 按照时间节点进行拆分,拆分规则就是filePattern--><TimeBasedTriggeringPolicy/></Policies><DefaultRolloverStrategy max="30"/></RollingFile></Appenders><Loggers><Root level="trace"><AppenderRef ref="rollingFile"/></Root></Loggers>
</Configuration>
3.2.2.5 自定义日志
<?xml version="1.0" encoding="UTF-8" ?><Configuration><properties><property name="logDir">F:\\CODE\\JAVA\\LogStudyV2\\LogStudy\\LOG4J2_StudyV2\\log</property><property name="pattern">[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %thread %L:%m%n</property></properties><Appenders>
<!-- 输出到控制台--><Console name="consoleAppender" target="SYSTEM_ERR"><patternLayout pattern="${pattern}"/></Console><!-- 输出到文件--><File name="fileAppender" fileName='${logDir}\\log4j2.log'><!-- 配置日志文件格式--><patternLayout pattern="${pattern}"/></File><!--fileName:日志文件名$${date:yyyy-MM-dd}:表示以日期为文件夹对日志文件进行归档
--><RollingFile name="rollingFile" fileName="${logDir}/rollog.log"filePattern="${logDir}/$${date:yyyy-MM-dd}/rollog-%d{yyyy-MM-dd-HH-mm}-%i.log"><Policies><!-- 在系统启动时,触发拆分规则,产生一个日志文件--><OnStartupTriggeringPolicy/><!-- 按照文件的大小进行拆分--><SizeBasedTriggeringPolicy size="10KB"/><!-- 按照时间节点进行拆分,拆分规则就是filePattern--><TimeBasedTriggeringPolicy/></Policies><DefaultRolloverStrategy max="30"/></RollingFile></Appenders><Loggers><!-- 自定义Logger--><Logger name="com.xlb" level="INFO"includeLocation="false" additivity="false"><!-- 将控制台输出的consoleAppender,设置为异步打印--><AppenderRef ref="consoleAppender"/></Logger><Root level="trace"><AppenderRef ref="consoleAppender"/></Root></Loggers>
</Configuration>
3.2.2.5 异步日志
3.2.2.6.1 xml中配置异步日志
<?xml version="1.0" encoding="UTF-8" ?><Configuration><properties><property name="logDir">F:\\CODE\\JAVA\\LogStudyV2\\LogStudy\\LOG4J2_StudyV2\\log</property><property name="pattern">[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %thread %L:%m%n</property></properties><Appenders>
<!-- 输出到控制台--><Console name="consoleAppender" target="SYSTEM_ERR"><patternLayout pattern="${pattern}"/></Console><!-- 输出到文件--><File name="fileAppender" fileName='${logDir}\\log4j2.log'><!-- 配置日志文件格式--><patternLayout pattern="${pattern}"/></File><!--fileName:日志文件名$${date:yyyy-MM-dd}:表示以日期为文件夹对日志文件进行归档
--><RollingFile name="rollingFile" fileName="${logDir}/rollog.log"filePattern="${logDir}/$${date:yyyy-MM-dd}/rollog-%d{yyyy-MM-dd-HH-mm}-%i.log"><Policies><!-- 在系统启动时,触发拆分规则,产生一个日志文件--><OnStartupTriggeringPolicy/><!-- 按照文件的大小进行拆分--><SizeBasedTriggeringPolicy size="10KB"/><!-- 按照时间节点进行拆分,拆分规则就是filePattern--><TimeBasedTriggeringPolicy/></Policies><DefaultRolloverStrategy max="30"/></RollingFile><!-- 异步日志--><Async name="myAsync"><AppenderRef ref="consoleAppender"/></Async></Appenders><Loggers><Root level="trace"><AppenderRef ref="rollingFile"/></Root></Loggers>
</Configuration>
3.2.2.6.2 全局异步日志
全局日志需要在properties文件中指明,xml文件中不需要特殊声明异步日志(文件名为log4j2.component.properties
)
Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
<?xml version="1.0" encoding="UTF-8" ?><Configuration><properties><property name="logDir">F:\\CODE\\JAVA\\LogStudyV2\\LogStudy\\LOG4J2_StudyV2\\log</property><property name="pattern">[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %thread %L:%m%n</property></properties><Appenders>
<!-- 输出到控制台--><Console name="consoleAppender" target="SYSTEM_ERR"><patternLayout pattern="${pattern}"/></Console><!-- 输出到文件--><File name="fileAppender" fileName='${logDir}\\log4j2.log'><!-- 配置日志文件格式--><patternLayout pattern="${pattern}"/></File><!--fileName:日志文件名$${date:yyyy-MM-dd}:表示以日期为文件夹对日志文件进行归档
--><RollingFile name="rollingFile" fileName="${logDir}/rollog.log"filePattern="${logDir}/$${date:yyyy-MM-dd}/rollog-%d{yyyy-MM-dd-HH-mm}-%i.log"><Policies><!-- 在系统启动时,触发拆分规则,产生一个日志文件--><OnStartupTriggeringPolicy/><!-- 按照文件的大小进行拆分--><SizeBasedTriggeringPolicy size="10KB"/><!-- 按照时间节点进行拆分,拆分规则就是filePattern--><TimeBasedTriggeringPolicy/></Policies><DefaultRolloverStrategy max="30"/></RollingFile><!-- 异步日志-->
<!-- <Async name="myAsync">-->
<!-- <AppenderRef ref="consoleAppender"/>-->
<!-- </Async>--></Appenders><Loggers><Root level="trace"><AppenderRef ref="consoleAppender"/></Root></Loggers>
</Configuration>
按照上面这种方式声明的也是异步日志
3.2.2.6.3 混合异步日志
混合异步日志需要引入这个依赖,否则会报错
<!-- 混合异步日志用--><dependency><groupId>com.lmax</groupId><artifactId>disruptor</artifactId><version>3.4.3</version></dependency>
<?xml version="1.0" encoding="UTF-8" ?><Configuration><properties><property name="logDir">F:\\CODE\\JAVA\\LogStudyV2\\LogStudy\\LOG4J2_StudyV2\\log</property><property name="pattern">[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %thread %L:%m%n</property></properties><Appenders>
<!-- 输出到控制台--><Console name="consoleAppender" target="SYSTEM_ERR"><patternLayout pattern="${pattern}"/></Console><!-- 输出到文件--><File name="fileAppender" fileName='${logDir}\\log4j2.log'><!-- 配置日志文件格式--><patternLayout pattern="${pattern}"/></File><!--fileName:日志文件名$${date:yyyy-MM-dd}:表示以日期为文件夹对日志文件进行归档
--><RollingFile name="rollingFile" fileName="${logDir}/rollog.log"filePattern="${logDir}/$${date:yyyy-MM-dd}/rollog-%d{yyyy-MM-dd-HH-mm}-%i.log"><Policies><!-- 在系统启动时,触发拆分规则,产生一个日志文件--><OnStartupTriggeringPolicy/><!-- 按照文件的大小进行拆分--><SizeBasedTriggeringPolicy size="10KB"/><!-- 按照时间节点进行拆分,拆分规则就是filePattern--><TimeBasedTriggeringPolicy/></Policies><DefaultRolloverStrategy max="30"/></RollingFile><!-- 异步日志-->
<!-- <Async name="myAsync">-->
<!-- <AppenderRef ref="consoleAppender"/>-->
<!-- </Async>--></Appenders><Loggers><Root level="trace"><AppenderRef ref="consoleAppender"/></Root><!-- 自定义Logger,让自定义的logger为异步loggerincludeLocation=false表示取出日志中的行号信息(记录日志的行号会使得日志记录的非常慢!)
--><AsyncLogger name="com.xlb" level="trace"includeLocation="false" additivity="false"><!-- 将控制台输出的consoleAppender,设置为异步打印--><AppenderRef ref="consoleAppender"/></AsyncLogger></Loggers>
</Configuration>
总结:上面介绍大致介绍了市面上这两款日志的使用流程,其实日志的使用基本上就是看如何对配置文件进行配置,配置文件配置好后就可以很方便的使用日志进行记录。其实市面上虽然有好几种日志框架,不过其实现的基本思想都差不多,即有下面几点共性:
1.都会分为不同的日志级别
1.1高于当前设置的日志级别就会打印
1.2低于当前设置的日志级别就不打印
2.都设置有输出处理器
2.1输出到控制台
2.2 输出到文件
2.3拆分文件
…3格式化输出:类似于[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %thread %L:%m%n
4异步日志
5日志父子级关系
6自定义日志
希望这篇文章对日志的使用有所帮助,希望能够一键三连呀~
如果想对日志有更深的理解,可以看下这门b站上的课程,这个可能前面20集左右是一个大佬现场直播手撸一个日志框架(没有借助IDE,在vim中一点点敲出来的,很强!!!),不过课程是使用C++讲解的,有兴趣的可以听一下,保证听完对日志会有一个更加深刻的认识!
手撸日志框架
相关文章:

JAVA主流日志框架梳理学习及使用
前言:目前市面上有挺多JAVA的日志框架,比如JUL(JDK自带的日志框架),Log4j,Logback,Log4j2等,有人可能有疑问说还有slf4j,不过slf4j不是一种日志框架的具体实现,而是一种日志门面(日志门面可以理解为是一种统…...
java多个设计模式解决大量if-else堆积
当面对大量的 if-else 语句时,可以考虑使用以下几种常见的设计模式来减少代码的复杂性和维护成本: 策略模式(Strategy Pattern):将各个分支的逻辑封装成不同的策略类,然后通过一个上下文类来根据条件选择合…...
js DOM的一些小操作 获取节点集合Node( getElementsByClassName等)
1. getElementsByClassName(names) 返回文档中所有含有指定类名的节点 document.getElementsByClassName(a) 返回所有类名为a的节点 2.getElementsByName(name) 返回文档中所有指定name的节点。 标签可以有name属性。 3. querySelectorAll(selectors) 返回文档中所有匹配…...

Arcgis导出为tiff
原有一幅影像,在进行一些操作之后,需要导出为tiff 比如我对他进行一个重采样,48m分辨率变为96m 在重采样后的数据图层上右键,导出数据 为什么有时会导出为.gdb格式的呢? 可能是位置处在一个文件地理数据库.gdb下...
nginx中的root and alias命令的区别
Ubuntu关于Nginx的命令: 1、安装Nginx: apt-get install nginx2、查看Nginx运行状态: systemctl status nginx3、启动Nginx: systemctl start nginx4、停止Nginx: systemctl stop nginx5、重启Nginx: …...

python提取图片型pdf中的文字(提取pdf扫描件文字)
前言 文字型pdf提取,python的库一大堆,但是图片型pdf和pdf扫描件提取,还是有些难度的,我们需要用到OCR(光学字符识别)功能。 一、准备 1、安装OCR(光学字符识别)支持库 首先要安…...

08‐Mysql全局优化与Mysql 8.0新特详解
文章目录 Mysql全局优化总结配置文件my.ini或my.cnf的全局参数最大连接数允许用户连接的最大数量MySQL能够暂存的连接数量JDBC连接空闲等待时长client连接空闲等待时长innodb线程并发数innodb存储引擎buffer pool缓存大小行锁锁定时间redo log写入策略binlog写入磁盘机制排序线…...

【LeetCode刷题笔记】155.最小栈
创作不易,本篇文章如果帮助到了你,还请点赞 关注支持一下♡>𖥦<)!! 主页专栏有更多知识,如有疑问欢迎大家指正讨论,共同进步! 更多算法知识专栏:算法分析🔥 给大家跳段街舞感谢…...

我的4096创作纪念日
机缘 岁月如梭,时光一晃已经在CSDN扎根4096天了。第一次注册CSDN好像还是在2012年,那会还没大学毕业。初入CSDN,只是把他当作自己编程时遇到问题的在线笔记记录而已,没想到无意间还帮助了其他遇到同样问题困扰的同学。而在这4096…...
Java Web 01_HTML4HTML5基础标签语法
HMTL基础 1.什么是HTML Hyper Text Markup Language (超文本标记语言)标记又俗称标签(tag),一般格式: <tagName></tagName> 如 <h1></h1>标签里还可以有属性(Attribute): <tagName Atrribute “value” />…...
Androidstudio加载编译时kotlin-compiler-embeddable一直下载中
打开网址 https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-compiler-embeddable/1.6.10/ 1.下载jar包 2.配置下载jar文件到.gradle文件中 文件路径:/Users/“用户名”/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embedd…...

案例073:基于微信小程序的智慧旅游平台开发
文末获取源码 开发语言:Java 框架:SSM JDK版本:JDK1.8 数据库:mysql 5.7 开发软件:eclipse/myeclipse/idea Maven包:Maven3.5.4 小程序框架:uniapp 小程序开发软件:HBuilder X 小程序…...
Flink系列之:Flink 1.8.0 中的状态 TTL:如何在 Apache Flink 中自动清理应用程序状态
Flink系列之:Flink 1.8.0 中的状态 TTL:如何在 Apache Flink 中自动清理应用程序状态 一、状态的瞬态性质二、用于持续清理应用程序状态的状态 TTL三、倒垃圾四、保持完整状态快照干净五、堆状态后端的增量清理六、RocksDB 后台压缩以过滤掉过期状态七、…...

2023 亚马逊云科技 re:Invent 大会探秘:Aurora 无限数据库的突破性应用
文章目录 一、前言二、Amazon Aurora 无限数据库2.1 亚马逊云科技数据库产品发展历程2.2 什么是 Amazon Aurora Limitless Database(无限数据库)2.3 Amazon Aurora Limitless Database 设计架构2.4 Amazon Aurora Limitless Database 分片功能2.5 使用 A…...

IDEA添加Apifox插件后,返回参数不详细解决办法
Apifox官方文档地址(文档中返回的是特殊情况,跟我现在项目的返回不一样,因此需要更改配置) 点击跳转到官方API地址 实现步骤分为两步:第一步:添加配置,第二步使用注解。 1.添加配置 打开Idea设置,添加配置…...
js多图合成一张图
具体思路 先设置画布的宽高,再将每个图片整理成一个对象的数组通过某个方法传出合成后的base64 (1)、创建一个画布的类,他的属性是canvas虚拟dom和ctx (2)、构造器初始化convas对象、ctx、convas的宽高 …...

利用原始套接字解决mac地址错误问题【南瑞SysKeeper-2000】
一:案例描述 一键可视顺控图像智能项目在网络部署过程中,对网络限制隔离安全性要求很高,用到正向隔离装置(南瑞SysKeeper-2000型号)。 图一 正向装置示意图 现场发现问题:直连网线情况下,我方…...
JVM- 为什么G1垃圾回收器需要有大对象区
G1(Garbage-First)垃圾回收器在Java虚拟机(JVM)中引入了大对象区(也称为Humongous Region或H-Region)的概念,主要是为了高效地处理大型对象。在垃圾回收的上下文中,大对象指的是那些…...
操作系统的界面
(1) 请说明系统生成和系统引导的过程。 解: 系统的生成过程:当裸机启动后,会运行一个特殊的程序来自动进行系统的生成(安装),生成系统之前需要先对硬件平台状况进行检查,或者从指定文件处读取…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...

springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...

【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)
LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 题目描述解题思路Java代码 题目描述 题目链接:LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...

基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)
引言 在嵌入式系统中,用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例,介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单,执行相应操作,并提供平滑的滚动动画效果。 本文设计了一个…...

STM32标准库-ADC数模转换器
文章目录 一、ADC1.1简介1. 2逐次逼近型ADC1.3ADC框图1.4ADC基本结构1.4.1 信号 “上车点”:输入模块(GPIO、温度、V_REFINT)1.4.2 信号 “调度站”:多路开关1.4.3 信号 “加工厂”:ADC 转换器(规则组 注入…...
HTML中各种标签的作用
一、HTML文件主要标签结构及说明 1. <!DOCTYPE html> 作用:声明文档类型,告知浏览器这是 HTML5 文档。 必须:是。 2. <html lang“zh”>. </html> 作用:包裹整个网页内容,lang"z…...