SLF4J源码解析-LoggerFactory(二)
承接前文SLF4J源码解析-LoggerFactory(一),本文则主要针对获取ILoggerFactory对象作下简单的分析
LoggerFactory#getILoggerFactory()
源码如下
public static ILoggerFactory getILoggerFactory() {
***
***
switch (INITIALIZATION_STATE) {
case SUCCESSFUL_INITILIZATION:
return StaticLoggerBinder.getSingleton().getLoggerFactory();
case NOP_FALLBACK_INITILIZATION:
return NOP_FALLBACK_FACTORY;
case FAILED_INITILIZATION:
throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
case ONGOING_INITILIZATION:
// support re-entrant behavior.
// See also http://bugzilla.slf4j.org/show_bug.cgi?id=106
return TEMP_FACTORY;
}
throw new IllegalStateException("Unreachable code");
}
根据前文的分析,SL4J获取Logger对象需要classpath下拥有
StaticLoggerBinder类,本文则选取logback API来作解析
StaticLoggerBinder.getSingleton().getLoggerFactory()-成功初始化状态下的获取ILoggerFactory()
StaticLoggerBinder.getSingleton()-获取StaticLoggerBinder实例
此处我们只需要分析下StaticLoggerBinder的静态初始化块
static {
SINGLETON.init();
}
紧接着看下init()方法
void init() {
try {
try {
//此处的defaultLoggerContext为LoggerContext
//此处也会去加载配置文件
new ContextInitializer(defaultLoggerContext).autoConfig();
} catch (JoranException je) {
Util.report("Failed to auto configure default logger context", je);
}
// logback-292
//检查是否defaultLoggerContext注册了StatusListener
if(!StatusUtil.contextHasStatusListener(defaultLoggerContext)) {
StatusPrinter.printInCaseOfErrorsOrWarnings(defaultLoggerContext);
}
//内部调用
contextSelectorBinder.init(defaultLoggerContext, KEY);
initialized = true;
} catch (Throwable t) {
// we should never get here
Util.report("Failed to instantiate [" + LoggerContext.class.getName()
+ "]", t);
}
}
看下ContextInitializer如何加载相应的配置文件
ContextInitializer#autoConfig()
直接看源码
public void autoConfig() throws JoranException {
//判断系统变量logback.statusListenerClass是否设定,设定了则注册
//StatusListener
StatusListenerConfigHelper.installIfAsked(loggerContext);
//查找相应的配置文件,我们可以简单的看下
URL url = findURLOfDefaultConfigurationFile(true);
if (url != null) {
//加载相应的配置文件
configureByResource(url);
} else {
//没有则创建名为console的ConsoleAppender
BasicConfigurator.configure(loggerContext);
}
}
我们看下ContextInitializer如何查找配置文件
ContextInitializer#findURLOfDefaultConfigurationFile()
直接阅读源码
public URL findURLOfDefaultConfigurationFile(boolean updateStatus) {
ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this);
//首先查找系统变量logback.configurationFile指定的配置文件
URL url = findConfigFileURLFromSystemProperties(myClassLoader, updateStatus);
if (url != null) {
return url;
}
//反之则查找classpath下是否存在名为logback.groovy配置文件
url = getResource(GROOVY_AUTOCONFIG_FILE, myClassLoader, updateStatus);
if (url != null) {
return url;
}
//反之则查找classpath下是否存在名为logback-test.xml配置文件
url = getResource(TEST_AUTOCONFIG_FILE, myClassLoader, updateStatus);
if (url != null) {
return url;
}
//最后则查找classpath下是否存在名为logback.xml的配置文件
return getResource(AUTOCONFIG_FILE, myClassLoader, updateStatus);
}
根据源码整理下logback加载配置文件的顺序
查找系统变量logback.configurationFile指定的配置文件
上述不存在则查找classpath下是否存在名为logback.groovy配置文件
上述不存在则查找classpath下是否存在名为logback-test.xml配置文件
最后查找classpath下是否存在名为logback.xml的配置文件
注意:此处的classpath特指根目录下,web环境下一般指
WEB-INF/classes根目录
ContextInitializer#configureByResource()-加载指定的配置文件
具体源码如下
public void configureByResource(URL url) throws JoranException {
//指定的文件查找不到则抛出异常
if (url == null) {
throw new IllegalArgumentException("URL argument cannot be null");
}
//针对结尾为groovy的配置文件进行解析
if (url.toString().endsWith("groovy")) {
if (EnvUtil.isGroovyAvailable()) {
// avoid directly referring to GafferConfigurator so as to avoid
// loading groovy.lang.GroovyObject . See also http://jira.qos.ch/browse/LBCLASSIC-214
GafferUtil.runGafferConfiguratorOn(loggerContext, this, url);
} else {
StatusManager sm = loggerContext.getStatusManager();
sm.add(new ErrorStatus("Groovy classes are not available on the class path. ABORTING INITIALIZATION.",
loggerContext));
}
}
//对结尾为xml的文件进行解析
if (url.toString().endsWith("xml")) {
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext(loggerContext);
configurator.doConfigure(url);
}
}
具体的解析步骤就不讲解了,读者有兴趣可自行去分析
NOPLoggerFactory#NOP_FALLBACK_INITILIZATION状态下生成的ILoggerFactory
此日志工厂主要生成不打印任何日志的Logger对象
小结
通过分析源码我们可以得知其他的API是如何结合SL4J来实现Logger原理的。本文是以logback为例的,具体的逻辑可见本文的详细内容
SLF4J源码解析-LoggerFactory(二)的更多相关文章
- SLF4J源码解析-LoggerFactory(一)
slf4j的含义为Simple logging facade for Java,其为简单的为java实现的日志打印工具,本文则对其源码进行简单的分析 JAVA调用SLF4J public class ...
- Cwinux源码解析(二)
我在我的个人博客上发表了第二篇解析文章.欢迎各位读者批评指正. Cwinux源码解析(二)
- # Volley源码解析(二) 没有缓存的情况下直接走网络请求源码分析#
Volley源码解析(二) 没有缓存的情况下直接走网络请求源码分析 Volley源码一共40多个类和接口.除去一些工具类的实现,核心代码只有20多个类.所以相对来说分析起来没有那么吃力.但是要想分析透 ...
- Spring事务源码解析(二)获取增强
在上一篇文章@EnableTransactionManagement注解解析中,我们搭建了源码阅读的环境,以及解析了开启Spring事务功能的注解@EnableTransactionManagemen ...
- Netty 源码解析(二):Netty 的 Channel
本文首发于微信公众号[猿灯塔],转载引用请说明出处 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty源码解析(一):开始 当前:Netty 源码解析(二): Netty 的 Channel ...
- AOP源码解析之二-创建AOP代理前传,获取AOP信息
AOP源码解析之二-创建AOP代理前传,获取AOP信息. 上篇文章对AOP的基本概念说清楚了,那么接下来的AOP还剩下两个大的步骤获取定义的AOP信息,生成代理对象扔到beanFactory中. 本篇 ...
- 老生常谈系列之Aop--Spring Aop源码解析(二)
老生常谈系列之Aop--Spring Aop源码解析(二) 前言 上一篇文章老生常谈系列之Aop--Spring Aop源码解析(一)已经介绍完Spring Aop获取advice切面增强方法的逻辑, ...
- 【vuejs深入三】vue源码解析之二 htmlParse解析器的实现
写在前面 一个好的架构需要经过血与火的历练,一个好的工程师需要经过无数项目的摧残. 昨天博主分析了一下在vue中,最为基础核心的api,parse函数,它的作用是将vue的模板字符串转换成ast,从而 ...
- RxJava2 源码解析(二)
概述 承接上一篇RxJava2 源码解析(一),本系列我们的目的: 知道源头(Observable)是如何将数据发送出去的. 知道终点(Observer)是如何接收到数据的. 何时将源头和 ...
随机推荐
- ubuntu输入某个目录测试该目录里.C文件里代码行数shell脚本
#!/bin/bash echo "★☆ ★☆ ★☆ ★☆ ★☆★☆★☆ ★☆ ★☆ ★☆ ★☆★" echo "★☆ 统计代码行数 ☆★&qu ...
- 第一章:eclipse 中修改字体大小和编码格式
eclipse 中修改字体大小的步骤: 1. 在 eclipse 的工具栏中,找到 weindows 下面的 preferences 2. 在 preferences 的 输出 font ,在 Bas ...
- 使用Vue-resource完成交互
使用vue-resource 引入vue-resource vue-resource就像jQuery里的$.ajax,是用来跟后端交互数据的,vue-resource是vue的一个插件,所以我们在开始 ...
- 【WeX5学习】 后端服务之访问数据库表
WeX5是跨段移动开发框架,将H5的标签封装成组件,实现可视化.组件化快速开发.实现一次开发,多端(iOS.安卓和微信)运行.WeX5的IDE基于Eclipse,提供了一个完全可视化.组件化.拖拽式开 ...
- redhat系列linux系统 修改主机名的正确方法
##注:无特别说明,以下称呼的linux系统统一视为redhat系linux redhat系列linux系统 如果想修改主机名 很多人可能都会以为是: $hostname NEW-NAME 或者在 / ...
- 简单谈谈js中的MVC
MVC是什么? MVC是一种架构模式,它将应用抽象为3个部分:模型(数据).视图.控制器(分发器). 本文将用一个经典的例子todoList来展开(代码在最后). 一个事件发生的过程(通信单向流动): ...
- TensorFlow conv2d实现卷积
tf.nn.conv2d是TensorFlow里面实现卷积的函数,参考文档对它的介绍并不是很详细,实际上这是搭建卷积神经网络比较核心的一个方法,非常重要 tf.nn.conv2d(input, fil ...
- 【echart】学习笔记
1. x 轴 y轴 的max min 只能为5的倍数 2.
- redis 一般性使用概述
最近一段时间与redis接触比较频繁.发现有些东西还是工作中经常会用到的,自己也花了点时间巩固下.本篇文章主要是以总结性的方式梳理,因为redis的主题很大,任何一个技术点展开都是几篇文章的量.也可以 ...
- 两百条微信小程序跳坑指南(不定时更新)
微信小程序联盟出品 跳坑textarea<二百二十三>不显示文本及textarea相关问题集合跳坑<二百一十三> background-image无法获取本地资源图片....跳 ...