- 浏览: 1843782 次
- 性别:
- 来自: 深圳
文章分类
- 全部博客 (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源码阅读(一)——环境搭建
放了一个长假回来啦,继续写本系列博客
这篇博客我们接着上一篇的主题,来介绍一下logback是怎么读取配置文件并初始化整个框架的。还是老规矩,先上总览图
从图中可以看到,logback框架的初始化是由ContextInitializer类来负责完成的,而实际进行配置的是GenericConfigurator类,它调用SaxEventRecorder类来负责读取logback.xml文件,然后由Interpreter类来进行解析,而最后真正的初始化工作,是由一系列Action组件来完成。接下来就实际看看代码
以上代码来自StaticLoggerBinder类,它在提供LoggerContext之前,就对LoggerContext进行初始化,初始化的入口方法,即是ContextInitializer类的autoConfig()方法
这里首先调用findURLOfDefaultConfigurationFile()方法,来寻找一个配置文件,一般就是logback.xml文件,如果没有找到,则用BasicConfigurator来进行默认配置,否则就调用configureByResource()方法,根据配置文件进行配置
这里如果配置文件是以.groovy结尾,就调用另一种方法进行配置,我没有跟进去看;如果是常规以.xml文件结尾,那么就用JoranConfigurator类来进行配置
这个方法则是打开配置文件的URL,转化成InputStream,然后继续调用
上面的WatchList,一般是走不进这个分支的,我也就没深入地看。接下来创建一个SaxEventRecorder类,由它负责读取XML文件,并解析成流,创建SaxEvent,这部分功能是JDK提供的。然后是一个核心方法buildInterpreter()
这里的核心是初始化了interpreter字段,这种设计其实我觉得是不太好的,因为把interpreter字段的初始化隐藏得很深,不容易看到
Interpreter在框架的配置中是一个很关键的类,logback是依赖这个类来进行初始化工作的。这里用到了RuleStore接口,RuleStore只有一个唯一的实现类SimpleRuleStore,这个类的作用是,把Pattern匹配到Action上,因为所有的配置工作,最终是由Action来完成的。作者对这个类的设计是十分精巧的,个人认为logback框架的初始化设计思路,是非常值得学习的,这部分内容也是我阅读logback源码感觉收获最大的地方
buildInterpreter()方法调用之后,调用play(recorder.saxEventList)方法,开始进行配置。注意,这个时候logback.xml文件已经被解析成了SAX流,并且保存在SaxEventRecorder的saxEventList字段里了。接下来就要重点分析一下Interpreter这个核心类的字段和方法,一些不重要和一目了然的字段和方法,这里就忽略了
以上的字段中,ruleStore正如前面提到的,是用来根据Sax节点,来匹配对应的Action。ruleStore是在Interpreter创建时初始化的,而且只初始化一次,因此logback.xml中的每个元素,用哪个Action来处理,都已经规定好了。如果在解析logback.xml的过程中,遇到了无法识别的元素,就会抛出异常
interpretationContext也非常关键,在Action组件实际处理过程中,大部分对象的出栈和入栈,都依赖这个类来实现
pattern存放了当前正在处理的元素
actionListStack则是对负责处理某元素的Action进行出栈、进栈的操作
介绍完了关键的字段,接下来看方法
这是入口方法,委托EventPlayer来处理SAX流
这个方法是对整个logback.xml配置文件的元素来循环遍历,并根据SaxEvent的类型,还给Interpreter类来处理,SaxEvent有3种,基本大同小异,我们用StartEvent来举例
这里设置了一下文档的Locator,然后继续调用
这个方法先得到元素的TagName,然后通过RuleStore来匹配一下,得到处理的Action列表,然后调用callBeginAction()方法来处理,如果SaxEvent类型是EndEvent,则这里是调用callEndAction()方法
这里就简单啦,循环遍历负责处理的Action,依次调用其begin()方法。类似的callEndAction(),则会循环遍历负责处理的Action,依次调用其end()方法
总结一下整个配置流程:
1、首先读取配置文件,如果没有找到配置文件,则用默认配置
2、如果找到配置文件logback.xml,则调用SAX解析器来解析该配置文件
3、初始化一个Interpreter对象,调用其play()方法
4、Interpreter对象委托EventPlayer对象,循环遍历XML文件中的所有节点
5、根据节点的类型(<element>、</element>、content),调用Interpreter中的startElement()、characters()、endElement()方法
6、Interpreter委托RuleStore来匹配元素名,选择合适的Action
7、委托Action组件来进行实际的配置
本篇博客的内容就结束了,把logback框架是怎么配置的讲了一半,但Action组件是怎么进行实际配置的,暂时没有涉及,下一篇博客就介绍这个方面的内容
这篇博客我们接着上一篇的主题,来介绍一下logback是怎么读取配置文件并初始化整个框架的。还是老规矩,先上总览图
从图中可以看到,logback框架的初始化是由ContextInitializer类来负责完成的,而实际进行配置的是GenericConfigurator类,它调用SaxEventRecorder类来负责读取logback.xml文件,然后由Interpreter类来进行解析,而最后真正的初始化工作,是由一系列Action组件来完成。接下来就实际看看代码
try { new ContextInitializer(defaultLoggerContext).autoConfig(); } catch (JoranException je) { Util.report("Failed to auto configure default logger context", je); }
以上代码来自StaticLoggerBinder类,它在提供LoggerContext之前,就对LoggerContext进行初始化,初始化的入口方法,即是ContextInitializer类的autoConfig()方法
public void autoConfig() throws JoranException { StatusListenerConfigHelper.installIfAsked(loggerContext); URL url = findURLOfDefaultConfigurationFile(true); if (url != null) { configureByResource(url); } else { BasicConfigurator.configure(loggerContext); } }
这里首先调用findURLOfDefaultConfigurationFile()方法,来寻找一个配置文件,一般就是logback.xml文件,如果没有找到,则用BasicConfigurator来进行默认配置,否则就调用configureByResource()方法,根据配置文件进行配置
public void configureByResource(URL url) throws JoranException { if (url == null) { throw new IllegalArgumentException("URL argument cannot be null"); } 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)); } } if (url.toString().endsWith("xml")) { JoranConfigurator configurator = new JoranConfigurator(); configurator.setContext(loggerContext); configurator.doConfigure(url); } }
这里如果配置文件是以.groovy结尾,就调用另一种方法进行配置,我没有跟进去看;如果是常规以.xml文件结尾,那么就用JoranConfigurator类来进行配置
final public void doConfigure(URL url) throws JoranException { try { informContextOfURLUsedForConfiguration(url); URLConnection urlConnection = url.openConnection(); // per http://jira.qos.ch/browse/LBCORE-105 // per http://jira.qos.ch/browse/LBCORE-127 urlConnection.setUseCaches(false); InputStream in = urlConnection.getInputStream(); doConfigure(in); in.close(); } catch (IOException ioe) { String errMsg = "Could not open URL [" + url + "]."; addError(errMsg, ioe); throw new JoranException(errMsg, ioe); } }
这个方法则是打开配置文件的URL,转化成InputStream,然后继续调用
// this is the most inner form of doConfigure whereto other doConfigure // methods ultimately delegate final public void doConfigure(final InputSource inputSource) throws JoranException { if(!ConfigurationWatchListUtil.wasConfigurationWatchListReset(context)) { informContextOfURLUsedForConfiguration(null); } SaxEventRecorder recorder = new SaxEventRecorder(); recorder.setContext(context); recorder.recordEvents(inputSource); buildInterpreter(); // disallow simultaneous configurations of the same context synchronized (context.getConfigurationLock()) { interpreter.play(recorder.saxEventList); } }
上面的WatchList,一般是走不进这个分支的,我也就没深入地看。接下来创建一个SaxEventRecorder类,由它负责读取XML文件,并解析成流,创建SaxEvent,这部分功能是JDK提供的。然后是一个核心方法buildInterpreter()
protected void buildInterpreter() { RuleStore rs = new SimpleRuleStore(context); addInstanceRules(rs); this.interpreter = new Interpreter(context, rs, initialPattern()); InterpretationContext ec = interpreter.getInterpretationContext(); ec.setContext(context); addImplicitRules(interpreter); addDefaultNestedComponentRegistryRules(ec.getDefaultNestedComponentRegistry()); }
这里的核心是初始化了interpreter字段,这种设计其实我觉得是不太好的,因为把interpreter字段的初始化隐藏得很深,不容易看到
Interpreter在框架的配置中是一个很关键的类,logback是依赖这个类来进行初始化工作的。这里用到了RuleStore接口,RuleStore只有一个唯一的实现类SimpleRuleStore,这个类的作用是,把Pattern匹配到Action上,因为所有的配置工作,最终是由Action来完成的。作者对这个类的设计是十分精巧的,个人认为logback框架的初始化设计思路,是非常值得学习的,这部分内容也是我阅读logback源码感觉收获最大的地方
buildInterpreter()方法调用之后,调用play(recorder.saxEventList)方法,开始进行配置。注意,这个时候logback.xml文件已经被解析成了SAX流,并且保存在SaxEventRecorder的saxEventList字段里了。接下来就要重点分析一下Interpreter这个核心类的字段和方法,一些不重要和一目了然的字段和方法,这里就忽略了
final private RuleStore ruleStore; final private InterpretationContext interpretationContext; private Pattern pattern; Stack<List> actionListStack;
以上的字段中,ruleStore正如前面提到的,是用来根据Sax节点,来匹配对应的Action。ruleStore是在Interpreter创建时初始化的,而且只初始化一次,因此logback.xml中的每个元素,用哪个Action来处理,都已经规定好了。如果在解析logback.xml的过程中,遇到了无法识别的元素,就会抛出异常
interpretationContext也非常关键,在Action组件实际处理过程中,大部分对象的出栈和入栈,都依赖这个类来实现
pattern存放了当前正在处理的元素
actionListStack则是对负责处理某元素的Action进行出栈、进栈的操作
介绍完了关键的字段,接下来看方法
public void play(List<SaxEvent> eventList) { player.play(eventList); }
这是入口方法,委托EventPlayer来处理SAX流
public void play(List<SaxEvent> seList) { eventList = seList; SaxEvent se; for(currentIndex = 0; currentIndex < eventList.size(); currentIndex++) { se = eventList.get(currentIndex); if(se instanceof StartEvent) { interpreter.startElement((StartEvent) se); // invoke fireInPlay after startElement processing interpreter.getInterpretationContext().fireInPlay(se); } if(se instanceof BodyEvent) { // invoke fireInPlay before characters processing interpreter.getInterpretationContext().fireInPlay(se); interpreter.characters((BodyEvent) se); } if(se instanceof EndEvent) { // invoke fireInPlay before endElement processing interpreter.getInterpretationContext().fireInPlay(se); interpreter.endElement((EndEvent) se); } } }
这个方法是对整个logback.xml配置文件的元素来循环遍历,并根据SaxEvent的类型,还给Interpreter类来处理,SaxEvent有3种,基本大同小异,我们用StartEvent来举例
public void startElement(StartEvent se) { setDocumentLocator(se.getLocator()); startElement(se.namespaceURI, se.localName, se.qName, se.attributes); }
这里设置了一下文档的Locator,然后继续调用
private void startElement(String namespaceURI, String localName, String qName, Attributes atts) { String tagName = getTagName(localName, qName); pattern.push(tagName); if (skip != null) { // every startElement pushes an action list pushEmptyActionList(); return; } List applicableActionList = getApplicableActionList(pattern, atts); if (applicableActionList != null) { actionListStack.add(applicableActionList); callBeginAction(applicableActionList, tagName, atts); } else { // every startElement pushes an action list pushEmptyActionList(); String errMsg = "no applicable action for [" + tagName + "], current pattern is [" + pattern + "]"; cai.addError(errMsg); } }
这个方法先得到元素的TagName,然后通过RuleStore来匹配一下,得到处理的Action列表,然后调用callBeginAction()方法来处理,如果SaxEvent类型是EndEvent,则这里是调用callEndAction()方法
void callBeginAction(List applicableActionList, String tagName, Attributes atts) { if (applicableActionList == null) { return; } Iterator i = applicableActionList.iterator(); while (i.hasNext()) { Action action = (Action) i.next(); // now let us invoke the action. We catch and report any eventual // exceptions try { action.begin(interpretationContext, tagName, atts); } catch (ActionException e) { skip = (Pattern) pattern.clone(); cai.addError("ActionException in Action for tag [" + tagName + "]", e); } catch (RuntimeException e) { skip = (Pattern) pattern.clone(); cai.addError("RuntimeException in Action for tag [" + tagName + "]", e); } } }
这里就简单啦,循环遍历负责处理的Action,依次调用其begin()方法。类似的callEndAction(),则会循环遍历负责处理的Action,依次调用其end()方法
总结一下整个配置流程:
1、首先读取配置文件,如果没有找到配置文件,则用默认配置
2、如果找到配置文件logback.xml,则调用SAX解析器来解析该配置文件
3、初始化一个Interpreter对象,调用其play()方法
4、Interpreter对象委托EventPlayer对象,循环遍历XML文件中的所有节点
5、根据节点的类型(<element>、</element>、content),调用Interpreter中的startElement()、characters()、endElement()方法
6、Interpreter委托RuleStore来匹配元素名,选择合适的Action
7、委托Action组件来进行实际的配置
本篇博客的内容就结束了,把logback框架是怎么配置的讲了一半,但Action组件是怎么进行实际配置的,暂时没有涉及,下一篇博客就介绍这个方面的内容
发表评论
-
小读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源码系列文章(五)——Appender
2011-09-16 21:03 13847明天要带老婆出国旅游 ... -
读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
2011-08-29 02:43 7537以前也读过一些开源项目的源码,主要是spring和ant,不过 ...
相关推荐
Spring Boot与Logback源码解读涉及了Spring Boot框架在启动过程中如何与Logback日志系统集成,以及Logback是如何进行初始化和配置的。下面将详细解读Logback和Spring Boot的相关知识点。 ### Logback初始化过程 ...
**logback-1.1.2源码包详解** **一、logback介绍** Logback 是一个用于日志记录的开源框架,由 Ceki Gülcü(也创建了广泛使用的 log4j)开发。它是对 log4j 的升级,旨在提供更高的性能、更灵活的配置以及更好的...
标题"扩展logback将日志输出到Kafka实例源码"涉及的技术点主要集中在如何将Logback与Kafka集成,使得日志可以被有效地发送到Kafka集群。这个过程通常涉及到以下几个步骤: 1. **添加依赖**:首先,你需要在项目的...
rar包中包括:logback源代码,以及struts2的基础的页面跳转,logback虽然是开源的,但它依赖的jar包找全不也不容易,当然你也可以用Maven去下载是最好的喽。 你可以访问:...
《logback jms源码分析及用法小结》 在Java世界中,日志管理是每个项目不可或缺的一部分。Logback作为一款强大的日志框架,因其高效、灵活和可配置性而深受开发者喜爱。本文将重点探讨Logback如何集成JMS(Java ...
接下来,我们关注 logback 的核心配置文件 —— `logback.xml`。这个文件通常放在 `src/main/resources` 目录下,因为这是 Maven 默认的资源目录。`logback.xml` 定义了日志记录的行为,如级别(TRACE, DEBUG, INFO,...
**Logback核心组件——logback-core-1.0.13.jar** `logback-core-1.0.13.jar`是Logback的基础组件,提供了日志记录的基本功能。这个JAR文件包括了日志事件的生命周期管理、日志级别定义、配置解析、Appender(输出...
接下来,我们来看看logback的配置文件——`logback.xml`。这是logback配置的核心,通过它可以定义日志级别(TRACE、DEBUG、INFO、WARN、ERROR、OFF),设置日志输出的目标(控制台、文件、网络等),以及定制日志...
默认情况下,Spring Boot使用Logback作为其日志系统,因为Logback在性能上优于Log4j,并且与Spring框架有良好的集成。本教程将详细介绍如何在Spring Boot中自定义日志配置,特别是通过`logback-spring.xml`文件来...
Logback 是一个流行的 Java 日志框架,由 Ceki Gülcü 创建,他是早期日志框架 Log4j 的主要开发者。Logback 是为了提供更高效、更灵活的日志记录解决方案而设计的,它不仅继承了 Log4j 的优点,还解决了一些性能和...
Logback 是一款广泛使用的日志记录框架,由 Ceki Gülcü 创建,作为其先前作品 Log4j 的改进版。这个压缩包包含了实现 Logback 功能所需的几个关键组件,以及一个配置文件,使得用户能够方便地管理和记录应用程序的...
“源码”标签意味着logback作为一个开源项目,它的源代码是公开的,开发者可以查看、学习甚至贡献到项目中。这为用户提供了深入了解其工作原理的机会,同时也使得自定义和扩展变得更加可能。 “工具”标签表明...
这个"maven+spring+jetty+logback简单项目源码"提供了一个基础框架,方便新手快速入门并实践这些技术。 首先,`Maven`是Apache开发的一个项目管理和综合工具,它通过一个项目对象模型(Project Object Model, POM)...
本资源包含的是关于`SpringMVC`、`Log4j2`、`Logback`以及`Jackson`的日志脱敏实现源码,提供了多种实现方式,旨在帮助开发者在保障信息安全的同时,充分利用日志进行系统分析。 1. **基于正则表达式的日志脱敏实现...
标签中的"logback"三次出现,强调了这个主题的核心——Logback日志框架。"logback-access-1"可能是对Logback访问模块的简称。"logback-classic-"和"logback-core-1.2"分别代表Logback的经典日志实现和核心库,它们是...
只要里面的logback-classic-1.1.7,logback-core-1.1.7,slf4j-api-1.7.21的JAR就可以打印出日志信息,而带有source表示对应的JAR包的源代码。可以要也可以不要
**日志框架Logback** 日志是任何软件系统中至关重要的组成部分,它为开发者提供了运行时的调试信息、错误报告以及性能分析数据。在Java世界里,Logback是一款高效、可配置的日志记录框架,由Ceki Gülcü(也是log4...
**日志框架Logback简介** Logback 是一个用于日志记录的开源框架,由 Ceki Gülcü 创建,他是早期广泛使用的日志框架 Log4j 的主要开发者。Logback 是作为 Log4j 的继承者而设计的,它在性能、灵活性和可配置性...
标题中的“扩展logback将日志输出到Kafka实例扩展源码”指的是在Java应用程序中,使用logback作为日志框架,并通过自定义appender(输出模块)将日志信息发送到Apache Kafka的消息队列中。Logback是SLF4J(Simple ...
本文将深入探讨如何在 Logback 中实现动态日志配置,并提供一个具体的示例源码分析。** ### 1. Logback 概述 Logback 是一个高效且灵活的日志框架,旨在提高系统的性能。它提供了日志记录、日志管理和日志部署等...