spring-logging

启动错误日志打印

可以看到用了一个很大的try-catch,所有的启动错误都通过统一的handleRunFailure来处理

在handleRunFailure方法里,做了几个事情:

发消息;打印错误日志(report;处理钩子方法。。只关心打印错误日志这里

reportFailure方法里会遍历异常reporter,每个reporter都有适用的异常,匹配上了就打印,否则走下面兜底逻辑。

(实际上SpringBoot默认提供了一个reporter实现:FailureAnalyzers

reportException逻辑分为两块,一个是把分析逻辑分发给具体的FailureAnalyzer,analyzer提供一个格式化的分析结果,提供给不同的FailureAnalysisReporter遍历打印。

(FailureAnalysisReporter默认也是提供了一个Logging实现

深入看一下analyze逻辑:主要是继承AbstractFailureAnalyzer 抽象类

分为两个步骤:

  1. findCause:判断这个异常是否是当前类关心的 & 返回关心异常类
    1. getCauseType通过子类的范型找到关心的异常类
    2. 通过循环找cause判断当前异常栈里是否包含当前关心异常类
  2. analyze,把异常栈提供给analyzer,进行错误分析并格式化返回

以一个子类为例,分析+组装结果

看代码的时候发现经常使用到工厂,仔细看一下工厂产品是如何组装的

ArgumentResolver的构造函数:接收两个参数,clazz, object

后面在使用的时候 resolver.resolve(argClazz) 判断参数argClazz 如果等于clazz,则返回object

ps:这个接口命名看着有点奇怪,Spring认为ExceptionReporter是工厂?

getSpringFactoriesInstances负责根据配置文件进行类初始化(当作构造方法使用

SpringFactoriesLoader.forxxx是构造函数,读取并解析META-INF/spring.factories文件,获得了工厂接口类型下的具体实现类列表

load负责把这些全类名实例化,具体逻辑在instantiateFactory里

instantiateFactory 负责通过工厂全类名对类进行实例化

  1. Class.forName类加载获得类clazz
  2. 从clazz中获得construtor
  3. 使用construtor通过反射获得类,args是从resolver里通过参数类型换的实例

感觉这里有点奇怪 为什么要使用这个resolver呢

  1. 使用一个全局的工厂类放在里面也可以
  2. resolver在类型上只支持一个类型 很局限
    这里迭代一下认知:argumentResolver支持and,可以支持多个类型

都看到这了,顺手看一下loggingSystem是如何初始化的

LoggingSystem初始化

LoggingApplicationListener

listener监听application消息,进行初始化(ApplicationStartingEvent

分为两个步骤

  1. 选择具体的实现类
  2. 执行beforeInitialize扩展点

这里选择具体的实现类逻辑如下

可以看到实际上是在当前的list里面按顺序取,这个list也是通过META-INF/spring.factories配置的:

这里有个问题,换别的loggingSystem的时候,这里是如何识别的呢?

先复习一下如何使用log4j2

  1. pom文件中,spring-boot-starter里排除starter-logging(logback,新增starter-log4j2

  1. src/main/resource 下新建log4j2.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="info">
<appenders>
<Console name="Console" target="SYSTEM_OUT" follow="true">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %t %-5level %logger{30}.%method - %msg%n" />
</Console>
</appenders>

<loggers>
<root level="info">
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>

(修改完了以后 在这里打个断点,发现真的变成了log4j2 真神奇

发现遍历时还是先判断logback,然后通过尝试类加载,判断是否选择logback

问题2 listener是什么时候被加载的?

参见https://yzaf.top/2024/spring-event/


spring-logging
https://yzaf.top/2024/spring-logging/
作者
why
发布于
2024年3月6日
许可协议