Slf4j适配第三方日志组件

1、slf4j应用背景

Java项目工程中,最常用的日志组件logback、log4j、Commons Logging 等。不同的日志组件开放出来的api肯定不一样的。

使用slf4j用有一个好处,项目中需要换日志框架,我们代码里面不需要修改,只需要将日志库jar文件替换即可。下面是调用slf4j下的LoggerFactory来获取Logger接口实例。

Logger logger = LoggerFactory.getLogger(SampleLogsApplication.class);

 我挺好奇的。slf4j是如何适配这些日志组件的,百度看看别的大咖写的这块的文章。也想自己做一个总结。

我这边只看了slf4j 适配 log4j、logback 这两款日志组件,其它的我没去看,接下来主要看slf4j是如何来适配这两款(logback、log4j)日志组件的。

<dependencies>
	<!-- slf4j-->
	<dependency>
		<groupId>org.slf4j</groupId>
		<artifactId>slf4j-api</artifactId>
		<version>1.7.30</version>
	</dependency>
	<!-- logback-classic-->
	<dependency>
		<groupId>ch.qos.logback</groupId>
		<artifactId>logback-classic</artifactId>
		<version>1.2.3</version>
	</dependency>
	<!-- logback-core-->
	<dependency>
		<groupId>ch.qos.logback</groupId>
		<artifactId>logback-core</artifactId>
		<version>1.2.3</version>
	</dependency>
	<!-- log4j-->
	<dependency>
		<groupId>log4j</groupId>
		<artifactId>log4j</artifactId>
		<version>1.2.17</version>
	</dependency>
	<dependency>
		<groupId>org.slf4j</groupId>
		<artifactId>slf4j-log4j12</artifactId>
		<version>1.7.21</version>
	</dependency>
</dependencies>

 2、slf4j源码阅读

public static Logger getLogger(String name) {
     //1、获取一个日志工厂,这个方法转到定义
     ILoggerFactory iLoggerFactory = getILoggerFactory();
     return iLoggerFactory.getLogger(name);
}

getLogger(String name) 这个方法也挺简单, 获取一个日志工厂,我们去看看getILoggerFactory方法去。

//对ILoggerFactory的状态做说明
static final int UNINITIALIZED = 0; //没初始化
static final int ONGOING_INITIALIZATION = 1; //正在初始化
static final int FAILED_INITIALIZATION = 2; //初始化失败
static final int SUCCESSFUL_INITIALIZATION = 3; //初始化成功
static final int NOP_FALLBACK_INITIALIZATION = 4; //无日志实现

// 获取ILoggerFactory日志工厂接口实例
public static ILoggerFactory getILoggerFactory() {
        //1、判断ILoggerFactory 是否初始化过
        if (INITIALIZATION_STATE == UNINITIALIZED) {
            synchronized (LoggerFactory.class) {
                //2、这个是我们最常见的双重校验
                if (INITIALIZATION_STATE == UNINITIALIZED) {
                    //3、修改ILoggerFactory 初始化的状态
                    INITIALIZATION_STATE = ONGOING_INITIALIZATION;
                    //4、这个方法操作成功,状态会修改成 SUCCESSFUL_INITIALIZATION
                    performInitialization();
                }
            }
        }
        switch (INITIALIZATION_STATE) {
        //5、ILoggerFactory初始化成功,执行这段
        case SUCCESSFUL_INITIALIZATION:
            return StaticLoggerBinder.getSingleton().getLoggerFactory();
        case NOP_FALLBACK_INITIALIZATION:
            return NOP_FALLBACK_FACTORY;
        case FAILED_INITIALIZATION:
            throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
        case ONGOING_INITIALIZATION:
            return SUBST_FACTORY;
        }
        throw new IllegalStateException("Unreachable code");
    }

 这段代码就是一个双重校验, 保证ILoggerFactory 只会被实例化一次。重点我们还是要去看performInitialization() 方法。

private final static void performInitialization() {
        //1、绑定,这个方法挺简单的,我们直接转到定义
        bind();
        if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) {
            versionSanityCheck();
        }
    }


private final static void bind() {
	try {
		Set<URL> staticLoggerBinderPathSet = null;
		if (!isAndroid()) {
            //2、这个方法其实就是查看 org.slf4j.impl.StaticLoggerBinder.class 在哪个jar里面,而且jar的路径信息
			staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
			reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
		}
		//2、关键代码在这里面 ... 
		StaticLoggerBinder.getSingleton();
		INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
		reportActualBinding(staticLoggerBinderPathSet);
	}
}

上述代码功能也挺简单的, findPossibleStaticLoggerBinderPathSet() 这个方法其实就是查看 org.slf4j.impl.StaticLoggerBinder.class 在哪个jar包下面。 

最重要的一段 StaticLoggerBinder.getSingleton() ,这StaticLoggerBinder是直接引用日志中对象。

从上图截图我们可以得知,不管是log4j还是logback,它们都有StaticLoggerBinder类,StaticLoggerBinder这个类的namespace一定是 org.slf4j.impl 。

调用StaticLoggerBinder.getSingleton()方法,其实就调用到日志库(log4j、logback)初始化方法, 既然初始化成功了,那么LoggerFactory接口实例也就预备好了。

 3、总结

我阅读slf4-api版本是1.7.30的,不同版本slf4j 适配日志库方式不一样,通过上面分析可以得知,日志库要想和slf4j集成,日志库需要提供一个StaticLoggerBinder类,并且namespace一定是org.slf4j.impl 。

不同日志库StaticLoggerBinder实现方式也不一样,这个自己去看一下就知道,我看到这块代码感觉有点怪怪的,这里用SPI去适配第三方日志库不是更好么?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值