Springboot加載日志子產品
Spring jcl
Spring jcl 是Springboot連接配接SLF4J的基礎包,實作了對Log4j 2.x API是否存在,以及Spring架構類路徑中的SLF4J 1.7api。
ServiceLoader
通過配置尋找接口的實作類,實作類的jar包的META-INF下建立一個檔案夾services,并在services下建立一個檔案,以接口的全限定名為檔案名,内容為實作類的全限定名。
參考連結:
https://www.jianshu.com/p/7601ba434ff4 https://blog.csdn.net/shi2huang/article/details/80308531Log4j擷取ConfigurationFactory
核心代碼
String ALL_TYPES = "*";
for (final ConfigurationFactory factory : getFactories()) {
final String[] types = factory.getSupportedTypes();
if (types != null) {
for (final String type : types) {
// 隻有 XmlConfigurationFactory 符合條件
if (type.equals(ALL_TYPES)) {
final Configuration config = factory.getConfiguration(loggerContext, name, configLocation);
if (config != null) {
return config;
}
}
}
}
}
Springboot加載log4j2的流程
Springboot 加載log4j2主要分為兩個階段,第一階段成為start, 第二階段為initalize
start階段
- LogAdapter利用Class.forName加載不同日志的實作,使用内部類進行調用
- log4j 通過PluginProcess對 @Plugin注釋識别ConfigurationFactory,具體可參考
Springboot配置log4j2爬坑
initalize階段
初始化階段,SpringApplication.run()方法的 SpringApplicationRunListeners
- beforeInitialize(), 判斷是否以slf4j橋接。
if (isBridgeJulIntoSlf4j()) {
removeJdkLoggingBridgeHandler();
SLF4JBridgeHandler.install();
}
// ClassUtils.isPresent() Sping 實作的類似Class.forName功能
ClassUtils.isPresent(BRIDGE_HANDLER, getClassLoader());
- LoggingApplicationListener 代碼配置onApplicationEvent
public void onApplicationEvent(ApplicationEvent event) {
// beforeInitalize 階段
if (event instanceof ApplicationStartingEvent) {
onApplicationStartingEvent((ApplicationStartingEvent) event);
}
// 環境配置,即initalizeing階段
else if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent(
(ApplicationEnvironmentPreparedEvent) event);
}
// 程式運作起來後,調用日志階段
else if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent((ApplicationPreparedEvent) event);
}
// 程式關閉
else if (event instanceof ContextClosedEvent && ((ContextClosedEvent) event)
.getApplicationContext().getParent() == null) {
onContextClosedEvent();
}
// 失敗
else if (event instanceof ApplicationFailedEvent) {
onApplicationFailedEvent();
}
}
- Log4j2判斷日志是否為同一執行個體,利用了identityHashCoder給AppClassLoader做身份哈希判重
- shutdownhook 學習(有時間在研究)
private void registerShutdownHookIfNecessary(Environment environment,
LoggingSystem loggingSystem) {
boolean registerShutdownHook = environment
.getProperty(REGISTER_SHUTDOWN_HOOK_PROPERTY, Boolean.class, false);
if (registerShutdownHook) {
Runnable shutdownHandler = loggingSystem.getShutdownHandler();
if (shutdownHandler != null
&& shutdownHookRegistered.compareAndSet(false, true)) {
registerShutdownHook(new Thread(shutdownHandler));
}
}
}
void registerShutdownHook(Thread shutdownHook) {
Runtime.getRuntime().addShutdownHook(shutdownHook);
}