Last updated on 2025-11-24T14:50:36+08:00
一、TODO
二、脑图
Xmind
Edraw

代码洪荒(面试宝典)
👉 https://www.notion.so/Java-2b5974fbda5e806899f7fa6b19c61c04?source=copy_link
三、Java 日志框架前置基础
1. Java 日志框架的发展史

四、JUL
1. JUL 概述
JUL(Java Util Logging),是 JDK 内置的日志记录框架,使用时无需额外引入第三方库,使用相对简单。
JUL 虽然能满足一般应用的日志需求,但相比 Log4j、SLF4J 等第三方框架,其扩展性和高级特性较为有限。
2. JUL 核心组件

Logger
Logger(记录器)是日志框架的入口,我们可以通过调用 Logger.getLogger(String name) 获取 Logger 实例,并调用其方法记录日志信息。
- 需要注意的是:
Logger 会根据我们设置的 Logger 日志级别来记录需要的日志,对于低于我们设定级别的日志,即使我们调用了日志的记录方法(如 logger.config(xxx)),这些日志也不会被 Logger 记录(可以理解为:日志的第一层过滤)
Logger 通常搭配 Level 和 Filter 使用
Filter
Filter(过滤器) 用于在日志记录被发送到 Handler 之前进行筛选,可以进行定制,决定哪些日志信息应该被接受,哪些应被过滤掉(可以理解为:日志的第二层过滤)
Handler
Handler(处理器),负责接收 Logger 记录的日志,并将日志消息输出到指定目标
Handler 分别有:
ConsoleHandler
- 日志输出到控制台
FileHandler
- 日志输出到文件
SocketHandler
- 日志输出到网络端点
MemoryHandler
- 日志暂存于内存,满足条件时批量输出
- 需要注意的是:
- 一个
Logger 可以关联多个 Handler,以便将日志消息输出到不同的目标。
Handler 会根据我们设置的 Handler 日志级别来输出需要的日志,对于低于设定级别的日志,即使 Logger 将其传递过来,这些日志也不会被输出(可以理解为:日志的第三层过滤)
Handler 通常搭配 Level 和 Formatter 使用
Formatter
Formatter(格式化组件) 定义了日志消息的输出格式。
Formatter 分别有:
SimpleFormatter
- 简单、易读的文本格式
XMLFormatter
- 以
XML 格式输出日志
- 需要注意的是:
- 原生
Java 并没有提供 JSON 格式的格式化组件
- 但是们可以通过自定义
Formatter 类来自定义输出格式
Level
Level(验证级别)定义了日志级别
Level 的级别顺序为:
OFF
- 禁止捕获所有级别的日志信息
SEVERE
- 错误信息,表示严重错误或异常情况,应用可能无法继续运行
WARNING
- 警告信息,提示潜在的问题,但应用仍然可以继续运行
INFO
- 输出常规运行信息,提供系统运行状态
CONFIG
- 输出配置项信息
FINE
- 调试信息(少),详细调试时使用
FINER
- 调试信息(中),详细调试时使用
FINEST
- 调试信息(多),详细调试时使用
ALL
- 捕获所有级别的日志信息
3. JUL 核心特性
JUL 是一个具备层次结构的日志记录器,采用父子关系进行组织。例如 com 是 com.example 的父级,而 com.example 又是 com.example.test 的父级,而最顶层的 com 则以根日志( RootLogger) 作为其父级。
而 JUL 包含以下核心特性:
- 继承的特性
- 如果我们没有为子级
Logger 手动设置日志级别,它会默认继承父级 Logger 的日志级别
- 日志向上传递的特性
- 每当子级
Logger(例如 com.example)记录一条日志时,首先会通过自身配置的 Handler 输出
- 随后,这条日志会向上传递至父级
Logger,并通过父级的 Handler 输出(在父级同样会进行过滤)
- 这个向上传递过程会逐级进行,最终到达最顶层的
RootLogger,并通过其 Handler 输出
- 我们可以禁用这种向上传递行为(通过
setUseParentHandlers(false))
[!NOTE] 注意事项
- 由于日志是逐条向上传递的,而不是等到底层
Handler 整体输出后再整体向上传递,因此可能会看到类似以下的日志输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 3月 12, 2025 10:47:37 上午 com.example.test.Main main 严重: severe 信息 3月 12, 2025 10:47:37 上午 com.example.test.Main main 严重: severe 信息 3月 12, 2025 10:47:37 上午 com.example.test.Main main 严重: severe 信息 3月 12, 2025 10:47:37 上午 com.example.test.Main main 警告: warning 信息 3月 12, 2025 10:47:37 上午 com.example.test.Main main 警告: warning 信息 3月 12, 2025 10:47:37 上午 com.example.test.Main main 警告: warning 信息 3月 12, 2025 10:47:37 上午 com.example.test.Main main 信息: info 信息 3月 12, 2025 10:47:37 上午 com.example.test.Main main 信息: info 信息 3月 12, 2025 10:47:37 上午 com.example.test.Main main 信息: info 信息
|
4. JUL 使用方式
4.1. 进行 JUL 相关配置
4.1.1. 文件配置
4.1.1.1. ${JAVA_HOME}/conf/logging.properties
4.1.1.1.1. 配置概述
该配置用于配置根日志管道
4.1.1.1.2. Logger 配置
1. 配置 Logger 的日志级别
4.1.1.1.3. Handler 配置
1. 配置 RootLogger 使用哪些 Handler
1
| handlers = java.util.logging.ConsoleHandler, java.util.logging.FileHandler
|
2. ConsoleHandler 的详细配置
1 2 3 4 5
| java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
|
3. FileHandler 的详细配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| java.util.logging.FileHandler.level = ALL
java.util.logging.FileHandler.pattern = D:\\EnglishDeployment\\logs\\JUL.%g.log
java.util.logging.FileHandler.limit = 10485760
java.util.logging.FileHandler.count = 5
1. true 1. 追加模式 2. 如果日志文件已经存在,新日志会接在旧日志后面继续写 2. false 1. 覆盖模式 2. 每次应用启动时,如果日志文件已存在,会先清空,从头写新的内容 java.util.logging.FileHandler.append = true
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
|
[!NOTE] 注意事项
- 如果需要将日志写入文件(即使用
FileHandler),需要注意以下三点:
JUL 只创建文件而不会自动生成文件所在的目录,因此必须手动创建 logs 目录,并确保程序具有相应的读写权限。
- 文件路径的格式应使用
\\ 而非 \
JUL 中的日志轮换机制流程如下:
JUL 先将日志记录在 JUL.0.log 文件中。
- 当
JUL.0.log 文件写满时,它会被重命名为 JUL.1.log,同时创建一个新的 JUL.0.log 继续记录。
- 随着
JUL.0.log 日志再次写满,JUL.1.log 会被重命名为 JUL.2.log,而 JUL.0.log 则再次重命名为 JUL.1.log,这样依次进行。
- 当文件数量达到最大限制时,最早的日志文件(如
JUL.4.log)将被删除,以腾出空间
4.1.2. 配置包日志管道
对于某些包下的代码,如果我们不希望完全沿用 RootLogger 的配置,可以在代码中手动为这些包单独配置
在下面的示例中,我们为 com.example.Main 包单独配置了日志管道(有入口,有出口,不如直接叫做日志管道),并且禁用了日志向上传递
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| public class Main { public static void main(String[] args) { ConsoleHandler consoleHandler = new ConsoleHandler(); SimpleFormatter simpleFormatter = new SimpleFormatter(); consoleHandler.setFormatter(simpleFormatter); Logger logger = Logger.getLogger("com.example.Main"); logger.setLevel(Level.INFO); logger.setUseParentHandlers(false); logger.addHandler(consoleHandler); logger.severe("severe 信息"); logger.warning("warning 信息"); logger.info("info 信息"); logger.config("config 信息"); logger.fine("fine 信息"); logger.finer("finer 信息"); logger.finest("finest 信息"); } }
|
[!NOTE] 注意事项
- 如果我们为每个类都单独写一堆日志配置,使用起来就会显得非常繁琐。更好的做法是写一个
LogUtil 工具类,在里面一次性为 com.example 包配置好日志管道,这样后续各个类只需要直接获取 Logger 就能记录日志了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class LogUtil { private static final Logger logger = Logger.getLogger("com.example"); static { ConsoleHandler handler = new ConsoleHandler(); handler.setFormatter(new SimpleFormatter()); handler.setLevel(Level.ALL); logger.addHandler(handler); logger.setUseParentHandlers(false); logger.setLevel(Level.ALL); } public static Logger getLogger() { return logger; } }
|
4.2. 使用 JUL 记录日志
1 2 3 4 5 6 7 8 9 10 11 12
| public class Test { public static void main(String[] args) { Logger logger = Logger.getLogger("com.example.Main"); logger.severe("severe 信息"); } }
|
[!NOTE] 注意事项
JUL 的 Logger 是按名字单例的,都会保存在全局的 LogManager 中。
- 如果你之前已经运行过配置好的
com.example.Main 层的 Logger,那么在其它地方获取同名的 Logger,拿到的就是这个已经配置过的实例。
- 但是如果你之前没有运行过,那么在获取时,
LogManager 会为 com.example.Main 新建一个 Logger,并使用默认配置(继承父级 Logger),再在其它地方获取同名的 Logger,拿到的就是这个已经配置过的实例(即便再运行配置好的 com.example.Main 层的 Logger)
JUL 还提供一种方便的日志记录方式,允许我们动态传递参数,从而代替拼接字符串:
1 2 3
| String name = "Ba Tian"; int age = 18; logger.log(Level.INFO,"学生的姓名为:{0},年龄为:{1}",new Object[]{name,age});
|
五、SLF4J
1. SLF4J 概述
SLF4J(Simple Logging Facade for Java)是一种日志门面框架,为各种日志框架提供统一的抽象接口(API),让开发者在应用中只需依赖于这一套 API,而无需针对不同的日志实现学习各自的专有 API
[!NOTE] 注意事项
SLF4J 只是个日志门面,自身不提供任何配置功能
- 如果需要配置日志,例如设置日志级别等,仍需按照具体日志实现(如
Log4J2、JUL 等)的配置方式,进行相关配置
2. SLF4J 支持的日志级别
SLF4J 支持的日志级别顺序为:
ERROR
- 输出错误信息,表示严重错误或异常情况,应用可能无法继续进行
WARN(最推荐)
- 输出警告信息,提示潜在的问题
INFO
- 输出常规运行信息,提供系统运行状态
DEBUF
- 输出调试信息,比如详细的配置解析过程
TRACE
- 输出最详细的信息,几乎是逐行解释发生了什么
[!NOTE] 注意事项
SLF4J 本身只是个日志门面,因此他没有默认的日志级别,其取决于我们使用的底层日志实现:
JUL
- 默认日志级别是
INFO
Log4J
- 默认日志级别是
ERROR
Log4J2
- 默认日志级别是
ERROR
3. SLF4J 使用方式
3.1. 添加相关依赖
- 创建后
slf4j-api
Maven
- https://mvnrepository.com/artifact/org.slf4j/slf4j-api
Gradle
log4j-slf4j2-impl
Maven
- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j2-impl
Gradle
1 2 3 4 5 6 7 8 9 10 11 12
| <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>2.1.0-alpha1</version> </dependency>
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j2-impl</artifactId> <version>3.0.0-beta2</version> <scope>compile</scope> </dependency>
|
[!NOTE] 注意事项
- 这里引入的
log4j-slf4j2-impl 依赖是一个适配器。
- 因为
SLF4J 诞生之前的日志框架,并未遵循 SLF4J 标准,因此无法在引入 SLF4J 依赖后,立即投入使用,需要额外引入适配器
- 而
SLF4J 之后的日志框架,如果已遵循 SLF4J 规范,则只需直接引入相关依赖即可正常使用。但如果日志框架未遵循 SLF4J 标准(例如 Log4J2),仍然需要引入适配器才能使用
3.2. 使用 SLF4J 记录日志
1 2 3 4 5 6 7 8 9 10 11 12
| public class Test { public static void main(String[] args) { Logger logger = LoggerFactory.getLogger("com.example.Main"); logger.trace("trace 信息"); logger.debug("debug 信息"); logger.info("info 信息"); logger.warn("warn 信息"); logger.error("error 信息"); } }
|
[!NOTE] 注意事项
SLF4J 同样提供另外一种记录方式,允许我们动态传递参数,从而代替拼接字符串:
1 2 3
| String name = "Ba Tian"; int age = 18; logger.log(Level.INFO,"学生的姓名为:{},年龄为:{}",name,age);
|
六、SLF4J + Log4J2
1. SLF4J + Log4J2 概述
使用 SLF4J 作为日志门面框架,搭配 Log4j2 的日志实现框架,绝对是当前市场上最强大、最灵活的日志功能实现方式。
2. Log4J2 相关组件
Log4j2 主要由日志记录器(Loggers)、输出控制器(Appenders)和日志格式化器(Layout)组成
Loggers
Loggers(日志记录器),负责记录日志,并控制日志的输出级别
- 需要注意的是,与
JUL 不同,Log4j2 中的日志信息在 Logger 中确定输出级别后,不会再经过 Handler 的再次过滤,这意味着 Logger 配置的输出级别直接决定最终的日志输出级别
Appenders
Appenders(输出控制器),负责把日志输出到指定位置
Appenders 分别有:
ConsoleAppender
- 将日志输出到控制台
FileAppender
- 将日志写入到单一文件中
RollingFileAppender
- 将日志写入到文件中,支持按大小和时间滚动
JDBCAppender
- 将日志存储到关系型数据库中
Layout
Layout(日志格式化器),决定了日志的格式化方式,即日志输出的具体格式
- 常用的
Layout 包括:
HTMLLayout
- 输出为
HTML 表格的格式
JSONLayout
- 输出为
JSON 格式
XMLLayout
- 输出为
XML 格式
SimpleLayout
- 简单的日志输出格式
PatternLayout(默认)
- 最强大的格式化组件,可以根据自定义日志输出格式
3. Log4J2 支持的日志级别
Log4J2 支持的级别顺序为:
OFF
- 禁止捕获所有级别的日志信息
FATAL
- 输出严重错误信息,应用可能无法继续运行
ERROR
- 输出错误信息,表示严重错误或异常情况,但应用仍然可以继续运行
WARN
- 输出警告信息,提示潜在的问题
INFO
- 输出常规运行信息,提供系统运行状态
DEBUG
- 输出调试信息,比如详细的配置解析过程
TRACE
- 输出最详细的信息,几乎是逐行解释发生了什么
ALL
- 捕获所有级别的日志信息
需要注意的是,无需担心 SLF4J 日志门面框架只有五个标准级别的限制,这是因为适配器在 SLF4J 和 Log4j2 之间建立了一套完整的映射关系:

