??xml version="1.0" encoding="utf-8" standalone="yes"?> common-logging是apache提供的一个通用的日志接口。用户可以自由选择W三方的日志lg作ؓ具体实现Q像log4jQ或者jdk自带的loggingQ?common-logging会通过动态查扄机制Q在E序q行时自动找出真正用的日志库。当Ӟcommon-logging内部有一个Simple logger的简单实玎ͼ但是功能很弱。所以用common-loggingQ通常都是配合着log4j来用。用它的好处就是,代码依赖是common-logging而非log4jQ?避免了和具体的日志方案直接耦合Q在有必要时Q可以更Ҏ志实现的W三方库?/span> 使用slf4j的常见代码:
昨天收到一个读者留aQ问作ؓE序员,有什么学习和工作上的好习惯可以借鉴Q想了想Q干脆附应R雅一下,ȝ个『高效能E序员的七个习惯』吧。DisclaimerQ一家之aQ可不信Q但也可以部分信?nbsp;
1. 拥抱unix哲学
每个E序员入门的W一堂和W二堂课应该是和unix哲学相关的内容,a之就是:做一件事Q做好它。具体点Q?/span>
2. 选一个样板,follow?/strong>
每个NBA新秀都有自己的样板,我们也M惯称某球新星ؓ『小|』,『小罗』。样板ؓ你提供了可模仿可q赶的对象,同时也让你审视自q竟想成ؓ什么样的程序员。我的样板是Greg Pass和Werner VogelsQ虽然我q辈子可能也达不C们的高度Q可qƈ不妨向着我心目中的明星一步步靠近?nbsp;
3. 写代码,而不是调代码
写Y件最p糕的体验恐怕是边写边调Q写一点,q行一下,再写一炏V是很多E序员都会这么干。原因有二:1. 不熟悉相关的代码Q类库)Q需要边写边q行保证代码的正?. C~程语言的REPL(Read-Evaluate-Print-LoopQ就是语a的shell)能力助长了这一行ؓ?nbsp;
写系lY件的人很这么做。他们手头糟p的工具让边写边调的行ؓ成ؓ效率杀?—— 如果E稍改动Q编译就要花d分钟Q甚x长的旉Q你q会q么q么Q所以他们往往是写完一个模块,再编译调试。(由此看来Q高效的工具有时候是把双刃剑啊)
我觉得写代码p写文章一P构思好Q有了大UԌ应该行云流水一样写下去Q一气呵成,然后回过头来再调整语句,修改错别字。如果写完一D,p回溯查之前写的内容,效率很低Q思维也会被打散?nbsp;
靠边写边调做出来的代码还往往质量不高。虽然局部经q了雕琢Q但整体上不那么协调Q看着L别扭。这好比雕刻,拿着一块石_你先是精修了dQ然后再一点一点刻画面部。等修到x的时候,d可能q大或过,即便再精,它也得不到赞赏?nbsp;
4. 聪明地调?/strong>
软gM出问题。遇到问题,很多E序员就会用IDE在各U可能的地方加断点调试,如果没有IDEQ那么各Uprint/log手段一齐抛出,有枣没枣打一杆子再说?nbsp;
优秀的程序员会在撰写代码的时候就考虑到调试问题,在系l关键的节点上注入各U等U的调试信息Q然后在需要的时候打开相应的调试别,摸瓜Q避免了不靠q臆测。这是调试之『道』?nbsp;
很多问题打开调试开兛_原形毕Ԍ但有时候靠调试信息扑ֈ了初步原因,q一步定位问题还需要具体的工具Q也是调试之『术』,如上文所qC断点调试。有些时候,遇到靠类似gdbQ如python的pdbQ的工具无法解决的问题时Q如性能问题Q,你还需要更多的调试工具做runtime profilingQ如systemtap?nbsp;
5. 使用标记语言来写文Q而非word/power point
不要使用只能使用特定软g才能打开的工具写文Q如word/page或者power point/keynote。要使用『放之四皆可用』的工具?nbsp;
java的市场口hQ『一ơ编写,到处q行』,对于文Q你也需要这L工具。Markdown(md) / Restructured Text(rst)Q以及Q何编辑语aQ甚xjadeQ就是这L工具。通过使用一U特定的文本格式Q你的文可以被~译成几乎Q意格式(htmlQrtfQlatexQpdfQepubQ?..Q,真正辑ֈ了『一ơ编写,到处q行』。最重要的是Q由于逻辑层(文章本nQ和表现层(各种格式Q字体,行距{)分离Q同L文档Q换个模板,有完全不一L形象?nbsp;
除非必须Q我现在所有的文都是md或者rst格式?nbsp;
6. 一切皆目
E序员的所有出应该项目制。Y件自不必_文档和各U碎片思想也要Ҏ相关性组l成目。D一些我自己的例子:
目制的好处是具备可回溯性。每个项目我可以用git来管理,q样Q几乎在M一台设备上我都可以看到我之前的工作。想想你三年前写的某个文,你还能找到它么?你还能找回你的修改历史么Q?nbsp;
目制的另一大好处是可以在其之上使能工具。比如说你看到的q些微信文章Q我随时可以“make publish YEAR=2014”来生成包含了2014q我所写文章的pdf?nbsp;
7. 心态开放,勇于试
在程序员C里,语言之争Q系l之争,软g思想之争几乎是常态。python vs rubyQgo vs java vs erlang vs rustQscala vs cljureQOOP vs FPQiOS vs Android。其实不黑猫白猫,抓到老鼠的就是好猫,facebookq用php呢。程序员应该用开攄心态去包容新的技术,新的思想Q勇于尝试,而不是立卛_定。这个世界最悲哀的是Q手里有把锤子,看什么都是钉子(或者说Q眼里就只能看见钉子Q?nbsp;
我接触mac旉不过三年。可q三q时_我从对mac不屑Q到深深热爱Q最l成为mac的一个重度用戗很多东西用q才知道Q不试不接触我可能永远zd自己下意识构{的无Ş之墙的另一辏V?/span>
]]>
从上q加载流E来看,只要引入了log4j q在classpath 配置了log4j.xml Q则commons-logging ׃使log4j 使用正常Q而代码里不需要依赖Q何log4j 的代码?/span>slf4j
slf4j全称为Simple Logging Facade for JAVAQjava单日志门面。类gApache Common-LoggingQ是对不同日志框架提供的一个门面封装,可以在部|的时候不修改M配置卛_接入一U日志实现方案。但是,他在~译旉态绑定真正的Log库。用SLF4JӞ如果你需要用某一U日志实玎ͼ那么你必选择正确的SLF4J的jar包的集合Q各U桥接包Q?/span>
slf4j静态绑定原?/strong>QSLF4J 会在~译时会l定import org.slf4j.impl.StaticLoggerBinder; 该类里面实现对具体日志方案的l定接入。Q何一U基于slf4j 的实现都要有一个这个类。如Qorg.slf4j.slf4j-log4j12-1.5.6: 提供?log4j 的一U适配实现?span style="color: #ff0000;">注意Q如果有L两个实现slf4j 的包同时出现Q那么就可能出现问题?/span>slf4j ?common-logging 比较
common-logging通过动态查扄机制Q在E序q行时自动找出真正用的日志库。由于它使用了ClassLoaderL和蝲入底层的日志库, D了象OSGIq样的框架无法正常工作,因ؓOSGI的不同的插g使用自己的ClassLoader?OSGI的这U机制保证了插g互相独立Q然而却使Apache Common-Logging无法工作?br />
slf4j?span style="color: #ff0000;">~译旉态绑?/span>真正的Log?因此可以再OSGI中用。另外,SLF4J 支持参数化的log字符Ԍ避免了之前ؓ了减字W串拼接的性能损耗而不得不写的if(logger.isDebugEnable())Q现在你可以直接写:logger.debug(“current user is: {}”, user)。拼装消息被推迟C它能够确定是不是要显C条消息的时候,但是获取参数的代价ƈ没有q免?/span>Log4j
Apache的一个开放源代码目Q通过使用Log4jQ我们可以控制日志信息输送的目的地是控制台、文件、GUIlg、甚x套接口服?器、NT的事件记录器、UNIX Syslog守护q程{;用户也可以控制每一条日志的输出格式Q通过定义每一条日志信息的U别Q用戯够更加细致地控制日志的生成过E。这些可以通过一?配置文g来灵zdq行配置Q而不需要修改程序代码?/span>LogBack
Logback是由log4j创始计的又一个开源日记组件。logback当前分成三个模块Qlogback-core,logback- classic和logback-access。logback-core是其它两个模块的基础模块。logback-classic是log4j的一?改良版本。此外logback-classic完整实现SLF4J API使你可以很方便地更换成其它日记系l如log4j或JDK14 Logging。logback-access讉K模块与Servlet容器集成提供通过Http来访问日记的功能?nbsp;Log4j ?LogBack 比较
LogBack作ؓ一个通用可靠、快速灵zȝ日志框架Q将作ؓLog4j的替代和SLF4Jl成新的日志pȝ的完整实现。LOGBack声称h极佳的性能Q?#8220; 某些关键操作Q比如判定是否记录一条日志语句的操作Q其性能得到了显著的提高。这个操作在LogBack中需?U秒Q而在Log4J中则需?0U秒?LogBack创徏记录器(loggerQ的速度也更快:13微秒Q而在Log4J中需?3微秒。更重要的是Q它获取已存在的记录器只需94U秒Q?Log4J需?234U秒Q时间减到?/23。跟JUL相比的性能提高也是显著?#8221;?另外QLOGBack的所有文档是全面免费提供的,不象Log4J那样只提供部分免Ҏ而需要用户去购买付费文档?nbsp;slf4j与其他各U日志组件的桥接
日志lg相关历史
Java 界里有许多实现日志功能的工具Q最早得到广泛用的?log4jQ许多应用程序的日志部分都交l了 log4jQ不q作为组件开发者,他们希望自己的组件不要紧紧依赖某一个工P毕竟在同一个时候还有很多其他很多日志工P假如一个应用程序用C两个lgQ恰好两个组件用不同的日志工具Q那么应用程序就会有两䆾日志输出了?br />
Z解决q个问题QApache Commons Logging Q之前叫 Jakarta Commons LoggingQJCLQ粉墨登场,JCL 只提?log 接口Q具体的实现则在q行时动态寻找。这样一来组件开发者只需要针?JCL 接口开发,而调用组件的应用E序则可以在q行时搭配自己喜好的日志实践工具?br />
所以即使到现在你仍会看到很多程序应?JCL + log4j q种搭配Q不q当E序规模来庞大时QJCL的动态绑定ƈ不是总能成功Q具体原因大家可?Google 一下,q里׃再赘qC。解x法之一是在程序部|时静态绑定指定的日志工具Q这是 SLF4J 产生的原因?br />
?JCL 一PSLF4J 也是只提?log 接口Q具体的实现是在打包应用E序时所攑օ的绑定器Q名字ؓ slf4j-XXX-version.jarQ来军_QXXX 可以?log4j12, jdk14, jcl, nop {,他们实现了跟具体日志工具Q比?log4jQ的l定及代理工作。D个例子:如果一个程序希望用 log4j 日志工具Q那么程序只需针对 slf4j-api 接口~程Q然后在打包时再攑օ slf4j-log4j12-version.jar ?log4j.jar 可以了?br />
现在q有一个问题,假如你正在开发应用程序所调用的组件当中已l用了 JCL 的,q有一些组建可能直接调用了 java.util.loggingQ这时你需要一个桥接器Q名字ؓ XXX-over-slf4j.jarQ把他们的日志输出重定向?SLF4JQ所谓的桥接器就是一个假的日志实现工P比如当你?jcl-over-slf4j.jar 攑ֈ CLASS_PATH Ӟ即某个lg原本是通过 JCL 输出日志的,现在却会?jcl-over-slf4j “骗到”SLF4J 里,然后 SLF4J 又会Ҏl定器把日志交给具体的日志实现工兗过E如?br />
Component
|
| log to Apache Commons Logging
V
jcl-over-slf4j.jar --- (redirect) ---> SLF4j ---> slf4j-log4j12-version.jar ---> log4j.jar ---> 输出日志
看到上面的流E图可能会发C个有的问题Q假如在 CLASS_PATH 里同时放|?log4j-over-slf4j.jar ?slf4j-log4j12-version.jar 会发生什么情况呢Q没错,日志会被t来t去Q最l进入死循环?br />
所以?SLF4J 的比较典型搭配就是把 slf4j-api、JCL 桥接器、java.util.loggingQJULQ桥接器、log4j l定器、log4j q??jar 攄?CLASS_PATH 里?br />
不过q不是所有APP容器都是使用 log4j 的,比如 Google AppEngine 它用的?java.util.loggingQJULQ,q时应用 SLF4J 的搭配就变成 slf4j-api、JCL桥接器、logj4桥接器、JULl定器这4?jar 攄?WEB-INF/lib 里?/span>
]]>
slf4j:Simple Logging Facade for JavaQؓjava提供的简单日志Facade。FacadeQ门面,更底层一点说是接口。他允许用户以自q喜好Q在工程中通过slf4j接入不同的日志系l。更直观一点,slf4j是个数据U,一端嵌入程序,另一端链接日志系l,从而实现将E序中的信息导入到日志系lƈ记录?nbsp;
因此Qslf4j入口是众多接口的集合,他不负责具体的日志实玎ͼ只在~译时负责寻扑适的日志pȝq行l定。具体有哪些接口Q全部都定义在slf4j-api中?/span>查看slf4j-api源码可以发玎ͼ里面除了public final class LoggerFactorycM外,都是接口定义。因此,slf4j-api本质是一个接口定义?/span>
下图比较清晰的描qC他们之间的关p:
当系l采用log4j作ؓ日志框架实现的调用关p:
首先pȝ包含slf4j-api作ؓ日志接入的接口;
at compile时slf4j-api中public final class LoggerFactorcM
private final static void bind() Ҏ会寻扑օ体的日志实现cȝ定,主要通过
StaticLoggerBinder.getSingleton();语句调用
slf4j-log4j12:链接slf4j-api和log4j中间的适配器。它实现了slf4j-apiz中StaticLoggerBinder接口Q从而得在~译时绑定的是slf4j-log4j12的getSingleton()Ҏ
log4j:q个是具体的日志pȝ。通过slf4j-log4j12初始化Log4jQ达到最l日志的输出?/span>