﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-星游领地-随笔分类-java</title><link>http://www.blogjava.net/watchzerg/category/52443.html</link><description /><language>zh-cn</language><lastBuildDate>Sun, 20 Jul 2014 20:24:36 GMT</lastBuildDate><pubDate>Sun, 20 Jul 2014 20:24:36 GMT</pubDate><ttl>60</ttl><item><title>logback_doc_manual_01_introduction_to_logback</title><link>http://www.blogjava.net/watchzerg/archive/2014/07/13/415757.html</link><dc:creator>王星游</dc:creator><author>王星游</author><pubDate>Sun, 13 Jul 2014 11:04:00 GMT</pubDate><guid>http://www.blogjava.net/watchzerg/archive/2014/07/13/415757.html</guid><wfw:comment>http://www.blogjava.net/watchzerg/comments/415757.html</wfw:comment><comments>http://www.blogjava.net/watchzerg/archive/2014/07/13/415757.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/watchzerg/comments/commentRss/415757.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/watchzerg/services/trackbacks/415757.html</trackback:ping><description><![CDATA[<div>最近把logback的文档翻了一遍，弄了些半笔记半翻译的文字出来，本来打算仅仅存在evernote里的，但还是费点功夫发出来吧，可能为别人提供些参考。</div><div>看我这文章标题起的，对搜索引擎拆词极端的不友好，哇哈哈哈哈&#8230;&#8230;<br /></div><div></div><div>链接：</div><div>slf4j笔记</div><div><a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415746.html">http://www.blogjava.net/watchzerg/archive/2014/07/13/415746.html</a></div><div>logback_doc_manual_01_introduction_to_logback<br /><div><a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415757.html">http://www.blogjava.net/watchzerg/archive/2014/07/13/415757.html</a></div></div><div></div><div>logback_doc_manual_02_architecture</div><div><a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415747.html">http://www.blogjava.net/watchzerg/archive/2014/07/13/415747.html</a></div><div>logback_doc_manual_03_configuration</div><div><a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415748.html">http://www.blogjava.net/watchzerg/archive/2014/07/13/415748.html</a></div><div>logback_doc_manual_04_appenders</div><div><a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415749.html">http://www.blogjava.net/watchzerg/archive/2014/07/13/415749.html</a></div><div>logback_doc_manual_05_encoders</div><div><a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415750.html">http://www.blogjava.net/watchzerg/archive/2014/07/13/415750.html</a></div><div>logback_doc_manual_06_layouts</div><div><a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415751.html">http://www.blogjava.net/watchzerg/archive/2014/07/13/415751.html</a></div><div>logback_doc_manual_07_filters</div><div><a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415752.html">http://www.blogjava.net/watchzerg/archive/2014/07/13/415752.html</a></div><div>logback_doc_manual_08_mapped_diagnostic_contexts</div><div><a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415753.html">http://www.blogjava.net/watchzerg/archive/2014/07/13/415753.html</a></div><div>logback_doc_manual_09_logging_separation</div><div><a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415754.html">http://www.blogjava.net/watchzerg/archive/2014/07/13/415754.html</a></div><div>logback_eclipse_plugin_beagle</div><div><a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415755.html">http://www.blogjava.net/watchzerg/archive/2014/07/13/415755.html</a></div><div>logback_config_demo</div><div><a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415756.html">http://www.blogjava.net/watchzerg/archive/2014/07/13/415756.html<br /><br /></a></div><div></div><div></div><div>logback-demo项目：</div><div>&nbsp; &nbsp; &nbsp;http://logback.qos.ch/demo.html</div><div>&nbsp; &nbsp; &nbsp;遇到有问题的，就把这个项目拔下来看看。</div><div>&nbsp; &nbsp; &nbsp;例如CyclicBufferAppender，在文档里貌似没有描述过，在appender这一章也找不到。</div><div>&nbsp; &nbsp; &nbsp;示例项目里，实现&#8220;在web页面上查看最近512条日志&#8221;，是手写的Servlet：ViewLastLog.java</div><div></div><div>logback-access:</div><div>&nbsp; &nbsp; &nbsp;http://logback.qos.ch/access.html&nbsp;</div><div>&nbsp; &nbsp; &nbsp;可以集成到jetty或者tomcat中，提供强大的http-access日志。</div><div>&nbsp; &nbsp; &nbsp;依赖于logback-core（不依赖slf4j和logback-classic）</div><div>&nbsp; &nbsp; &nbsp;如果与tomcat6.x集成，可能会崩溃哦～，建议用tomcat7.x。实在想用tomcat6.x，可以用logback-access版本0.9.30</div><div>&nbsp; &nbsp; &nbsp;可以拦截和打印每个http的request和response。</div><div></div><div>&nbsp; &nbsp; &nbsp;Apache Tomcat中的日志是通过借助Apache Commons Logging库实现的，这个库对不同的日志框架做了一个简单包装。使Tomcat有能力记录跨日志级别的多层次日志，而且不需要依赖特定的日志框架。</div><div>&nbsp; &nbsp; &nbsp;从Tomcat 6.0开始，Tomcat引入一个对Apache Commons Logging重命名包后的私有实现，从而允许web应用使用他们自己独立的原Apache Commons Logging库的lib包。在默认的发布包中，Apache Commons Logging私有实现是简单被硬编码到java.util.logging框架。</div><div>&nbsp; &nbsp; &nbsp;实际使用中，通过配置org.apache.catalina.valves.AccessLogValve可以让tomcat打印访问日志（默认禁用掉的）</div><img src ="http://www.blogjava.net/watchzerg/aggbug/415757.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/watchzerg/" target="_blank">王星游</a> 2014-07-13 19:04 <a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415757.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>logback_config_demo</title><link>http://www.blogjava.net/watchzerg/archive/2014/07/13/415756.html</link><dc:creator>王星游</dc:creator><author>王星游</author><pubDate>Sun, 13 Jul 2014 11:03:00 GMT</pubDate><guid>http://www.blogjava.net/watchzerg/archive/2014/07/13/415756.html</guid><wfw:comment>http://www.blogjava.net/watchzerg/comments/415756.html</wfw:comment><comments>http://www.blogjava.net/watchzerg/archive/2014/07/13/415756.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/watchzerg/comments/commentRss/415756.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/watchzerg/services/trackbacks/415756.html</trackback:ping><description><![CDATA[我自己常用的一个logback配置框架，有需要再在上面添加：<br /><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #0000FF; ">&lt;?</span><span style="color: #FF00FF; ">xml&nbsp;version="1.0"&nbsp;encoding="UTF-8"</span><span style="color: #0000FF; ">?&gt;</span><br /><span style="color: #008080; ">&nbsp;2</span>&nbsp;<span style="color: #008000; ">&lt;!--</span><span style="color: #008000; ">&nbsp;&lt;configuration&nbsp;scan="true"&nbsp;scanPeriod="60&nbsp;seconds"&gt;&nbsp;&nbsp;</span><span style="color: #008000; ">--&gt;</span><br /><span style="color: #008080; ">&nbsp;3</span>&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">configuration</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">&nbsp;4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">&lt;!--</span><span style="color: #008000; ">&nbsp;print&nbsp;configuration&nbsp;status&nbsp;on&nbsp;console&nbsp;</span><span style="color: #008000; ">--&gt;</span><br /><span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">statusListener&nbsp;</span><span style="color: #FF0000; ">class</span><span style="color: #0000FF; ">="ch.qos.logback.core.status.OnConsoleStatusListener"</span><span style="color: #0000FF; ">/&gt;</span><br /><span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">&lt;!--</span><span style="color: #008000; ">&nbsp;Beagle:&nbsp;eclipse&nbsp;plugin&nbsp;</span><span style="color: #008000; ">--&gt;</span><br /><span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">consolePlugin&nbsp;</span><span style="color: #0000FF; ">/&gt;</span><br /><span style="color: #008080; ">&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">&lt;!--</span><span style="color: #008000; ">&nbsp;log&nbsp;path&nbsp;</span><span style="color: #008000; ">--&gt;</span><br /><span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">property&nbsp;</span><span style="color: #FF0000; ">name</span><span style="color: #0000FF; ">="LOG_PATH"</span><span style="color: #FF0000; ">&nbsp;value</span><span style="color: #0000FF; ">="d:/log"</span><span style="color: #FF0000; ">&nbsp;</span><span style="color: #0000FF; ">/&gt;</span><br /><span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">&lt;!--</span><span style="color: #008000; ">&nbsp;&lt;property&nbsp;resource="resource1.properties"&nbsp;/&gt;&nbsp;</span><span style="color: #008000; ">--&gt;</span><br /><span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">&lt;!--</span><span style="color: #008000; ">&nbsp;console&nbsp;appender&nbsp;</span><span style="color: #008000; ">--&gt;</span><br /><span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">appender&nbsp;</span><span style="color: #FF0000; ">name</span><span style="color: #0000FF; ">="STDOUT"</span><span style="color: #FF0000; ">&nbsp;class</span><span style="color: #0000FF; ">="ch.qos.logback.core.ConsoleAppender"</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">encoder</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">pattern</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%d{HH:mm:ss.SSS}&nbsp;[%t]&nbsp;%-5p&nbsp;&nbsp;%c{1}&nbsp;-&nbsp;%m%n<br /><span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">pattern</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">20</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">encoder</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">21</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">appender</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">22</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">&lt;!--</span><span style="color: #008000; ">&nbsp;default&nbsp;appender&nbsp;</span><span style="color: #008000; ">--&gt;</span><br /><span style="color: #008080; ">24</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">appender&nbsp;</span><span style="color: #FF0000; ">name</span><span style="color: #0000FF; ">="COMMON-DEFAULT-APPENDER"</span><span style="color: #FF0000; ">&nbsp;class</span><span style="color: #0000FF; ">="ch.qos.logback.core.rolling.RollingFileAppender"</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">File</span><span style="color: #0000FF; ">&gt;</span>${LOG_PATH}/common-default.log<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">File</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">26</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">rollingPolicy&nbsp;</span><span style="color: #FF0000; ">class</span><span style="color: #0000FF; ">="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">27</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">FileNamePattern</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">28</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${LOG_PATH}/common-default.%d.log.gz<br /><span style="color: #008080; ">29</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">&lt;!--</span><span style="color: #008000; ">&nbsp;${LOG_PATH}/%d{yyyy-MM,aux}/common-default.%d.log.gz&nbsp;</span><span style="color: #008000; ">--&gt;</span><br /><span style="color: #008080; ">30</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">FileNamePattern</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">31</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">rollingPolicy</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">32</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">encoder</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">33</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">Pattern</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">34</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%d&nbsp;[%t]&nbsp;%-5p&nbsp;&nbsp;%c{1}&nbsp;-&nbsp;%m%n<br /><span style="color: #008080; ">35</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">Pattern</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">36</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">encoder</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">37</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">&lt;!--</span><span style="color: #008000; ">&nbsp;&lt;immediateFlush&gt;false&lt;/immediateFlush&gt;&nbsp;&nbsp;</span><span style="color: #008000; ">--&gt;</span><br /><span style="color: #008080; ">38</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">appender</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">39</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">40</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">&lt;!--</span><span style="color: #008000; ">&nbsp;error&nbsp;appender&nbsp;</span><span style="color: #008000; ">--&gt;</span><br /><span style="color: #008080; ">41</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">appender&nbsp;</span><span style="color: #FF0000; ">name</span><span style="color: #0000FF; ">="COMMON-ERROR-APPENDER"</span><span style="color: #FF0000; ">&nbsp;class</span><span style="color: #0000FF; ">="ch.qos.logback.core.rolling.RollingFileAppender"</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">42</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">filter&nbsp;</span><span style="color: #FF0000; ">class</span><span style="color: #0000FF; ">="ch.qos.logback.classic.filter.ThresholdFilter"</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">43</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">level</span><span style="color: #0000FF; ">&gt;</span>ERROR<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">level</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">44</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">filter</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">45</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">File</span><span style="color: #0000FF; ">&gt;</span>${LOG_PATH}/common-error.log<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">File</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">46</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">rollingPolicy&nbsp;</span><span style="color: #FF0000; ">class</span><span style="color: #0000FF; ">="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">47</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">FileNamePattern</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">48</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${LOG_PATH}/common-error.%d.log.gz<br /><span style="color: #008080; ">49</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">&lt;!--</span><span style="color: #008000; ">&nbsp;${LOG_PATH}/%d{yyyy-MM,aux}/common-error.%d.log.gz&nbsp;</span><span style="color: #008000; ">--&gt;</span><br /><span style="color: #008080; ">50</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">FileNamePattern</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">51</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">rollingPolicy</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">52</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">encoder</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">53</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">Pattern</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">54</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%d&nbsp;[%t]&nbsp;%-5p&nbsp;&nbsp;%c{1}&nbsp;-&nbsp;%m%n<br /><span style="color: #008080; ">55</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">Pattern</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">56</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">encoder</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">57</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">&lt;!--</span><span style="color: #008000; ">&nbsp;&lt;immediateFlush&gt;false&lt;/immediateFlush&gt;&nbsp;&nbsp;</span><span style="color: #008000; ">--&gt;</span><br /><span style="color: #008080; ">58</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">appender</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">59</span>&nbsp;<br /><span style="color: #008080; ">60</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">&lt;!--</span><span style="color: #008000; ">&nbsp;root&nbsp;logger&nbsp;</span><span style="color: #008000; ">--&gt;</span><br /><span style="color: #008080; ">61</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">root</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">62</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">level&nbsp;</span><span style="color: #FF0000; ">value</span><span style="color: #0000FF; ">="DEBUG"</span><span style="color: #0000FF; ">/&gt;</span><br /><span style="color: #008080; ">63</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">appender-ref&nbsp;</span><span style="color: #FF0000; ">ref</span><span style="color: #0000FF; ">="STDOUT"</span><span style="color: #0000FF; ">/&gt;</span><br /><span style="color: #008080; ">64</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">appender-ref&nbsp;</span><span style="color: #FF0000; ">ref</span><span style="color: #0000FF; ">="COMMON-DEFAULT-APPENDER"</span><span style="color: #0000FF; ">/&gt;</span><br /><span style="color: #008080; ">65</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">appender-ref&nbsp;</span><span style="color: #FF0000; ">ref</span><span style="color: #0000FF; ">="COMMON-ERROR-APPENDER"</span><span style="color: #0000FF; ">/&gt;</span><br /><span style="color: #008080; ">66</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">root</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">67</span>&nbsp;<br /><span style="color: #008080; ">68</span>&nbsp;<span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">configuration</span><span style="color: #0000FF; ">&gt;</span><br /><span style="color: #008080; ">69</span>&nbsp;</div><img src ="http://www.blogjava.net/watchzerg/aggbug/415756.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/watchzerg/" target="_blank">王星游</a> 2014-07-13 19:03 <a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415756.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>logback_eclipse_plugin_beagle</title><link>http://www.blogjava.net/watchzerg/archive/2014/07/13/415755.html</link><dc:creator>王星游</dc:creator><author>王星游</author><pubDate>Sun, 13 Jul 2014 11:01:00 GMT</pubDate><guid>http://www.blogjava.net/watchzerg/archive/2014/07/13/415755.html</guid><wfw:comment>http://www.blogjava.net/watchzerg/comments/415755.html</wfw:comment><comments>http://www.blogjava.net/watchzerg/archive/2014/07/13/415755.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/watchzerg/comments/commentRss/415755.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/watchzerg/services/trackbacks/415755.html</trackback:ping><description><![CDATA[<div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"><a href="http://logback.qos.ch/beagle/index.html">http://logback.qos.ch/beagle/index.html</a></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">先安装依赖插件：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">http://download.eclipse.org/technology/nebula/snapshot &nbsp; &nbsp;(注意这个是稳定的release版的地址，只需要安装&#8220;Nubula Release Individual Widgets&#8221;中的&#8220;Nebula Grid Feature&#8221;即可)</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">再安装logback-beagle插件：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">http://logback.qos.ch/p2/ ( "Logback" "Logback Beagle" "SLF4J"这三个都得选)</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">完成后按&#8220;alt-shift-Q,Q&#8221;弹出view选择框，找到beagle打开即可（之后需要在logback-test.xml里配置&lt;consolePlugin /&gt;，参见logback文档）。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">在logback-test.xml里加上配置&lt;consolePlugin /&gt;即可</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;configuration debug="true"&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp;&lt;!-- sends logs to logback-beagle --&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp;&lt;consolePlugin /&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;/configuration&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&#8212;&#8212;实际上这个配置会自动创建一个SocketAppender，并把日志发到本机的4321端口。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">单击停止滚动，双击开始滚动</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">右键菜单可以跳转到调用行，也可以查看最多8行调用栈</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">配置：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">eclipse的preference里:</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;Run/Debug -&nbsp;Beagle</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在这里可以自定义控制台输出的pattern</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;General - Appearance - Colors and Fonts</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 可以单独对Beagle设置字体</div></div><img src ="http://www.blogjava.net/watchzerg/aggbug/415755.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/watchzerg/" target="_blank">王星游</a> 2014-07-13 19:01 <a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415755.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>logback_doc_manual_09_logging_separation</title><link>http://www.blogjava.net/watchzerg/archive/2014/07/13/415754.html</link><dc:creator>王星游</dc:creator><author>王星游</author><pubDate>Sun, 13 Jul 2014 11:00:00 GMT</pubDate><guid>http://www.blogjava.net/watchzerg/archive/2014/07/13/415754.html</guid><wfw:comment>http://www.blogjava.net/watchzerg/comments/415754.html</wfw:comment><comments>http://www.blogjava.net/watchzerg/archive/2014/07/13/415754.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/watchzerg/comments/commentRss/415754.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/watchzerg/services/trackbacks/415754.html</trackback:ping><description><![CDATA[<div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"><a href="http://logback.qos.ch/manual/loggingSeparation.html">http://logback.qos.ch/manual/loggingSeparation.html</a></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">主要处理多个应用程序运行在同一个web容器，并且每个应用使用各自独立的日志环境。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&#8212;&#8212;想想一个tomcat运行了多个项目&#8212;&#8212;也就是&#8220;一个JVM，多个ClassLoader，每个ClassLoader拥有自己独立的Logger Context&#8221;的问题。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">Context Selectors</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;调用LoggerFactory.getLogger("foo")的时候，会要求SLF4J绑定一个ILoggerFactory，如果SLF4J使用的是logback，那么&#8220;绑定ILoggerFactory&#8221;的方法，会代理给一个ContextSelector实例，该实例会根据情况返回最合适的LoggerContext对象&#8212;&#8212;这个对象实现了ILoggerFactory接口。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;默认总是返回DefaultContextSelector，可以在系统属性里通过logback.ContextSelector属性指定自己的类。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">ContextJNDISelector</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;根据JNDI查找Selector&#8212;&#8212;这样可以在各个项目的web.xml里配置自己的JNDI环境变量。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;为了在单个web项目重启和关闭的时候，对应的logger Context可以被回收，最好配置ContextDetachingSCL监听器</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;不过每次获取logger都查找JNDI太慢，可以配置LoggerContextFilter过滤器来避免&#8212;&#8212;会在每个http请求到来的时候把logger context放在线程内部，从而允许之后跳过JNDI搜索。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;此时最好把logger全声明成static的，减少logger的获取总次数。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">Taming static references in shared libraries</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;如果有一个类属于共享包，被两个web项目同时引用</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1，当这个类使用非静态logger时，一切良好，来自两个web项目的调用，会返回各自的logger context。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2，当这个类使用静态logger时，会错误的返回首次调用它的web项目的logger context&#8212;&#8212;对这个问题ContextJNDISelector无能为力（eluded a solution for eons... 哈哈哈哈）</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;对于上述的&#8220;来自共类的静态logger，获取不同的logger context&#8221;的问题，有几个的办法：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1，共享类改成非静态logger&#8212;&#8212;一般不现实，因为共享类的源码往往不受项目控制。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2，把共享类挪到web项目里&#8212;&#8212;也够呛，一个两个类还好，那么多第三方依赖咋弄？</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3，所以还有一种取巧的办法：用SiftingAppender，根据JNDI信息把不同的日志分别输出到不同的文件里去（logback提供了JNDIBasedContextDiscriminator帮助做这事儿）&#8212;&#8212;也就是说，两个项目分享同一个logger，等到其关联的appender需要把event输出到文件时，再临时决定输出到哪个文件。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;上述第3种方法有一个问题：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;假如项目A和项目B都使用共享包S。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 项目A启动并调用S的时候，就已经把S的logger context设置为A了，日志会写入A.log中。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; B启动并调用S的时候logger contex依然是A（不过因为配置了SiftingAppender的存在，B的日志依然可以写到正确的B.log中）</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#8212;&#8212;也就是说，共享logger的问题并没有实质解决，这个logger还是只能属于A或者B其中之一，只不过logger在写日志前根据MDC里的JNDI可以将日志写到正确的文件中去。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;而初始化了两个不同的logger context都指向B.log，存在多个线程写同一个文件的不安全问题&#8212;&#8212;需要对appender配置prudent参数来解决（会影响性能）。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;（正常使用都是一个web container部署一个web项目，很少遇到上述情况。这部分文档看的很蛋疼&#8230;&#8230;）</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div></div><img src ="http://www.blogjava.net/watchzerg/aggbug/415754.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/watchzerg/" target="_blank">王星游</a> 2014-07-13 19:00 <a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415754.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>logback_doc_manual_07_filters</title><link>http://www.blogjava.net/watchzerg/archive/2014/07/13/415752.html</link><dc:creator>王星游</dc:creator><author>王星游</author><pubDate>Sun, 13 Jul 2014 10:59:00 GMT</pubDate><guid>http://www.blogjava.net/watchzerg/archive/2014/07/13/415752.html</guid><wfw:comment>http://www.blogjava.net/watchzerg/comments/415752.html</wfw:comment><comments>http://www.blogjava.net/watchzerg/archive/2014/07/13/415752.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/watchzerg/comments/commentRss/415752.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/watchzerg/services/trackbacks/415752.html</trackback:ping><description><![CDATA[<div><a href="http://logback.qos.ch/manual/filters.html" style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">http://logback.qos.ch/manual/filters.html</a><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">logback-classic有两种filter：Regular filters和turbo filters，挂在appender上</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">Regular filters</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;只有一个decide()方法，返回DENY, NEUTRAL or ACCEPT</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">LevelFilter</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;filter class="ch.qos.logback.classic.filter.LevelFilter"&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &lt;level&gt;INFO&lt;/level&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &lt;onMatch&gt;ACCEPT&lt;/onMatch&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &lt;onMismatch&gt;DENY&lt;/onMismatch&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;/filter&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">ThresholdFilter</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;高于或等于指定日志级别的记录，会返回NEUTRAL</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;filter class="ch.qos.logback.classic.filter.ThresholdFilter"&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &lt;level&gt;INFO&lt;/level&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;/filter&gt;&nbsp; &nbsp; &nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">EvaluatorFilter</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;EventEvaluator的实现判断某个条件是否满足。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;GEventEvaluator</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 接受groovy语法的布尔表达式作为判断条件，需要依赖Groovy运行时，表达式语句在配置的时候完成编译。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; logback会自动将目标事件作为一个变量传进来，可以用&#8220;event&#8221;或者&#8220;e&#8221;来引用。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;TRACE, DEBUG, INFO, WARN and ERROR这些级别也引入了，所以可以这样判断相等：&nbsp;"event.level == DEBUG" 。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 其他比较符，大于小于，需要转换成int再比较。</div><blockquote style="color: #000000; font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div>&nbsp; &nbsp; &lt;filter class="ch.qos.logback.core.filter.EvaluatorFilter"&gt; &nbsp; &nbsp; &nbsp;</div><div>&nbsp; &nbsp; &nbsp; &lt;evaluator class="ch.qos.logback.classic.boolex.GEventEvaluator"&gt;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &lt;expression&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;e.level.toInt() &gt;= WARN.toInt() &amp;amp;&amp;amp; &nbsp;&lt;!-- Stands for &amp;&amp; in XML --&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;!(e.mdc?.get("req.userAgent") =~ /Googlebot|msnbot|Yahoo/ )</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &lt;/expression&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;/evaluator&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;OnMismatch&gt;DENY&lt;/OnMismatch&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;OnMatch&gt;NEUTRAL&lt;/OnMatch&gt;</div><div>&nbsp; &nbsp; &lt;/filter&gt;</div></blockquote><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;JaninoEventEvaluator</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 使用java表达式，使用上比基于groovy的GEventEvaluator繁琐，但执行速度更快。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 详情略。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">Matchers</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;执行上面的过滤器时，可以调用String.matches()方法，但代价是每次需要重编译一个正则Pattern对象。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;所以可以预先定义和编译一个，以便复用。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;详情略。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">TurboFilters</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;跟普通过滤器功能一样，但是：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1，TurboFilter是跟logging context关联的，而不是跟appender关联。作用域更大。不仅在指定appender使用时，而且在每次logging请求时都会被调用。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2，他们是在LoggingEvent对象创建之前被调用，过滤时不需要event实例做参数，所以性能更高（因为在event创建之前就已经执行过滤了）。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;内置了一些TurboFilter：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;MDCFilter &nbsp; &nbsp; 测试指定的值是否存在于MDC中</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;DynamicThresholdFilter &nbsp; &nbsp; 基于MDC的key和level来限流</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;MarkerFilter &nbsp; &nbsp; 测试指定的marker是否出现在请求中</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DuplicateMessageFilter</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;自动过滤相同的消息。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 使用简单的字符串比对&#8212;&#8212;即使两个字符串基本相同，相差一两个字母：也会被认为不同。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 仅比较raw字符串，用{}转义过的字符串不去比较。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 可以通过AllowedRepetitions设置允许的重复上限，超过上限的会被抛弃。默认大小为5</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 需要通过一个内部cache来保存老的消息以便判断，可以通过CacheSize设置缓存大小，默认100.</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">在evaluator的expression里，将logging时间与项目启动时间对比，可以控制仅输出&#8220;项目启动后20秒内的某类型日志&#8221;&#8212;&#8212;这个对于&#8220;确认某个定时任务在启动时是运行状态&#8221;很有用，例如：</div><blockquote style="color: #000000; font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div>&lt;filter class="ch.qos.logback.core.filter.EvaluatorFilter"&gt;</div><div>&nbsp; &lt;evaluator name="loggingTaskEval"&gt;</div><div>&nbsp; &nbsp; &lt;expression&gt;</div><div>&nbsp; &nbsp; &nbsp; logger.getName().contains("LoggingTask") &amp;amp;&amp;amp;</div><div>&nbsp; &nbsp; &nbsp; message.contains("Howdydy-diddly-ho") &amp;amp;&amp;amp;</div><div>&nbsp; &nbsp; &nbsp; (timeStamp - event.getStartTime()) &gt;= 20000</div><div>&nbsp; &nbsp; &lt;/expression&gt;</div><div>&nbsp; &lt;/evaluator&gt;</div><div>&nbsp; &lt;OnMatch&gt;DENY&lt;/OnMatch&gt;</div><div>&lt;/filter&gt;</div></blockquote><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div></div><img src ="http://www.blogjava.net/watchzerg/aggbug/415752.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/watchzerg/" target="_blank">王星游</a> 2014-07-13 18:59 <a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415752.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>logback_doc_manual_08_mapped_diagnostic_contexts</title><link>http://www.blogjava.net/watchzerg/archive/2014/07/13/415753.html</link><dc:creator>王星游</dc:creator><author>王星游</author><pubDate>Sun, 13 Jul 2014 10:59:00 GMT</pubDate><guid>http://www.blogjava.net/watchzerg/archive/2014/07/13/415753.html</guid><wfw:comment>http://www.blogjava.net/watchzerg/comments/415753.html</wfw:comment><comments>http://www.blogjava.net/watchzerg/archive/2014/07/13/415753.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/watchzerg/comments/commentRss/415753.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/watchzerg/services/trackbacks/415753.html</trackback:ping><description><![CDATA[<div><a href="http://logback.qos.ch/manual/mdc.html" style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">http://logback.qos.ch/manual/mdc.html</a><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">MDC（注意这个类在org.slf4j包里）</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;基于&#8220;多个线程同步处理多个请求&#8221;的假设来设计的，上下文信息记录。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#8212;&#8212;子线程会自动拷贝双亲线程的这类信息。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#8212;&#8212;如果没有附加处理的话，放入线程池处理的任务会丢失MDC上下文。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 该设计假定向MDC放数据的速度不会太快。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">最常用的web场景，是集成在一个servlet的Filter中，在请求时载入MDC信息，doFilter处理完成后卸载MDC信息。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&#8212;&#8212;最好在&#8220;验证用户&#8221;这个Filter之后（或者之中）进行，这样可以把用户验证信息（包括但不限于用户名）写入MDC。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">交给线程池处理(submit)之前：MDC.getCopyOfContextMap()，把返回的map当作参数传给任务线程</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">线程池处理代码的第一行：MDC.setContextMapValues()，把接到的map参数设置到本线程的MDC中（别忘了最后清除掉）</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">MDCInsertingServletFilter</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;将web请求常用信息设置到MDC中：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; req.remoteHost as returned by the getRemoteHost() method</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; req.xForwardedFor value of the "X-Forwarded-For" header</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; req.requestURI &nbsp; &nbsp; &nbsp; as returned by getRequestURI() method</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; req.requestURL as returned by getRequestURL() method</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; req.queryString as returned by getQueryString() method</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; req.userAgent &nbsp; &nbsp; &nbsp;value of the "User-Agent" header</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;web.xml中的配置</div><blockquote style="color: #000000; font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div>&lt;filter&gt;</div><div>&nbsp; &lt;filter-name&gt;MDCInsertingServletFilter&lt;/filter-name&gt;</div><div>&nbsp; &lt;filter-class&gt;</div><div>&nbsp; &nbsp; ch.qos.logback.classic.helpers.MDCInsertingServletFilter</div><div>&nbsp; &lt;/filter-class&gt;</div><div>&lt;/filter&gt;</div><div>&lt;filter-mapping&gt;</div><div>&nbsp; &lt;filter-name&gt;MDCInsertingServletFilter&lt;/filter-name&gt;</div><div>&nbsp; &lt;url-pattern&gt;/*&lt;/url-pattern&gt;</div><div>&lt;/filter-mapping&gt;&nbsp;</div></blockquote><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;注意filter顺序，经过该filter过滤之后，其它filter才能打印出MDC信息（特别是struts之类依赖filter处理主逻辑的）</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;使用例子：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;%X{req.remoteHost} %X{req.requestURI}%n%d - %m%n</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&#8212;&#8212;其实没多大意义，还是自己写这个filter，挑选自己的有效信息比较好。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div></div><img src ="http://www.blogjava.net/watchzerg/aggbug/415753.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/watchzerg/" target="_blank">王星游</a> 2014-07-13 18:59 <a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415753.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>logback_doc_manual_05_encoders</title><link>http://www.blogjava.net/watchzerg/archive/2014/07/13/415750.html</link><dc:creator>王星游</dc:creator><author>王星游</author><pubDate>Sun, 13 Jul 2014 10:58:00 GMT</pubDate><guid>http://www.blogjava.net/watchzerg/archive/2014/07/13/415750.html</guid><wfw:comment>http://www.blogjava.net/watchzerg/comments/415750.html</wfw:comment><comments>http://www.blogjava.net/watchzerg/archive/2014/07/13/415750.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/watchzerg/comments/commentRss/415750.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/watchzerg/services/trackbacks/415750.html</trackback:ping><description><![CDATA[<div><a href="http://logback.qos.ch/manual/encoders.html" style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">http://logback.qos.ch/manual/encoders.html</a><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">Encoder</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;负责将事件对象转换为字节数组.</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;目前只有PatternLayoutEncoder是唯一有用的Encoder。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">LayoutWrappingEncoder</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;兼容的包装器（因为老版本的logback是跳过Encoder直接依赖Layout的）</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">PatternLayoutEncoder</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;针对PatternLayout（最常用的layout）定制的兼容包装器。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;immediateFlush属性：是否将日志立刻写入磁盘，默认为true。将这个选项设为false可以达高4到5倍的吞吐量。</div><blockquote style="color: #000000; font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div>&lt;appender name="FILE" class="ch.qos.logback.core.FileAppender"&gt;&nbsp;</div><div>&nbsp; &lt;file&gt;foo.log&lt;/file&gt;</div><div>&nbsp; &lt;encoder&gt;</div><div>&nbsp; &nbsp; &lt;pattern&gt;%d %-5level [%thread] %logger{0}: %msg%n&lt;/pattern&gt;</div><div>&nbsp; &nbsp; &lt;!-- this quadruples logging throughput --&gt;</div><div>&nbsp; &nbsp;&nbsp;<strong>&lt;immediateFlush&gt;false&lt;/immediateFlush&gt;</strong></div><div>&nbsp; &lt;/encoder&gt;&nbsp;</div><div>&lt;/appender&gt;</div></blockquote><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;outputPatternAsHeader属性：在日志文件的顶部输出一行字符串样式，默认flase。</div><blockquote style="color: #000000; font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div>&lt;appender name="FILE" class="ch.qos.logback.core.FileAppender"&gt;&nbsp;</div><div>&nbsp; &lt;file&gt;foo.log&lt;/file&gt;</div><div>&nbsp; &lt;encoder&gt;</div><div>&nbsp; &nbsp; &lt;pattern&gt;%d %-5level [%thread] %logger{0}: %msg%n&lt;/pattern&gt;</div><div>&nbsp; &nbsp;&nbsp;<strong>&lt;outputPatternAsHeader&gt;true&lt;/outputPatternAsHeader&gt;</strong></div><div>&nbsp; &lt;/encoder&gt;&nbsp;</div><div>&lt;/appender&gt;</div></blockquote><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;输出结果：</div><blockquote style="color: #000000; font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div>#logback.classic pattern: %d [%thread] %-5level %logger{36} - %msg%n</div><div>2012-04-26 14:54:38,461 [main] DEBUG com.foo.App - Hello world</div><div>2012-04-26 14:54:38,461 [main] DEBUG com.foo.App - Hi again</div></blockquote><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div></div><img src ="http://www.blogjava.net/watchzerg/aggbug/415750.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/watchzerg/" target="_blank">王星游</a> 2014-07-13 18:58 <a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415750.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>logback_doc_manual_06_layouts</title><link>http://www.blogjava.net/watchzerg/archive/2014/07/13/415751.html</link><dc:creator>王星游</dc:creator><author>王星游</author><pubDate>Sun, 13 Jul 2014 10:58:00 GMT</pubDate><guid>http://www.blogjava.net/watchzerg/archive/2014/07/13/415751.html</guid><wfw:comment>http://www.blogjava.net/watchzerg/comments/415751.html</wfw:comment><comments>http://www.blogjava.net/watchzerg/archive/2014/07/13/415751.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/watchzerg/comments/commentRss/415751.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/watchzerg/services/trackbacks/415751.html</trackback:ping><description><![CDATA[<div><a href="http://logback.qos.ch/manual/layouts.html" style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">http://logback.qos.ch/manual/layouts.html</a><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">PatternLayout</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;转换模式类似于C语言里的printf()。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">转移字符：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;c{length}</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;lo{length}</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;logger{length}</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 其中的length代表输出的logger长度。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 设为0的话例外，仅输出最右边的logger名。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 其余情况会自动计算，尽量使得输出的总字符串长度小于指定长度&#8212;&#8212;但是，最右边的logger名称无论如何会完整保留，同时前面的每一级logger，最少会被精简到1个字符。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#8212;&#8212;%c{1}</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;C{length}</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;class{length}</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 打印调用者的类名称，设置方法与上面一样。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 性能不高。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;contextName</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;cn</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 打印logger在event最初绑定的logger context的名称。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;d{pattern}</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;date{pattern}</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;d{pattern, timezone}</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;date{pattern, timezone}</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 输入日志时间，使用java.text.SimpleDateFormat的日期格式化方法。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 如果不指定日期格式，默认使用ISO8601，也就是2006-10-20 14:06:49,812这种形式。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#8212;&#8212;%d</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;F / file</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 输出java源文件的名称。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 性能不高。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;caller{depth}</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;caller{depth, evaluator-1, ... evaluator-n}</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 打印日志事件的调用堆栈。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 使用评估器evaluator决定是否打印。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;L</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;line</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 输出日志记录请求发起的行数。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 性能不高。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;m</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;msg</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;message</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 日志正文</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#8212;&#8212;%m</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;M</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;method</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 日志调用方法名。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 性能不高</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;n</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 操作系统对应的换行符</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#8212;&#8212;%n</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;p</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;le</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;level</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 日志等级</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;r</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;relative</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 应用程序启动到日志创建的相对时间</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;t</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;thread</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 线程名</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#8212;&#8212;%t</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;X{key:-defaultVal}</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;mdc{key:-defaultVal}</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MDC信息</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;ex{depth}&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;exception{depth}&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;throwable{depth}&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;ex{depth, evaluator-1, ..., evaluator-n}&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;exception{depth, evaluator-1, ..., evaluator-n}&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;throwable{depth, evaluator-1, ..., evaluator-n}</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 输出异常堆栈深度（如果有的话），默认full全部输出。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 可以指定的参数值：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;short：打印堆栈的第一行</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;full：打印所有行</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;任何数字：指定行数</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;使用评估器evaluator决定是否打印。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;xEx{depth}&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;xException{depth}&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;xThrowable{depth}&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;xEx{depth, evaluator-1, ..., evaluator-n}&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;xException{depth, evaluator-1, ..., evaluator-n}&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;xThrowable{depth, evaluator-1, ..., evaluator-n}</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 跟上面的类似，但是附加了包信息。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;如果包信息不准确（是猜测的），那么会自动在包信息前面附加一个&#8220;~&#8221;字符。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 如果在日志信息模式里，未指定任何异常格式，那么系统会自动在末尾加上一个%xEx。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;如果不想打印包信息（例如netbean里会出问题），那么在日志模式的末尾明确指定%ex即可，就会输出不包含包信息的堆栈。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;如果想不打印任何异常堆栈信息，可以使用%nopex。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#8212;&#8212;%xEx</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;nopex&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;nopexception&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 加上%nopex可以阻止系统自动在日志模式末尾添加%xEx&#8212;&#8212;也就是完全禁止异常堆栈打印。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;marker</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 输出关联的marker信息，如果marker多级关联，会都打印出来。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;property{key}</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 输出key关联的属性&#8212;&#8212;定义在logger context或者system properties里面。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;replace(p){r, t}</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 将p中的所有符合r正则的字符串，都替换成t。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 例如%replace(%logger%msg){'\.', '/'}，会将输出的logger和msg信息中的点号都替换成斜杠。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;rEx{depth}&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;rootException{depth}&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;rEx{depth, evaluator-1, ..., evaluator-n}&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;rootException{depth, evaluator-1, ..., evaluator-n}</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 类似于xEx，也会打印异常的包信息，但是会将root exception打印到前面，跟普通的异常打印顺序是反着的。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;转义百分号： \%</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;正常情况下转义字符会被正确分割，但有些时候例外，例如%date%nHello，系统会解析%nHello失败。如果真的需要在%n后紧跟一个Hello，可以这样：%date%n{}Hello</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;我一般用这个：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;%d [%t] %-5p &nbsp;%c{1} - %m%n</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">------------------------------------------------------------------</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">Format modifiers</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;控制数据段的补齐。<br /> &nbsp; &nbsp; &nbsp;例如 %20.30logger&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 如果logger长度小于20，则从左边用空格补齐；如果logger长度大于30，则从开头(左边)切去多余字符。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 如果20或者30前面有负号，则左右颠倒。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;假如想给日志级别只输出1个字符（T,D,W,I,E），不需要自己写一个Converter，而只需要配置一下即可：%.-1level</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">转义选项：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;如果转义选项里面包含特殊字符（特别是在使用正则表达式的时候），例如大小括号、逗号、空格，那么可以用单引号或双引号括起来，例如：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&lt;pattern&gt;%-5level - %replace(%msg){'\d{14,16}', 'XXXX'}%n&lt;/pattern&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&#8212;&#8212;这个可以把14到16位的数字（信用卡号）转换为XXXX。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">------------------------------------------------------------------</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">括号的特殊作用：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;%-30(%d{HH:mm:ss.SSS} [%thread]) %-5level %logger{32} - %msg%n</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;可以让括号里的两个表达式联合起来按照30个字符补齐。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;括号可以用反斜杠转义：\(%d{HH:mm:ss.SSS} [%thread]\)</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">------------------------------------------------------------------</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">Coloring</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;着色，window需要引其它包，linux和mac os本身支持着色。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;样例：&lt;pattern&gt;[%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg %n&lt;/pattern&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %highlight会将ERROR设为红色加粗，WARN设为红色，INFO设为蓝色，其余默认。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %cyan会将logger名称设为蓝绿色。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">------------------------------------------------------------------</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">Evaluators</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;EventEvaluator类的实现，用来评估一个事件是否符合打印条件。</div><blockquote style="color: #000000; font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div>&nbsp; &lt;evaluator name="DISP_CALLER_EVAL"&gt;</div><div>&nbsp; &nbsp; &lt;expression&gt;logger.contains("chapters.layouts") &amp;amp;&amp;amp; \</div><div>&nbsp; &nbsp; &nbsp; message.contains("who calls thee")&lt;/expression&gt;</div><div>&nbsp; &lt;/evaluator&gt;</div><div></div><div>&nbsp; &lt;appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"&gt;&nbsp;</div><div>&nbsp; &nbsp; &lt;encoder&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;pattern&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; %-4relative [%thread] %-5level - %msg%n%caller{2, DISP_CALLER_EVAL}</div><div>&nbsp; &nbsp; &nbsp; &lt;/pattern&gt;</div><div>&nbsp; &nbsp; &lt;/encoder&gt;</div><div>&nbsp; &lt;/appender&gt;</div></blockquote><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;注意因为xml的关系，要用&amp;amp;转义&amp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;应用场景：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 例如，如果日志级别是WARN以上，并且logger是来自一个财务模块&#8212;&#8212;那么就打印caller信息。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;注意：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在%caller转义模式中，当Evaluators返回true的时候才输出。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在%ex转义模式中，当Evaluatorstrue的时候不输出。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;例如下面的配置，当异常对象为TestException时，不输出。</div><blockquote style="color: #000000; font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div>&nbsp; &lt;evaluator name="DISPLAY_EX_EVAL"&gt;</div><div>&nbsp; &nbsp; &lt;expression&gt;throwable != null &amp;amp;&amp;amp; throwable instanceof &nbsp;\</div><div>&nbsp; &nbsp; &nbsp; chapters.layouts.TestException&lt;/expression&gt;</div><div>&nbsp; &lt;/evaluator&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</div><div>&nbsp; &lt;appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"&gt;</div><div>&nbsp; &nbsp; &lt;encoder&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;pattern&gt;%msg%n%ex{full, DISPLAY_EX_EVAL}&lt;/pattern&gt;</div><div>&nbsp; &nbsp; &lt;/encoder&gt;</div><div>&nbsp; &lt;/appender&gt;</div></blockquote><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">------------------------------------------------------------------</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">Creating a custom conversion specifier</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;略</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">------------------------------------------------------------------</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">HTMLLayout</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;使用html表格来布局日志信息。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;可以使用普通的pattern转义符，但转义字符之前，不许用包括空格在内的任何字符分隔。</div><blockquote style="color: #000000; font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div>&nbsp; &lt;appender name="FILE" class="ch.qos.logback.core.FileAppender"&gt;</div><div>&nbsp; &nbsp; &lt;encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"&gt;</div><div>&nbsp; &nbsp; &nbsp;&nbsp;<strong>&lt;layout class="ch.qos.logback.classic.html.HTMLLayout"&gt;</strong></div><div><strong>&nbsp; &nbsp; &nbsp; &nbsp; &lt;pattern&gt;%relative%thread%mdc%level%logger%msg&lt;/pattern&gt;</strong></div><div><strong>&nbsp; &nbsp; &nbsp; &lt;/layout&gt;</strong></div><div>&nbsp; &nbsp; &lt;/encoder&gt;</div><div>&nbsp; &nbsp; &lt;file&gt;test.html&lt;/file&gt;</div><div>&nbsp; &lt;/appender&gt;</div></blockquote><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;HTMLLayout会自动创建一个DefaultThrowableRenderer，将异常信息打印到完整的一行里。如果不想这样，可以指定一个NOPThrowableRenderer。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">用CSS指定表格的样式：略</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">该Layout最常见的用法是配合SMTPAppender，发送html格式的日志邮件。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">------------------------------------------------------------------</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">Logback access</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;略</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div></div><img src ="http://www.blogjava.net/watchzerg/aggbug/415751.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/watchzerg/" target="_blank">王星游</a> 2014-07-13 18:58 <a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415751.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>logback_doc_manual_04_appenders</title><link>http://www.blogjava.net/watchzerg/archive/2014/07/13/415749.html</link><dc:creator>王星游</dc:creator><author>王星游</author><pubDate>Sun, 13 Jul 2014 10:57:00 GMT</pubDate><guid>http://www.blogjava.net/watchzerg/archive/2014/07/13/415749.html</guid><wfw:comment>http://www.blogjava.net/watchzerg/comments/415749.html</wfw:comment><comments>http://www.blogjava.net/watchzerg/archive/2014/07/13/415749.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/watchzerg/comments/commentRss/415749.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/watchzerg/services/trackbacks/415749.html</trackback:ping><description><![CDATA[<div><a href="http://logback.qos.ch/manual/appenders.html" style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">http://logback.qos.ch/manual/appenders.html</a><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">Appender都集成ch.qos.logback.core.Appender接口。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">每个Appender可以绑定若干个Filter。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">每个Appender可以将任务代理给Layout或者Encoder。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">每个Layout或者Encoder只能属于1个Appender。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">Appener也可以不包含Layout或者encoder，例如SocketAppender，直接把Event序列化传输。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">ch.qos.logback.core.AppenderBase这是一个抽象类，对Appender接口提供了骨架实现，线程安全。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">ch.qos.logback.core.UnsynchronizedAppenderBase是对应的线程不安全的类，但是可以将线程安全性委托给下一层的类（例如OutputStream）</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">OutputStreamAppender是文件输出和控制台输出Appender的父类，类层次结构如下：<br /><img src="http://www.blogjava.net/images/blogjava_net/watchzerg/logback-4-1.png" width="724" height="596" alt="" /><br /><br /><div><div>ConsoleAppender</div><div>&nbsp; &nbsp; &nbsp;输出到System.out or System.err</div><div></div><div>可配置属性：</div><div>&nbsp; &nbsp; &nbsp;encoder</div><div>&nbsp; &nbsp; &nbsp;target: &nbsp; &nbsp; 默认是System.out</div><div>&nbsp; &nbsp; &nbsp;withJansi： &nbsp; &nbsp; 默认false，用来在windows中支持控制台色彩的</div><div></div><div>样例：</div><div>&nbsp; &lt;appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"&gt;</div><div>&nbsp; &nbsp; &lt;encoder&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;pattern&gt;%-4relative [%thread] %-5level %logger{35} - %msg %n&lt;/pattern&gt;</div><div>&nbsp; &nbsp; &lt;/encoder&gt;</div><div>&nbsp; &lt;/appender&gt;</div><div></div><div>----------------------------------------------------------</div><div>FileAppender</div><div>&nbsp; &nbsp; &nbsp;写入到文件（新消息到来，写入前，才会判断是否该分割文件等）</div><div></div><div>可配置属性：</div><div>&nbsp; &nbsp; &nbsp;append： &nbsp; &nbsp; 文件追加，默认为true</div><div>&nbsp; &nbsp; &nbsp;encoder： &nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp;file： &nbsp; &nbsp; 文件路径和名词（如果windows下，记得分隔符转义）</div><div>&nbsp; &nbsp; &nbsp;prudent： &nbsp; &nbsp; 谨慎模式，不同JVM（甚至存在于不同主机上）安全的写入同一个文件。默认关闭。</div><div></div><div>默认每行都flush到磁盘，可以修改Encoder的immediateFlush属性来改变这一行为。</div><div></div><div>样例：</div><div>&nbsp; &lt;appender name="FILE" class="ch.qos.logback.core.FileAppender"&gt;</div><div>&nbsp; &nbsp; &lt;file&gt;testFile.log&lt;/file&gt;</div><div>&nbsp; &nbsp; &lt;append&gt;true&lt;/append&gt;</div><div>&nbsp; &nbsp; &lt;encoder&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;pattern&gt;%-4relative [%thread] %-5level %logger{35} - %msg%n&lt;/pattern&gt;</div><div>&nbsp; &nbsp; &lt;/encoder&gt;</div><div>&nbsp; &lt;/appender&gt;</div><div></div><div>唯一名词的记录文件（通过启动时间戳）：</div><div>&nbsp; &lt;timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/&gt;</div><div>&nbsp; &lt;appender name="FILE" class="ch.qos.logback.core.FileAppender"&gt;</div><div>&nbsp; &nbsp; &lt;file&gt;log-${bySecond}.txt&lt;/file&gt;</div><div>&nbsp; &nbsp; &lt;encoder&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;pattern&gt;%logger{35} - %msg%n&lt;/pattern&gt;</div><div>&nbsp; &nbsp; &lt;/encoder&gt;</div><div>&nbsp; &lt;/appender&gt;</div><div>&#8212;&#8212;这样就可以在每次项目启动时生成一个新的文件。</div><div>默认是使用xml解析的时间，也可以指定使用log context的创建时间：</div><div>&nbsp; &nbsp; &nbsp;&lt;timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;timeReference="contextBirth"/&gt;</div><div></div><div>----------------------------------------------------------</div><div>RollingFileAppender</div><div>&nbsp; &nbsp; &nbsp;滚动记录日志文件</div><div>&nbsp; &nbsp; &nbsp;有两个子组件：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; RollingPolicy &#8212;&#8212;接管&#8220;滚动&#8221;操作，控制该操作如何发生</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TriggeringPolicy &#8212;&#8212;决定滚动操作是否发生，何时发生</div><div>&nbsp; &nbsp; &nbsp;默认情况下，必须同时含有上述两个组件。不过有的RollingPolicy也实现了后者的接口，那么可以身兼2职。</div><div></div><div>可配置属性：</div><div>&nbsp; &nbsp; &nbsp;file：</div><div>&nbsp; &nbsp; &nbsp;append：</div><div>&nbsp; &nbsp; &nbsp;encoder：</div><div>&nbsp; &nbsp; &nbsp;rollingPolicy：</div><div>&nbsp; &nbsp; &nbsp;triggeringPolicy：</div><div>&nbsp; &nbsp; &nbsp;prudent：</div><div></div><div>RollingPolicy</div><div>&nbsp; &nbsp; &nbsp;包含的操作：将当前的日志文件归档（并重命名），压缩（如果需要）</div><div></div><div>TimeBasedRollingPolicy</div><div>&nbsp; &nbsp; &nbsp;最常用的，基于时间滚动，同时实现了RollingPolicy和TriggeringPolicy</div><div>&nbsp; &nbsp; &nbsp;可配置属性：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fileNamePattern： &nbsp; &nbsp; 文件名匹配格式</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;文件名+日期定义器&#8220;%d&#8221;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;日期定义器的格式在SimpleDateFormat中定义</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;滚动周期是通过日期定义器推断出来的</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;其父元素RollingFileAppender中file属性可以省略（因为可以用fileNamePattern猜测出当前时间的日志名）</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 也可以不省略，这样可以为&#8220;当前日志文件&#8221;和&#8220;归档日志文件&#8221;分别制定不同的路径</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;日志定义器中的正反斜杠都会被认为是目录分隔符</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;可以指定多个日期定义器，但只能有1个是主要的，其余的必须标记为aux（辅助的）</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; maxHistory： &nbsp; &nbsp; 最大文件数</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cleanHistoryOnStart： &nbsp; &nbsp; 启动时清除历史归档日志</div><div></div><div>&nbsp; &nbsp; &nbsp;对fileNamePattern的更详细的解释和示例：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;/wombat/foo.%d &nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;按天分隔日志</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;未指定格式，所以默认为yyyy-MM-dd（按天滚动）</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;如果在RollingFileAppender中指定了file（默认日志文件名）：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 今天日志为 /wombat/foo.2006-11-24</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 昨天日志为 /wombat/foo.2006-11-23</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;如果没有在RollingFileAppender中指定file为&#8220;/wombat/foo.txt&#8221;，</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 今天日志为 /wombat/foo.txt</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 昨天日志为 /wombat/foo.2006-11-23</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#8212;&#8212;其实不指定默认日志文件名的方式更好，因为避免了滚动时重命名操作，也就避免了潜在异常。</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;/wombat/%d{yyyy/MM}/foo.txt</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;按&#8220;年/月&#8221;分两级文件夹，文件名固定为&#8220;foo.txt&#8221;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;如果在RollingFileAppender中指定了file（默认日志文件名）：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2006年10月日志为&nbsp;/wombat/2006/10/foo.txt</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2006年11月日志为&nbsp;/wombat/2006/11/foo.txt</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;如果没有在RollingFileAppender中指定file为&#8220;/wombat/foo.txt&#8221;，</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 当前正在写的日志永远为&nbsp;/wombat/foo.txt</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 归档的日志格式为&nbsp;/wombat/2006/10/foo.txt</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;/wombat/foo.%d{yyyy-ww}.log</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;每个星期归档一个新文件（注意具体&#8220;哪天算是一个星期的第一天&#8221;取决于系统locale属性）</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;/wombat/foo%d{yyyy-MM-dd_HH}.log</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;每小时一次归档</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;/wombat/foo%d{yyyy-MM-dd_HH-mm}.log</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;每分钟一次归档</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;/foo/%d{yyyy-MM,aux}/%d.log</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;每天一次归档，但每个月一个新文件夹</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div>&nbsp; &nbsp; &nbsp;如果fileNamePattern文件名是以.gz或者.zip结尾的，那么TimeBasedRollingPolicy会自动压缩：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;/wombat/foo.%d.gz</div><div></div><div>&nbsp; &nbsp; &nbsp;日志归档是&#8220;记录日志的事件&#8221;触发的，所以有一定延迟。例如第二天的第一条日志是临晨01:00才过来，那么这个时候才会归档前一天的日志。</div><div></div><div>配置样例：</div><div>&nbsp; &lt;appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"&gt;</div><div>&nbsp; &nbsp; &lt;file&gt;logFile.log&lt;/file&gt;</div><div>&nbsp; &nbsp; &lt;rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;fileNamePattern&gt;logFile.%d{yyyy-MM-dd}.log&lt;/fileNamePattern&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;maxHistory&gt;30&lt;/maxHistory&gt;</div><div>&nbsp; &nbsp; &lt;/rollingPolicy&gt;</div><div></div><div>&nbsp; &nbsp; &lt;encoder&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;pattern&gt;%-4relative [%thread] %-5level %logger{35} - %msg%n&lt;/pattern&gt;</div><div>&nbsp; &nbsp; &lt;/encoder&gt;</div><div>&nbsp; &lt;/appender&gt;</div><div></div><div>----------------------------------------------------------</div><div>FixedWindowRollingPolicy</div><div>&nbsp; &nbsp; &nbsp;可配置属性：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;minIndex:</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;maxIndex:</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;fileNamePattern: &nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;必须包含&#8220;%i&#8221;占位符，用来表示将当前索引值插入什么位置。</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;例如&#8220;MyLogFile%i.log&#8221;配合&#8220;最小1，最大3&#8221;，表示文件名为：MyLogFile1.log, MyLogFile2.log, MyLogFile3.log</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;同样加上zip或gz后缀可以启用压缩</div><div>&nbsp; &nbsp; &nbsp;因为每次需要很多重命名操作（重命名次数等于window size），所以如果设置size超过20，会被强制指定为20.</div><div></div><div>&nbsp; &nbsp; &nbsp;配置样例：</div><div>&nbsp; &lt;appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"&gt;</div><div>&nbsp; &nbsp; &lt;file&gt;test.log&lt;/file&gt;</div><div></div><div>&nbsp; &nbsp; &lt;rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;fileNamePattern&gt;tests.%i.log.zip&lt;/fileNamePattern&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;minIndex&gt;1&lt;/minIndex&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;maxIndex&gt;3&lt;/maxIndex&gt;</div><div>&nbsp; &nbsp; &lt;/rollingPolicy&gt;</div><div></div><div>&nbsp; &nbsp; &lt;triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;maxFileSize&gt;5MB&lt;/maxFileSize&gt;</div><div>&nbsp; &nbsp; &lt;/triggeringPolicy&gt;</div><div>&nbsp; &nbsp; &lt;encoder&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;pattern&gt;%-4relative [%thread] %-5level %logger{35} - %msg%n&lt;/pattern&gt;</div><div>&nbsp; &nbsp; &lt;/encoder&gt;</div><div>&nbsp; &lt;/appender&gt;</div><div>----------------------------------------------------------</div><div>SizeAndTimeBasedFNATP（File Naming And Triggering Policy）&#8212;&#8212;是TimeBasedRollingPolicy的一个子组件</div><div>&nbsp; &nbsp; &nbsp;配置样例：</div><div>&nbsp; &lt;appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"&gt;</div><div>&nbsp; &nbsp; &lt;file&gt;mylog.txt&lt;/file&gt;</div><div>&nbsp; &nbsp; &lt;rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;!-- rollover daily --&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;fileNamePattern&gt;mylog-%d{yyyy-MM-dd}.%i.txt&lt;/fileNamePattern&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;timeBasedFileNamingAndTriggeringPolicy</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- or whenever the file size reaches 100MB --&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &lt;maxFileSize&gt;100MB&lt;/maxFileSize&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;/timeBasedFileNamingAndTriggeringPolicy&gt;</div><div>&nbsp; &nbsp; &lt;/rollingPolicy&gt;</div><div>&nbsp; &nbsp; &lt;encoder&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;pattern&gt;%msg%n&lt;/pattern&gt;</div><div>&nbsp; &nbsp; &lt;/encoder&gt;</div><div>&nbsp; &lt;/appender&gt;</div><div>&nbsp; &nbsp; &nbsp;&#8212;&#8212;每天滚动一个文件，如果文件体积达到100M，则也拆分。</div><div>&nbsp; &nbsp; &nbsp;&#8212;&#8212;也支持自动删除老文件，可以通过maxHistory指定保存的最多文件数（每天最多这么多，还是一共最多这么多？）</div><div></div><div>----------------------------------------------------------</div><div>SizeBasedTriggeringPolicy&#8212;&#8212;一般配合FixedWindowRollingPolicy使用</div><div>&nbsp; &nbsp; &nbsp;指定文件超过&#8220;maxFileSize&#8221;指定大小时，上层RollingFileAppender触发滚动操作。</div><div>&nbsp; &nbsp; &nbsp;默认&#8220;10MB&#8221;，可以指定各种后缀：KB,MB,GB</div><div></div><div>----------------------------------------------------------</div><div>----------------------------------------------------------</div><div></div><div>SocketAppender and SSLSocketAppender</div><div>以及后面关于网络，数据库，远程日志服务器，JNDI等&#8230;&#8230;省略&#8230;&#8230;</div><div></div><div>----------------------------------------------------------</div><div>SiftingAppender</div><div>&nbsp; &nbsp; &nbsp;可以根据指定的变量分割文件。例如根据用户ID，则每个用户一个日志文件。</div><div>&nbsp; &nbsp; &nbsp;</div><div>&nbsp; &nbsp; &nbsp;可配置参数：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;timeout：如果一个关联的appender如果超过默认30分钟没有被访问，则被SiftingAppender卸载掉。</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;maxAppenderCount：可以最大追踪的关联appender数量，默认int最大值。</div><div>&nbsp; &nbsp; &nbsp;这个Appener会把日志记录动作代理给关联的appender。</div><div>&nbsp; &nbsp; &nbsp;选择条件由Discriminator指定，默认为MDCBasedDiscriminator。</div><div></div><div>&nbsp; &nbsp; &nbsp;示例，假设应用程序这样设置了MDC信息：</div><blockquote style="color: #000000; text-align: -webkit-auto; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div>logger.debug("Application started");</div><div>MDC.put("userid", "Alice");</div><div>logger.debug("Alice says hello");&nbsp;</div></blockquote><div>&nbsp; &nbsp; &nbsp;然后这样配置：</div><div>&nbsp; &lt;appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender"&gt;</div><div>&nbsp; &nbsp; &lt;!-- in the absence of the class attribute, it is assumed that the</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;desired discriminator type is</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ch.qos.logback.classic.sift.MDCBasedDiscriminator --&gt;</div><div>&nbsp; &nbsp; &lt;discriminator&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;key&gt;userid&lt;/key&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;defaultValue&gt;unknown&lt;/defaultValue&gt;</div><div>&nbsp; &nbsp; &lt;/discriminator&gt;</div><div>&nbsp; &nbsp; &lt;sift&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;appender name="FILE-${userid}" class="ch.qos.logback.core.FileAppender"&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &lt;file&gt;${userid}.log&lt;/file&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &lt;append&gt;false&lt;/append&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &lt;layout class="ch.qos.logback.classic.PatternLayout"&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;pattern&gt;%d [%thread] %level %mdc %logger{35} - %msg%n&lt;/pattern&gt;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &lt;/layout&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;/appender&gt;</div><div>&nbsp; &nbsp; &lt;/sift&gt;</div><div>&nbsp; &lt;/appender&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</div><div></div><div>&nbsp; &nbsp; &nbsp;因为确定timeout和maxAppenderCount比较困难，所以如果程序可以知道&#8220;执行到某个地方很可能应该关闭对应的appender&#8221;，那么可以明确指定一个FINALIZE_SESSION的marker。这样siftingAppender关联的对应appender，会在接到这个marker的几秒钟后关闭。例如：</div><div>import static ch.qos.logback.classic.ClassicConstants.FINALIZE_SESSION_MARKER;</div><div>&nbsp; void job(String jobId) {</div><div>&nbsp; &nbsp; MDC.put("jobId", jobId);</div><div>&nbsp; &nbsp; logger.info("Starting job.");</div><div>&nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; // will cause the nested appender reach end-of-life. It will</div><div>&nbsp; &nbsp; // linger for a few seconds.</div><div>&nbsp; &nbsp; logger.info(FINALIZE_SESSION_MARKER, "About to end the job");</div><div></div><div>&nbsp; &nbsp; try {</div><div>&nbsp; &nbsp; &nbsp; .. perform clean up</div><div>&nbsp; &nbsp; } catch(Exception e); &nbsp;</div><div>&nbsp; &nbsp; &nbsp; // This log statement will be handled by the lingering appender.&nbsp;</div><div>&nbsp; &nbsp; &nbsp; // No new appender will be created.</div><div>&nbsp; &nbsp; &nbsp; logger.error("unexpected error while cleaning up", e);</div><div>&nbsp; &nbsp; }</div><div>&nbsp; }</div><div></div><div>----------------------------------------------------------</div><div>SMTPAppender</div><div>&nbsp; &nbsp; &nbsp;将日志事件缓存指定的数量，被特定事件触发后，异步发送邮件。</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;smtpHost &nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;smtpPort &nbsp; &nbsp; 默认25</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;to &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;发送目标，多个联系人可以用逗号隔开，也可以用多个&lt;to&gt;元素</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; from &nbsp; &nbsp; &nbsp;发送者邮箱，如果想包含名字，可以用特定格式&#8220;Adam Smith &amp;lt;smith@moral.org&amp;gt;&#8221;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;subject &nbsp; &nbsp; 邮件标题，可以使用PatternLayout的转义字符，会用&#8220;触发该邮件的日志事件&#8221;的信息替换转义字符</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;discriminator &nbsp; &nbsp; 默认只有一个缓存。通过指定该属性，可以有多个缓存，这样可以根据事件信息发给不同的人或者ip</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;evaluator &nbsp; &nbsp; 声明一个&lt;EventEvaluator/&gt;元素，通过class属性指定类型。默认为OnErrorEvaluator，也可以自己指定OnMarkerEvaluator,JaninoEventEvaluator,GEventEvaluator</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;cyclicBufferTracker &nbsp; &nbsp; 环形缓存跟踪器，基于discriminator的返回值工作。默认保存缓存大小为256</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;username &nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;password &nbsp; &nbsp;&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;STARTTLS &nbsp; &nbsp; 如果开启，会发起STARTTLS命令，导致连接转换为SSL。连接默认是不使用加密的。默认为false</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;SSL &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;如果开启，那么使用SSL连接。默认false。</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;charsetEncoding &nbsp; &nbsp; 默认UTF-8</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;localhost &nbsp; &nbsp; 如果SMTP发送方的hostname没配置好，邮件服务器可能拒绝请求，这个时候可以设置这个值为客户端全名。</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;asynchronousSending &nbsp; &nbsp; 异步发送，默认true。特定情况下需要设置为false，例如应用程序发送完邮件就会立即关闭。</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;includeCallerData &nbsp; &nbsp; 包含调用者信息，默认为false。</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;sessionViaJNDI &nbsp; &nbsp; logback依赖javax.mail.Session来发送邮件。该属性默认为false，SMTPAppender会根据配置构建新的Session。如果设为true，会去web容器寻找Session对象，此时应用程序不应该再依赖mail.jar等</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;jndiLocation &nbsp; &nbsp; 查找JNDI的路径，例如"java:comp/env/mail/Session"</div><div></div><div>&nbsp; &nbsp; &nbsp;最多保存256条日志事件，否则内存消耗太大（不建议自己指定其它值）。</div><div>&nbsp; &nbsp; &nbsp;发邮件依赖JavaMail API (mail.jar)和JavaBeans Activation Framework (activation.jar) &#8212;&#8212;maven里引入前者会自动依赖后者。</div><div></div><div>&nbsp; &nbsp; &nbsp;发送者和接收者都可以是动态属性：</div><blockquote style="color: #000000; text-align: -webkit-auto; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div>&lt;appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender"&gt;</div><div>&nbsp; &lt;smtpHost&gt;${smtpHost}&lt;/smtpHost&gt;</div><div>&nbsp; &lt;to&gt;<strong>${to}</strong>&lt;/to&gt;</div><div>&nbsp; &lt;from&gt;<strong>${from}</strong>&lt;/from&gt;</div><div>&nbsp; &lt;layout class="ch.qos.logback.classic.html.HTMLLayout"/&gt;</div><div>&lt;/appender&gt;</div></blockquote><div>&nbsp; &nbsp; &nbsp;注意上面的layout也可以用patternLayout：</div><blockquote style="color: #000000; text-align: -webkit-auto; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div>&nbsp; &nbsp; &lt;layout class="ch.qos.logback.classic.PatternLayout"&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;pattern&gt;%date %-5level %logger{35} - %message%n&lt;/pattern&gt;</div><div>&nbsp; &nbsp; &lt;/layout&gt;</div></blockquote><div></div><div>触发事件：</div><div>&nbsp; &nbsp; &nbsp;默认是OnErrorEvaluator，但可以自己定制。SMTPAppender仅维护一个Evaluator，这个Evaluator可以自己维护状态，例如可以实现一个CounterBasedEvaluator。</div><div>&nbsp; &nbsp; &nbsp;</div><div>基于标记Marker的事件触发：</div><blockquote style="color: #000000; text-align: -webkit-auto; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div>Marker notifyAdmin = MarkerFactory.getMarker("NOTIFY_ADMIN");</div><div>logger.error(notifyAdmin,</div><div>&nbsp; "This is a serious an error requiring the admin's attention",</div><div>&nbsp; &nbsp;new Exception("Just testing"));</div></blockquote><div></div><blockquote style="color: #000000; text-align: -webkit-auto; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div>&nbsp; &lt;appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender"&gt;</div><div>&nbsp; &nbsp; &lt;evaluator class="ch.qos.logback.classic.boolex.OnMarkerEvaluator"&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;marker&gt;NOTIFY_ADMIN&lt;/marker&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;!-- you specify add as many markers as you want --&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;marker&gt;TRANSACTION_FAILURE&lt;/marker&gt;</div><div>&nbsp; &nbsp; &lt;/evaluator&gt;</div><div>&nbsp; &lt;/appender&gt;</div></blockquote><div></div><div>还可以使用更加通用的JaninoEventEvaluator或者GEventEvaluator，他们提供更复杂更强大的甄别功能（也包含了OnMarkerEvaluator的功能）。</div><div></div><div>身份验证/STARTTLS/SSL</div><div>&nbsp; &nbsp; &nbsp;SMTPAppender支持用户名和密码的加密验证。</div><div>&nbsp; &nbsp; &nbsp;STARTTLS方式是先使用非加密方式建立连接，然后切换到SSL（常用于server-server交互）。</div><div>&nbsp; &nbsp; &nbsp;SSL方式是直接建立SSL连接（一般用于client-sever交互）。</div><div></div><div>Appender configuration for Gmail (SSL)</div><blockquote style="color: #000000; text-align: -webkit-auto; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div>&lt;appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender"&gt;</div><div>&nbsp; &nbsp; &lt;smtpHost&gt;smtp.gmail.com&lt;/smtpHost&gt;</div><div>&nbsp; &nbsp; &lt;smtpPort&gt;465&lt;/smtpPort&gt;</div><div>&nbsp; &nbsp; &lt;SSL&gt;true&lt;/SSL&gt;</div><div>&nbsp; &nbsp; &lt;username&gt;YOUR_USERNAME@gmail.com&lt;/username&gt;</div><div>&nbsp; &nbsp; &lt;password&gt;YOUR_GMAIL_PASSWORD&lt;/password&gt;&nbsp; &nbsp;</div><div>&nbsp; &lt;/appender&gt;</div></blockquote><div></div><div>SMTPAppender for Gmail (STARTTLS)</div><blockquote style="color: #000000; text-align: -webkit-auto; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div>&nbsp; &lt;appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender"&gt;</div><div>&nbsp; &nbsp; &lt;smtpHost&gt;smtp.gmail.com&lt;/smtpHost&gt;</div><div>&nbsp; &nbsp; &lt;smtpPort&gt;587&lt;/smtpPort&gt;</div><div>&nbsp; &nbsp; &lt;STARTTLS&gt;true&lt;/STARTTLS&gt;</div><div>&nbsp; &nbsp; &lt;username&gt;YOUR_USERNAME@gmail.com&lt;/username&gt;</div><div>&nbsp; &nbsp; &lt;password&gt;YOUR_GMAIL_xPASSWORD&lt;/password&gt;&nbsp; &nbsp;&nbsp;</div><div>&nbsp; &lt;/appender&gt;</div></blockquote><div></div><div>Discriminator</div><div>&nbsp; &nbsp; &nbsp;用MDCBasedDiscriminator做示例，根据MDC的值，维护多个缓存</div><blockquote style="color: #000000; text-align: -webkit-auto; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div>&nbsp; &lt;appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender"&gt;</div><div><strong>&nbsp; &nbsp; &lt;discriminator class="ch.qos.logback.classic.sift.MDCBasedDiscriminator"&gt;</strong></div><div><strong>&nbsp; &nbsp; &nbsp; &lt;key&gt;req.remoteHost&lt;/key&gt;</strong></div><div><strong>&nbsp; &nbsp; &nbsp; &lt;defaultValue&gt;default&lt;/defaultValue&gt;</strong></div><div><strong>&nbsp; &nbsp; &lt;/discriminator&gt;</strong></div><div>&nbsp; &nbsp; &lt;subject&gt;${HOSTNAME} --&nbsp;<strong>%X{req.remoteHost}</strong>&nbsp;%msg"&lt;/subject&gt;</div><div>&nbsp; &nbsp; &lt;layout class="ch.qos.logback.classic.html.HTMLLayout"&gt;</div><div>&nbsp; &nbsp; &nbsp; &lt;pattern&gt;%date%level%thread%<strong>X{req.remoteHost}</strong>%X{req.requestURL}%logger%msg&lt;/pattern&gt;</div><div>&nbsp; &nbsp; &lt;/layout&gt;</div><div>&nbsp; &lt;/appender&gt;</div></blockquote><div>&nbsp; &nbsp; &nbsp;上面的例子先利用了MDCInsertingServletFilter把请求方的hostname或ip设置到MDC中。</div><div>&nbsp; &nbsp; &nbsp;每一个remoteHost都有一个自己的buffer，一旦某个remoteHost触发了发送邮件的请求，那么该buffer里的256条信息会被发送出去。</div><div></div><div>Buffer管理：</div><div>&nbsp; &nbsp; &nbsp;上面的例子，每一个远程地址都有自己的buffer，会极大的消耗内存。</div><div>&nbsp; &nbsp; &nbsp;默认情况下，logback内部最多允许64个buffer同时存在，LRU算法换出。超过30分钟未使用的buffer也会被换出。该值可以通过maxNumberOfBuffers来设置。<br /><div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 这里有问题，通过各种手段都无法设置此值，貌似是个bug，我在尽我所能查遍所有资料后，在stackoverflowh和官方jira上提了这个问题：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<a href="http://stackoverflow.com/questions/24836151">http://stackoverflow.com/questions/24836151</a></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<a href="http://jira.qos.ch/browse/LOGBACK-996">http://jira.qos.ch/browse/LOGBACK-996</a>&nbsp;</div></div></div><div>&nbsp; &nbsp; &nbsp;在高强度系统中，上面的2个保护机制不够，需要加入手工管理：通过明确指定&#8220;FINALIZE_SESSION&#8221;这个Marker，来告诉logback去释放对应的buffer，这样就可以安全的将maxNumberOfBuffers设置为512乃至1024。（具体设置办法参照SiftingAppender里描述的）</div><div></div><div>这里是官方的一个SMTPAppender的例子：</div><div><a href="http://logback.qos.ch/recipes/emailPerTransaction.html">http://logback.qos.ch/recipes/emailPerTransaction.html</a></div><div>注意Marker可以叠加，所以如果有必要，可以把&#8220;发送邮件的Marker&#8221;和&#8220;终结Session（以便清理buffer）的Marker&#8221;关联在一起。</div><div>&nbsp; &nbsp; &nbsp;Marker SMTP_TRIGGER = MarkerFactory.getMarker("SMTP_TRIGGER");</div><div>&nbsp; &nbsp; &nbsp;SMTP_TRIGGER.add(FINALIZE_SESSION_MARKER);</div><div>----------------------------------------------------------</div><div>AsyncAppender</div><div>&nbsp; &nbsp; &nbsp;类似于单独的一个事件分发器，所以必须引用另一个appender。</div><div>&nbsp; &nbsp; &nbsp;用一个BlockingQueue缓冲事件，然后创建一个线程，从队列里获取事件并分发给引用的appender。</div><div>&nbsp; &nbsp; &nbsp;默认情况下，如果队列达到80%的容量，则丢弃TRACE,DEBUG,INFO级别的日志。</div><div>&nbsp; &nbsp; &nbsp;应用程序停止的时候，会通知LoggerContext停止，在停止各个Appender时，AsyncAppender会停止接收日志，并将信息flush到磁盘。</div><div></div><div>&nbsp; &nbsp; &nbsp;配置参数：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;queueSize：默认256</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;discardingThreshold：默认队列20%可用的时候开始选择性抛弃信息，设为0表示不抛弃</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;includeCallerData：是否包括调用者信息（重开销），默认只复制线程名和MDC信息（因为切换了线程，其余信息会丢失）</div><div>&nbsp; &nbsp; &nbsp;队列全满的时候，写日志动作会被block，直到队列有可用空间。</div><div>----------------------------------------------------------</div><div>自定义Appender</div><div>&nbsp; &nbsp; &nbsp;略</div><div>---------------------------------------------------------- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div>----------------------------------------------------------</div><div>Logback Access</div><div>&nbsp; &nbsp; &nbsp;大部分Appender，在logback-classic与logback-access中使用方式类似。</div></div><br /><br /></div></div><img src ="http://www.blogjava.net/watchzerg/aggbug/415749.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/watchzerg/" target="_blank">王星游</a> 2014-07-13 18:57 <a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415749.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>logback_doc_manual_03_configuration</title><link>http://www.blogjava.net/watchzerg/archive/2014/07/13/415748.html</link><dc:creator>王星游</dc:creator><author>王星游</author><pubDate>Sun, 13 Jul 2014 10:56:00 GMT</pubDate><guid>http://www.blogjava.net/watchzerg/archive/2014/07/13/415748.html</guid><wfw:comment>http://www.blogjava.net/watchzerg/comments/415748.html</wfw:comment><comments>http://www.blogjava.net/watchzerg/archive/2014/07/13/415748.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/watchzerg/comments/commentRss/415748.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/watchzerg/services/trackbacks/415748.html</trackback:ping><description><![CDATA[<div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"><a href="http://logback.qos.ch/manual/configuration.html">http://logback.qos.ch/manual/configuration.html</a></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">-------------------------------------------------------</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">与spring的配置：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">貌似官网上没有介绍，但是作者在github上建立了一个扩展项目用于logback与spring结合。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"><a href="https://github.com/qos-ch/logback-extensions">https://github.com/qos-ch/logback-extensions</a></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">目前最新版本是0.1.2，很多maven公开库里已经有了。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">maven配置：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;dependency&gt; &nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;groupId&gt;org.logback-extensions&lt;/groupId&gt; &nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;artifactId&gt;logback-ext-spring&lt;/artifactId&gt; &nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;version&gt;0.1.2&lt;/version&gt; &nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;/dependency&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">web.xml配置日志框架启动监听器：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;!-- logback配置文件 --&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;context-param&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;param-name&gt;logbackConfigLocation&lt;/param-name&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;param-value&gt;/WEB-INF/classes/logback.xml&lt;/param-value&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;/context-param&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;!-- logback加载监听器 --&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;listener&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;listener-class&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ch.qos.logback.ext.spring.web.LogbackConfigListener</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;/listener-class&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;/listener&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">-------------------------------------------------------</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">logback中的配置：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">可以用java程序配置，也可以用xml或者groovy脚本配置。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">使用 http://logback.qos.ch/translator/ 可以把log4j的配置自动转换过来。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">logback内部查找配置的过程：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;1，在classpath查找&#8220;logback.groovy&#8221;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;2，在classpath查找&#8220;logback-test.xml&#8221;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;3，在classpath查找&#8220;logback.xml&#8221;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;4，使用自身的BasicConfigurator做基本配置，所有日志被输出到控制台。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&#8212;&#8212; 一般把&#8220;logback-test.xml&#8221;放到maven的测试路径，把&#8220;logback.xml&#8221;放到maven的正式路径，前者优先级更高。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">logback的状态，加载配置文件的过程：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;代码打印：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; StatusPrinter.print(lc);</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;配置文件形式打印：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&lt;configuration debug="true"&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; ...&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&lt;/configuration&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;也可以通过设置StatusListener来监听logback的启动和打印状态&#8212;&#8212;在生产环境挺有用，因为配置文件路径挺深。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">通过在系统变量里加入"logback.configurationFile"指定logback配置文件路径：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;java -Dlogback.configurationFile=/path/to/config.xml chapters.configuration.MyApp1</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">设置自动扫描和遇到变更时重新加载配置文件（不指定周期的话默认每1分钟）：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;configuration scan="true" scanPeriod="30 seconds"&gt;&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp;...&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;/configuration&gt;&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;每当N个（logback会自动调节）日志请求，logback会检查一下扫描周期是否已经到达，如到达再检查配置文件。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">通过web访问状态信息：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">在web.xml配置：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;servlet&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;servlet-name&gt;ViewStatusMessages&lt;/servlet-name&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;servlet-class&gt;ch.qos.logback.classic.ViewStatusMessagesServlet&lt;/servlet-class&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &lt;/servlet&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &lt;servlet-mapping&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;servlet-name&gt;ViewStatusMessages&lt;/servlet-name&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;url-pattern&gt;/lbClassicStatus&lt;/url-pattern&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &lt;/servlet-mapping&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">然后访问：http://host/yourWebapp/lbClassicStatus</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">注册控制台状态监听器：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;java代码方式：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();&nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; StatusManager statusManager = lc.getStatusManager();</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; OnConsoleStatusListener onConsoleListener = new OnConsoleStatusListener();</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; statusManager.add(onConsoleListener);</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;用配置文件方式：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;configuration&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" /&gt; &nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/configuration&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;系统变量方式：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; java -Dlogback.statusListenerClass=ch.qos.logback.core.status.OnConsoleStatusListener</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">停止logback：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;java代码方式：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; loggerContext.stop();</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;web应用：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;ServletContextListener.contextDestroyed()会自动调用上面的stop方法。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">-------------------------------------------------------</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">配置文件格式：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;最外层是&lt;configuration&gt;元素，里面有&lt;appender&gt;&lt;logger&gt;&lt;root&gt;元素</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;logger&gt;元素：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;level属性可以这些值：TRACE, DEBUG, INFO, WARN, ERROR, ALL, OFF，也可以明确指定继承：INHERITED或者NULL</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;包含若干&lt;appender-ref&gt;元素，指定appender的名字。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">从DEBUG改为INFO级别：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;configuration&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &lt;appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &lt;!-- encoders are assigned the type</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &lt;encoder&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &lt;pattern&gt;%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n&lt;/pattern&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &lt;/encoder&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &lt;/appender&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &lt;logger name="chapters.configuration" level="INFO"/&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &lt;!-- Strictly speaking, the level attribute is not necessary since --&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &lt;!-- the level of the root level is set to DEBUG by default. &nbsp; &nbsp; &nbsp; --&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &lt;root level="DEBUG"&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &lt;appender-ref ref="STDOUT" /&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &lt;/root&gt; &nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;/configuration&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">-------------------------------------------------------</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">配置Appender：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;name和class属性</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;内嵌0个或1个layout元素，0个或多个encoder元素，0个或多个filter元素。还可以内嵌任意数量的appdenter类的属性（例如自定义的appender类）。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;layout元素应该内嵌具体的layout类，但是默认就是PatternLayoutEncoder。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">Appender的累加性：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;logger会记录在所有绑定在它自身的appender，同时也会记录在该logger祖先的appender上，所以有可能重复记录！</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">配置Logger Context（可以用在&#8220;多个项目写入同一个日志文件&#8221;这种情况）：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;configuration&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &lt;contextName&gt;myAppName&lt;/contextName&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; ...</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;/configuration&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">-------------------------------------------------------</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">变量替换：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;configuration&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &lt;property name="USER_HOME" value="/home/sebastien" /&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &lt;appender name="FILE" class="ch.qos.logback.core.FileAppender"&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &lt;file&gt;${USER_HOME}/myApp.log&lt;/file&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; ...</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &lt;/appender&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp;...</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;/configuration&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&#8212;&#8212;上面的变量定义在系统属性里也可以：java -DUSER_HOME="/home/sebastien" MyApp2</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">变量也可以定义在文件里：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;configuration&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &lt;property file="src/main/java/chapters/configuration/variables1.properties" /&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &lt;appender name="FILE" class="ch.qos.logback.core.FileAppender"&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;file&gt;${USER_HOME}/myApp.log&lt;/file&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;...</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp;&lt;/appender&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp;...</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;/configuration&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&#8212;&#8212;对应路径的文件里应该加入&#8220;USER_HOME=/home/sebastien&#8221;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（这路径挺诡异啊，是maven的结构，那打包后岂不是不能用了？）</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">像这样引用classpath的还靠谱些：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;property resource="resource1.properties" /&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">变量可以指定作用域：local，context，system</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">变量可以相互引用：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;USER_HOME=/home/sebastien</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;fileName=myApp.log</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;destination=${USER_HOME}/${fileName}</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">命名引用：如果"userid"会被替换为"alice"，那么"${${userid}.password}"会被替换为"alice.password"对应的值。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">变量可以指定默认值：${aName:-golden} &nbsp;&#8212;&#8212;这就指定了默认值golden</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">变量的默认值也可以引用变量：&nbsp;"${id:-${userid}}</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">预置变量：HOSTNAME,CONTEXT_NAME</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">可以通过timestamp元素定义一个当前的日期和时间的动态元素。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">可以自己继承PropertyDefiner实现动态生成属性，现在内置了2个动态属性生成器：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;FileExistsPropertyDefiner &nbsp; &nbsp; 如果指定路径文件存在，则将指定属性设为&#8220;true&#8221;，反之亦然</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;ResourceExistsPropertyDefiner &nbsp; &nbsp; 如果指定资源存在，则将指定属性设为&#8220;true&#8221;，反之亦然</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">条件语句：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp;&lt;!-- if-then form --&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp;&lt;if condition="some conditional expression"&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &lt;then&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; ...</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &lt;/then&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &lt;/if&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &lt;!-- if-then-else form --&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &lt;if condition="some conditional expression"&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &lt;then&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; ...</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &lt;/then&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &lt;else&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; ...</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &lt;/else&gt; &nbsp; &nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &lt;/if&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">判断条件只支持context变量和system变量，用property()或者p()来引用&#8212;&#8212;如果没有设定对应变量，这两个方法会返回空串（而不是null）</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">isDefine()和isNull()分别判断变量是否设置和变量是否为空。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;if condition='property("HOSTNAME").contains("torino")'&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;...</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;/if&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">可以从JNDI读取变量值（作用域为local）。也可以将从JNDI读取的变量存入另一个不同作用域的变量。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;configuration&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp;&lt;insertFromJNDI env-entry-name="java:comp/env/appName" as="appName" /&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &nbsp;...</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;/configuration&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">-------------------------------------------------------</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">文件包含（可以使用相对路径。当前路径已经在当前项目中定义，所以没必要与配置文件路径关联）：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;configuration&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &lt;include file="src/main/java/chapters/configuration/includedConfig.xml"/&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; ...</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;/configuration&gt;&nbsp; &nbsp; &nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">被包含的文件必须用&lt;include&gt;标签包裹：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;included&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &lt;appender name="includedConsole" class="ch.qos.logback.core.ConsoleAppender"&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &lt;encoder&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp; &lt;pattern&gt;"%d - %m%n"&lt;/pattern&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &lt;/encoder&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &lt;/appender&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&lt;/included&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">还可以关联资源（例如classpath下的某个文件）：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;include resource="includedConfig.xml"/&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">还可以关联URL：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;include url="http://some.host.com/includedConfig.xml"/&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">可以指定此次文件包含为&#8220;可选的&#8221;：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&lt;include optional="true" ..../&gt;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">-------------------------------------------------------</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">LoggerContextListener</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">其中一个实现LevelChangePropagator会监听日志环境的合适的生命周期，并把日志级别的变化传播给JUL，这样JUL关闭的日志不会再传递给slf4j，用这种方式对性能冲击较小，适合jul-to-slf4j的桥接包。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div></div><img src ="http://www.blogjava.net/watchzerg/aggbug/415748.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/watchzerg/" target="_blank">王星游</a> 2014-07-13 18:56 <a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415748.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>logback_doc_manual_02_architecture</title><link>http://www.blogjava.net/watchzerg/archive/2014/07/13/415747.html</link><dc:creator>王星游</dc:creator><author>王星游</author><pubDate>Sun, 13 Jul 2014 10:55:00 GMT</pubDate><guid>http://www.blogjava.net/watchzerg/archive/2014/07/13/415747.html</guid><wfw:comment>http://www.blogjava.net/watchzerg/comments/415747.html</wfw:comment><comments>http://www.blogjava.net/watchzerg/archive/2014/07/13/415747.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/watchzerg/comments/commentRss/415747.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/watchzerg/services/trackbacks/415747.html</trackback:ping><description><![CDATA[<div><a href="http://logback.qos.ch/manual/architecture.html" style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">http://logback.qos.ch/manual/architecture.html</a><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">Logger, Appender and Layout</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">-------------------------------------------------------</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">Logger:</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">Logger继承关系：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">com.foo是com.foo.Bar的双亲（parent），同时也是其祖先（ancestor）</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">java是java.util.Vector的祖先，但不是其双亲。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">root Logger是所有logger的祖先，可以这样获取：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">日志级别，在ch.qos.logback.classic.Level中，有TRACE, DEBUG, INFO, WARN and ERROR</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">日志级别类是final的，如果想扩展，可以用Marker类。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">如果一个logger没有指定级别，那么它继承最近的祖先的级别。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">root Logger默认是debug级别。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">日志级别：TRACE &lt; DEBUG &lt; INFO &lt; &nbsp;WARN &lt; ERROR.</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">如果日志记录请求&#8212;&#8212;例如logger.info()&#8212;&#8212;的级别大于等于其logger的级别，那么该请求生效。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">使用LoggerFactory.getLogger(String param)获取的logger，只要参数一致，那么获取到的logger也一致。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">即使先创建子logger，再创建双亲logger，后者也会正确的插到logger树上。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">-------------------------------------------------------</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">Appenders and Layouts:</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;一个logger可以绑定多个appender。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;默认情况：每一个日志请求，会被发送到logger对应的所有Appender，以及更高层logger对应的所有appender上。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;如果把某个logger的additivity标志设为false，那么这个logger会记录自身和下层（孙子logger）的日志，但不会再向上传递&#8212;&#8212;也就是把下层的logger的日志拦截到了当前这一层logger为止了。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;PatternLayout控制输出的格式，类似C语言的printf格式。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">-------------------------------------------------------</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">参数化记录日志：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;与slf4j完全相同</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">-------------------------------------------------------</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">日志记录的调用时序图：<br /><img src="http://www.blogjava.net/images/blogjava_net/watchzerg/logback-1-1.png" width="1351" height="423" alt="" /></div></div><img src ="http://www.blogjava.net/watchzerg/aggbug/415747.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/watchzerg/" target="_blank">王星游</a> 2014-07-13 18:55 <a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415747.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>slf4j笔记</title><link>http://www.blogjava.net/watchzerg/archive/2014/07/13/415746.html</link><dc:creator>王星游</dc:creator><author>王星游</author><pubDate>Sun, 13 Jul 2014 10:49:00 GMT</pubDate><guid>http://www.blogjava.net/watchzerg/archive/2014/07/13/415746.html</guid><wfw:comment>http://www.blogjava.net/watchzerg/comments/415746.html</wfw:comment><comments>http://www.blogjava.net/watchzerg/archive/2014/07/13/415746.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/watchzerg/comments/commentRss/415746.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/watchzerg/services/trackbacks/415746.html</trackback:ping><description><![CDATA[<div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">特性：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"><div>classes are loaded by the JVM</div> slf4j不需要classloader的原理(而common-logging需要classloader，所以会内存泄漏或者别的加载问题)<br /> Mapped Diagnostic Context (MDC)只有log4j和logback支持，slf4j也支持</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">支持自定义日志级别（Marker），目前只有logback对其进行了实现。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">支持国际化（个人认为：有毛用啊&#8230;&#8230;）</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">-----------------------------------------------------------</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">用法：</div><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">log性能：</span><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">以下这种形式，不管是否log，都会损失拼接字符串的时间：</span><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));</span><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">以下这种形式，是对上述情况的改进，但很臃肿：</span><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">if(logger.isDebugEnabled()) {</span><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));</span><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">}</span><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">以下这种，在slf4j里支持，很完美：</span><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">logger.debug("The entry is {}.", entry);</span><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">多个参数的情况：</span><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">logger.debug("The new entry is {}. It replaces {}.", entry, oldEntry);</span><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">很多参数的情况（也可以利用Object...，不用显式指定Object[]）：</span><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">logger.debug("Value {} was inserted between {} and {}.", new Object[] {newVal, below, above});</span><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">对{}进行转义：</span><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">以下情况不需要转移(slf4j它只认紧挨着的{}符号)</span><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">logger.debug("Set {1,2} differs from {}", "3");</span><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">以下情况也不需要转义：</span><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">logger.debug("Set {1,2} differs from {{}}", "3");</span><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">实在需要转义时可以这样：</span><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">logger.debug("Set \\{} differs from {}", "3");</span><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">实在不需要转义时可以这样：</span><br style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;" /><span style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">logger.debug("File name is C:\\\\{}.", "file.zip");</span><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">打印异常对象的堆栈信息，除了这种形式：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">debug(String msg, Throwable t);</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">还可以结合参数化（转移字符{}）来使用：</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">logger.error("Failed to format {}", s, e);</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;&#8212;&#8212;框架会发现最后一个参数是多余的，并查看其是否是一个异常对象，如果是则输出堆栈，否则忽略。</div><div style="font-family: Tahoma; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"><div>-----------------------------------------------------------</div><div>logger声明的讨论：</div><div>static和non-static各有好处：</div><div>&nbsp; &nbsp; &nbsp;static的CPU和内存性能更好</div><div>&nbsp; &nbsp; &nbsp;non-static对IOC更友好，而且在多个应用共用一套类库时，可以保持各自的日志环境</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; （logback无论如何都是安全的，但如果在多个应用分享同一个类库，并且为static的，那log4j会出问题：所有的日志都打印到第一个加载到内存的日志对象中）</div><div>&nbsp; &nbsp; &nbsp;在slf4j的1.5.3之后，non-static的logger不需要标记transient关键字，也不会被序列化（怎么做到的？）</div><div></div><div>建议的声明方式（我觉得加上static比较好，还有private）：</div><div>final (static) Logger logger = LoggerFactory.getLogger(MyClass.class);</div> -----------------------------------------------------------<br /> 迁移工具： <div><a href="http://www.slf4j.org/migrator.html">http://www.slf4j.org/migrator.html</a></div><div></div><div>-----------------------------------------------------------</div><div>实现包：</div><div>唯一必要的包：slf4j-api.jar</div><div>slf4j-log4j12-1.6.4.jar<br /> &nbsp; &nbsp; &nbsp;Binding for log4j version 1.2, a widely used logging framework. You also need to place log4j.jar on your class path.</div><div>&nbsp; &nbsp; &nbsp;需要把log4j的包也一同放进来。<br /> slf4j-jdk14-1.6.4.jar<br /> &nbsp; &nbsp; &nbsp;Binding for java.util.logging, also referred to as JDK 1.4 logging</div><div>&nbsp; &nbsp; &nbsp;绑定到jdk的日志中<br /> slf4j-nop-1.6.4.jar<br /> &nbsp; &nbsp; &nbsp;Binding for NOP, silently discarding all logging.</div><div>&nbsp; &nbsp; &nbsp;绑定到&#8220;无操作&#8221;，静默。<br /> slf4j-simple-1.6.4.jar<br /> &nbsp; &nbsp; &nbsp;Binding for Simple implementation, which outputs all events to System.err. Only messages of level INFO and higher are printed. This binding may be useful in the context of small applications.</div><div>&nbsp; &nbsp; &nbsp;最简单的实现，直接输出到控制台<br /> slf4j-jcl-1.6.4.jar<br /> &nbsp; &nbsp; &nbsp;Binding for Jakarta Commons Logging. This binding will delegate all SLF4J logging to JCL.</div><div>&nbsp; &nbsp; &nbsp;绑定到common-logging，桥接过去。</div><div>logback-classic-1.0.13.jar (requires logback-core-1.0.13.jar)</div><div>&nbsp; &nbsp; &nbsp; 绑定到原生实现的logback上，性能最高<br /><img src="http://www.blogjava.net/images/blogjava_net/watchzerg/slf4j-1.png" width="1152" height="636" alt="" /><br /><br /><div><div>在maven中声明包的实现：</div><div>对于普通项目（并不是一个工具包）：</div><div>&nbsp; &nbsp; &nbsp;logback：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 声明对logback-classic-1.0.13.jar的依赖即可，会自动关联依赖slf4j-api-1.7.7.jar和logback-core-1.0.13.jar（显式声明这两个关联依赖也可以）</div><div>&nbsp; &nbsp; &nbsp;log4j：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 声明对slf4j-log4j12-1.7.7.jar的依赖即可，会自动关联依赖slf4j-api-1.7.7.jar和log4j-1.2.17.jar</div><div>&nbsp; &nbsp; &nbsp;jdk log：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 声明对slf4j-jdk14-1.7.7.jar的依赖即可，会自动关联依赖slf4j-api-1.7.7.jar</div><div>对于工具包项目：</div><div>&nbsp; &nbsp; &nbsp;仅仅依赖slf4j-api即可，让用户自己决定底层用什么实现。</div><div></div><div>二进制兼容性：</div><div>&nbsp; &nbsp; &nbsp;各个api绑定包，与下面的日志实现包，其版本必须对应。比如slf4j-api-1.7.7.jar应该对应slf4j-simple-1.7.7.jar.</div><div>&nbsp; &nbsp; &nbsp;而上层的应用程序，与其依赖的slf4j-api是各个版本都完全兼容的。</div><div></div><div>支持MDC，同时需要底层的日志包也支持，例如logback或者log4j。</div><div>-----------------------------------------------------------</div><div>桥接包：</div><div><a href="http://www.slf4j.org/legacy.html">http://www.slf4j.org/legacy.html</a></div><div>1，从Jakarta Commons Logging (JCL)迁移到slf4j：&nbsp;用&#8220;jcl-over-slf4j.jar&#8221;替换掉&#8220;commons-logging.jar&#8221;即可</div><div>&nbsp; &nbsp; &nbsp;如果在maven中：1，明确的标记exclusion掉common-logging.jar。2，声明common-logging.jar的依赖范围为&#8220;provided&#8221;（在IED里显示不太好，注意顺序）。</div><div>2，很少见的特殊情况，想要把slf4j日志转移到JCL上：用slf4j-jcl.jar包</div><div>&nbsp; &nbsp; &nbsp;&#8212;&#8212;上述两个包不能一起用，否则死循环（这很好理解）</div><div>3，从log4j迁移到slf4j（居然直接针对log4j编码，太2了）：用&#8220;log4j-over-slf4j.jar&#8221;替换掉&#8220;log4j.jar&#8221;即可。</div><div>&nbsp; &nbsp; &nbsp;&#8212;&#8212;上述包不能与&#8220;slf4j-log4j12.jar&#8221;一起用，否则死循环（一样的道理）。</div><div>4，从java.util.logging（JUL）迁移到slf4j&#8212;&#8212;jvm自己的类不允许随便替换，所以这里比较复杂(SLF4JBridgeHandler+jul-to-slf4j.jar)，而且有性能问题，很少用到，用的时候再研究。</div><div>&nbsp; &nbsp; &nbsp;&nbsp;&#8212;&#8212;上述包不能与&#8220;slf4j-jdk14.jar&#8221;一起用，否则死循环（一样的道理）。</div></div><img src="http://www.blogjava.net/images/blogjava_net/watchzerg/slf4j-2.png" width="1587" height="1123" alt="" /><br /><br /><br /><br /><br /><br /><br /></div></div></div><img src ="http://www.blogjava.net/watchzerg/aggbug/415746.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/watchzerg/" target="_blank">王星游</a> 2014-07-13 18:49 <a href="http://www.blogjava.net/watchzerg/archive/2014/07/13/415746.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java中Thread合理的中止,退出,暂停方式</title><link>http://www.blogjava.net/watchzerg/archive/2012/11/17/391505.html</link><dc:creator>王星游</dc:creator><author>王星游</author><pubDate>Sat, 17 Nov 2012 12:24:00 GMT</pubDate><guid>http://www.blogjava.net/watchzerg/archive/2012/11/17/391505.html</guid><wfw:comment>http://www.blogjava.net/watchzerg/comments/391505.html</wfw:comment><comments>http://www.blogjava.net/watchzerg/archive/2012/11/17/391505.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/watchzerg/comments/commentRss/391505.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/watchzerg/services/trackbacks/391505.html</trackback:ping><description><![CDATA[<div>最近研究Thread时看到篇好文《Java 理论与实践: 处理 InterruptedException》，摘录下来备用：</div>
<div>http://www.ibm.com/developerworks/cn/java/j-jtp05236.html</div>
<div>1,当一个方法抛出 InterruptedException 时，它不仅告诉您它可以抛出一个特定的检查异常，而且还告诉您其他一些事情。例如，它告诉您它是一个阻塞（blocking）方法，如果您响应得当的话，它将尝试消除阻塞并尽早返回。</div>
<div>2,当一个方法抛出 InterruptedException 时，它是在告诉您，如果执行该方法的线程被中断，它将尝试停止它正在做的事情而提前返回，并通过抛出 InterruptedException 表明它提前返回。 行为良好的阻塞库方法应该能对中断作出响应并抛出 InterruptedException，以便能够用于可取消活动中，而不至于影响响应。</div>
<div>3,如果抛出 InterruptedException 意味着一个方法是阻塞方法，那么调用一个阻塞方法则意味着您的方法也是一个阻塞方法，而且您应该有某种策略来处理 InterruptedException。通常最容易的策略是执行清理，然后自己抛出 InterruptedException，将它传播给调用者。</div>
<div>4,如果捕捉到 InterruptedException 但是不能重新抛出它，那么应该保留中断发生的证据，以便调用栈中更高层的代码能知道中断，并对中断作出响应。该任务可以通过调用当前线程的interrupt() 以 &#8220;中断当前线程自己&#8221; 来完成。</div>
<div>5,对于执行一个循环中的代码的任务，通常只需为每一个循环迭代检查一次中断。取决于循环执行的时间有多长，任何代码可能要花一些时间才能注意到线程已经被中断（或者是通过调用 Thread.isInterrupted() 方法轮询中断状态，或者是调用一个阻塞方法）。</div>
<div>6,不可中断的阻塞方法:并非所有的阻塞方法都抛出 InterruptedException。输入和输出流类会阻塞等待 I/O 完成，但是它们不抛出 InterruptedException，而且在被中断的情况下也不会提前返回。然而，对于套接字 I/O，如果一个线程关闭套接字，则那个套接字上的阻塞 I/O 操作将提前结束，并抛出一个 SocketException。java.nio 中的非阻塞 I/O 类也不支持可中断 I/O，但是同样可以通过关闭通道或者请求 Selector 上的唤醒来取消阻塞操作。</div>
<div></div><br />
<div>另据别的文章(忘了出处了):</div>
<div>interrupt方法其实只是改变了中断状态而已,而sleep、wait和join这些方法的内部会不断的检查中断状态的值，从而自己抛出InterruptEdException。</div>
<div>&#8212;&#8212;所以该异常从&#8220;设置&#8221;到&#8220;抛出&#8221;不是即时的，但是只要调用过程有上述方法之一，就会最终检测到终端状态并抛出异常。</div>
<div></div><br />
<div>Thread类中destory,resume,stop,suspend这些废弃方法引用了一篇说明文章：</div>
<div>《Why Are Thread.stop, Thread.suspend,Thread.resume and Runtime.runFinalizersOnExit Deprecated?》</div>
<div>http://docs.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html</div>
<div>以下是根据其写的demo:<br />
<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080; ">&nbsp; 1</span>&nbsp;<span style="color: #008000; ">/**</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">&nbsp;&nbsp;2</span>&nbsp;<span style="color: #008000; ">&nbsp;*&nbsp;</span><span style="color: #808080; ">@author</span><span style="color: #008000; ">&nbsp;watchzerg<br />
</span><span style="color: #008080; ">&nbsp;&nbsp;3</span>&nbsp;<span style="color: #008000; ">&nbsp;</span><span style="color: #008000; ">*/</span><br />
<span style="color: #008080; ">&nbsp;&nbsp;4</span>&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;ThreadManager&nbsp;<span style="color: #0000FF; ">implements</span>&nbsp;Runnable{<br />
<span style="color: #008080; ">&nbsp;&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">线程对象引用</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">&nbsp;&nbsp;6</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;Thread&nbsp;myThread;<br />
<span style="color: #008080; ">&nbsp;&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">休眠间隔</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">&nbsp;&nbsp;8</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">long</span>&nbsp;interval=1000l;<br />
<span style="color: #008080; ">&nbsp;&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">用volatile保证变量同步</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">&nbsp;10</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">volatile</span>&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;threadSuspended;<br />
<span style="color: #008080; ">&nbsp;11</span>&nbsp;<br />
<span style="color: #008080; ">&nbsp;12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">开始</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">&nbsp;13</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;start(){<br />
<span style="color: #008080; ">&nbsp;14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myThread=<span style="color: #0000FF; ">new</span>&nbsp;Thread(<span style="color: #0000FF; ">this</span>,"myThread");<br />
<span style="color: #008080; ">&nbsp;15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myThread.start();<br />
<span style="color: #008080; ">&nbsp;16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">&nbsp;17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">&nbsp;18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">/**</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">&nbsp;19</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;线程体(执行内容)：<br />
</span><span style="color: #008080; ">&nbsp;20</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;如果线程不需要sleep之类的阻塞方法，<br />
</span><span style="color: #008080; ">&nbsp;21</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;可以通过Thread.isInterrupted()方法来检测中断<br />
</span><span style="color: #008080; ">&nbsp;22</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">*/</span><br />
<span style="color: #008080; ">&nbsp;23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />
<span style="color: #008080; ">&nbsp;24</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;run()&nbsp;{<br />
<span style="color: #008080; ">&nbsp;25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;thisThread=Thread.currentThread();<br />
<span style="color: #008080; ">&nbsp;26</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>(myThread==thisThread){<br />
<span style="color: #008080; ">&nbsp;27</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">try</span>{<br />
<span style="color: #008080; ">&nbsp;28</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(interval);<br />
<span style="color: #008080; ">&nbsp;29</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(myThread.getName()+"&nbsp;is&nbsp;running.");<br />
<span style="color: #008080; ">&nbsp;30</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">先if一下，避免每次都进入同步块带来的开销</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">&nbsp;31</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(threadSuspended&amp;&amp;myThread==thisThread){<br />
<span style="color: #008080; ">&nbsp;32</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">synchronized</span>(<span style="color: #0000FF; ">this</span>){<br />
<span style="color: #008080; ">&nbsp;33</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">/*</span><span style="color: #008000; ">&nbsp;如果线程在suspend状态被stop，那么myThread==null<br />
</span><span style="color: #008080; ">&nbsp;34</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;它在下一个循环就快速退出，不再等待了<br />
</span><span style="color: #008080; ">&nbsp;35</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;不过话说，wait方法本身也会抛中断异常的<br />
</span><span style="color: #008080; ">&nbsp;36</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;所以我觉得这里去掉"myThread==thisThread"也行<br />
</span><span style="color: #008080; ">&nbsp;37</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;元方，你怎么看？<br />
</span><span style="color: #008080; ">&nbsp;38</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #008000; ">*/</span><br />
<span style="color: #008080; ">&nbsp;39</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>(threadSuspended&amp;&amp;myThread==thisThread){<br />
<span style="color: #008080; ">&nbsp;40</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wait();<br />
<span style="color: #008080; ">&nbsp;41</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">&nbsp;42</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">&nbsp;43</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">&nbsp;44</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span style="color: #0000FF; ">catch</span>(InterruptedException&nbsp;e){<br />
<span style="color: #008080; ">&nbsp;45</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(thisThread.getName()+<br />
<span style="color: #008080; ">&nbsp;46</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"&nbsp;is&nbsp;interrupted&nbsp;by&nbsp;InterruptedException.");<br />
<span style="color: #008080; ">&nbsp;47</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">如果这里不打算处理此异常,而又无法抛出去,可以重新断言自己:<br />
</span><span style="color: #008080; ">&nbsp;48</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">Thread.currentThread().interrupt();</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">&nbsp;49</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">&nbsp;50</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">&nbsp;51</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(thisThread.getName()+":&nbsp;I'm&nbsp;out,&nbsp;do&nbsp;you&nbsp;copy?&nbsp;");<br />
<span style="color: #008080; ">&nbsp;52</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">&nbsp;53</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">&nbsp;54</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">/**</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">&nbsp;55</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;停止线程:<br />
</span><span style="color: #008080; ">&nbsp;56</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;如果是sleep状态，是interrupt起作用；<br />
</span><span style="color: #008080; ">&nbsp;57</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;如果是运行状态，是myThread==null终止了循环<br />
</span><span style="color: #008080; ">&nbsp;58</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">*/</span><br />
<span style="color: #008080; ">&nbsp;59</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">synchronized</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;stop(){<br />
<span style="color: #008080; ">&nbsp;60</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(myThread==<span style="color: #0000FF; ">null</span>){<br />
<span style="color: #008080; ">&nbsp;61</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>;<br />
<span style="color: #008080; ">&nbsp;62</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">&nbsp;63</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;moribund=myThread;<br />
<span style="color: #008080; ">&nbsp;64</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myThread=<span style="color: #0000FF; ">null</span>;<br />
<span style="color: #008080; ">&nbsp;65</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;moribund.interrupt();<br />
<span style="color: #008080; ">&nbsp;66</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">&nbsp;67</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">&nbsp;68</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">/**</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">&nbsp;69</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;挂起线程：<br />
</span><span style="color: #008080; ">&nbsp;70</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;反转条件，并通知其它等待线程<br />
</span><span style="color: #008080; ">&nbsp;71</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">*/</span><br />
<span style="color: #008080; ">&nbsp;72</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">synchronized</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;suspend(){<br />
<span style="color: #008080; ">&nbsp;73</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threadSuspended=!threadSuspended;<br />
<span style="color: #008080; ">&nbsp;74</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(!threadSuspended){<br />
<span style="color: #008080; ">&nbsp;75</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;notify();<br />
<span style="color: #008080; ">&nbsp;76</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">&nbsp;77</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">&nbsp;78</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">&nbsp;79</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">test</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">&nbsp;80</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;main(String[]&nbsp;args)&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;Exception&nbsp;{<br />
<span style="color: #008080; ">&nbsp;81</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThreadManager&nbsp;manager=<span style="color: #0000FF; ">new</span>&nbsp;ThreadManager();<br />
<span style="color: #008080; ">&nbsp;82</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">开始</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">&nbsp;83</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;manager.start();<br />
<span style="color: #008080; ">&nbsp;84</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("sys:starting<img src="http://www.blogjava.net/Images/dot.gif" alt="" />");<br />
<span style="color: #008080; ">&nbsp;85</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(10000l);<br />
<span style="color: #008080; ">&nbsp;86</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">暂停</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">&nbsp;87</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;manager.suspend();<br />
<span style="color: #008080; ">&nbsp;88</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("sys:suspend<img src="http://www.blogjava.net/Images/dot.gif" alt="" />");<br />
<span style="color: #008080; ">&nbsp;89</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(10000l);<br />
<span style="color: #008080; ">&nbsp;90</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">恢复</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">&nbsp;91</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;manager.suspend();<br />
<span style="color: #008080; ">&nbsp;92</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("sys:resume<img src="http://www.blogjava.net/Images/dot.gif" alt="" />");<br />
<span style="color: #008080; ">&nbsp;93</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(10000l);<br />
<span style="color: #008080; ">&nbsp;94</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">暂停</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">&nbsp;95</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;manager.suspend();<br />
<span style="color: #008080; ">&nbsp;96</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("sys:suspend<img src="http://www.blogjava.net/Images/dot.gif" alt="" />");<br />
<span style="color: #008080; ">&nbsp;97</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(5000l);<br />
<span style="color: #008080; ">&nbsp;98</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">在暂停状态下停止</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">&nbsp;99</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;manager.stop();<br />
<span style="color: #008080; ">100</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("sys:stop<img src="http://www.blogjava.net/Images/dot.gif" alt="" />");<br />
<span style="color: #008080; ">101</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(10000l);<br />
<span style="color: #008080; ">102</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">退出</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">103</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("sys:exit<img src="http://www.blogjava.net/Images/dot.gif" alt="" />now&nbsp;what?");<br />
<span style="color: #008080; ">104</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">105</span>&nbsp;}</div>
</div><img src ="http://www.blogjava.net/watchzerg/aggbug/391505.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/watchzerg/" target="_blank">王星游</a> 2012-11-17 20:24 <a href="http://www.blogjava.net/watchzerg/archive/2012/11/17/391505.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>mongoDB java驱动学习笔记</title><link>http://www.blogjava.net/watchzerg/archive/2012/09/22/388346.html</link><dc:creator>王星游</dc:creator><author>王星游</author><pubDate>Sat, 22 Sep 2012 14:32:00 GMT</pubDate><guid>http://www.blogjava.net/watchzerg/archive/2012/09/22/388346.html</guid><wfw:comment>http://www.blogjava.net/watchzerg/comments/388346.html</wfw:comment><comments>http://www.blogjava.net/watchzerg/archive/2012/09/22/388346.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/watchzerg/comments/commentRss/388346.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/watchzerg/services/trackbacks/388346.html</trackback:ping><description><![CDATA[<div></div><div>指定新mongo实例：</div><div>Mongo m = new Mongo();</div><div>Mongo m = new Mongo( "localhost" );</div><div>Mongo m = new Mongo( "localhost" , 27017 );</div><div>// or, to connect to a replica set, supply a seed list of members</div><div>Mongo m = new Mongo(Arrays.asList(new ServerAddress("localhost", 27017),</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new ServerAddress("localhost", 27018),</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new ServerAddress("localhost", 27019)));</div><div>然后发起连接（必须指定数据库名，可以不存在）</div><div>DB db = m.getDB( "mydb" );</div><div></div><div>注意Mongo已经实现了连接池，并且是线程安全的。</div><div></div><div>大部分用户使用mongodb都在安全内网下，但如果将mongodb设为安全验证模式，就需要在客户端提供用户名和密码：</div><div>boolean auth = db.authenticate(myUserName, myPassword);</div><div></div><div>获取集合(collection)的名称列表(类似show databases):</div><div>Set&lt;String&gt; colls = db.getCollectionNames();</div><div></div><div>获取一个集合（以便增删改查操作）：</div><div>DBCollection coll = db.getCollection("testCollection")</div><div></div><div>-------------------------------------------------------------</div><div>先假设要插入的json数据如下：</div><div>{</div><div>&nbsp; &nbsp;"name" : "MongoDB",</div><div>&nbsp; &nbsp;"type" : "database",</div><div>&nbsp; &nbsp;"count" : 1,</div><div>&nbsp; &nbsp;"info" : {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;x : 203,</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;y : 102</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div>}</div><div></div><div>将其插入数据库：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; BasicDBObject doc = new BasicDBObject();</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; doc.put("name", "MongoDB");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; doc.put("type", "database");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; doc.put("count", 1);</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; BasicDBObject info = new BasicDBObject();</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; info.put("x", 203);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; info.put("y", 102);</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; doc.put("info", info);</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; coll.insert(doc);</div><div></div><div>-------------------------------------------------------------</div><div>设定write concern，以便操作失败时得到提示：</div><div>m.setWriteConcern(WriteConcern.SAFE);</div><div>-------------------------------------------------------------</div><div>查找一个/第一个记录：</div><div>DBObject myDoc = coll.findOne();</div><div>System.out.println(myDoc);</div><div></div><div>注意：属性名不能以下划线或者美元符号开始，mongodb自己保留。</div><div></div><div>获取总记录数：</div><div>System.out.println(coll.getCount());</div><div></div><div>使用游标操作查询结果：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; DBCursor cursor = coll.find();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; try {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while(cursor.hasNext()) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(cursor.next());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; } finally {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cursor.close();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div></div><div>条件查询：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; BasicDBObject query = new BasicDBObject();</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; query.put("i", 71);</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; cursor = coll.find(query);</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; try {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while(cursor.hasNext()) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(cursor.next());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; } finally {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cursor.close();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div></div><div>如果想使用shell里的类似以下语句的功能：</div><div>db.things.find({j: {$ne: 3}, k: {$gt: 10} });</div><div>在java驱动里，{$ne: 3}也是一个普通的DBObject：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; BasicDBObject query = new BasicDBObject();</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; query.put("j", new BasicDBObject("$ne", 3));</div><div>&nbsp; &nbsp; &nbsp; &nbsp; query.put("k", new BasicDBObject("$gt", 10));</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; cursor = coll.find(query);</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; try {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while(cursor.hasNext()) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(cursor.next());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; } finally {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cursor.close();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div></div><div>条件查询一批数据：</div><div>以下是查询i &gt; 50的记录：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; query = new BasicDBObject();</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; query.put("i", new BasicDBObject("$gt", 50)); &nbsp;// e.g. find all where i &gt; 50</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; cursor = coll.find(query);</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; try {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while(cursor.hasNext()) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(cursor.next());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; } finally {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cursor.close();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</div><div>以下是查询20 &lt; i &lt;= 30的记录：</div><div>&nbsp; &nbsp; &nbsp; &nbsp; query = new BasicDBObject();</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; query.put("i", new BasicDBObject("$gt", 20).append("$lte", 30)); &nbsp;// i.e. &nbsp; 20 &lt; i &lt;= 30</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; cursor = coll.find(query);</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; try {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while(cursor.hasNext()) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(cursor.next());</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; } finally {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cursor.close();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div></div><div>-------------------------------------------------------------</div><div>创建索引：</div><div>指定collection和要index的列即可，1代表升序，-1代表降序。</div><div>coll.createIndex(new BasicDBObject("i", 1)); &nbsp;// create index on "i", ascending</div><div></div><div>获取索引列表：</div><div>List&lt;DBObject&gt; list = coll.getIndexInfo();</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (DBObject o : list) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(o);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div></div><div>-------------------------------------------------------------</div><div>数据库管理相关的命令：</div><div></div><div>获取数据库名称列表：</div><div>m.getDatabaseNames()</div><div></div><div>删除数据库：</div><div>m.dropDatabase("my_new_db");</div><div></div><div>-------------------------------------------------------------</div><div>聚合函数：使用DBCollection.aggregate()产生聚合任务:</div><div>http://www.mongodb.org/display/DOCS/Using+The+Aggregation+Framework+with+The+Java+Driver</div><div></div><div>// create our pipeline operations, first with the $match</div><div>DBObject match = new BasicDBObject("$match", new BasicDBObject("type", "airfare") );</div><div></div><div>// build the $projection operation</div><div>DBObject fields = new BasicDBObject("department", 1);</div><div>fields.put("amount", 1);</div><div>fields.put("_id", 0);</div><div>DBObject project = new BasicDBObject("$project", fields );</div><div></div><div>// Now the $group operation</div><div>DBObject groupFields = new BasicDBObject( "_id", "$department");</div><div>groupFields.put("average", new BasicDBObject( "$avg", "$amount"));</div><div>DBObject group = new BasicDBObject("$group", groupFields);</div><div></div><div>// run aggregation</div><div>AggregationOutput output = collection.aggregate( match, project, group );</div><div></div><div>返回结果是一个AggregationOutput对象，可以用以下方式获取其中信息：</div><div>public Iterable&lt;DBObject&gt; results()</div><div>public CommandResult getCommandResult</div><div>public DBObject getCommand()</div><div>示例：</div><div>System.out.println(output.getCommandResult());</div><div></div><div>{</div><div>"serverUsed" : "/127.0.0.1:27017" ,</div><div>"result" : [</div><div>{"_id" : "Human Resources" , "average" : 74.91735537190083} ,</div><div>{"_id" : "Sales" , "average" : 72.30275229357798} ,</div><div>{"_id" : "Engineering" , "average" : 74.1}</div><div>] ,</div><div>"ok" : 1.0</div><div>}</div><div>-------------------------------------------------------------</div><div>使用DBObject存取对象：</div><div>http://www.mongodb.org/display/DOCS/Java+-+Saving+Objects+Using+DBObject</div><div></div><div>假设一个类叫做twitter，存储前必须实现DBObject接口：</div><div>public class Tweet implements DBObject {</div><div>&nbsp; &nbsp; /* ... */</div><div>}</div><div></div><div>然后就可以存了：</div><div>Tweet myTweet = new Tweet();</div><div>myTweet.put("user", userId);</div><div>myTweet.put("message", msg);</div><div>myTweet.put("date", new Date());</div><div>collection.insert(myTweet);</div><div></div><div>一个文档从数据库取出时，自动被转为DBObject。如果想取出时转为需要的类，可以先调用DBCollection.setObjectClass()，然后再进行类型强制转换：</div><div>collection.setObjectClass(Tweet.class);</div><div>Tweet myTweet = (Tweet)collection.findOne();</div><div></div><div>如果想要改变Tweet类的属性，可以改完后再存入：</div><div>Tweet myTweet = (Tweet)collection.findOne();</div><div>myTweet.put("message", newMsg);</div><div>collection.save(myTweet);</div><div></div><div>-------------------------------------------------------------</div><div>JAVA驱动的并发：</div><div>http://www.mongodb.org/display/DOCS/Java+Driver+Concurrency</div><div></div><div>mongodb的java驱动是线程安全的，如果是在web服务环境下，应该创建单例的mongo对象，用这个对象处理每一个请求。mongo对象维护一个内部连接池（默认大小为10），对于每个请求（查找插入等），java线程会从线程池取一个连接，执行操作，然后释放连接&#8212;&#8212;这意味着每次操作所使用的连接很有可能是不同的。</div><div>------------------------------</div><div>在复制（replica）模式下，如果设置slaveOK选项为on，那么读操作会被均匀的分布到各个slave上。这意味着对于同一个线程，一个写操作后紧跟着的一个读操作，有可能被发送到不同的服务器上（写操作发送到master上，读操作发送到slave上），这样读操作有可能不会立刻反映出上一个写操作的数据(因为主从的异步性)。</div><div>如果你想要确保在一个session中完整的一致性（例如在一个http请求中），你可能希望java驱动是用同一个socket连接，这时你可以通过使用"consistent request"来达到目的&#8212;&#8212;在操作前后分别调用requestStart()和requestDone()。</div><div></div><div>DB db...;</div><div>db.requestStart();</div><div>try {</div><div>&nbsp; &nbsp;//Ensures that a connection exists for the "consistent request"</div><div>&nbsp; &nbsp;db.requestEnsureConnection();</div><div></div><div>&nbsp; &nbsp;code....</div><div>} finally {</div><div>&nbsp; &nbsp;db.requestDone();</div><div>}</div><div>------------------------------</div><div>在单独写操作上的WriteConcern选项：</div><div>默认情况下，每次写操作后，连接就被释放回连接池&#8212;&#8212;此时你调用getLastError()是没用的。</div><div>所以可以采用两种方式：</div><div>1，使用类似WriteConcern.SAFE这样的写策略来代替默认策略，这样java驱动会自动首先调用getLastError()，然后才将连接放回连接池。</div><div></div><div>DBCollection coll...;</div><div>coll.insert(..., WriteConcern.SAFE);</div><div></div><div>2，采用上述的requestStart()和requestDone()方式来维持连接不被释放，中间调用getLastError()获取错误信息。</div><div></div><div>DB db...;</div><div>DBCollection coll...;</div><div>db.requestStart();</div><div>try {</div><div>&nbsp; &nbsp;coll.insert(...);</div><div>&nbsp; &nbsp;DBObject err = db.getLastError();</div><div>} finally {</div><div>&nbsp; &nbsp;db.requestDone();</div><div>}</div><div></div><div>这两种方式等价。</div><div></div><div>-------------------------------------------------------------</div><div>java类型：</div><div>http://www.mongodb.org/display/DOCS/Java+Types</div><div>----------------------------</div><div>Object id被用来自动生成唯一的ID：</div><div>ObjectId id = new ObjectId();</div><div>ObjectId copy = new ObjectId(id);</div><div></div><div>----------------------------</div><div>正则表达式：</div><div>java驱动使用JDK的java.util.regex.Pattern表达正则：</div><div>Pattern john = Pattern.compile("joh?n", CASE_INSENSITIVE);</div><div>BasicDBObject query = new BasicDBObject("name", john);</div><div>// finds all people with "name" matching /joh?n/i</div><div>DBCursor cursor = collection.find(query);</div><div></div><div>----------------------------</div><div>java驱动使用JDK的 java.util.Date表示日期时间：</div><div>Date now = new Date();</div><div>BasicDBObject time = new BasicDBObject("ts", now);</div><div>collection.save(time);</div><div></div><div>----------------------------</div><div>com.mongodb.DBRef被用来表示数据库引用(官方一般建议手动引用)：</div><div>DBRef addressRef = new DBRef(db, "foo.bar", address_id);</div><div>DBObject address = addressRef.fetch();</div><div></div><div>DBObject person = BasicDBObjectBuilder.start()</div><div>&nbsp; &nbsp; .add("name", "Fred")</div><div>&nbsp; &nbsp; .add("address", addressRef)</div><div>&nbsp; &nbsp; .get();</div><div>collection.save(person);</div><div></div><div>DBObject fred = collection.findOne();</div><div>DBRef addressObj = (DBRef)fred.get("address");</div><div>addressObj.fetch()</div><div></div><div>----------------------------</div><div>二进制数据：</div><div>java中的字节数组会自动被包装成二进制数据存入数据库。</div><div>二进制类可以被用来表示二进制对象，这可以用来取一个自定义类型的字节。</div><div></div><div>----------------------------</div><div>时间戳数据(BSONTimestamp对象)：</div><div>时间戳数据是一个mongoDB使用的特殊对象，表示一个(以秒为单位的时间，自增ID)的键值对，这被用于主从复制的操作日志中。</div><div></div><div>----------------------------</div><div>代码对象：</div><div>用于表示javascript代码，例如保存可执行的方法到system.js集合中。</div><div>Code和CodeWScope类用来表示这种数据。</div><div>注意有些方法(比如map/reduce)接收字符串，但是在驱动中将其包装为代码对象。</div><div></div><div>----------------------------</div><div>嵌套对象：</div><div>在javascript里面这样一个json文档：</div><div>{</div><div>&nbsp; &nbsp; "x" : {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; "y" : 3</div><div>&nbsp; &nbsp; }</div><div>}</div><div>在java中对应的形式是：</div><div>BasicDBObject y = new BasicDBObject("y", 3);</div><div>BasicDBObject x = new BasicDBObject("x", y);</div><div></div><div>----------------------------</div><div>数组：</div><div>java中所有实现List接口的都被以数组形式在数据库中保存：</div><div>所以如果想保存这样一个json:</div><div>{</div><div>&nbsp; &nbsp; "x" : [</div><div>&nbsp; &nbsp; &nbsp; &nbsp; 1,</div><div>&nbsp; &nbsp; &nbsp; &nbsp; 2,</div><div>&nbsp; &nbsp; &nbsp; &nbsp; {"foo" : "bar"},</div><div>&nbsp; &nbsp; &nbsp; &nbsp; 4</div><div>&nbsp; &nbsp; ]</div><div>}</div><div>在java中可以这么做：</div><div>ArrayList x = new ArrayList();</div><div>x.add(1);</div><div>x.add(2);</div><div>x.add(new BasicDBObject("foo", "bar"));</div><div>x.add(4);</div><div>BasicDBObject doc = new BasicDBObject("x", x);</div><div>-------------------------------------------------------------</div><div>在java驱动中的优先读取策略（Read Preferences）和节点标记（Tagging）</div><div>http://www.mongodb.org/display/DOCS/Read+Preferences+and+Tagging+in+The+Java+Driver</div><div>用来允许应用程序开发者能将读写操作指定在某个主从集合的成员节点上。</div><div>2.2版本在节点标记(node tagging)带来些新的东西让你能更好的控制你的数据的读写。</div><div>java驱动的2.9.0集成了mongodb2.2提供的所有新特性。</div><div>----------------------------</div><div>优先读取策略（Read Preferences）：</div><div>用于提供客户端程序选择那个节点来读取，有以下五个选择：</div><div>PRIMARY : 默认方式，从主节点读取，如果主节点不可用则抛出异常，无法与标签（tags）一起使用。</div><div>PRIMARY PREFERRED : 优先读取主节点，失败的话从副节点读取。</div><div>SECONDARY : 从副节点读取，失败则抛异常。</div><div>SECONDARY PREFERRED : 优先读取副节点，失败则从主节点读取。</div><div>NEAREST : 从最近的节点读取，&#8220;最近&#8221;的定义为ping的响应时间最短(也得满足15毫秒以内)。</div><div></div><div>java实现：类ReadPreference的工厂模式可以创建对应上述五种策略的对象：</div><div>ReadPreference.primary();</div><div>ReadPreference.primaryPreferred();</div><div>ReadPreference.secondary();</div><div>ReadPreference.secondaryPreferred();</div><div>ReadPreference.nearest();</div><div></div><div>例如：假设我们的应用需要保持强一致性(写入的数据立即可以被读出)，但是我们又希望万一主库挂掉以后，从库依然可以读取。这种情况下，我们需要选择PRIMARY PREFERRED模式：</div><div>ReadPreference preference = ReadPreference.primaryPreferred();</div><div>DBCursor cur = new DBCursor(collection, query, null, preference);</div><div></div><div>java驱动保持着各个节点的状态信息（每隔一段时间ping一次所有节点），在这个例子中，java驱动会检测到主库的挂掉，从而将读操作指向从节点。</div><div>----------------------------</div><div>节点标记(Tags)：</div><div>在mongoDB2.0之后，主从集群中的每一个节点都可以被标记一个描述，称为tags。可以用来标记一个节点的位置，和在集群中的从属关系或者特性。这可以让你的应用程序从指定节点中读写。</div><div></div><div>例子：</div><div>假设我们要运行一个三节点的主从集群，三个节点分别在三个不同地理位置的数据中心当中。我们希望确保我们的数据在灾难中也可以恢复，所以我们对每一个节点标记其地理位置，配置文件样例如下：</div><div>foo:SECONDARY&gt; rs.conf()</div><div>{</div><div>&nbsp; &nbsp; "_id":"foo",</div><div>&nbsp; &nbsp; "version":103132,</div><div>&nbsp; &nbsp; &nbsp;"members":[</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "_id":0,</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"host":"localhost:27017",</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"priority":10,</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"tags":{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"datacenter":"Los Angeles",</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "region":"US_West"</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "_id":1,</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"host":"localhost:27018",</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"tags":{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"datacenter":"San Jose",</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "region":"US_West"</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "_id":2,</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"host":"localhost:27019",</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"tags":{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"datacenter":"Richmond",</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "region":"US_Eest"</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp;],</div><div>&nbsp; &nbsp; &nbsp;"settings":{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"getLastErrorModes":{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "DRSafe":{</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"region":2</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp;}</div><div>}</div><div>foo:SECONDARY&gt;</div><div></div><div>注意上面settings字段，我们定义了一个新的getLastErrorModes对象，键为DRSafe。当我们客户端采用此错误模式作为WriteConcern的时候，它会使写操作在完成前复制到至少两个节点上。下面是使用的例子：</div><div>//使用自定义的getLastErrorMode创建WriteConcern</div><div>WriteConcern concern = new WriteConcern("DRSafe");</div><div>//使用自定义的WriteConcern进行写操作</div><div>coll.insert(new BasicDBObject("name", "simple doc"), concern);</div><div></div><div>----------------------------</div><div>在优先读取策略（Read Preferences）中使用节点标记(Tags)：</div><div></div><div>假如我们想要将读请求发送到最近的节点上以便减少请求延时：</div><div>DBObject query = new BasicDBObject("name", "simple doc")</div><div>DBObject result = coll.findOne(query, null, ReadPreference.nearest());</div><div>这样java驱动会自动将读请求发送到ping值最小的节点(也有可能是主节点)。</div><div></div><div>但是，如果我们的java驱动可以确定自己的请求发送源位置，那么就可以明确指定将读请求发送到距离最近的数据中心。再看上面的例子，假如这个读请求来自南加利福尼亚，我们就明确指定这个读请求到Los Angeles数据中心：</div><div>// initialize a properly tagged read preference</div><div>ReadPreference tagged_pref = ReadPreference.secondaryPreferred(new BasicDBObject("datacenter", "Los Angeles"));</div><div>// include the tagged read preference in this request}}</div><div>DBObject result = coll.findOne(}}</div><div>new BasicDBObject("name", "simple doc"), null, tagged_pref);</div><div></div><div>下面的例子指定多个tag，如果读请求在Los Angeles失败，则发送到"US_West"区域的某个节点：</div><div>// read from either LA or US_West</div><div>DBObject tagSetOne = new BasicDBObject("datacenter", "Los Angeles"):</div><div>DBObject tagSetTwo = new BasicDBObject("region", "US_West");</div><div>ReadPreference pref = ReadPreference.primaryPreferred(tagSetOne, tagSetTwo);</div><div></div><div>下面的例子同样指定多个tag，首先请求"datacenter=Los Angeles"且"rack=1"的节点，如果失败则查找"region=US_West"的节点</div><div>// read from either LA or US_West</div><div>DBObject tagSetOne = new BasicDBObject("datacenter", "Los Angeles");</div><div>tagSetOne.put("rack", "1");</div><div>DBObject tagSetTwo = new BasicDBObject("region", "US_West");</div><div>ReadPreference pref = ReadPreference.primaryPreferred(tagSetOne, tagSetTwo);</div><div></div><div>优先读取策略（Read Preferences）可以在operation, collection, DB, Mongo, MongoOptions, MongoURI各个级别来设置，而且设置会以slaveOK和WriteConcer类似的方式来继承。</div><div>优先读取策略（Read Preferences）在支持主从复制的服务器上(1.6+)都可以使用。</div><div>在优先读取策略（Read Preferences）中使用节点标记(Tags)在所有支持节点标记的服务器(2.0+)都可以使用。</div><div>在分片(shard)上使用节点标记(Tags)，必须是2.2+版本的服务器才可以。</div><div></div><img src ="http://www.blogjava.net/watchzerg/aggbug/388346.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/watchzerg/" target="_blank">王星游</a> 2012-09-22 22:32 <a href="http://www.blogjava.net/watchzerg/archive/2012/09/22/388346.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>morphia与spring的整合</title><link>http://www.blogjava.net/watchzerg/archive/2012/09/21/388291.html</link><dc:creator>王星游</dc:creator><author>王星游</author><pubDate>Fri, 21 Sep 2012 10:09:00 GMT</pubDate><guid>http://www.blogjava.net/watchzerg/archive/2012/09/21/388291.html</guid><wfw:comment>http://www.blogjava.net/watchzerg/comments/388291.html</wfw:comment><comments>http://www.blogjava.net/watchzerg/archive/2012/09/21/388291.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/watchzerg/comments/commentRss/388291.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/watchzerg/services/trackbacks/388291.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 最近研究mongoDB的各种pojo-mapping框架，中意的就两个：morphia和spring-data-mongodb。本来想着spring-data-mongodb与spring的结合更紧密些，但悲剧的是其要求spring3.0.x以上版本，与生产环境不符。查了查stackoverflow，大家评价morphia更老牌更稳定一些，于是就用这个了。研究了一番，果然与spring整合起来很麻...&nbsp;&nbsp;<a href='http://www.blogjava.net/watchzerg/archive/2012/09/21/388291.html'>阅读全文</a><img src ="http://www.blogjava.net/watchzerg/aggbug/388291.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/watchzerg/" target="_blank">王星游</a> 2012-09-21 18:09 <a href="http://www.blogjava.net/watchzerg/archive/2012/09/21/388291.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>mongodb的morphia框架学习笔记(补充)</title><link>http://www.blogjava.net/watchzerg/archive/2012/09/21/388280.html</link><dc:creator>王星游</dc:creator><author>王星游</author><pubDate>Fri, 21 Sep 2012 09:19:00 GMT</pubDate><guid>http://www.blogjava.net/watchzerg/archive/2012/09/21/388280.html</guid><wfw:comment>http://www.blogjava.net/watchzerg/comments/388280.html</wfw:comment><comments>http://www.blogjava.net/watchzerg/archive/2012/09/21/388280.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/watchzerg/comments/commentRss/388280.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/watchzerg/services/trackbacks/388280.html</trackback:ping><description><![CDATA[<div>morphia的更新操作详解：</div><div>-------------------------</div><div>用id字段匹配是最快的，因为mongodb默认为id列做了索引：</div><div>Query&lt;Hotel&gt; updateQuery = datastore.createQuery(Hotel.class).field("_id").equal(hotel.getId());</div><div></div><div>除了"_id"外，还有一种静态常量描述ID的方式：</div><div>Query&lt;Hotel&gt; updateQuery = datastore.createQuery(Hotel.class).field(Mapper.ID_KEY).equal(hotel.getId());</div><div></div><div>注意，用的是equal()方法，而不是equals()方法！</div><div>-------------------------</div><div>set和unset方法：</div><div></div><div>改旅店名：</div><div>ops = datastore.createUpdateOperations(Hotel.class).set("name", "Fairmont Chateau Laurier");</div><div></div><div>改旅店地址名：</div><div>ops = datastore.createUpdateOperations(Hotel.class).set("address.city", "Ottawa");</div><div></div><div>删除name属性，会导致下次读取时name=null</div><div>ops = datastore.createUpdateOperations(Hotel.class).unset("name");</div><div>-------------------------</div><div>inc和dec方法：</div><div></div><div>星级加1：</div><div>ops = datastore.createUpdateOperations(Hotel.class).inc("stars");</div><div></div><div>星级加4：</div><div>ops = datastore.createUpdateOperations(Hotel.class).inc("stars", 4);</div><div>-------------------------</div><div>add和addAll方法：</div><div></div><div>将11加入房间号数组中：</div><div>ops = datastore.createUpdateOperations(Hotel.class).add("roomNumbers", 11);</div><div>这与add("roomNumbers", 11, false)等价</div><div></div><div>在非数组字段上执行add操作将报错。</div><div>add的第三个参数标识&#8220;是否加入重复元素&#8221;。若为true，如果已存在相同元素，不会加入，也不会报错。</div><div>-------------------------</div><div>removeFirst/Last/All方法：</div><div></div><div>假设目前是[ 1, 2, 3, 3 ]，运行以下方法之后：</div><div>ops = datastore.createUpdateOperations(Hotel.class).removeAll("roomNumbers", 3);</div><div>就剩下了[ 1, 2 ]&#8212;&#8212;所有的3都被移除了。</div><div></div><div>假设目前是[ 1, 2, 3, 3 ]，运行以下方法之后：</div><div>ops = datastore.createUpdateOperations(Hotel.class).removeAll("roomNumbers", Arrays.asList(2, 3));</div><div>就剩下了[ 1 ] &#8212;&#8212;所有的2和3都被移除了。</div><div>-------------------------</div><div>多重操作：</div><div>ops = datastore.createUpdateOperations(Hotel.class).set("city", "Ottawa").inc("stars");</div><div></div><div>如果在同一个updateOperation对象上对同一个字段多次操作，结果是不定的。</div><div>-------------------------</div><div>update/updateFirst方法：</div><div></div><div>在默认driver里，使用update默认只更新第一个元素(multi默认为false)。</div><div>但是在morphia里，update影响所有记录(对应的底层driver里的update第四个参数multi为true)，updateFirst才是影响第一个元素(对应的底层driver里的update第四个参数multi为false)。</div><div>-------------------------</div><div>createIfMissing参数：</div><div>morphia里所有的方法都重载，最后可以附加一个参数&#8220;createIfMissing&#8221;</div><div>对应的底层driver或者shell里的操作是upsert = true：</div><div>db.collection.update( criteria, objNew, true, multi );</div><div></div><div>-------------------------------------------------</div><div>乐观锁注解@Version的使用：</div><div>http://code.google.com/p/morphia/wiki/MongoNewsletterArticleDec2010</div><div></div><div>class Person {</div><div>&nbsp; @Id String name;</div><div>&nbsp; String phone;</div><div></div><div>&nbsp; @Version</div><div>&nbsp; long version;</div><div>}</div><div></div><div>Person me = new Person("Scott Hernandez");</div><div>ds.save(me) //保存一个person</div><div>Person meAgain = ds.get(Person.class, "Scott Hernandez"); //把这个person读出来先放着</div><div>me.setPhone("111-376-7379");&nbsp;</div><div>ds.save(me); //把原来的me修改一下再存进去，版本号已经变化</div><div>meAgain.setPhone("123-376-7379");</div><div>ds.save(meAgain); //刚次读出来的meAgain是老版本号，此时存储将抛出并发异常</div><div></div><div>注：目前乐观锁的版本号实现方式是时间戳，根据作者的回答：</div><div>http://code.google.com/p/morphia/wiki/MongoNewsletterArticleDec2010</div><div>下一个版本的morphia将使用自增数字来代替时间戳作为乐观锁的版本号使用，以避免多服务器时间不一致等问题。</div><div></div><img src ="http://www.blogjava.net/watchzerg/aggbug/388280.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/watchzerg/" target="_blank">王星游</a> 2012-09-21 17:19 <a href="http://www.blogjava.net/watchzerg/archive/2012/09/21/388280.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LinkedList的源码阅读笔记</title><link>http://www.blogjava.net/watchzerg/archive/2012/09/08/387288.html</link><dc:creator>王星游</dc:creator><author>王星游</author><pubDate>Fri, 07 Sep 2012 19:11:00 GMT</pubDate><guid>http://www.blogjava.net/watchzerg/archive/2012/09/08/387288.html</guid><wfw:comment>http://www.blogjava.net/watchzerg/comments/387288.html</wfw:comment><comments>http://www.blogjava.net/watchzerg/archive/2012/09/08/387288.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/watchzerg/comments/commentRss/387288.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/watchzerg/services/trackbacks/387288.html</trackback:ping><description><![CDATA[<div>1，基本的链表实现，内部类Node表示存储节点。</div><div>2，移除某个节点时，会手动将节点的item属性设为null，以便GC更好的收集。</div><div>3，addAll()方法也并没有调用入参的集合的迭代器，而是将其toArray()后，循环这个数组。</div><div>4，调用clear()时，为了防止某个迭代器还在引用，也为了GC的回收，将每个节点的内容及前后引用都手动设置为null。</div><div>5，定位某个位置的节点时，根据位置距离头尾的距离来决定从first还是last节点开始查找。</div><div>6，LinkedList在内部覆盖了listIterator()，但是没有覆盖iterator()，所以LinkedList.iterator()调用过程如下：</div><div>LinkedList.iterator() -&gt; AbstractSequentialList.iterator() -&gt; AbstractList.listIterator() -&gt; LinkedList.listIterator(int index)</div><div>最终返回的是LinkedList.ListItr对象实例，稍微有点绕，有兴趣的朋友可以打断点试试。</div><div>7，如果没有ListIterator.nextIndex()，里面其实可以不用设定nextIndex变量来记录当前位置的。</div><div>8，序列化时会将size和&#8220;顺序排列的元素流&#8221;依次跟在&#8220;默认ArrayList对象流&#8221;后面。</div><img src ="http://www.blogjava.net/watchzerg/aggbug/387288.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/watchzerg/" target="_blank">王星游</a> 2012-09-08 03:11 <a href="http://www.blogjava.net/watchzerg/archive/2012/09/08/387288.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ArrayList的源码阅读笔记</title><link>http://www.blogjava.net/watchzerg/archive/2012/09/07/387269.html</link><dc:creator>王星游</dc:creator><author>王星游</author><pubDate>Fri, 07 Sep 2012 10:50:00 GMT</pubDate><guid>http://www.blogjava.net/watchzerg/archive/2012/09/07/387269.html</guid><wfw:comment>http://www.blogjava.net/watchzerg/comments/387269.html</wfw:comment><comments>http://www.blogjava.net/watchzerg/archive/2012/09/07/387269.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/watchzerg/comments/commentRss/387269.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/watchzerg/services/trackbacks/387269.html</trackback:ping><description><![CDATA[<div>JDK版本：1.7</div><div>1，使用构造方法或者addAll()方法批量加入某个Collection的元素时，为了效率考虑，是调用目标的toArray()方法，然后批量数组复制的。</div><div>2，在添加单个元素或批量添加元素时，都要检查一下确保数组可以容纳本次操作所要添加的数目，必要时扩展数组。</div><div>3，扩展数组时做到&#8220;一步到位&#8221;，在&#8220;容纳本次添加操作的最小数组长度&#8221;和&#8220;当前数组长度的1.5倍&#8221;之间取最大值。</div><div>4，为效率考虑，contains()、indexOf()和lastIndexOf()方法采用的是数组循环遍历，而不是调用自身的迭代器。</div><div>5，调用clone()后的新对象，修改计数器modCount会被重置为0.</div><div>6，数组从某一位置起批量移动的时候调用System.arraycopy()，源数组与目标数组为同一个，指定起始位置和偏移量即可。</div><div>7，与移除元素有关的方法仅仅是将目标位置设为null，其余的交给GC。</div><div>8，调用clear()之后，数组长度不变，只是改了引用和size&#8212;&#8212;必要时可以调用trimToSize()来缩小数组到真实容量。</div><div>9，调用removeAll()和retainAll()取空集和交集时，在自身的数组上遍历，用遍历过的部分当作新的存储空间，需要读写指针各一个。</div><div><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;batchRemove(Collection&lt;?&gt;&nbsp;c,&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;complement)&nbsp;{<br /><span style="color: #008080; ">&nbsp;2</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">final</span>&nbsp;Object[]&nbsp;elementData&nbsp;=&nbsp;<span style="color: #0000FF; ">this</span>.elementData;<br /><span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;r&nbsp;=&nbsp;0,&nbsp;w&nbsp;=&nbsp;0;<br /><span style="color: #008080; ">&nbsp;4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;modified&nbsp;=&nbsp;<span style="color: #0000FF; ">false</span>;<br /><span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">try</span>&nbsp;{<br /><span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;(;&nbsp;r&nbsp;&lt;&nbsp;size;&nbsp;r++)<br /><span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(c.contains(elementData[r])&nbsp;==&nbsp;complement)<br /><span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elementData[w++]&nbsp;=&nbsp;elementData[r];<br /><span style="color: #008080; ">&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">finally</span>&nbsp;{<br /><span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Preserve&nbsp;behavioral&nbsp;compatibility&nbsp;with&nbsp;AbstractCollection,<br /></span><span style="color: #008080; ">11</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;even&nbsp;if&nbsp;c.contains()&nbsp;throws.</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">12</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(r&nbsp;!=&nbsp;size)&nbsp;{<br /><span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.arraycopy(elementData,&nbsp;r,<br /><span style="color: #008080; ">14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elementData,&nbsp;w,<br /><span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;size&nbsp;-&nbsp;r);<br /><span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;w&nbsp;+=&nbsp;size&nbsp;-&nbsp;r;<br /><span style="color: #008080; ">17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(w&nbsp;!=&nbsp;size)&nbsp;{<br /><span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;(<span style="color: #0000FF; ">int</span>&nbsp;i&nbsp;=&nbsp;w;&nbsp;i&nbsp;&lt;&nbsp;size;&nbsp;i++)<br /><span style="color: #008080; ">20</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elementData[i]&nbsp;=&nbsp;<span style="color: #0000FF; ">null</span>;<br /><span style="color: #008080; ">21</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;modCount&nbsp;+=&nbsp;size&nbsp;-&nbsp;w;<br /><span style="color: #008080; ">22</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;size&nbsp;=&nbsp;w;<br /><span style="color: #008080; ">23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;modified&nbsp;=&nbsp;<span style="color: #0000FF; ">true</span>;<br /><span style="color: #008080; ">24</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">26</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;modified;<br /><span style="color: #008080; ">27</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</div></div><div></div><div><span style="white-space:pre">	</span>这里没看懂的是方法第一行为什么要声明一个&#8220;final&#8221;的引用，代码结构上完全可以去掉，是为了执行效率？</div><div>10，内部数组是transient类型的，不会被自动序列化。序列化时会将&#8220;数组长度值&#8221;和&#8220;顺序排列的数组元素流&#8221;依次跟在&#8220;默认ArrayList对象流&#8221;后面。</div><div>11，每次内容修改都会更改modCount计数器。迭代器初始化时复制此计数器，之后每次迭代都检查此计数器以实现快速失败特性。</div><div>12，subList只是一个指向parentList的包装视图，且可以多层包装。</div><img src ="http://www.blogjava.net/watchzerg/aggbug/387269.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/watchzerg/" target="_blank">王星游</a> 2012-09-07 18:50 <a href="http://www.blogjava.net/watchzerg/archive/2012/09/07/387269.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java中Writer的线程安全性</title><link>http://www.blogjava.net/watchzerg/archive/2012/09/02/386777.html</link><dc:creator>王星游</dc:creator><author>王星游</author><pubDate>Sat, 01 Sep 2012 16:13:00 GMT</pubDate><guid>http://www.blogjava.net/watchzerg/archive/2012/09/02/386777.html</guid><wfw:comment>http://www.blogjava.net/watchzerg/comments/386777.html</wfw:comment><comments>http://www.blogjava.net/watchzerg/archive/2012/09/02/386777.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/watchzerg/comments/commentRss/386777.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/watchzerg/services/trackbacks/386777.html</trackback:ping><description><![CDATA[<div>以前负责一个项目，我负责从一个超大的文本文件中读取信息存入数据库再进一步分析。而文本文件内容是每行一个json串。我在解析的过程中发现，有很小的概率json串的结构会破坏，比如前一个json串只写了半行，后面就被另一个json串覆盖掉了。</div><div>与产生日志的部门沟通，他们说是多线程使用log4j写入，可能偶尔会有串行。</div><div>具体他们是否使用log4j的AsyncAppender我不太了解，暂时也没去看log4j的源码，当时只是简单的忽略异常的行了事儿。</div><div>现在比较闲，想测试一下jdk里面各种输出方式，例如Writer，在多线程交替写入文件一行时是否会出现串行的情况，于是便出现了本文。</div><div></div><div>测试分两部分：</div><div>1，多个线程各自开启一个FileWriter写入同一个文件。</div><div>2，多个线程共用一个FileWriter写入同一个文件。</div><div>--------------------------------------------------</div><div>首先来看FileWriter的JDK说明：</div><div>&#8220;某些平台一次只允许一个 FileWriter（或其他文件写入对象）打开文件进行写入&#8221;&#8212;&#8212;如果是这样，那么第1个测试便不用做了，可事实上至少在windows下并非如此。</div><div></div><div>上代码(别嫌丑，咱是在IO，不是在测多线程，您说是吧？)：</div><div>1，多个线程各自开启一个FileWriter写入同一个文件。</div><div><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">在100毫秒的时间内，10个线程各自开一个FileWriter，<br /></span><span style="color: #008080; ">&nbsp;2</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">同时向同一个文件写入字符串，每个线程每次写一行。<br /></span><span style="color: #008080; ">&nbsp;3</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">测试结果：文件内容出现混乱，串行</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;4</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;multiThreadWriteFile()&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;IOException{<br /><span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File&nbsp;file=<span style="color: #0000FF; ">new</span>&nbsp;File(basePath+jumpPath+fileName);<br /><span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;file.createNewFile();<br /><span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">创建10个线程</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;9</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;totalThreads=10;<br /><span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WriteFileThread[]&nbsp;threads=<span style="color: #0000FF; ">new</span>&nbsp;WriteFileThread[totalThreads];<br /><span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>(<span style="color: #0000FF; ">int</span>&nbsp;i=0;i&lt;totalThreads;i++){<br /><span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WriteFileThread&nbsp;thread=<span style="color: #0000FF; ">new</span>&nbsp;WriteFileThread(file,i);<br /><span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threads[i]=thread;<br /><span style="color: #008080; ">14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">启动10个线程</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">17</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>(Thread&nbsp;thread:&nbsp;threads){<br /><span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thread.start();<br /><span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">20</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">21</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">主线程休眠100毫秒</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">22</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">try</span>&nbsp;{<br /><span style="color: #008080; ">23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(100);<br /><span style="color: #008080; ">24</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">catch</span>&nbsp;(InterruptedException&nbsp;e)&nbsp;{<br /><span style="color: #008080; ">25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br /><span style="color: #008080; ">26</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">27</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">28</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">所有线程停止</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">29</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>(WriteFileThread&nbsp;thread:&nbsp;threads){<br /><span style="color: #008080; ">30</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thread.setToStop();<br /><span style="color: #008080; ">31</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">32</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("还楞着干什么，去看一下文件结构正确与否啊！");<br /><span style="color: #008080; ">33</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</div><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;WriteFileThread&nbsp;<span style="color: #0000FF; ">extends</span>&nbsp;Thread{<br /><span style="color: #008080; ">&nbsp;2</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;toStop=<span style="color: #0000FF; ">false</span>;<br /><span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;FileWriter&nbsp;writer;<br /><span style="color: #008080; ">&nbsp;4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;threadNum;<br /><span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;String&nbsp;lineSeparator;<br /><span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WriteFileThread(File&nbsp;file,<span style="color: #0000FF; ">int</span>&nbsp;threadNum)&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;IOException{<br /><span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lineSeparator=System.getProperty("line.separator");<br /><span style="color: #008080; ">&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writer=<span style="color: #0000FF; ">new</span>&nbsp;FileWriter(file,<span style="color: #0000FF; ">true</span>);<br /><span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">this</span>.threadNum=threadNum;<br /><span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br /><span style="color: #008080; ">14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;run()&nbsp;{<br /><span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>(!toStop){<br /><span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">try</span>&nbsp;{<br /><span style="color: #008080; ">17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writer.append("线程"+threadNum+"正在写入文件，"&nbsp;+<br /><span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"妈妈说名字要很长才能够测试出这几个线程有没有冲突啊，"&nbsp;+<br /><span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"不过还是没有论坛里帖子的名字长，怎么办呢？"&nbsp;+<br /><span style="color: #008080; ">20</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"哎呀，后面是换行符了"+lineSeparator);<br /><span style="color: #008080; ">21</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">22</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">catch</span>&nbsp;(IOException&nbsp;e)&nbsp;{<br /><span style="color: #008080; ">23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br /><span style="color: #008080; ">24</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">26</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("---------线程"+threadNum+"停止执行了");<br /><span style="color: #008080; ">27</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">28</span>&nbsp;<br /><span style="color: #008080; ">29</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;setToStop()&nbsp;{<br /><span style="color: #008080; ">30</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">this</span>.toStop&nbsp;=&nbsp;<span style="color: #0000FF; ">true</span>;<br /><span style="color: #008080; ">31</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">32</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</div></div><div>测试结果：</div><div>产生5MB左右的文本文件，里面出现大约5%的文本串行现象。</div><div>--------------------------------------------------</div><div>接下来我们看多个线程共用一个FileWriter写入同一个文件的情况：</div><div>在Writer抽象类里面有一个protected类型的lock属性，是一个简单Object对象。</div><div>JDK里对这个lock属性的描述如下：&#8220;用于同步针对此流的操作的对象。为了提高效率，字符流对象可以使用其自身以外的对象来保护关键部分。因此，子类应使用此字段中的对象，而不是 this 或者同步的方法。 &#8221;&#8212;&#8212;看来，多线程共用同一个writer的方案有戏。</div><div></div><div>继续看下源代码，从FileWriter的writer方法开始看起，调用过程如下：</div><div>FileWriter-&gt;OutputStreamWriter.write-&gt;StreamEncoder.write</div><div>其中StreamEncoder.write的源码如下：</div><div>(JDK自带源码不包括StreamExcoder，可以在这里查看 http://www.docjar.com/html/api/sun/nio/cs/StreamEncoder.java.html)</div><div><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;write(<span style="color: #0000FF; ">char</span>&nbsp;cbuf[],&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;off,&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;len)&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;IOException&nbsp;{<br /><span style="color: #008080; ">&nbsp;2</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">synchronized</span>&nbsp;(lock)&nbsp;{<br /><span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ensureOpen();<br /><span style="color: #008080; ">&nbsp;4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;((off&nbsp;&lt;&nbsp;0)&nbsp;||&nbsp;(off&nbsp;&gt;&nbsp;cbuf.length)&nbsp;||&nbsp;(len&nbsp;&lt;&nbsp;0)&nbsp;||<br /><span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((off&nbsp;+&nbsp;len)&nbsp;&gt;&nbsp;cbuf.length)&nbsp;||&nbsp;((off&nbsp;+&nbsp;len)&nbsp;&lt;&nbsp;0))&nbsp;<br /><span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">throw</span>&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;IndexOutOfBoundsException();<br /><span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(len&nbsp;==&nbsp;0)&nbsp;{<br /><span style="color: #008080; ">&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>;<br /><span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;implWrite(cbuf,&nbsp;off,&nbsp;len);<br /><span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">13</span>&nbsp;}</div></div><div>可以看到FileWriter在写入时，同步在了对应的FileOutputStream对象上&#8212;&#8212;依此分析，多个线程共用一个FileWriter写入同一个文件，一次一行的情况下，不会出现串行。</div><div>写代码测试一下：</div><div><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">多线程争抢写入同一个文件的测试，一次一行<br /></span><span style="color: #008080; ">&nbsp;2</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">多个线程公用一个FileWriter<br /></span><span style="color: #008080; ">&nbsp;3</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">测试结果：</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;4</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;multiThreadWriteFile2()&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;IOException{<br /><span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File&nbsp;file=<span style="color: #0000FF; ">new</span>&nbsp;File(basePath+jumpPath+fileName);<br /><span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;file.createNewFile();<br /><span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileWriter&nbsp;fw=<span style="color: #0000FF; ">new</span>&nbsp;FileWriter(file);<br /><span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">创建10个线程</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">10</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;totalThreads=10;<br /><span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WriteFileThread2[]&nbsp;threads=<span style="color: #0000FF; ">new</span>&nbsp;WriteFileThread2[totalThreads];<br /><span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>(<span style="color: #0000FF; ">int</span>&nbsp;i=0;i&lt;totalThreads;i++){<br /><span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WriteFileThread2&nbsp;thread=<span style="color: #0000FF; ">new</span>&nbsp;WriteFileThread2(fw,i);<br /><span style="color: #008080; ">14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threads[i]=thread;<br /><span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">启动10个线程</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">18</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>(Thread&nbsp;thread:&nbsp;threads){<br /><span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thread.start();<br /><span style="color: #008080; ">20</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">21</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">22</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">主线程休眠100毫秒</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">23</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">try</span>&nbsp;{<br /><span style="color: #008080; ">24</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(100);<br /><span style="color: #008080; ">25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">catch</span>&nbsp;(InterruptedException&nbsp;e)&nbsp;{<br /><span style="color: #008080; ">26</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br /><span style="color: #008080; ">27</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">28</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">29</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">所有线程停止</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">30</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>(WriteFileThread2&nbsp;thread:&nbsp;threads){<br /><span style="color: #008080; ">31</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thread.setToStop();<br /><span style="color: #008080; ">32</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">33</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("还楞着干什么，去看一下文件结构正确与否啊！");<br /><span style="color: #008080; ">34</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</div><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;WriteFileThread2&nbsp;<span style="color: #0000FF; ">extends</span>&nbsp;Thread{<br /><span style="color: #008080; ">&nbsp;2</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;toStop=<span style="color: #0000FF; ">false</span>;<br /><span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;FileWriter&nbsp;writer;<br /><span style="color: #008080; ">&nbsp;4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;threadNum;<br /><span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;String&nbsp;lineSeparator;<br /><span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WriteFileThread2(FileWriter&nbsp;writer,<span style="color: #0000FF; ">int</span>&nbsp;threadNum){<br /><span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lineSeparator=System.getProperty("line.separator");<br /><span style="color: #008080; ">&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">this</span>.writer=writer;<br /><span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">this</span>.threadNum=threadNum;<br /><span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br /><span style="color: #008080; ">14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;run()&nbsp;{<br /><span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>(!toStop){<br /><span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">try</span>&nbsp;{<br /><span style="color: #008080; ">17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writer.append("线程"+threadNum+"正在写入文件，"&nbsp;+<br /><span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"妈妈说名字要很长才能够测试出这几个线程有没有冲突啊，"&nbsp;+<br /><span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"不过还是没有论坛里帖子的名字长，怎么办呢？"&nbsp;+<br /><span style="color: #008080; ">20</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"哎呀，后面是换行符了"+lineSeparator);<br /><span style="color: #008080; ">21</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">catch</span>&nbsp;(IOException&nbsp;e)&nbsp;{<br /><span style="color: #008080; ">22</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br /><span style="color: #008080; ">23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">24</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("---------线程"+threadNum+"停止执行了");<br /><span style="color: #008080; ">26</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">27</span>&nbsp;<br /><span style="color: #008080; ">28</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;setToStop()&nbsp;{<br /><span style="color: #008080; ">29</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">this</span>.toStop&nbsp;=&nbsp;<span style="color: #0000FF; ">true</span>;<br /><span style="color: #008080; ">30</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">31</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</div></div><div>测试结果：</div><div>产生2.2MB左右的文本文件，里面没有出现任何串行现象。</div><div>--------------------------------------------------</div><div>那么BufferedWriter又如何呢？</div><div>按道理BufferedWriter只是把别的Writer装饰了一下，在底层写的时候也是同步的。</div><div>看源码：</div><div><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">1</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;flushBuffer()&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;IOException&nbsp;{<br /><span style="color: #008080; ">2</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">synchronized</span>&nbsp;(lock)&nbsp;{<br /><span style="color: #008080; ">3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ensureOpen();<br /><span style="color: #008080; ">4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(nextChar&nbsp;==&nbsp;0)<br /><span style="color: #008080; ">5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>;<br /><span style="color: #008080; ">6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.write(cb,&nbsp;0,&nbsp;nextChar);<br /><span style="color: #008080; ">7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nextChar&nbsp;=&nbsp;0;<br /><span style="color: #008080; ">8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</div></div><div>BufferedWriter.write和BufferedWriter.flushBuffer的方法同步在了被包装的Writer这个对象上。</div><div>也就是说，BufferedWriter.write和BufferedWriter.flushBuffer都有同步块包围，说明按上述环境测试时，是不会出现串行现象的。</div><div>--------------------------------------------------</div><div>最终结果：</div><div>1，windows下，可以开多个线程操作多个FileWriter写入同一个文件，多个FileWriter切换时，会导致相互交错，破坏字符串结构的完整性。</div><div>2，多个线程操作FileWriter或者BufferedWriter时，每一次写入操作都是可以保证原子性的，也即：FileWriter或者BufferedWriter是线程安全的&#8212;&#8212;呃，这个结论貌似好简单啊，JDK文档里有说明吗？没看到啊。</div><div>3，由于第2条中的线程安全，写入速度下降超过一半。</div><div></div><img src ="http://www.blogjava.net/watchzerg/aggbug/386777.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/watchzerg/" target="_blank">王星游</a> 2012-09-02 00:13 <a href="http://www.blogjava.net/watchzerg/archive/2012/09/02/386777.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java集合框架印象</title><link>http://www.blogjava.net/watchzerg/archive/2012/08/27/386317.html</link><dc:creator>王星游</dc:creator><author>王星游</author><pubDate>Sun, 26 Aug 2012 17:26:00 GMT</pubDate><guid>http://www.blogjava.net/watchzerg/archive/2012/08/27/386317.html</guid><wfw:comment>http://www.blogjava.net/watchzerg/comments/386317.html</wfw:comment><comments>http://www.blogjava.net/watchzerg/archive/2012/08/27/386317.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/watchzerg/comments/commentRss/386317.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/watchzerg/services/trackbacks/386317.html</trackback:ping><description><![CDATA[<div><div>http://docs.oracle.com/javase/6/docs/technotes/guides/collections/overview.html</div><div>集合框架层次上比较复杂，网上有无数文字和图片来说明，这里按我的思路整理了一下:</div><div>省略了AbstractCollection,AbstractList等层次的抽象类</div><div>省略了RoleList等javax包中的应用方向的实现</div><div>省略了Vector,Stack,HashTable这些著名的老家伙。</div><div>按照我的一般认识进行归类，例如LinkedList同时实现了Deque和List，这里归入List中；再例如Deque本应继承自Queue，但这里放在同一个级别上。</div><div>一切都是为了尽可能建立一个较清晰的第一印象，知道该在什么场景下使用什么类。</div><div>-------------------------------------------------</div><div>Collection<span style="white-space:pre">	</span>集合接口(传统包util)</div><div><span style="white-space:pre">	</span>Queue<span style="white-space:pre">	</span>队列</div><div><span style="white-space:pre">		</span>PriorityQueue<span style="white-space:pre">	</span>无界优先级队列</div><div><span style="white-space:pre">	</span>Deque<span style="white-space:pre">	</span>双端队列</div><div><span style="white-space:pre">		</span>ArrayDeque<span style="white-space:pre">	</span>基于数组的无界双端队列，做队列和栈都很合适</div><div><span style="white-space:pre">	</span>List<span style="white-space:pre">	</span>有序集合</div><div><span style="white-space:pre">		</span>ArrayList<span style="white-space:pre">	</span>基于数组的有序集合</div><div><span style="white-space:pre">		</span>LinkedList<span style="white-space:pre">	</span>基于链表的有序结合(其实也是一个Deque)</div><div><span style="white-space:pre">	</span>Set</div><div><span style="white-space:pre">		</span>EnumSet<span style="white-space:pre">	</span>枚举专用的set，效率高</div><div><span style="white-space:pre">		</span>HashSet<span style="white-space:pre">	</span>基本的快速哈希Set，基于HashMap</div><div><span style="white-space:pre">			</span>LinkedHashSet<span style="white-space:pre">	</span>附加了链表的哈希Set，插入慢，迭代快，有序</div><div><span style="white-space:pre">		</span>TreeSet<span style="white-space:pre">	</span>插入时就维持顺序，基于TreeMap实现，可快速获取子集</div><div></div><div>总结：</div><div>栈和队列，用ArrayDeque或者linkedList(各有千秋)；其余类的适应范围都比较明确。</div><div>-------------------------------------------------</div><div>Collection<span style="white-space:pre">	</span>集合接口(并发包concurrent)</div><div><span style="white-space:pre">	</span>Queue<span style="white-space:pre">	</span>队列</div><div><span style="white-space:pre">		</span>ConcurrentLinkedQueue<span style="white-space:pre">	</span>基于链接节点的无界线程安全队列</div><div><span style="white-space:pre">		</span>BlockingQueue<span style="white-space:pre">	</span>阻塞队列</div><div><span style="white-space:pre">			</span>ArrayBlockingQueue<span style="white-space:pre">	</span>基于数组的有界阻塞队列</div><div><span style="white-space:pre">			</span>DelayQueue<span style="white-space:pre">	</span>无界阻塞队列，只有在延迟期满时才能从中提取元素</div><div><span style="white-space:pre">			</span>LinkedBlockingQueue<span style="white-space:pre">	</span>基于链表的无界阻塞队列</div><div><span style="white-space:pre">			</span>PriorityBlockingQueue 带优先级的无界阻塞队列</div><div><span style="white-space:pre">			</span>SynchronousQueue 无容量的同步队列，两个线程插入与移除交替进行</div><div><span style="white-space:pre">	</span>Deque<span style="white-space:pre">	</span>双端队列</div><div><span style="white-space:pre">		</span>BlockingDeque<span style="white-space:pre">	</span>阻塞双端队列</div><div><span style="white-space:pre">			</span>LinkedBlockingDeque<span style="white-space:pre">	</span>基于链表的阻塞双端队列</div><div><span style="white-space:pre">	</span>List<span style="white-space:pre">	</span>有序集合</div><div><span style="white-space:pre">		</span>CopyOnWriteArrayList 可变操作通过底层复制来实现，适合多读取，少修改</div><div><span style="white-space:pre">	</span>Set</div><div><span style="white-space:pre">		</span>ConcurrentSkipListSet<span style="white-space:pre">	</span>多线程可以安全地发执行各种操作，迭代器弱一致</div><div><span style="white-space:pre">		</span>CopyOnWriteArraySet<span style="white-space:pre">	</span>可变操作通过底层复制来实现，适合多读取，少修改</div><div><span style="white-space:pre">		</span></div><div>总结：</div><div>1，ConcurrentLinkedQueue与LinkedBlockingQueue：</div><div>http://www.javacodegeeks.com/2010/09/java-best-practices-queue-battle-and.html#ixzz1seaiSLwp</div><div>如果生产者与消费者的关系是&#8220;多对多&#8221;，选LinkedBlockingQueue(阻塞方式)要快很多，代价是迭代遍历的效率奇低。</div><div>如果生产者与消费者的关系是&#8220;一对多&#8221;或者&#8220;多对一&#8221;，选ConcurrentLinkedQueue(无等待方式)会有一定性能提升。</div><div>2，ArrayBlockingQueue比LinkedBlockingQueue的表现更稳定和更可预测，但是后者的吞吐量往往更高。</div><div>3，List：</div><div>CopyOnWriteArrayList貌似只适合&#8220;多读取，少写入&#8221;的场景，其余情况还是乖乖的Collections.synchronizedList()吧。</div><div>4，Set：</div><div>ConcurrentSkipListSet可以当作并发版的TreeSet。</div><div>CopyOnWriteArraySet可以当作并发版的linkedHashSet，适合多读取，少修改。</div><div>奇怪的是java没有提供ConcurrentHashSet，按理说基于ConcurrentHashMap可以实现的。</div><div>读写都频繁的同步Set只能凑合了，用ConcurrentSkipListSet可能比synchronizedSet要强？</div><div>http://dhruba.name/2009/08/05/concurrent-set-implementations-in-java-6/</div><div>按上面的链接说法，可以试试这个：</div><div>Collections.newSetFromMap(new ConcurrentHashMap&lt;Object,Boolean&gt;())</div><div>Use this when you have large sets, a good (and fast) hash function and can estimate the set size and needed concurrency before creating the map.</div><div>-------------------------------------------------</div><div>Map<span style="white-space:pre">	</span>映射接口 (传统包util)</div><div><span style="white-space:pre">	</span>EnumMap<span style="white-space:pre">	</span>枚举专用的map，效率高</div><div><span style="white-space:pre">	</span>HashMap<span style="white-space:pre">	</span>基本的快速哈希表</div><div><span style="white-space:pre">		</span>LinkedHashMap<span style="white-space:pre">	</span>附加了链表的哈希表，插入慢，迭代快，有序</div><div><span style="white-space:pre">	</span>IdentityHashMap<span style="white-space:pre">	</span>实现中用&#8220;==&#8221;运算代替&#8220;equals()&#8221;作为判断键和值是否相等</div><div><span style="white-space:pre">	</span>TreeMap<span style="white-space:pre">	</span>基于红黑树，插入时就维持顺序，可快速获取子集</div><div><span style="white-space:pre">	</span>WeakHashMap<span style="white-space:pre">	</span>以&#8220;弱键&#8221;实现，其中的键可能会被垃圾回收，导致此映射被移除</div><div>-------------------------------------------------</div><div>Map<span style="white-space:pre">	</span>映射接口 (并发包concurrent)</div><div><span style="white-space:pre">	</span>ConcurrentMap</div><div><span style="white-space:pre">		</span>ConcurrentHashMap<span style="white-space:pre">	</span></div><div><span style="white-space:pre">		</span>ConcurrentSkipListMap<span style="white-space:pre">	</span></div><div>总结：</div><div>ConcurrentHashMap可以当作并发版的HashMap</div><div>ConcurrentSkipListMap可以当作并发版的TreeMap</div><div>-------------------------------------------------<span style="white-space:pre">	</span></div><div>How to choose which Java collection class to use?</div><div>http://www.javamex.com/tutorials/collections/how_to_choose_2.shtml</div><div>the Queue interface</div><div>http://www.javamex.com/tutorials/synchronization_concurrency_8_queues_2.shtml</div><div>-------------------------------------------------<span style="white-space:pre">	</span></div><div>吐槽：不知道&#8220;基于数组的无界双端队列&#8221;这句话中的&#8220;无界&#8221;会不会被敏感掉，想起了&#8220;十六嘴交换机&#8221;的故事。</div></div><img src ="http://www.blogjava.net/watchzerg/aggbug/386317.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/watchzerg/" target="_blank">王星游</a> 2012-08-27 01:26 <a href="http://www.blogjava.net/watchzerg/archive/2012/08/27/386317.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>