- 浏览: 1843811 次
- 性别:
- 来自: 深圳
文章分类
- 全部博客 (665)
- 闲话 (17)
- ruby (1)
- javascript (40)
- linux (7)
- android (22)
- 开发过程 (11)
- 哥也读读源代码 (13)
- JVM (1)
- ant (2)
- Hibernate (3)
- jboss (3)
- web service (17)
- https (4)
- java基础 (17)
- spring (7)
- servlet (3)
- 杂记 (39)
- struts2 (10)
- logback (4)
- 多线程 (2)
- 系统诊断 (9)
- UI (4)
- json (2)
- Java EE (7)
- eclipse相关 (4)
- JMS (1)
- maven (19)
- 版本管理 (7)
- sso (1)
- ci (1)
- 设计 (18)
- 戒烟 (4)
- http (9)
- 计划 (4)
- HTML5 (3)
- chrome extensions (5)
- tomcat源码阅读 (4)
- httpd (5)
- MongoDB (3)
- node (2)
最新评论
-
levin_china:
勾选了,还是找不到
用spring annotation声明的bean,当打包在jar中时,无法被扫描到 -
GGGGeek:
我用的maven-3.5.0,还没有遇到这种情况,使用jar ...
用spring annotation声明的bean,当打包在jar中时,无法被扫描到 -
GGGGeek:
受益匪浅,从组织项目结构,到技术细节,讲的很到位,只是博主不再 ...
一个多maven项目聚合的实例 -
Aaron-Joe-William:
<?xml version="1.0" ...
hibernate逆向工程 -
li272355201:
http://archive.apache.org/dist/ ...
tomcat源码阅读(一)——环境搭建
以前也读过一些开源项目的源码,主要是spring和ant,不过那会都没记录下来,也没仔细消化吸收,现在时间久了忘了好多,而且模模糊糊地感觉学到了一些东西,但具体是什么也说不出个所以然来。深刻反省,这样读源码效果太差。
前几天决定重新开始读源码,并把读源码的过程和收获记录下来。想了想决定先用1-2个月时间把logback的源码看一下。目的是……,好吧,没什么目的,就是想读一下。
大家知道,slf4j为各种日志框架提供了一个统一的界面,使用户可以用统一的接口记录日志,但是动态地决定真正的实现框架。logback,log4j,common-logging等框架都实现了这些接口。所以分析logback,首先要从它怎么对接slf4j说起。
slf4j框架本身是非常简单的,一共只有3个package,不到30个class。而且其中很多类在读源码的时候是不必深究的。
PS:插一句题外话,很多朋友看到一个项目里动辄几十个package,数不清的类,当时就蒙了,然后读了几天就放弃了。这里我说2个建议:
1、源代码的类虽然很多,但是一般是有一个清晰的结构的(当然有些项目确实结构混乱,东一撮西一撮的,那没关系,不读就是了)。所以在深入到具体的细节之前,应该先把整个代码的结构梳理清楚,再一块一块地往下读。梳理清楚了脉络和结构,可以直接跳过不想深究的细节,只要知道它是干什么的就行了,当用到的时候再来看
2、源代码的类虽然很多,但是一般会有一个入口。比如hibernate的SessionFactory,spring的ApplicationContext,logback的LoggerFactory。从入口进去,一点点地读,必要的时候使用debug功能跟着走一走,相信会清晰很多
说完题外话,回到slf4j。slf4j最关键的是2个接口,和一个入口类。搞清楚了这3个,对slf4j就会比较清楚了。
最关键的2个接口,分别是Logger和ILoggerFactory。最关键的入口类,是LoggerFactory
所有的具体实现框架,一定会实现Logger接口和ILoggerFactory接口。前者实际记录日志,后者用来提供Logger,重要性不言自明。而LoggerFactory类,则是前面说过的入口类。
不管实现框架是什么,要获取Logger对象,都是通过这个类的getLogger()方法,所以这个类也非常重要。具体实现框架和slf4j的对接,就是通过这个类
如图,每个日志框架都需要实现ILoggerFactory接口,来说明自己是怎么提供Logger的。像log4j、logback能够提供父子层级关系的Logger,就是在ILoggerFactory的实现类里实现的。同时,它们也需要实现Logger接口,以完成记录日志。为啥log4j和logback可以一个Logger对应多个Appender?这就要去分析它们的Logger实现类。
slf4j自带的NOPLoggerFactory,实现了ILoggerFactory,其getLogger()方法很简单,就是返回一个NOPLogger
NOPLogger实现了Logger接口,它就更简单,如同它的名字一样:什么都不做
下面就是关键的LoggerFactory类了,这个入口类是怎么提供Logger的呢?
首先它调用一个private的getILoggerFactory()方法,获得一个ILoggerFactory的实现类,然后委托这个实现类提供一个Logger实现类。就是这样把获取实际Logger的工作,委托给具体的日志框架上,比如log4j、logback、common-logging等
为了获得ILoggerFactory的实现类,它首先判断初始化是否成功,如果没成功,它会委托NOPLoggerFactory来提供Logger,最终结果就是一个没实现的NOPLogger。如果初始化成功了,就是和日志框架对接成功,就委托日志框架的ILoggerFactory来提供Logger的实现。
在初始化里,它要做3个工作。首先是检查classpath里是否存在多个日志框架,如果有就会抛出警告信息,提示用户只保留一个。然后是关键的bind()方法,绑定实现框架。最后再检查一下版本完整性。
这段代码提到了一个最关键的StaticLoggerBinder类,检查是否有这个类存在,以及这个类有没有getSingleton()方法,如果有,就视为绑定成功。其实这个类还必须有getLoggerFactory()方法,否则虽然绑定成功,但是到了运行期,一样会抛出NoSuchMethodException。我认为这里是slf4j设计不好的地方,应该在bind()方法里,就检查一下StaticLoggerBinder有没有实现getLoggerFactory()方法。
这个StaticLoggerBinder类,就是具体实现框架和slf4j框架对接的接口。
这就介绍完了logback是怎么和slf4j对接的。不止是logback,任何日志框架,一定都是通过自己的StaticLoggerBinder类,来和slf4j对接。这个类的实现,在不同的框架中不同,比如后面会说到,在logback中,这个类被设计为或者简单的返回一个默认的LoggerContext(LoggerContext是ILoggerFactory在logback中的实现),或者通过ContextSelector(logback特有的)来选择一个LoggerContext并返回。
大家可能会有一个疑问:在LoggerFactory类的bind()方法里,依赖了StaticLoggerBinder类,但是slf4j框架里又没有这个类,那么框架一开始是怎么编译通过并发布成jar包的呢?
我认为应该是这样的:
作者一开始的时候,是以类似图里的包结构组织代码的。为了编译通过,作者写了一个StaticLoggerBinder类
然后,作者把org.slf4j、org.slf4j.helpers、org.slf4j.spi这3个package发布为slf4j-api.jar。把org.slf4j.impl发布为slf4j-nop.jar
用户实际使用的时候,必须要引入slf4j-api.jar和具体实现框架,比如log4j.jar,以及对接用的slf4j-log4j.jar,不需要引入slf4j-nop.jar
最后,大家可能还有一个疑问:为什么log4j和logback这么相似,又为什么log4j和logback可以和slf4j结合地这么好呢?这是因为,这3个框架的作者,根本是同一个人。这位大哥应该可以算作日志界的战斗机了
前几天决定重新开始读源码,并把读源码的过程和收获记录下来。想了想决定先用1-2个月时间把logback的源码看一下。目的是……,好吧,没什么目的,就是想读一下。
大家知道,slf4j为各种日志框架提供了一个统一的界面,使用户可以用统一的接口记录日志,但是动态地决定真正的实现框架。logback,log4j,common-logging等框架都实现了这些接口。所以分析logback,首先要从它怎么对接slf4j说起。
slf4j框架本身是非常简单的,一共只有3个package,不到30个class。而且其中很多类在读源码的时候是不必深究的。
PS:插一句题外话,很多朋友看到一个项目里动辄几十个package,数不清的类,当时就蒙了,然后读了几天就放弃了。这里我说2个建议:
1、源代码的类虽然很多,但是一般是有一个清晰的结构的(当然有些项目确实结构混乱,东一撮西一撮的,那没关系,不读就是了)。所以在深入到具体的细节之前,应该先把整个代码的结构梳理清楚,再一块一块地往下读。梳理清楚了脉络和结构,可以直接跳过不想深究的细节,只要知道它是干什么的就行了,当用到的时候再来看
2、源代码的类虽然很多,但是一般会有一个入口。比如hibernate的SessionFactory,spring的ApplicationContext,logback的LoggerFactory。从入口进去,一点点地读,必要的时候使用debug功能跟着走一走,相信会清晰很多
说完题外话,回到slf4j。slf4j最关键的是2个接口,和一个入口类。搞清楚了这3个,对slf4j就会比较清楚了。
最关键的2个接口,分别是Logger和ILoggerFactory。最关键的入口类,是LoggerFactory
所有的具体实现框架,一定会实现Logger接口和ILoggerFactory接口。前者实际记录日志,后者用来提供Logger,重要性不言自明。而LoggerFactory类,则是前面说过的入口类。
Logger logger = LoggerFactory.getLogger(Main.class);
不管实现框架是什么,要获取Logger对象,都是通过这个类的getLogger()方法,所以这个类也非常重要。具体实现框架和slf4j的对接,就是通过这个类
如图,每个日志框架都需要实现ILoggerFactory接口,来说明自己是怎么提供Logger的。像log4j、logback能够提供父子层级关系的Logger,就是在ILoggerFactory的实现类里实现的。同时,它们也需要实现Logger接口,以完成记录日志。为啥log4j和logback可以一个Logger对应多个Appender?这就要去分析它们的Logger实现类。
slf4j自带的NOPLoggerFactory,实现了ILoggerFactory,其getLogger()方法很简单,就是返回一个NOPLogger
public class NOPLoggerFactory implements ILoggerFactory { public NOPLoggerFactory() { // nothing to do } public Logger getLogger(String name) { return NOPLogger.NOP_LOGGER; } }
NOPLogger实现了Logger接口,它就更简单,如同它的名字一样:什么都不做
/** A NOP implementation. */ final public void info(String msg) { // NOP } /** A NOP implementation. */ final public void info(String format, Object arg1) { // NOP } /** A NOP implementation. */ final public void info(String format, Object arg1, Object arg2) { // NOP }
下面就是关键的LoggerFactory类了,这个入口类是怎么提供Logger的呢?
public static Logger getLogger(String name) { ILoggerFactory iLoggerFactory = getILoggerFactory(); return iLoggerFactory.getLogger(name); }
首先它调用一个private的getILoggerFactory()方法,获得一个ILoggerFactory的实现类,然后委托这个实现类提供一个Logger实现类。就是这样把获取实际Logger的工作,委托给具体的日志框架上,比如log4j、logback、common-logging等
public static ILoggerFactory getILoggerFactory() { if (INITIALIZATION_STATE == UNINITIALIZED) { INITIALIZATION_STATE = ONGOING_INITILIZATION; performInitialization(); } 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"); }
为了获得ILoggerFactory的实现类,它首先判断初始化是否成功,如果没成功,它会委托NOPLoggerFactory来提供Logger,最终结果就是一个没实现的NOPLogger。如果初始化成功了,就是和日志框架对接成功,就委托日志框架的ILoggerFactory来提供Logger的实现。
private final static void performInitialization() { singleImplementationSanityCheck(); bind(); if (INITIALIZATION_STATE == SUCCESSFUL_INITILIZATION) { versionSanityCheck(); } }
在初始化里,它要做3个工作。首先是检查classpath里是否存在多个日志框架,如果有就会抛出警告信息,提示用户只保留一个。然后是关键的bind()方法,绑定实现框架。最后再检查一下版本完整性。
private final static void bind() { try { // the next line does the binding StaticLoggerBinder.getSingleton(); INITIALIZATION_STATE = SUCCESSFUL_INITILIZATION; emitSubstituteLoggerWarning(); } catch (NoClassDefFoundError ncde) { String msg = ncde.getMessage(); if (msg != null && msg.indexOf("org/slf4j/impl/StaticLoggerBinder") != -1) { INITIALIZATION_STATE = NOP_FALLBACK_INITILIZATION; Util .report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\"."); Util.report("Defaulting to no-operation (NOP) logger implementation"); Util.report("See " + NO_STATICLOGGERBINDER_URL + " for further details."); } else { failedBinding(ncde); throw ncde; } } catch(java.lang.NoSuchMethodError nsme) { String msg = nsme.getMessage(); if (msg != null && msg.indexOf("org.slf4j.impl.StaticLoggerBinder.getSingleton()") != -1) { INITIALIZATION_STATE = FAILED_INITILIZATION; Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding."); Util.report("Your binding is version 1.5.5 or earlier."); Util.report("Upgrade your binding to version 1.6.x. or 2.0.x"); } throw nsme; } catch (Exception e) { failedBinding(e); throw new IllegalStateException("Unexpected initialization failure", e); } }
这段代码提到了一个最关键的StaticLoggerBinder类,检查是否有这个类存在,以及这个类有没有getSingleton()方法,如果有,就视为绑定成功。其实这个类还必须有getLoggerFactory()方法,否则虽然绑定成功,但是到了运行期,一样会抛出NoSuchMethodException。我认为这里是slf4j设计不好的地方,应该在bind()方法里,就检查一下StaticLoggerBinder有没有实现getLoggerFactory()方法。
这个StaticLoggerBinder类,就是具体实现框架和slf4j框架对接的接口。
这就介绍完了logback是怎么和slf4j对接的。不止是logback,任何日志框架,一定都是通过自己的StaticLoggerBinder类,来和slf4j对接。这个类的实现,在不同的框架中不同,比如后面会说到,在logback中,这个类被设计为或者简单的返回一个默认的LoggerContext(LoggerContext是ILoggerFactory在logback中的实现),或者通过ContextSelector(logback特有的)来选择一个LoggerContext并返回。
大家可能会有一个疑问:在LoggerFactory类的bind()方法里,依赖了StaticLoggerBinder类,但是slf4j框架里又没有这个类,那么框架一开始是怎么编译通过并发布成jar包的呢?
我认为应该是这样的:
作者一开始的时候,是以类似图里的包结构组织代码的。为了编译通过,作者写了一个StaticLoggerBinder类
private final ILoggerFactory loggerFactory; private StaticLoggerBinder() { loggerFactory = new NOPLoggerFactory(); } public ILoggerFactory getLoggerFactory() { return loggerFactory; }
然后,作者把org.slf4j、org.slf4j.helpers、org.slf4j.spi这3个package发布为slf4j-api.jar。把org.slf4j.impl发布为slf4j-nop.jar
用户实际使用的时候,必须要引入slf4j-api.jar和具体实现框架,比如log4j.jar,以及对接用的slf4j-log4j.jar,不需要引入slf4j-nop.jar
最后,大家可能还有一个疑问:为什么log4j和logback这么相似,又为什么log4j和logback可以和slf4j结合地这么好呢?这是因为,这3个框架的作者,根本是同一个人。这位大哥应该可以算作日志界的战斗机了
发表评论
-
小读spring ioc源码(五)——BeanDefinitionDocumentReader
2012-07-28 13:11 2816上一篇博客说到,BeanDefinition的解析,已经走到了 ... -
小读spring ioc源码(四)——BeanDefinitionReader
2012-07-24 19:02 2440上一篇博客说到,ApplicationContext将解析Be ... -
小读spring ioc源码(三)——XmlWebApplicationContext初始化的整体过程
2012-07-12 16:54 2923上一篇说到,ContextLoader ... -
小读spring ioc源码(二)——ContextLoaderListener
2012-06-25 18:41 2872实际开发中,比较多的项目是web项目,这时候加载spring, ... -
小读spring ioc源码(一)——整体介绍
2012-06-18 22:59 2604最近在读spring ioc的源码,用EA画了几张比较清楚的类 ... -
读logback源码系列文章(八)——记录日志的实际工作类Encoder
2011-10-17 20:34 3012本系列的博客从logback怎么对接slf4j开始,逐步介绍了 ... -
读logback源码系列文章(七)——配置的实际工作类Action
2011-10-11 22:59 3564上篇博客介绍了ContextInitializer类如何把框架 ... -
读logback源码系列文章(六)——ContextInitializer
2011-10-09 21:46 6835放了一个长假回来啦,继续写本系列博客 这篇博客我们接着上一篇 ... -
读logback源码系列文章(五)——Appender
2011-09-16 21:03 13848明天要带老婆出国旅游 ... -
读logback源码系列文章(四)——记录日志
2011-09-12 02:22 4434今天晚上本来想来写一下Logger怎么记录日志,以及Appen ... -
读logback源码系列文章(三)——创建Logger
2011-09-07 21:35 6214上一篇博客介绍了logback的StaticLoggerBin ... -
读logback源码系列文章(二)——提供ILoggerFactory
2011-09-07 20:07 6661上篇博客介绍了logback是 ...
相关推荐
"logback-slf4j日志配置文件下载即可使用" logback-slf4j是Java领域中一种常用的日志记录解决方案,它通过结合slf...logback-slf4j日志配置文件提供了一种灵活、可靠的日志记录解决方案,能够满足不同的日志记录需求。
当我们提到“log4j-slf4j+logback1.3.0”时,这意味着在一个项目中,SLF4J被用作日志的抽象层,而Logback 1.3.0作为实际的日志实现。这样的组合允许开发者利用SLF4J的简单API编写日志代码,同时享受Logback提供的高...
Logback是日志框架,而SLF4J(Simple Logging Facade for Java)则是一个日志抽象层,它们共同为Java应用程序提供灵活且高效的日志记录能力。 **SLF4J介绍** SLF4J(Simple Logging Facade for Java)是一个接口层...
SLF4J(Simple Logging Facade for Java)是Java中的一种日志门面(Logging Facade),它为各种日志框架提供了一个简单的统一接口,如Log4j、Java Util Logging、Logback等。通过SLF4J,开发者可以在运行时绑定任意...
SLF4J(Simple Logging Facade for Java)是Java中一个重要的日志抽象层,它为各种日志框架,如Log4j、java.util.logging、Logback等提供了一个统一的接口。通过SLF4J,开发者可以在不修改代码的情况下更换底层的...
SLF4J(Simple Logging Facade for Java)是一个日志门面,它为各种日志框架提供了统一的接口,如Log4j、Logback等。它的主要目的是让开发者能够在部署时自由选择所需的日志实现,而无需修改代码。SLF4J通过引入`...
"Logback + SLF4J Web项目源码" 提示我们这是一个基于Logback和SLF4J的日志管理系统,用于web应用程序。Logback是Java平台上的一个日志框架,它是一个替代log4j的更高效、更灵活的工具。SLF4J(Simple Logging ...
SLF4J(Simple Logging Facade for Java)是Java日志框架的一个抽象层,它提供了一个统一的API,允许开发人员在运行时插入所需的日志框架。SLF4J允许您选择任何支持的底层日志库,如Logback、Log4j、Java Util ...
https://github.com/tomcat-slf4j-logback/tomcat-slf4j-logback上的jar与源码,网络不好,下载不易,特此分享。包括: logback-1.2.3.zip Tomcat7.0.82\tomcat-juli-7.0.82-slf4j-1.7.25-logback-1.2.3.zip Tomcat...
本文将深入探讨三个重要的Java日志框架——Log4j、Logback和SLF4J,并分析它们之间的关系和使用场景。 **Log4j** Log4j是Apache组织的一个开源项目,是Java世界中最先广泛使用的日志记录框架之一。它的核心功能...
SLF4J的主要目的是为各种日志框架,如log4j、logback等,提供一个统一的接口,使得应用程序可以独立于具体的日志实现进行开发,提高了代码的可移植性和灵活性。 标题中的"slf4j-log4j12-1.7.12.jar"是SLF4J的一个...
SLF4J(Simple Logging Facade for Java)是Java中的一种日志门面(Logging Facade),它为各种日志框架提供了一个简单的统一接口,如Log4j、Java Util Logging、Logback等。这个jar包是SLF4J的核心组件,用于在应用...
slf4j,logback.xml
SLF4J(Simple Logging Facade for Java)是Java中的一种日志抽象层,它为各种日志框架,如Log4j、Logback等提供了一个统一的接口。SLF4J的设计目标是允许最终用户在部署其应用程序时插入所需的日志库。这样,开发者...
SLF4J(Simple Logging Facade for Java)是Java中的一种日志抽象层,它提供了一个接口,允许用户在运行时动态地绑定到各种具体的日志框架,如Log4j、Java内置的日志或者Logback等。这个设计使得开发者可以在不修改...
SLF4J(Simple Logging Facade for Java)是Java中的一种日志抽象层,它为各种日志框架,如Log4j、Logback等提供一个简单的接口,使得开发者能够在不改变代码的情况下更换日志实现。这个接口使得应用程序的代码与...
SLF4J提供了一个抽象层,允许开发者在运行时选择合适的日志实现,比如Log4j、Logback等。这个"slf4j-log4j12.jar"文件就是SLF4J与Log4j 1.2桥接器的实现,它使得SLF4J调用能够被Log4j 1.2的日志系统捕获并处理。 1....
**SLF4J(Simple Logging Facade for Java)** 是一个为各种日志框架提供简单统一接口的Java库,使得最终用户能够在部署时插入所需的日志实现,如Log4j、Logback等。**Logback** 则是SLF4J的推荐后端实现,由Log4j的...
SLF4J(Simple Logging Facade for Java)是Java中的一种日志抽象层,它为各种日志框架提供了一个统一的API,如Log4j、Java Util Logging、Logback等。这个API允许开发者在部署应用时选择合适的日志实现,而无需修改...
SLF4J提供了一个抽象层,允许开发人员在不修改代码的情况下切换不同的日志框架,如Log4j、Logback等。而Log4j12则是Apache Log4j的第二个主要版本,它提供了丰富的日志记录功能和性能优化。 SLF4J的核心思想是引入...