4. SLF4J + Log4J2 使用方式
4.1. 添加相关依赖
- 创建时
Web
Spring Web
- 创建后
slf4j-api
Maven
- https://mvnrepository.com/artifact/org.slf4j/slf4j-api
Gradle
log4j-api
Maven
- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api
Gradle
log4j-core
Maven
- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core
Gradle
disruptor
Maven
- https://mvnrepository.com/artifact/com.lmax/disruptor
Gradle
log4j-slf4j2-impl
Maven
- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j2-impl
Gradle
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>2.1.0-alpha1</version> </dependency>
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.24.3</version> </dependency>
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.24.3</version> </dependency>
<dependency> <groupId>com.lmax</groupId> <artifactId>disruptor</artifactId> <version>3.4.4</version> </dependency>
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j2-impl</artifactId> <version>2.24.3</version> </dependency>
|
[!NOTE] 注意事项
log4j-api 是 Log4j 的日志门面,为什么在已有 SLF4J 门面的情况下仍需要引入?
- 虽然
SLF4J 是一个通用日志门面,但在使用 Log4j2 作为日志实现时,SLF4J 实际上会访问调用 log4j-api,再由它对接 Log4j2 的具体实现
- 为什么引入的是
Log4j2 依赖,看起来却像是在引入 Log4j 依赖?
- 如果依赖的版本号是
2.x.x,说明引入的确实是 Log4j2
4.2. 进行 Log4J2 相关配置
4.2.1. Xml 配置
4.2.1.1. resources/log4j2.xml
4.2.1.1.1. 配置概述
该配置用于配置 Loggers、Appenders、Layout
[!NOTE] 注意事项
- 文件名必须固定,并且
Log4J2 默认会按照一定顺序在类路径下查找配置文件:
log4j2.xml
log4j2.json(log4j2.jsn)
log4j2.yaml(log4j2.yml)
log4j2.properties
4.2.1.1.2. Tiny 配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="30">
<Properties> <Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n</Property> <Property name="LOG_PATH">D:\\EnglishDeployment\\logs</Property> </Properties> <Appenders> </Appenders> <Loggers> </Loggers>
</Configuration>
|
4.2.1.1.3. 配置 Appenders
1. 配置 ConsoleAppender
1 2 3
| <Console name="ConsoleAppender" target="SYSTEM_OUT"> <PatternLayout pattern="${LOG_PATTERN}"/> </Console>
|
target
- 输出的位置
- 可选参数包括:
SYSTEM_OUT
- 输出到标准输出流(
System.out)
SYSTEM_ERR
- 输出到标准错误流(
System.err)
2. 配置 FileAppender
1 2 3
| <File name="FileAppender" fileName="${LOG_PATH}/app.log"> <PatternLayout pattern="${LOG_PATTERN}"/> </File>
|
3. 配置 RollingFileAppender
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <RollingFile name="RollingFileAppender" fileName="${LOG_PATH}/rolling.log" filePattern="${LOG_PATH}/rolling-%d{yyyy-MM-dd}-%i.log"> <PatternLayout pattern="${LOG_PATTERN}"/> <Policies> <SizeBasedTriggeringPolicy size="10MB"/> <TimeBasedTriggeringPolicy/> </Policies> <DefaultRolloverStrategy max="7"/> </RollingFile>
|
4. JDBCAppender
4.2.1.1.4. 配置 Loggers
1. 根 Logger 配置
1 2 3 4 5 6 7 8 9
| <Root level="INFO">
<AppenderRef ref="ConsoleAppender"/> <AppenderRef ref="RollingFileAppender"/> </Root>
|
2. 包 Logger 配置
1 2 3 4
| <Logger name="com.example.service" level="DEBUG" additivity="false"> <AppenderRef ref="FileAppender"/> </Logger>
|
additivity
- 日志是否向上传递
3. 混合异步日志配置
混合异步日志是指:在保持根日志管道为同步模式的前提下,为特定包的日志管道单独配置为异步模式。
1 2 3
| <AsyncLogger name="com.example.async" level="INFO" additivity="false" includeLocation="false"> <AppenderRef ref="ConsoleAppender"/> </AsyncLogger>
|
includeLocation
- 日志中是否包含行号信息
- 由于获取行号信息会影响日志记录性能,建议将其设置为
false 以提升效率
4.2.1.2. resources/log4j2.component.properties
4.2.1.2.1. 配置概述
全局异步日志是指:所有日志记录的操作统一设置为异步模式
而该配置用于配置异步模式
[!NOTE] 注意事项
- 文件名必须固定
4.2.1.2.2. 具体配置
1
| Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
|
4.3. 使用 Log4J2 记录日志
1 2 3 4 5 6 7 8 9 10 11 12
| public class Test { public static void main(String[] args) { Logger logger = LoggerFactory.getLogger("com.example.Main"); logger.trace("trace 信息"); logger.debug("debug 信息"); logger.info("info 信息"); logger.warn("warn 信息"); logger.error("error 信息"); } }
|
七、Spring Boot Starter Log4J2
1. 快速上手
1.1. 添加相关依赖
- 创建时
Web
Spring Web
- 创建后
spring-boot-starter-log4j2
Maven
- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-log4j2
Gradle
lombok
Maven
- https://mvnrepository.com/artifact/org.projectlombok/lombok
Gradle
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency>
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
|
[!NOTE] 注意事项
- 在添加
spring-boot-starter-web 依赖时,需要排除 spring-boot-starter-logging。因为 Spring Web 默认使用 SLF4J + Logback
lombok 提供了 @Slf4j,我们一般要添加该依赖
1.2. 进行 Log4J2 相关配置
1.3. 使用 SLF4J 记录日志
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Slf4j public class Test { public void test() { Logger logger = LoggerFactory.getLogger("com.example.Main"); logger.trace("trace 信息"); logger.debug("debug 信息"); logger.info("info 信息"); logger.warn("warn 信息"); logger.error("error 信息"); } }
|
[!NOTE] 注意事项
- 以上述代码为例,
@Slf4j 会在编译阶段自动添加 private static final Logger log = LoggerFactory.getLogger(MyService.class)