﻿<?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-CONAN ZONE-文章分类-JAVA</title><link>http://www.blogjava.net/conans/category/32554.html</link><description>你越挣扎我就越兴奋</description><language>zh-cn</language><lastBuildDate>Fri, 09 Dec 2011 15:19:10 GMT</lastBuildDate><pubDate>Fri, 09 Dec 2011 15:19:10 GMT</pubDate><ttl>60</ttl><item><title>BTrace使用</title><link>http://www.blogjava.net/conans/articles/365924.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Thu, 08 Dec 2011 14:03:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/365924.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;BTrace(https://btrace.dev.java.net/) 是一个非常不错的java诊断工具, 最近试着用了一下, 文档比较少, 主要是看例子吧.&nbsp; BTrace 中的B表示bytecode, 表明它是在字节码层面上对代码进行trace&nbsp;用来在运行中的java类中注入trace代码, 并对运行中的目标程序进行热交换(hotswap)&nbsp;bt...&nbsp;&nbsp;<a href='http://www.blogjava.net/conans/articles/365924.html'>阅读全文</a><img src ="http://www.blogjava.net/conans/aggbug/365924.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2011-12-08 22:03 <a href="http://www.blogjava.net/conans/articles/365924.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>log4j详解与实战(转)</title><link>http://www.blogjava.net/conans/articles/355064.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Tue, 26 Jul 2011 07:03:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/355064.html</guid><description><![CDATA[<p>log4j是一个非常强大的log记录软件，下面我们就来看看在项目中如何使log4j。</p>
<p>&nbsp;</p>
<p>首先当然是得到log4j的jar档，推荐使用1.2.X版，下载地址：</p>
<p><a href="http://logging.apache.org/log4j/1.2/download.html">http://logging.apache.org/log4j/1.2/download.html</a> </p>
<p>&nbsp;</p>
<p>我们先看一个最简单的示例：</p>
<p><strong>【示例1】</strong> </p>
<p><span style="font-size: medium; color: #0000ff">项目结构：</span> </p>
<p><img style="border-right: black 1px solid; border-top: black 1px solid; border-left: black 1px solid; border-bottom: black 1px solid" alt="" src="http://www.iteye.com/upload/attachment/99808/5429dd5f-c45b-350c-a40c-307f0a852358.png" /><br /><br />【注：<span style="color: #ff0000">由于这里的多个项目公用一个jar档，我们可以创建一个专门放置jar档的Java工程，然后将jar档放到lib目录下。在要使用的工程中按图所示进行引用</span> 】</p>
<p>&nbsp;</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<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">package</span><span style="color: #000000">&nbsp;com.coderdream.log4j;<br /></span><span style="color: #008080">&nbsp;2</span>&nbsp;<span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;3</span>&nbsp;<span style="color: #000000"></span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;org.apache.log4j.Logger;<br /></span><span style="color: #008080">&nbsp;4</span>&nbsp;<span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;5</span>&nbsp;<span style="color: #000000"></span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;HelloLog4j&nbsp;{<br /></span><span style="color: #008080">&nbsp;6</span>&nbsp;<span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;7</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;Logger&nbsp;logger&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;Logger.getLogger(HelloLog4j.</span><span style="color: #0000ff">class</span><span style="color: #000000">);<br /></span><span style="color: #008080">&nbsp;8</span>&nbsp;<span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;9</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">/**</span><span style="color: #008000"><br /></span><span style="color: #008080">10</span>&nbsp;<span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080">@param</span><span style="color: #008000">&nbsp;args<br /></span><span style="color: #008080">11</span>&nbsp;<span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">*/</span><span style="color: #000000"><br /></span><span style="color: #008080">12</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;main(String[]&nbsp;args)&nbsp;{<br /></span><span style="color: #008080">13</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;System.out.println("This&nbsp;is&nbsp;println&nbsp;message.");<br /></span><span style="color: #008080">14</span>&nbsp;<span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /></span><span style="color: #008080">15</span>&nbsp;<span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;记录debug级别的信息</span><span style="color: #008000"><br /></span><span style="color: #008080">16</span>&nbsp;<span style="color: #008000"></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.debug(</span><span style="color: #000000">"</span><span style="color: #000000">This&nbsp;is&nbsp;debug&nbsp;message.</span><span style="color: #000000">"</span><span style="color: #000000">);<br /></span><span style="color: #008080">17</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;记录info级别的信息</span><span style="color: #008000"><br /></span><span style="color: #008080">18</span>&nbsp;<span style="color: #008000"></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(</span><span style="color: #000000">"</span><span style="color: #000000">This&nbsp;is&nbsp;info&nbsp;message.</span><span style="color: #000000">"</span><span style="color: #000000">);<br /></span><span style="color: #008080">19</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;记录error级别的信息</span><span style="color: #008000"><br /></span><span style="color: #008080">20</span>&nbsp;<span style="color: #008000"></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.error(</span><span style="color: #000000">"</span><span style="color: #000000">This&nbsp;is&nbsp;error&nbsp;message.</span><span style="color: #000000">"</span><span style="color: #000000">);<br /></span><span style="color: #008080">21</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br /></span><span style="color: #008080">22</span>&nbsp;<span style="color: #000000">}</span></div>
<p><span style="font-size: medium; color: #0000ff">&nbsp;配置文件log4j.properties:</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<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: #000000">#可以设置级别：debug</span><span style="color: #000000">&gt;</span><span style="color: #000000">info</span><span style="color: #000000">&gt;</span><span style="color: #000000">error<br /></span><span style="color: #008080">&nbsp;2</span>&nbsp;<span style="color: #000000">#debug：显示debug、info、error<br /></span><span style="color: #008080">&nbsp;3</span>&nbsp;<span style="color: #000000">#info：显示info、error<br /></span><span style="color: #008080">&nbsp;4</span>&nbsp;<span style="color: #000000">#error：只error<br /></span><span style="color: #008080">&nbsp;5</span>&nbsp;<span style="color: #000000">log4j.rootLogger</span><span style="color: #000000">=</span><span style="color: #000000">debug,appender1<br /></span><span style="color: #008080">&nbsp;6</span>&nbsp;<span style="color: #000000">#log4j.rootLogger</span><span style="color: #000000">=</span><span style="color: #000000">info,appender1<br /></span><span style="color: #008080">&nbsp;7</span>&nbsp;<span style="color: #000000">#log4j.rootLogger</span><span style="color: #000000">=</span><span style="color: #000000">error,appender1<br /></span><span style="color: #008080">&nbsp;8</span>&nbsp;<span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;9</span>&nbsp;<span style="color: #000000">#输出到控制台<br /></span><span style="color: #008080">10</span>&nbsp;<span style="color: #000000">log4j.appender.appender1</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.ConsoleAppender<br /></span><span style="color: #008080">11</span>&nbsp;<span style="color: #000000">#样式为TTCCLayout<br /></span><span style="color: #008080">12</span>&nbsp;<span style="color: #000000">log4j.appender.appender1.layout</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.TTCCLayout</span></div><span style="font-size: small; color: #ff0000">输出结果：</span><br />
<p></span>&nbsp;</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000">[main]&nbsp;DEBUG&nbsp;com.coderdream.log4j.HelloLog4j&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;This&nbsp;is&nbsp;debug&nbsp;message.<br />[main]&nbsp;INFO&nbsp;com.coderdream.log4j.HelloLog4j&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;This&nbsp;is&nbsp;info&nbsp;message.<br />[main]&nbsp;ERROR&nbsp;com.coderdream.log4j.HelloLog4j&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;This&nbsp;is&nbsp;error&nbsp;message.</span></div>
<p><br />&nbsp;</p>
<p>通过配置文件可知，我们需要配置3个方面的内容：</p>
<p>1、根目录（级别和目的地）；</p>
<p>2、目的地（控制台、文件等等）；</p>
<p>3、输出样式。</p>
<p><strong><span style="font-size: medium; color: #0000ff"><br />下面我们来看看Log4J的类图：</span> </strong></p>
<p><br /><img style="border-right: black 1px solid; border-top: black 1px solid; border-left: black 1px solid; border-bottom: black 1px solid" alt="" src="http://www.iteye.com/upload/attachment/99825/3889d0d4-9d5a-3af3-8b20-926b0a043666.png" /></p>
<p>&nbsp;</p>
<p><strong>Logger - 日志写出器，供程序员输出日志信息 </strong><br /><strong>Appender - 日志目的地，把格式化好的日志信息输出到指定的地方去 </strong><br />ConsoleAppender - 目的地为控制台的Appender <br />FileAppender - 目的地为文件的Appender <br />RollingFileAppender - 目的地为大小受限的文件的Appender <br /><strong>Layout - 日志格式化器，用来把程序员的logging request格式化成字符串</strong> <br />PatternLayout - 用指定的pattern格式化logging request的Layout </p>
<p><span lang="EN-US"><span style="font-size: medium"><strong><span style="color: #0000ff"><br /><span style="color: #000000">Log4j基本使用方法</span> </span></strong></span><br /><br />　　Log4j由三个重要的组件构成：日志信息的优先级，日志信息的输出目的地，日志信息的输出格式。日志信息的优先级从高到低有ERROR、WARN、 INFO、DEBUG，分别用来指定这条日志信息的重要程度；日志信息的输出目的地指定了日志将打印到控制台还是文件中；而输出格式则控制了日志信息的显示内容。<br /><br />　　<strong><span style="font-size: medium; color: #0000ff">一、定义配置文件</span> </strong><br /><br />　　其实您也可以完全不使用配置文件，而是在代码中配置Log4j环境。但是，使用配置文件将使您的应用程序更加灵活。Log4j支持两种配置文件格式，一种是XML格式的文件，一种是Java特性文件（键=值）。下面我们介绍使用Java特性文件做为配置文件的方法：<br /><br />　　<span style="font-size: small; color: #0000ff">1.配置根Logger，其语法为：</span> <br /><br />　　log4j.rootLogger = [ level ] , appenderName, appenderName, &#8230;<br /><br />　　其中，level 是日志记录的优先级，分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定义的级别。Log4j建议只使用四个级别，优先级从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的级别，您可以控制到应用程序中相应级别的日志信息的开关。比如在这里定义了INFO级别，则应用程序中所有DEBUG级别的日志信息将不被打印出来。 appenderName就是指B日志信息输出到哪个地方。您可以同时指定多个输出目的地。<br /><br />　　<span style="font-size: small; color: #0000ff">2.配置日志信息输出目的地Appender，其语法为：</span> <br /><br />　　log4j.appender.appenderName = fully.qualified.name.of.appender.class<br />　　log4j.appender.appenderName.option1 = value1<br />　　&#8230;<br />　　log4j.appender.appenderName.option = valueN<br /><br />　　其中，Log4j提供的appender有以下几种：<br />　　org.apache.log4j.ConsoleAppender（控制台），<br />　　org.apache.log4j.FileAppender（文件），<br />　　org.apache.log4j.DailyRollingFileAppender（每天产生一个日志文件），<br />　　org.apache.log4j.RollingFileAppender（文件大小到达指定尺寸的时候产生一个新的文件），<br />　　org.apache.log4j.WriterAppender（将日志信息以流格式发送到任意指定的地方）<br /><br />　　<span style="font-size: small; color: #0000ff">3.配置日志信息的格式（布局），其语法为：</span> <br /><br />　　log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class<br />　　log4j.appender.appenderName.layout.option1 = value1<br />　　&#8230;<br />　　log4j.appender.appenderName.layout.option = valueN<br /><br />　　其中，Log4j提供的layout有以e几种：<br />　　org.apache.log4j.HTMLLayout（以HTML表格形式布局），<br />　　org.apache.log4j.PatternLayout（可以灵活地指定布局模式），<br />　　org.apache.log4j.SimpleLayout（包含日志信息的级别和信息字符串），<br />　　org.apache.log4j.TTCCLayout（包含日志产生的时间、线程、类别等等信息）<br /><br />　　Log4J采用类似C语言中的printf函数的打印格式格式化日志信息，打印参数如下： %m 输出代码中指定的消息<br /><br />　　%p 输出优先级，即DEBUG，INFO，WARN，ERROR，FATAL<br />　　%r 输出自应用启动到输出该log信息耗费的毫秒数<br />　　%c 输出所属的类目，通常就是所在类的全名<br />　　%t 输出产生该日志事件的线程名<br />　　%n 输出一个回车换行符，Windows平台为&#8220;rn&#8221;，Unix平台为&#8220;n&#8221;<br />　　%d 输出日志时间点的日期或时间，默认格式为ISO8601，也可以在其后指定格式，比如：%d{yyy MMM dd HH:mm:ss,SSS}，输出类似：2002年10月18日 22：10：28，921<br />　　%l 输出日志事件的发生位置，包括类目名、发生的线程，以及在代码中的行数。举例：Testlog4.main(TestLog4.java:10)<br /><br />　　<span style="color: #0000ff"><strong><span style="font-size: medium">二、在代码中使用Log4j</span> </strong></span><br /><br />　　<span style="font-size: medium; color: #0000ff">1.得到记录器</span> <br /><br />　　使用Log4j，第一步就是获取日志记录器，这个记录器将负责控制日志信息。其语法为：<br /><br />　　public static Logger getLogger( String name)<br /><br />　　通过指定的名字获得记录器，如果必要的话，则为这个名字创建一个新的记录器。Name一般取本类的名字，比如：<br /><br />　　static Logger logger = Logger.getLogger ( ServerWithLog4j.class.getName () )<br /><br />　　<span style="font-size: medium; color: #0000ff">2.读取配置文件</span> <br /><br />　　当获得了日志记录器之后，第二步将配置Log4j环境，其语法为：<br /><br />　　BasicConfigurator.configure ()： 自动快速地使用缺省Log4j环境。<br />　　PropertyConfigurator.configure ( String configFilename) ：读取使用Java的特性文件编写的配置文件。<br />　　DOMConfigurator.configure ( String filename ) ：读取XML形式的配置文件。<br /><br />　　<span style="font-size: medium; color: #0000ff">3.插入记录信息（格式化日志信息）</span> <br /><br />　　当上两个必要步骤执行完毕，您就可以轻松地使用不同优先级别的日志记录语句插入到您想记录日志的任何地方，其语法如下：<br /><br />　　Logger.debug ( Object message ) ;<br />　　Logger.info ( Object message ) ;<br />　　Logger.warn ( Object message ) ;<br />　　Logger.error ( Object message ) ; </span></p>
<p><br />&nbsp;</p>
<p><span style="font-size: medium"><strong>示例2～示例8</strong> </span></p>
<p>&nbsp;</p>
<p><strong>【示例2】</strong> 输出为文本文件或HTML文件</p>
<p>&nbsp;</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000">#设置级别：<br />log4j.rootLogger</span><span style="color: #000000">=</span><span style="color: #000000">debug,appender1<br /><br />#输出到文件(这里默认为追加方式)<br />log4j.appender.appender1</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.FileAppender<br />#设置文件输出路径<br />#【</span><span style="color: #000000">1</span><span style="color: #000000">】文本文件<br />#log4j.appender.appender1.File</span><span style="color: #000000">=</span><span style="color: #000000">c:</span><span style="color: #000000">/</span><span style="color: #000000">Log4JDemo02.log<br />#【</span><span style="color: #000000">2</span><span style="color: #000000">】HTML文件<br />log4j.appender.appender1.File</span><span style="color: #000000">=</span><span style="color: #000000">c:</span><span style="color: #000000">/</span><span style="color: #000000">Log4JDemo02.html<br />#设置文件输出样式<br />#log4j.appender.appender1.layout</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.TTCCLayout<br />log4j.appender.appender1.layout</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.HTMLLayout</span></div>
<p><br /><strong>【</strong> <strong>示例3】</strong> 输出为文本文件或HTML文件</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000">#设置级别和多个目的地<br />log4j.rootLogger</span><span style="color: #000000">=</span><span style="color: #000000">debug,appender1,appender2<br /><br />#输出到控制台<br />log4j.appender.appender1</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.ConsoleAppender<br />#设置输出样式<br />log4j.appender.appender1.layout</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.TTCCLayout<br /><br />#输出到文件(这里默认为追加方式)<br />log4j.appender.appender2</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.FileAppender<br />#设置文件输出路径<br />#【</span><span style="color: #000000">1</span><span style="color: #000000">】文本文件<br />#log4j.appender.appender2.File</span><span style="color: #000000">=</span><span style="color: #000000">c:</span><span style="color: #000000">/</span><span style="color: #000000">Log4JDemo02.log<br />#【</span><span style="color: #000000">2</span><span style="color: #000000">】HTML文件<br />log4j.appender.appender2.File</span><span style="color: #000000">=</span><span style="color: #000000">c:</span><span style="color: #000000">/</span><span style="color: #000000">Log4JDemo02.html<br />#设置文件输出样式<br />#log4j.appender.appender2.layout</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.TTCCLayout<br />log4j.appender.appender2.layout</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.HTMLLayout</span></div><strong>【示例4】</strong> SimpleLayout样式<br />
<p>&nbsp;</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000">#设置级别和目的地<br />log4j.rootLogger</span><span style="color: #000000">=</span><span style="color: #000000">debug,appender1<br /><br />#输出到控制台<br />log4j.appender.appender1</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.ConsoleAppender<br />#设置输出样式<br />log4j.appender.appender1.layout</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.SimpleLayout</span></div>
<p><br /><strong><span style="color: #ff0000"><strong></strong>&nbsp;<span style="font-size: medium">输出结果：</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000">DEBUG&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;This&nbsp;is&nbsp;debug&nbsp;message.<br />INFO&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;This&nbsp;is&nbsp;info&nbsp;message.<br />ERROR&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;This&nbsp;is&nbsp;error&nbsp;message.</span></div>
<p></span></span><strong>【示例5】</strong> 自定义样式</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000">#设置级别和目的地<br />log4j.rootLogger</span><span style="color: #000000">=</span><span style="color: #000000">debug,appender1<br /><br />#输出到控制台<br />log4j.appender.appender1</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.ConsoleAppender<br />#设置输出样式<br />log4j.appender.appender1.layout</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.PatternLayout<br />#自定义样式<br />#&nbsp;</span><span style="color: #000000">%</span><span style="color: #000000">r&nbsp;时间&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000"><br />#&nbsp;</span><span style="color: #000000">%</span><span style="color: #000000">t&nbsp;方法名&nbsp;main<br />#&nbsp;</span><span style="color: #000000">%</span><span style="color: #000000">p&nbsp;优先级&nbsp;DEBUG</span><span style="color: #000000">/</span><span style="color: #000000">INFO</span><span style="color: #000000">/</span><span style="color: #000000">ERROR<br />#&nbsp;</span><span style="color: #000000">%</span><span style="color: #000000">c&nbsp;所属类的全名(包括包名)<br />#&nbsp;</span><span style="color: #000000">%</span><span style="color: #000000">l&nbsp;发生的位置，在某个类的某行<br />#&nbsp;</span><span style="color: #000000">%</span><span style="color: #000000">m&nbsp;输出代码中指定的讯息，如log(message)中的message<br />#&nbsp;</span><span style="color: #000000">%</span><span style="color: #000000">n&nbsp;输出一个换行<br /><br />log4j.appender.appender1.layout.ConversionPattern</span><span style="color: #000000">=%</span><span style="color: #000000">r&nbsp;[</span><span style="color: #000000">%</span><span style="color: #000000">t]&nbsp;[</span><span style="color: #000000">%</span><span style="color: #000000">p]&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">%</span><span style="color: #000000">c&nbsp;</span><span style="color: #000000">-%</span><span style="color: #000000">l&nbsp;</span><span style="color: #000000">-%</span><span style="color: #000000">m</span><span style="color: #000000">%</span><span style="color: #000000">n</span></div>
<p><span style="font-size: medium; color: #ff0000">输出结果：</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080">1</span>&nbsp;<span style="color: #000000">0</span><span style="color: #000000">&nbsp;[main]&nbsp;[DEBUG]&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;com.coderdream.log4j.HelloLog4j&nbsp;<br /></span><span style="color: #008080">2</span>&nbsp;<span style="color: #000000"></span><span style="color: #000000">-</span><span style="color: #000000">com.coderdream.log4j.HelloLog4j.main(HelloLog4j.java:</span><span style="color: #000000">16</span><span style="color: #000000">)&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">This&nbsp;is&nbsp;debug&nbsp;message.<br /></span><span style="color: #008080">3</span>&nbsp;<span style="color: #000000"></span><span style="color: #000000">31</span><span style="color: #000000">&nbsp;[main]&nbsp;[INFO]&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;com.coderdream.log4j.HelloLog4j&nbsp;<br /></span><span style="color: #008080">4</span>&nbsp;<span style="color: #000000"></span><span style="color: #000000">-</span><span style="color: #000000">com.coderdream.log4j.HelloLog4j.main(HelloLog4j.java:</span><span style="color: #000000">18</span><span style="color: #000000">)&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">This&nbsp;is&nbsp;info&nbsp;message.<br /></span><span style="color: #008080">5</span>&nbsp;<span style="color: #000000"></span><span style="color: #000000">31</span><span style="color: #000000">&nbsp;[main]&nbsp;[ERROR]&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;com.coderdream.log4j.HelloLog4j&nbsp;<br /></span><span style="color: #008080">6</span>&nbsp;<span style="color: #000000"></span><span style="color: #000000">-</span><span style="color: #000000">com.coderdream.log4j.HelloLog4j.main(HelloLog4j.java:</span><span style="color: #000000">20</span><span style="color: #000000">)&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">This&nbsp;is&nbsp;error&nbsp;message.</span></div>
<p></span><strong>【示例6】</strong> 多目的地、自定义样式</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #000000">#设置级别和目的地<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.rootLogger</span><span style="color: #000000">=</span><span style="color: #000000">debug</span><span style="color: #000000">,</span><span style="color: #000000">appender1</span><span style="color: #000000">,</span><span style="color: #000000">appender2<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />#输出到控制台<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.appender1</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.ConsoleAppender<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />#设置输出样式<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.appender1.layout</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.PatternLayout<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />#自定义样式<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />#&nbsp;%r&nbsp;时间&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />#&nbsp;%t&nbsp;方法名&nbsp;main<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />#&nbsp;%p&nbsp;优先级&nbsp;DEBUG/INFO/ERROR<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />#&nbsp;%c&nbsp;所属类的全名(包括包名)<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />#&nbsp;%l&nbsp;发生的位置，在某个类的某行<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />#&nbsp;%m&nbsp;输出代码中指定的讯息，如log(message)中的message<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />#&nbsp;%n&nbsp;输出一个换行符号<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.appender1.layout.ConversionPattern</span><span style="color: #000000">=</span><span style="font-weight: bold; color: #800000">[</span><span style="color: #800000">%d{yy/MM/dd&nbsp;HH:mm:ss:SSS}</span><span style="font-weight: bold; color: #800000">][</span><span style="color: #800000">%C-%M</span><span style="font-weight: bold; color: #800000">]</span><span style="color: #000000">&nbsp;%m%n<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />#输出到文件(这里默认为追加方式)<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.appender2</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.FileAppender<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />#设置文件输出路径<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />#【</span><span style="color: #000000">1</span><span style="color: #000000">】文本文件<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.appender2.File</span><span style="color: #000000">=</span><span style="color: #000000">c:/Log4JDemo06.log<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />#设置文件输出样式<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.appender2.layout</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.PatternLayout<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.appender2.layout.ConversionPattern</span><span style="color: #000000">=</span><span style="font-weight: bold; color: #800000">[</span><span style="color: #800000">%d{HH:mm:ss:SSS}</span><span style="font-weight: bold; color: #800000">][</span><span style="color: #800000">%C-%M</span><span style="font-weight: bold; color: #800000">]</span><span style="color: #000000">&nbsp;-%m%n</span></div>
<p><strong>【示例7】</strong> <span style="font-size: medium"><strong><span style="color: #0000ff">【企业应用】设置</span> <span style="color: #0000ff">特定包的级别和目的地</span> </strong></span></p>
<p>先增加一个包，新建一个类：</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff">package</span><span style="color: #000000">&nbsp;com.coderdream.log4jDao;<br /><br /></span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;org.apache.log4j.Logger;<br /><br /></span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;HelloDao&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;Logger&nbsp;logger&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;Logger.getLogger(HelloDao.</span><span style="color: #0000ff">class</span><span style="color: #000000">);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">/**</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080">@param</span><span style="color: #008000">&nbsp;args<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">*/</span><span style="color: #000000"><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;main(String[]&nbsp;args)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;记录debug级别的信息</span><span style="color: #008000"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.debug(</span><span style="color: #000000">"</span><span style="color: #000000">This&nbsp;is&nbsp;debug&nbsp;message&nbsp;from&nbsp;Dao.</span><span style="color: #000000">"</span><span style="color: #000000">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;记录info级别的信息</span><span style="color: #008000"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(</span><span style="color: #000000">"</span><span style="color: #000000">This&nbsp;is&nbsp;info&nbsp;message&nbsp;from&nbsp;Dao.</span><span style="color: #000000">"</span><span style="color: #000000">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;记录error级别的信息</span><span style="color: #008000"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.error(</span><span style="color: #000000">"</span><span style="color: #000000">This&nbsp;is&nbsp;error&nbsp;message&nbsp;from&nbsp;Dao.</span><span style="color: #000000">"</span><span style="color: #000000">);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></div>
<p><br /><span style="color: #0000ff"><strong><span style="font-size: small">如果这个类作为基类，如J2EE中的BaseDao、BaseAction、BaseService等等，则我们可以将各层的日志信息分类输出到各个文件。</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000">#省略根，只设置特定包的级别和目的地<br />log4j.logger.com.coderdream.log4j</span><span style="color: #000000">=</span><span style="color: #000000">debug</span><span style="color: #000000">,</span><span style="color: #000000">appender1<br />log4j.logger.com.coderdream.log4jDao</span><span style="color: #000000">=</span><span style="color: #000000">info</span><span style="color: #000000">,</span><span style="color: #000000">appender1</span><span style="color: #000000">,</span><span style="color: #000000">appender2<br /><br />#输出到控制台<br />log4j.appender.appender1</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.ConsoleAppender<br />#设置输出样式<br />log4j.appender.appender1.layout</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.PatternLayout<br />#自定义样式<br />#&nbsp;%r&nbsp;时间&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000"><br />#&nbsp;%t&nbsp;方法名&nbsp;main<br />#&nbsp;%p&nbsp;优先级&nbsp;DEBUG/INFO/ERROR<br />#&nbsp;%c&nbsp;所属类的全名(包括包名)<br />#&nbsp;%l&nbsp;发生的位置，在某个类的某行<br />#&nbsp;%m&nbsp;输出代码中指定的讯息，如log(message)中的message<br />#&nbsp;%n&nbsp;输出一个换行符号<br />log4j.appender.appender1.layout.ConversionPattern</span><span style="color: #000000">=</span><span style="font-weight: bold; color: #800000">[</span><span style="color: #800000">%d{yy/MM/dd&nbsp;HH:mm:ss:SSS}</span><span style="font-weight: bold; color: #800000">][</span><span style="color: #800000">%C-%M</span><span style="font-weight: bold; color: #800000">]</span><span style="color: #000000">&nbsp;%m%n<br /><br />#输出到文件(这里默认为追加方式)<br />log4j.appender.appender2</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.FileAppender<br />#设置文件输出路径<br />#【</span><span style="color: #000000">1</span><span style="color: #000000">】文本文件<br />log4j.appender.appender2.File</span><span style="color: #000000">=</span><span style="color: #000000">c:/Log4JDemo07_Dao.log<br />#设置文件输出样式<br />log4j.appender.appender2.layout</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.PatternLayout<br />log4j.appender.appender2.layout.ConversionPattern</span><span style="color: #000000">=</span><span style="font-weight: bold; color: #800000">[</span><span style="color: #800000">%d{HH:mm:ss:SSS}</span><span style="font-weight: bold; color: #800000">][</span><span style="color: #800000">%C-%M</span><span style="font-weight: bold; color: #800000">]</span><span style="color: #000000">&nbsp;-%m%n</span></div><strong>【示例8】</strong> log4j.xml的配置方式<br />
<p></span></strong></span></p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<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><span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;2</span>&nbsp;<span style="color: #000000"></span><span style="color: #0000ff">&lt;!</span><span style="color: #ff00ff">DOCTYPE&nbsp;log4j:configuration&nbsp;SYSTEM&nbsp;"log4j.dtd"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;3</span>&nbsp;<span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;4</span>&nbsp;<span style="color: #000000"></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">log4j:configuration&nbsp;</span><span style="color: #ff0000">xmlns:log4j</span><span style="color: #0000ff">="http://jakarta.apache.org/log4j/"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;5</span>&nbsp;<span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;6</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">appender&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="appender1"</span><span style="color: #ff0000"><br /></span><span style="color: #008080">&nbsp;7</span>&nbsp;<span style="color: #ff0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class</span><span style="color: #0000ff">="org.apache.log4j.RollingFileAppender"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;8</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">param&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="File"</span><span style="color: #ff0000">&nbsp;value</span><span style="color: #0000ff">="logfile08.html"</span><span style="color: #ff0000">&nbsp;</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;9</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">param&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="MaxFileSize"</span><span style="color: #ff0000">&nbsp;value</span><span style="color: #0000ff">="1MB"</span><span style="color: #ff0000">&nbsp;</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br /></span><span style="color: #008080">10</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">param&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="MaxBackupIndex"</span><span style="color: #ff0000">&nbsp;value</span><span style="color: #0000ff">="5"</span><span style="color: #ff0000">&nbsp;</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br /></span><span style="color: #008080">11</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">layout&nbsp;</span><span style="color: #ff0000">class</span><span style="color: #0000ff">="org.apache.log4j.HTMLLayout"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br /></span><span style="color: #008080">12</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">layout</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br /></span><span style="color: #008080">13</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">appender</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br /></span><span style="color: #008080">14</span>&nbsp;<span style="color: #000000"><br /></span><span style="color: #008080">15</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">root</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br /></span><span style="color: #008080">16</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><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: #ff0000">&nbsp;</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br /></span><span style="color: #008080">17</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">appender-ref&nbsp;</span><span style="color: #ff0000">ref</span><span style="color: #0000ff">="appender1"</span><span style="color: #ff0000">&nbsp;</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br /></span><span style="color: #008080">18</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">root</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br /></span><span style="color: #008080">19</span>&nbsp;<span style="color: #000000"></span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">log4j:configuration</span><span style="color: #0000ff">&gt;</span></div>
<p>为了提高效率，我们可以在写日志前增加判断：</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008000">//</span><span style="color: #008000">&nbsp;记录debug级别的信息</span><span style="color: #008000"><br /></span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(logger.isDebugEnabled())&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;logger.debug(</span><span style="color: #000000">"</span><span style="color: #000000">This&nbsp;is&nbsp;debug&nbsp;message&nbsp;from&nbsp;Dao.</span><span style="color: #000000">"</span><span style="color: #000000">);<br />}<br /><br /></span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;记录info级别的信息</span><span style="color: #008000"><br /></span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(logger.isInfoEnabled())&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;logger.info(</span><span style="color: #000000">"</span><span style="color: #000000">This&nbsp;is&nbsp;info&nbsp;message&nbsp;from&nbsp;Dao.</span><span style="color: #000000">"</span><span style="color: #000000">);<br />}<br /><br /></span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;记录error级别的信息</span><span style="color: #008000"><br /></span><span style="color: #000000">logger.error(</span><span style="color: #000000">"</span><span style="color: #000000">This&nbsp;is&nbsp;error&nbsp;message&nbsp;from&nbsp;Dao.</span><span style="color: #000000">"</span><span style="color: #000000">);</span></div>
<p><br /><br /><br /><br /><br /><br /><br /></strong><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /></p><img src ="http://www.blogjava.net/conans/aggbug/355064.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2011-07-26 15:03 <a href="http://www.blogjava.net/conans/articles/355064.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>log4j详解</title><link>http://www.blogjava.net/conans/articles/345084.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Thu, 24 Feb 2011 09:14:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/345084.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 日志论 在应用程序中输出日志有有三个目的：（1）监视代码中变量的变化情况，把数据周期性地记录到文件中供其他应用进行统计分析工作。 （2）跟踪代码运行进轨迹，作为日后审计的依据。 （3）担当集成开发环境中的调试器，向文件或控制台打印代码的调试信息。 Apache能用日志包（Commons Logging Package）是Apache的一个开放源代码项目，它提供了一组通用的日志接...&nbsp;&nbsp;<a href='http://www.blogjava.net/conans/articles/345084.html'>阅读全文</a><img src ="http://www.blogjava.net/conans/aggbug/345084.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2011-02-24 17:14 <a href="http://www.blogjava.net/conans/articles/345084.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Log4j性能调优</title><link>http://www.blogjava.net/conans/articles/345083.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Thu, 24 Feb 2011 09:10:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/345083.html</guid><description><![CDATA[不久前在系统中完成了监控的功能，监控系统的信息量很大，用户对页面的每一个点击都会产生记录，每天下来的日志量有2G多，我用log4j把这些监控记录
放在日志里，然后进行异步处理，但即使是这样，记录日志会对磁盘IO产生频繁的访问，而IO通常就是系统的瓶颈所在。于是对log4j配置进行一些调优就
成了必要。下面是我系统中的log4j配置：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">log4j.rootLogger</span><span style="color: #000000;">=</span><span style="color: #000000;">ERROR</span><span style="color: #000000;">,</span><span style="color: #000000;">fileout</span><span style="color: #000000;">,</span><span style="color: #000000;">stdout<br />
<span style="color: red;"><span style="color: #000000;">log4j.logger.monitorLogger</span><span style="color: #000000;">=</span><span style="color: #000000;">INFO</span><span style="color: #000000;">,</span><span style="color: #000000;">monitorAppender<br />
log4j.additivity.monitorLogger</span><span style="color: #000000;">=</span><span style="color: #000000;">false</span></span></span><span style="color: #000000;"><br />
<br />
log4j.appender.stdout</span><span style="color: #000000;">=</span><span style="color: #000000;">org.apache.log4j.ConsoleAppender<br />
log4j.appender.stdout.layout</span><span style="color: #000000;">=</span><span style="color: #000000;">org.apache.log4j.PatternLayout<br />
log4j.appender.stdout.layout.ConversionPattern</span><span style="color: #000000;">=</span><span style="color: #000000;">%d&nbsp;(%F:%L)&nbsp;%-5p&nbsp;%c&nbsp;-&nbsp;%m%n<br />
<br />
log4j.appender.fileout</span><span style="color: #000000;">=</span><span style="color: #000000;">org.apache.log4j.DailyRollingFileAppender<br />
log4j.appender.fileout.File</span><span style="color: #000000;">=</span><span style="color: #000000;">logs/server_log.txt<br />
log4j.appender.fileout.layout</span><span style="color: #000000;">=</span><span style="color: #000000;">org.apache.log4j.PatternLayout<br />
log4j.appender.fileout.layout.ConversionPattern</span><span style="color: #000000;">=</span><span style="color: #000000;">%d&nbsp;</span><span style="color: #800000; font-weight: bold;">[</span><span style="color: #800000;">%t</span><span style="color: #800000; font-weight: bold;">]</span><span style="color: #000000;">&nbsp;(%F:%L)&nbsp;%-5p&nbsp;%c&nbsp;-&nbsp;%m%n<br />
<br />
log4j.appender.monitorAppender</span><span style="color: #000000;">=</span><span style="color: #000000;">org.apache.log4j.DailyRollingFileAppender<br />
log4j.appender.monitorAppender.File</span><span style="color: #000000;">=</span><span style="color: #000000;">mtlogs/mt_log.txt<br />
log4j.appender.monitorAppender.layout</span><span style="color: #000000;">=</span><span style="color: #000000;">org.apache.log4j.PatternLayout<br />
log4j.appender.monitorAppender.layout.ConversionPattern</span><span style="color: #000000;">=</span><span style="color: #000000;">%m%n<br />
log4j.appender.monitorAppender.DatePattern</span><span style="color: #000000;">=</span><span style="color: #000000;">'.'yyyy-MM-dd-HH<br />
log4j.appender.monitorAppender.BufferedIO</span><span style="color: #000000;">=</span><span style="color: #000000;">true<br />
#Buffer单位为字节，默认是8K<br />
<span style="color: red;"><span style="color: #000000;">log4j.appender.monitorAppender.BufferSize</span><span style="color: #000000;">=</span><span style="color: #000000;">8192</span></span></span></div>
1）<span style="color: #ff0000;">log4j.additivity.monitorLogger=false<br />
<span style="color: #000000;">这个选项用于控制监控logger的日志不会输出到rootlogger，否则无论会产生许多重复的数据，同时也会影响性能；<br />
<br />
2）</span></span><span style="color: #ff0000;">log4j.appender.monitorAppender.DatePattern='.'yyyy-MM-dd-HH<br />
<span style="color: #000000;">这个选项用于告诉</span></span>DailyRollingFileAppender每小时输出日志，而不是默认的一天输出一次，因为监控日志的数据量很巨大，如果以天为单位输出，日志文件会很大（G级），而且再处理会很耗时。<br />
其他一些输出选项还有：<br />
1)'.'yyyy-MM: 每月 <br />
2)'.'yyyy-ww: 每周 <br />
3)'.'yyyy-MM-dd: 每天 <br />
4)'.'yyyy-MM-dd-a: 每天两次 <br />
5)'.'yyyy-MM-dd-HH: 每小时 <br />
6)'.'yyyy-MM-dd-HH-mm: 每分钟 <span style="color: #ff0000;"><br />
<br />
<span style="color: #000000;">3）</span></span><span style="color: #ff0000;">log4j.appender.monitorAppender.BufferedIO=true<br />
</span><span style="color: #ff0000;">log4j.appender.monitorAppender.BufferSize=8192<br />
<span style="color: #000000;">这
个选项用于告诉log4j输出日志的时候采用缓冲的方式，而不是即时flush方式，并且设定了缓冲为8K，8K是默认值，可以根据日志输出的情况来修
改。这个选项很重要，在测试中发现，当并发访问很高，例如每一秒100个并发以上，使用缓存跟不使用缓冲差距很大。具体数字我这里就不列出来了。<br />
另外我想说的是，log4j输出缓冲日志是以8K为单位的，因为磁盘的一个block为8K，这样可以减少碎片，也就是说假设你设置缓存为18K，log4j在16K（8K*2)的时候就会输出），而不是18K。<br />
<br />
4）组装输出内容之前可对logger的输出级别先进行判断而不要完全依赖log4j控制，因为组装输出日志内容也是要损耗效率的。<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //若log4j并未开启info级日志记录，直接返回<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(!monitorLogger.isInfoEnabled()){<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; StringBuilder log = new StringBuilder();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; logSql.append(logPk+" ");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br />
<br />
5）使用异步输出 org.apache.log4j.AsyncAppender，异步输出必须使用xml方式配置才能支持，我把上面properties形式的配置文件用xml表达一下：<br />
</span></span>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><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><span style="color: #000000;"><br />
</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">log4j:configuration&nbsp;</span><span style="color: #ff0000;">debug</span><span style="color: #0000ff;">="true"</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><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;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class</span><span style="color: #0000ff;">="org.apache.log4j.ConsoleAppender"</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">layout&nbsp;</span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="org.apache.log4j.PatternLayout"</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">param&nbsp;</span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="ConversionPattern"</span><span style="color: #ff0000;">&nbsp;value</span><span style="color: #0000ff;">="%d&nbsp;(%F:%L)&nbsp;%-5p&nbsp;%c&nbsp;-&nbsp;%m%n"</span><span style="color: #ff0000;">&nbsp;</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">layout</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">appender</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">appender&nbsp;</span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="fileout"</span><span style="color: #ff0000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class</span><span style="color: #0000ff;">="org.apache.log4j.DailyRollingFileAppender"</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">layout&nbsp;</span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="org.apache.log4j.PatternLayout"</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">param&nbsp;</span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="ConversionPattern"</span><span style="color: #ff0000;">&nbsp;value</span><span style="color: #0000ff;">="%d&nbsp;[%t]&nbsp;(%F:%L)&nbsp;%-5p&nbsp;%c&nbsp;-&nbsp;%m%n"</span><span style="color: #ff0000;">&nbsp;</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">layout</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">param&nbsp;</span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="File"</span><span style="color: #ff0000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value</span><span style="color: #0000ff;">="logs/server_log.txt"</span><span style="color: #ff0000;">&nbsp;</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">appender</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">appender&nbsp;</span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="monitorAppender"</span><span style="color: #ff0000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class</span><span style="color: #0000ff;">="org.apache.log4j.DailyRollingFileAppender"</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">layout&nbsp;</span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="org.apache.log4j.PatternLayout"</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">param&nbsp;</span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="ConversionPattern"</span><span style="color: #ff0000;">&nbsp;value</span><span style="color: #0000ff;">="%m%n"</span><span style="color: #ff0000;">&nbsp;</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">layout</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">param&nbsp;</span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="DatePattern"</span><span style="color: #ff0000;">&nbsp;value</span><span style="color: #0000ff;">="'.'yyyy-MM-dd-HH"</span><span style="color: #ff0000;">&nbsp;</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">param&nbsp;</span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="File"</span><span style="color: #ff0000;">&nbsp;value</span><span style="color: #0000ff;">="mtlogs/mt_log.txt"</span><span style="color: #ff0000;">&nbsp;</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">param&nbsp;</span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="BufferedIO"</span><span style="color: #ff0000;">&nbsp;value</span><span style="color: #0000ff;">="true"</span><span style="color: #ff0000;">&nbsp;</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">&lt;!--</span><span style="color: #008000;">&nbsp;8K为一个写单元&nbsp;</span><span style="color: #008000;">--&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">param&nbsp;</span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="BufferSize"</span><span style="color: #ff0000;">&nbsp;value</span><span style="color: #0000ff;">="8192"</span><span style="color: #ff0000;">&nbsp;</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">appender</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">appender&nbsp;</span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="async"</span><span style="color: #ff0000;">&nbsp;class</span><span style="color: #0000ff;">="org.apache.log4j.AsyncAppender"</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">appender-ref&nbsp;</span><span style="color: #ff0000;">ref</span><span style="color: #0000ff;">="monitorAppender"</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">appender</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">root</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">priority&nbsp;</span><span style="color: #ff0000;">value</span><span style="color: #0000ff;">="error"</span><span style="color: #ff0000;">&nbsp;</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><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: #ff0000;">&nbsp;</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">appender-ref&nbsp;</span><span style="color: #ff0000;">ref</span><span style="color: #0000ff;">="fileout"</span><span style="color: #ff0000;">&nbsp;</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">root</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">category&nbsp;</span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="com.danga.MemCached"</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">priority&nbsp;</span><span style="color: #ff0000;">value</span><span style="color: #0000ff;">="error"</span><span style="color: #ff0000;">&nbsp;</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">appender-ref&nbsp;</span><span style="color: #ff0000;">ref</span><span style="color: #0000ff;">="fileout"</span><span style="color: #ff0000;">&nbsp;</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">category&nbsp;</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">category&nbsp;</span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="com.opensymphony"</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">priority&nbsp;</span><span style="color: #ff0000;">value</span><span style="color: #0000ff;">="error"</span><span style="color: #ff0000;">&nbsp;</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">appender-ref&nbsp;</span><span style="color: #ff0000;">ref</span><span style="color: #0000ff;">="fileout"</span><span style="color: #ff0000;">&nbsp;</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">category&nbsp;</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">category&nbsp;</span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="monitorLogger"</span><span style="color: #ff0000;">&nbsp;additivity</span><span style="color: #0000ff;">="false"</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">priority&nbsp;</span><span style="color: #ff0000;">value</span><span style="color: #0000ff;">="info"</span><span style="color: #ff0000;">&nbsp;</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">appender-ref&nbsp;</span><span style="color: #ff0000;">ref</span><span style="color: #0000ff;">="async"</span><span style="color: #ff0000;">&nbsp;</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">category&nbsp;</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br />
</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">log4j:configuration</span><span style="color: #0000ff;">&gt;</span></div>
<span style="color: #ff0000;"><span style="color: #000000;">配置中红色的部分就是用于支持异步输出的，在用jmeter测试的过程中发觉使用异步方式，工作的不是很稳定。性能的提升也不显著。所以最后并没有采用。<br />
<br />
</span></span>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">InputStream&nbsp;in</span><span style="color: #000000;">=</span><span style="color: #0000ff;">null</span><span style="color: #000000;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;">&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;in&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;Log4jConfigLocator.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">.getResourceAsStream(fileName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(fileName.endsWith(</span><span style="color: #000000;">"</span><span style="color: #000000;">.xml</span><span style="color: #000000;">"</span><span style="color: #000000;">)){<br />
&nbsp;&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;">载入XML格式的配置文件</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Document&nbsp;doc&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(in);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DOMConfigurator.configure(doc.getDocumentElement());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><span style="color: #0000ff;">else</span><span style="color: #000000;">{<br />
&nbsp;&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;">载入properties格式的配置文件</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Properties&nbsp;props&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Properties();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;props.load(in);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PropertyConfigurator.configure(props);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span></div>
<br />
<br />
<img src ="http://www.blogjava.net/conans/aggbug/345083.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2011-02-24 17:10 <a href="http://www.blogjava.net/conans/articles/345083.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转】单例模式完全剖析 </title><link>http://www.blogjava.net/conans/articles/344524.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Thu, 17 Feb 2011 03:16:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/344524.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 概要 单例模式是最简单的设计模式之一，但是对于Java的开发者来说，它却有很多缺陷。在本月的专栏中，David Geary探讨了单例模式以及在面对多线程（multithreading)、类装载器（classloaders）和序列化 (serialization)时如何处理这些缺陷。 单例模式适合于一个类只有一个实例的情况，比如窗口管理器，打印缓冲池和文件系统，它们都是原型的例子。典型的...&nbsp;&nbsp;<a href='http://www.blogjava.net/conans/articles/344524.html'>阅读全文</a><img src ="http://www.blogjava.net/conans/aggbug/344524.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2011-02-17 11:16 <a href="http://www.blogjava.net/conans/articles/344524.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>动态非侵入拦截</title><link>http://www.blogjava.net/conans/articles/282635.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Tue, 16 Jun 2009 08:18:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/282635.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 动态非侵入拦截什么叫无侵入拦截？&nbsp;在JAVA中要拦截一个方法调用，有多种方式，最容易也是最流行的就是动态代理。动态代理方式实现起来简单，你只要提供一个接口和拦截处理的handler并在invoke中提供要拉截的方法调用时的附件操作，然后所有对需要拦截的方法所在的对象都由代理来生成就可以在运行时动态地实现对方法调进行拦截。&nbsp;事实上动态代理模式从描述上也看出了它...&nbsp;&nbsp;<a href='http://www.blogjava.net/conans/articles/282635.html'>阅读全文</a><img src ="http://www.blogjava.net/conans/aggbug/282635.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2009-06-16 16:18 <a href="http://www.blogjava.net/conans/articles/282635.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>centos5.2下手动安装JDK6</title><link>http://www.blogjava.net/conans/articles/253816.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Sun, 08 Feb 2009 13:17:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/253816.html</guid><description><![CDATA[<p>centos5.2自带的了jdk，但还是1.4的版本，太老掉牙了，tomcat6都没发跑起来。显然没法满足我们的要求。我们先查看一下，如下所示： <br />
</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://exceljava.javaeye.com/blog/305908#"><img alt="复制代码" src="http://exceljava.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>[root</span><span class="annotation">@localhost</span><span>&nbsp;soft]#&nbsp;java&nbsp;-version &nbsp;&nbsp;</span></span></li>
    <li><span>java&nbsp;version&nbsp;&#8220;</span><span class="number">1.4</span><span>.</span><span class="number">2</span><span>&#8243; &nbsp;&nbsp;</span></span></li>
    <li><span>gij&nbsp;(GNU&nbsp;libgcj)&nbsp;version&nbsp;</span><span class="number">4.1</span><span>.</span><span class="number">2</span><span>&nbsp;</span><span class="number">20071124</span><span>&nbsp;(Red&nbsp;Hat&nbsp;</span><span class="number">4.1</span><span>.</span><span class="number">2</span><span>-</span><span class="number">42</span><span>)&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">[root@localhost soft]# java -version
java version &#8220;1.4.2&#8243;
gij (GNU libgcj) version 4.1.2 20071124 (Red Hat 4.1.2-42)</pre>
<p><br />
&nbsp; 注意，根据我在5.2下安装的情况，似乎不卸载自带的1.4，设置jdk6的安装无法生效。为了避免这种情况，我们首先还是卸载掉其自带的1.4版本的jdk。 <br />
</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://exceljava.javaeye.com/blog/305908#"><img alt="复制代码" src="http://exceljava.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>[root</span><span class="annotation">@localhost</span><span>&nbsp;soft]#&nbsp;rpm&nbsp;-qa&nbsp;|&nbsp;grep&nbsp;jdk &nbsp;&nbsp;</span></span></li>
    <li><span>[root</span><span class="annotation">@localhost</span><span>&nbsp;soft]#&nbsp;rpm&nbsp;-qa&nbsp;|&nbsp;grep&nbsp;gcj &nbsp;&nbsp;</span></span></li>
    <li><span>libgcj-</span><span class="number">4.1</span><span>.</span><span class="number">2</span><span>-</span><span class="number">42</span><span>.el5 &nbsp;&nbsp;</span></span></li>
    <li><span>java-</span><span class="number">1.4</span><span>.</span><span class="number">2</span><span>-gcj-compat-</span><span class="number">1.4</span><span>.</span><span class="number">2.0</span><span>-40jpp.</span><span class="number">115</span><span>&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">[root@localhost soft]# rpm -qa | grep jdk
[root@localhost soft]# rpm -qa | grep gcj
libgcj-4.1.2-42.el5
java-1.4.2-gcj-compat-1.4.2.0-40jpp.115</pre>
<p><br />
<br />
上面先确认jdk的具体版本号，然后 <br />
</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://exceljava.javaeye.com/blog/305908#"><img alt="复制代码" src="http://exceljava.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>root</span><span class="annotation">@localhost</span><span>&nbsp;jdk1.</span><span class="number">6</span><span>.0_11]#&nbsp;yum&nbsp;-y&nbsp;remove&nbsp;java-</span><span class="number">1.4</span><span>.</span><span class="number">2</span><span>-gcj-compat-</span><span class="number">1.4</span><span>.</span><span class="number">2.0</span><span>-40jpp.</span><span class="number">115</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>Setting&nbsp;up&nbsp;Remove&nbsp;Process &nbsp;&nbsp;</span></li>
    <li><span>Resolving&nbsp;Dependencies&#8230;&#8230;&#8230;..(开始卸载) &nbsp;&nbsp;</span></li>
    <li><span>Removed:&nbsp;java-</span><span class="number">1.4</span><span>.</span><span class="number">2</span><span>-gcj-compat.i386&nbsp;</span><span class="number">0</span><span>:</span><span class="number">1.4</span><span>.</span><span class="number">2.0</span><span>-40jpp.</span><span class="number">115</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>Dependency&nbsp;Removed:&nbsp;antlr.i386&nbsp;</span><span class="number">0</span><span>:</span><span class="number">2.7</span><span>.</span><span class="number">6</span><span>-4jpp.</span><span class="number">2</span><span>&nbsp;bsf.i386&nbsp;</span><span class="number">0</span><span>:</span><span class="number">2.3</span><span>.</span><span class="number">0</span><span>-11jpp.</span><span class="number">1</span><span>&nbsp;bsh.i386&nbsp;</span><span class="number">0</span><span>:</span><span class="number">1.3</span><span>.</span><span class="number">0</span><span>-9jpp.</span><span class="number">1</span><span>&nbsp;gjdoc.i386&nbsp;</span><span class="number">0</span><span>:</span><span class="number">0.7</span><span>.</span><span class="number">7</span><span>-</span><span class="number">12</span><span>.el5&nbsp;hsqldb.i386&nbsp;</span><span class="number">1</span><span>:</span><span class="number">1.8</span><span>.</span><span class="number">0.9</span><span>-1jpp.</span><span class="number">2</span><span>&nbsp;openoffice.org-calc.i386 &nbsp;&nbsp;</span></span></li>
    <li><span class="number">1</span><span>:</span><span class="number">2.3</span><span>.</span><span class="number">0</span><span>-</span><span class="number">6.5</span><span>.el5&nbsp;openoffice.org-core.i386&nbsp;</span><span class="number">1</span><span>:</span><span class="number">2.3</span><span>.</span><span class="number">0</span><span>-</span><span class="number">6.5</span><span>.el5&nbsp;openoffice.org-draw.i386&nbsp;</span><span class="number">1</span><span>:</span><span class="number">2.3</span><span>.</span><span class="number">0</span><span>-</span><span class="number">6.5</span><span>.el5&nbsp;openoffice.org-graphicfilter.i386&nbsp;</span><span class="number">1</span><span>:</span><span class="number">2.3</span><span>.</span><span class="number">0</span><span>-</span><span class="number">6.5</span><span>.el5&nbsp;openoffice.org-impress.i386 &nbsp;&nbsp;</span></span></li>
    <li><span class="number">1</span><span>:</span><span class="number">2.3</span><span>.</span><span class="number">0</span><span>-</span><span class="number">6.5</span><span>.el5&nbsp;openoffice.org-langpack-zh_CN.i386&nbsp;</span><span class="number">1</span><span>:</span><span class="number">2.3</span><span>.</span><span class="number">0</span><span>-</span><span class="number">6.5</span><span>.el5&nbsp;openoffice.org-langpack-zh_TW.i386&nbsp;</span><span class="number">1</span><span>:</span><span class="number">2.3</span><span>.</span><span class="number">0</span><span>-</span><span class="number">6.5</span><span>.el5&nbsp;openoffice.org-math.i386&nbsp;</span><span class="number">1</span><span>:</span><span class="number">2.3</span><span>.</span><span class="number">0</span><span>-</span><span class="number">6.5</span><span>.el5&nbsp;openoffice.org- &nbsp;&nbsp;</span></span></li>
    <li><span>writer.i386&nbsp;</span><span class="number">1</span><span>:</span><span class="number">2.3</span><span>.</span><span class="number">0</span><span>-</span><span class="number">6.5</span><span>.el5&nbsp;openoffice.org-xsltfilter.i386&nbsp;</span><span class="number">1</span><span>:</span><span class="number">2.3</span><span>.</span><span class="number">0</span><span>-</span><span class="number">6.5</span><span>.el5&nbsp;tomcat5-jsp-</span><span class="number">2.0</span><span>-api.i386&nbsp;</span><span class="number">0</span><span>:</span><span class="number">5.5</span><span>.</span><span class="number">23</span><span>-0jpp.</span><span class="number">7</span><span>.el5&nbsp;tomcat5-servlet-</span><span class="number">2.4</span><span>-api.i386&nbsp;</span><span class="number">0</span><span>:</span><span class="number">5.5</span><span>.</span><span class="number">23</span><span>-0jpp.</span><span class="number">7</span><span>.el5&nbsp;xalan- &nbsp;&nbsp;</span></span></li>
    <li><span>j2.i386&nbsp;</span><span class="number">0</span><span>:</span><span class="number">2.7</span><span>.</span><span class="number">0</span><span>-6jpp.</span><span class="number">1</span><span>&nbsp;xerces-j2.i386&nbsp;</span><span class="number">0</span><span>:</span><span class="number">2.7</span><span>.</span><span class="number">1</span><span>-7jpp.</span><span class="number">2</span><span>&nbsp;xml-commons-apis.i386&nbsp;</span><span class="number">0</span><span>:</span><span class="number">1.3</span><span>.</span><span class="number">02</span><span>-</span><span class="number">0</span><span>.b2.7jpp.</span><span class="number">10</span><span>&nbsp;xml-commons-resolver.i386&nbsp;</span><span class="number">0</span><span>:</span><span class="number">1.1</span><span>-1jpp.</span><span class="number">12</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>Complete!(卸载完成)&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">root@localhost jdk1.6.0_11]# yum -y remove java-1.4.2-gcj-compat-1.4.2.0-40jpp.115
Setting up Remove Process
Resolving Dependencies&#8230;&#8230;&#8230;..(开始卸载)
Removed: java-1.4.2-gcj-compat.i386 0:1.4.2.0-40jpp.115
Dependency Removed: antlr.i386 0:2.7.6-4jpp.2 bsf.i386 0:2.3.0-11jpp.1 bsh.i386 0:1.3.0-9jpp.1 gjdoc.i386 0:0.7.7-12.el5 hsqldb.i386 1:1.8.0.9-1jpp.2 openoffice.org-calc.i386
1:2.3.0-6.5.el5 openoffice.org-core.i386 1:2.3.0-6.5.el5 openoffice.org-draw.i386 1:2.3.0-6.5.el5 openoffice.org-graphicfilter.i386 1:2.3.0-6.5.el5 openoffice.org-impress.i386
1:2.3.0-6.5.el5 openoffice.org-langpack-zh_CN.i386 1:2.3.0-6.5.el5 openoffice.org-langpack-zh_TW.i386 1:2.3.0-6.5.el5 openoffice.org-math.i386 1:2.3.0-6.5.el5 openoffice.org-
writer.i386 1:2.3.0-6.5.el5 openoffice.org-xsltfilter.i386 1:2.3.0-6.5.el5 tomcat5-jsp-2.0-api.i386 0:5.5.23-0jpp.7.el5 tomcat5-servlet-2.4-api.i386 0:5.5.23-0jpp.7.el5 xalan-
j2.i386 0:2.7.0-6jpp.1 xerces-j2.i386 0:2.7.1-7jpp.2 xml-commons-apis.i386 0:1.3.02-0.b2.7jpp.10 xml-commons-resolver.i386 0:1.1-1jpp.12
Complete!(卸载完成)</pre>
<p><br />
下面开始手动安装，我用的安装包是jdk-6u11-linux-i586.bin，没有使用red hat平台通用的rpm包。 <br />
首先，通过ssh将jdk-6u11-linux-i586.bin上传到/home/xjj/soft下。然后，要给jdk-6u11-linux-i586.bin <br />
分配权限，具体的这里要给它可执行的权限，输入：chmod +x jdk-6u11-linux-i586.bin，这里参数x即使执行权限。 <br />
</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://exceljava.javaeye.com/blog/305908#"><img alt="复制代码" src="http://exceljava.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>[root</span><span class="annotation">@localhost</span><span>&nbsp;soft]#&nbsp;chmod&nbsp;+x&nbsp;jdk-6u11-linux-i586.bin&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">[root@localhost soft]# chmod +x jdk-6u11-linux-i586.bin</pre>
<p><br />
<br />
然后解压：./jdk-6u11-linux-i586.bin, <br />
<br />
</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://exceljava.javaeye.com/blog/305908#"><img alt="复制代码" src="http://exceljava.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>[root</span><span class="annotation">@localhost</span><span>&nbsp;soft]#&nbsp;./jdk-6u11-linux-i586.bin&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">[root@localhost soft]# ./jdk-6u11-linux-i586.bin</pre>
<p><br />
<br />
执行之后会有一堆agreement什么的，一路more下去。接着有个确认安装的，输入yes，然后回车。开始解压。一直到 <br />
</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://exceljava.javaeye.com/blog/305908#"><img alt="复制代码" src="http://exceljava.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>Java(TM)&nbsp;SE&nbsp;Development&nbsp;Kit&nbsp;</span><span class="number">6</span><span>&nbsp;successfully&nbsp;installed. &nbsp;&nbsp;</span></span></li>
    <li><span>......... &nbsp;&nbsp;</span></li>
    <li><span>Press&nbsp;Enter&nbsp;to&nbsp;</span><span class="keyword">continue</span><span>..... &nbsp;&nbsp;</span></span></li>
    <li><span>Done.&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">Java(TM) SE Development Kit 6 successfully installed.
.........
Press Enter to continue.....
Done.</pre>
<p><br />
<br />
看看解压后的文件先 <br />
</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://exceljava.javaeye.com/blog/305908#"><img alt="复制代码" src="http://exceljava.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>[root</span><span class="annotation">@localhost</span><span>&nbsp;soft]#&nbsp;ls &nbsp;&nbsp;</span></span></li>
    <li><span>jdk1.</span><span class="number">6</span><span>.0_11&nbsp;jdk-6u11-linux-i586.bin &nbsp;&nbsp;</span></span></li>
    <li><span>[root</span><span class="annotation">@localhost</span><span>&nbsp;soft]#&nbsp;cd&nbsp;jdk1.</span><span class="number">6</span><span>.0_11 &nbsp;&nbsp;</span></span></li>
    <li><span>[root</span><span class="annotation">@localhost</span><span>&nbsp;jdk1.</span><span class="number">6</span><span>.0_11]#&nbsp;ls &nbsp;&nbsp;</span></span></li>
    <li><span>bin&nbsp;db&nbsp;include&nbsp;lib&nbsp;man&nbsp;README_ja.html&nbsp;register.html&nbsp;register_zh_CN.html&nbsp;src.zip &nbsp;&nbsp;</span></li>
    <li><span>COPYRIGHT&nbsp;demo&nbsp;jre&nbsp;LICENSE&nbsp;README.html&nbsp;README_zh_CN.html&nbsp;register_ja.html&nbsp;sample&nbsp;THIRDPARTYLICENSEREADME.txt&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">[root@localhost soft]# ls
jdk1.6.0_11 jdk-6u11-linux-i586.bin
[root@localhost soft]# cd jdk1.6.0_11
[root@localhost jdk1.6.0_11]# ls
bin db include lib man README_ja.html register.html register_zh_CN.html src.zip
COPYRIGHT demo jre LICENSE README.html README_zh_CN.html register_ja.html sample THIRDPARTYLICENSEREADME.txt</pre>
<p><br />
哈哈，看到我们熟悉的东西了吧完成解压。一般都将安装文件放在usr/local下，当然你不这样也拿你没办法。所以，先执行拷贝： <br />
</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://exceljava.javaeye.com/blog/305908#"><img alt="复制代码" src="http://exceljava.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>[root</span><span class="annotation">@localhost</span><span>&nbsp;soft]#&nbsp;mv&nbsp;jdk1.</span><span class="number">6</span><span>.0_11&nbsp;/usr/local &nbsp;&nbsp;</span></span></li>
    <li><span>[root</span><span class="annotation">@localhost</span><span>&nbsp;xjj]#&nbsp;cd&nbsp;../.. &nbsp;&nbsp;</span></span></li>
    <li><span>[root</span><span class="annotation">@localhost</span><span>&nbsp;/]#&nbsp;ls &nbsp;&nbsp;</span></span></li>
    <li><span>bin&nbsp;dev&nbsp;home&nbsp;lost+found&nbsp;misc&nbsp;net&nbsp;proc&nbsp;sbin&nbsp;srv&nbsp;tmp&nbsp;var &nbsp;&nbsp;</span></li>
    <li><span>boot&nbsp;etc&nbsp;lib&nbsp;media&nbsp;mnt&nbsp;opt&nbsp;root&nbsp;selinux&nbsp;sys&nbsp;usr &nbsp;&nbsp;</span></li>
    <li><span>[root</span><span class="annotation">@localhost</span><span>&nbsp;/]#&nbsp;cd&nbsp;/usr/local &nbsp;&nbsp;</span></span></li>
    <li><span>[root</span><span class="annotation">@localhost</span><span>&nbsp;local]#&nbsp;ls &nbsp;&nbsp;</span></span></li>
    <li><span>bin&nbsp;etc&nbsp;games&nbsp;include&nbsp;jdk1.</span><span class="number">6</span><span>.0_11&nbsp;lib&nbsp;libexec&nbsp;sbin&nbsp;share&nbsp;src&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">[root@localhost soft]# mv jdk1.6.0_11 /usr/local
[root@localhost xjj]# cd ../..
[root@localhost /]# ls
bin dev home lost+found misc net proc sbin srv tmp var
boot etc lib media mnt opt root selinux sys usr
[root@localhost /]# cd /usr/local
[root@localhost local]# ls
bin etc games include jdk1.6.0_11 lib libexec sbin share src</pre>
<p><br />
好了，jdk已经成功搬运到了/usr/local下，然后就是最后一步，设置环境变量了。这里有两中设置，一种是通过export设置临时生效，重启 <br />
之后设置会丢失，一种是将设置写入/etc/profile文件中，可以一直生效。所以，最好的设置当然是写入文件中了。先执行下面命令： <br />
</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://exceljava.javaeye.com/blog/305908#"><img alt="复制代码" src="http://exceljava.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>[root</span><span class="annotation">@localhost</span><span>&nbsp;jdk1.</span><span class="number">6</span><span>.0_11]#&nbsp;vi&nbsp;/etc/profile&nbsp;&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">[root@localhost jdk1.6.0_11]# vi /etc/profile </pre>
<p><br />
打开profile文件后输入i进入insert模式，在文件中添加如下内容。 <br />
</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://exceljava.javaeye.com/blog/305908#"><img alt="复制代码" src="http://exceljava.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>export&nbsp;JAVA_HOME=/usr/local/jdk1.</span><span class="number">6</span><span>.0_11 &nbsp;&nbsp;</span></span></li>
    <li><span>export&nbsp;PATH=$PATH:$JAVA_HOME/bin &nbsp;&nbsp;</span></li>
    <li><span>export&nbsp;CLASSPATH=.:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/rt.jar&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">export JAVA_HOME=/usr/local/jdk1.6.0_11
export PATH=$PATH:$JAVA_HOME/bin
export CLASSPATH=.:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/rt.jar</pre>
<p><br />
然后esc，输入:x,保存退出。然后需要设置让更改生效： <br />
</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://exceljava.javaeye.com/blog/305908#"><img alt="复制代码" src="http://exceljava.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>[root</span><span class="annotation">@localhost</span><span>&nbsp;local]#&nbsp;source&nbsp;/etc/profile&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">[root@localhost local]# source /etc/profile</pre>
<p><br />
&nbsp; <br />
<br />
当然，如果你喜欢重启的话，你reboot也可以。 <br />
<br />
好了看看现在的jdk版本吧： <br />
</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://exceljava.javaeye.com/blog/305908#"><img alt="复制代码" src="http://exceljava.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>[root</span><span class="annotation">@localhost</span><span>&nbsp;local]#&nbsp;java&nbsp;-version &nbsp;&nbsp;</span></span></li>
    <li><span>java&nbsp;version&nbsp;&#8220;</span><span class="number">1.6</span><span>.0_11&#8243; &nbsp;&nbsp;</span></span></li>
    <li><span>Java(TM)&nbsp;SE&nbsp;Runtime&nbsp;Environment&nbsp;(build&nbsp;</span><span class="number">1.6</span><span>.0_11-b03) &nbsp;&nbsp;</span></span></li>
    <li><span>Java&nbsp;HotSpot(TM)&nbsp;Client&nbsp;VM&nbsp;(build&nbsp;</span><span class="number">11.0</span><span>-b16,&nbsp;mixed&nbsp;mode,&nbsp;sharing)&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">[root@localhost local]# java -version
java version &#8220;1.6.0_11&#8243;
Java(TM) SE Runtime Environment (build 1.6.0_11-b03)
Java HotSpot(TM) Client VM (build 11.0-b16, mixed mode, sharing)</pre>
<p><br />
</p>
<img src ="http://www.blogjava.net/conans/aggbug/253816.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2009-02-08 21:17 <a href="http://www.blogjava.net/conans/articles/253816.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java程序类加载完全揭密</title><link>http://www.blogjava.net/conans/articles/251110.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Tue, 13 Jan 2009 05:00:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/251110.html</guid><description><![CDATA[<p>类加载是java语言提供的最强大的机制之一。尽管类加载并不是讨论的热点话题，但所有的编程人员都应该了解其工作机制，明白如何做才能让其满足我们的需要。这能有效节省我们的编码时间，从不断调试ClassNotFoundException,
ClassCastException的工作中解脱出来。
<br />
<br />
这篇文章从基础讲起，比如代码与数据的不同之处是什么，他们是如何构成一个实例或对象的。然后深入探讨java虚拟机（JVM）是如何利用类加载器读取代码，以及java中类加载器的主要类型。接着用一个类加载的基本算法看一下类加载器如何加载一个内部类。本文的下一节演示一段代码来说明扩展和开发属于自己的类加载器的必要性。紧接着解释如何使用定制的类加载器来完成一个一般意义上的任务，使其可以加载任意远端客户的代码，在JVM中定义，实例化并执行它。本文包括了J2EE关于类加载的规范——事实上这已经成为了J2EE的标准之一。<br />
&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;&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;&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 />
<strong>类与数据</strong><br />
<br />
一个类代表要执行的代码，而数据则表示其相关状态。状态时常改变，而代码则不会。当我们将一个特定的状态与一个类相对应起来，也就意味着将一个类事例化。尽管相同的类对应的实例其状态千差万别，但其本质都对应着同一段代码。在JAVA中，一个类通常有着一个.class文件，但也有例外。在JAVA的运行时环境中（Java
runtime），每一个类都有一个以第一类(first-class)的Java对象所表现出现的代码，其是java.lang.Class的实例。我们编译一个JAVA文件，编译器都会嵌入一个public,
static,
final修饰的类型为java.lang.Class，名称为class的域变量在其字节码文件中。因为使用了public修饰，我们可以采用如下的形式对其访问：<br />
<br />
</p>
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc">
    <tbody>
        <tr>
            <td>java.lang.Class klass =
            Myclass.class;</td>
        </tr>
    </tbody>
</table>
<br />
一旦一个类被载入JVM中，同一个类就不会被再次载入了（切记，同一个类）。这里存在一个问题就是什么是&#8220;同一个类&#8221;？正如一个对象有一个具体的状态，即标识，一个对象始终和其代码(类)相关联。同理，载入JVM的类也有一个具体的标识，我们接下来看。<br />
<br />
在Java中，一个类用其完全匹配类名(fully
qualified class
name)作为标识，这里指的完全匹配类名包括包名和类名。但在JVM中一个类用其全名和一个加载类ClassLoader的实例作为唯一标识。因此，如果一个名为Pg的包中，有一个名为Cl的类，被类加载器KlassLoader的一个实例kl1加载，Cl的实例，即C1.class在JVM中表示为(Cl,
Pg, kl1)。这意味着两个类加载器的实例(Cl, Pg, kl1) 和 (Cl, Pg,
kl2)是不同的，被它们所加载的类也因此完全不同，互不兼容的。那么在JVM中到底有多少种类加载器的实例？下一节我们揭示答案。<br />
<br />
<strong>类加载器</strong><br />
<br />
在JVM中，每一个类都被java.lang.ClassLoader的一些实例来加载.类ClassLoader是在包中java.lang里，开发者可以自由地继承它并添加自己的功能来加载类。<br />
<br />
无论何时我们键入java
MyMainClass来开始运行一个新的JVM，&#8220;引导类加载器(bootstrap class
loader)&#8221;负责将一些关键的Java类，如java.lang.Object和其他一些运行时代码先加载进内存中。运行时的类在JRE\lib\rt.jar包文件中。因为这属于系统底层执行动作，我们无法在JAVA文档中找到引导类加载器的工作细节。基于同样的原因，引导类加载器的行为在各JVM之间也是大相径庭。<br />
同理，如果我们按照如下方式：<br />
<br />
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc">
    <tbody>
        <tr>
            <td>log(java.lang.String.class.getClassLoader());</td>
        </tr>
    </tbody>
</table>
<p><br />
来获取java的核心运行时类的加载器，就会得到null。<br />
<br />
接下来介绍java的扩展类加载器。扩展库提供比java运行代码更多的特性，我们可以把扩展库保存在由java.ext.dirs属性提供的路径中。<br />
<br />
(编辑注：java.ext.dirs属性指的是系统属性下的一个key，所有的系统属性可以通过System.getProperties()方法获得。在编者的系统中，java.ext.dirs的value是&#8221;
C:\Program
Files\Java\jdk1.5.0_04\jre\lib\ext&#8221;。下面将要谈到的如java.class.path也同属系统属性的一个key。)<br />
<br />
类ExtClassLoader专门用来加载所有java.ext.dirs下的.jar文件。开发者可以通过把自己的.jar文件或库文件加入到扩展目录的classpath，使其可以被扩展类加载器读取。<br />
<br />
从开发者的角度，第三种同样也是最重要的一种类加载器是AppClassLoader。这种类加载器用来读取所有的对应在java.class.path系统属性的路径下的类。<br />
<br />
Sun的java指南中，文章&#8220;理解扩展类加载&#8221;（Understanding
Extension Class
Loading）对以上三个类加载器路径有更详尽的解释，这是其他几个JDK中的类加载器<br />
<br />
●java.net.URLClassLoader
<br />
<br />
●java.security.SecureClassLoader
<br />
<br />
●java.rmi.server.RMIClassLoader
<br />
<br />
●sun.applet.AppletClassLoader <br />
<br />
java.lang.Thread，包含了public
ClassLoader
getContextClassLoader()方法，这一方法返回针对一具体线程的上下文环境类加载器。此类加载器由线程的创建者提供，以供此线程中运行的代码在需要加载类或资源时使用。如果此加载器未被建立，缺省是其父线程的上下文类加载器。原始的类加载器一般由读取应用程序的类加载器建立。</p>
<p>&nbsp;</p>
<p align="center">&nbsp;&nbsp;&nbsp;&nbsp;&lt;二&gt;</p>
<p align="center"><strong>类加载器如何工作？<br />
<br />
</strong>　　除了引导类加载器，所有的类加载器都有一个父类加载器，不仅如此，所有的类加载器也都是java.lang.ClassLoader类型。以上两种类加载器是不同的，而且对于开发者自订制的类加载器的正常运行也至关重要。最重要的方面是正确设置父类加载器。任何类加载器，其父类加载器是加载该类加载器的类加载器实例。（记住，类加载器本身也是一个类！）<br />
<br />
使用loadClass()方法可以从类加载器中获得该类。我们可以通过java.lang.ClassLoader的源代码来了解该方法工作的细节，如下：<br />
<br />
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc">
    <tbody>
        <tr>
            <td>protected synchronized Class&lt;?&gt; loadClass (String name, boolean
            resolve) throws ClassNotFoundException<br />
            {<br />
            // First check if the class is
            already loaded <br />
            Class c = findLoadedClass(name); <br />
            if (c == null)
            <br />
            {<br />
            try <br />
            {<br />
            if (parent != null)<br />
            {<br />
            c =
            parent.loadClass(name, false);<br />
            } else {<br />
            c =
            findBootstrapClass0(name);<br />
            }<br />
            } catch (ClassNotFoundException e) {
            <br />
            // If still not found, then invoke // findClass to find the class.
            <br />
            c = findClass(name);<br />
            }<br />
            }<br />
            if (resolve)
            <br />
            {<br />
            resolveClass(c);<br />
            }<br />
            return
            c;<br />
            }</td>
        </tr>
    </tbody>
</table>
<br />
我们可以使用ClassLoader的两种构造方法来设置父类加载器：<br />
<br />
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc">
    <tbody>
        <tr>
            <td>public class MyClassLoader extends ClassLoader<br />
            {<br />
            public
            MyClassLoader()<br />
            {<br />
            super(MyClassLoader.class.getClassLoader());<br />
            }<br />
            }</td>
        </tr>
    </tbody>
</table>
<br />
或<br />
<br />
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc">
    <tbody>
        <tr>
            <td>public class MyClassLoader extends ClassLoader<br />
            {<br />
            public
            MyClassLoader()<br />
            {<br />
            super(getClass().getClassLoader());<br />
            }<br />
            }</td>
        </tr>
    </tbody>
</table>
<br />
第一种方式较为常用，因为通常不建议在构造方法里调用getClass()方法，因为对象的初始化只是在构造方法的出口处才完全完成。因此，如果父类加载器被正确建立，当要示从一个类加载器的实例获得一个类时，如果它不能找到这个类，它应该首先去访问其父类。如果父类不能找到它(即其父类也不能找不这个类，等等)，而且如果findBootstrapClass0()方法也失败了，则调用findClass()方法。findClass()方法的缺省实现会抛出ClassNotFoundException，当它们继承java.lang.ClassLoader来订制类加载器时开发者需要实现这个方法。findClass()的缺省实现方式如下：<br />
<br />
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc">
    <tbody>
        <tr>
            <td>protected Class&lt;?&gt; findClass(String name) throws
            ClassNotFoundException { throw new ClassNotFoundException(name);
            }</td>
        </tr>
    </tbody>
</table>
<br />
在findClass()方法内部，类加载器需要获取任意来源的字节码。来源可以是文件系统，URL，数据库，可以产生字节码的另一个应用程序，及其他类似的可以产生java规范的字节码的来源。你甚至可以使用BCEL
(Byte Code Engineering
Library：字节码工程库)，它提供了运行时创建类的捷径。BCEL已经被成功地使用在以下方面：编译器，优化器，混淆器，代码产生器及其他分析工具。一旦字节码被检索，此方法就会调用defineClass()方法，此行为对不同的类加载实例是有差异的。因此，如果两个类加载实例从同一个来源定义一个类，所定义的结果是不同的。<br />
<br />
JAVA语言规范（Java
language
specification）详细解释了JAVA执行引擎中的类或接口的加载（loading），链接（linking）或初始化（initialization）过程。<br />
<br />
图一显示了一个主类称为MyMainClass的应用程序。依照之前的阐述，MyMainClass.class会被AppClassLoader加载。
MyMainClass创建了两个类加载器的实例：CustomClassLoader1 和
CustomClassLoader2,他们可以从某数据源（比如网络）获取名为Target的字节码。这表示类Target的类定义不在应用程序类路径或扩展类路径。在这种情况下，如果MyMainClass想要用自定义的类加载器加载Target类，CustomClassLoader1和CustomClassLoader2会分别独立地加载并定义Target.class类。这在java中有重要的意义。如果Target类有一些静态的初始化代码，并且假设我们只希望这些代码在JVM中只执行一次，而这些代码在我们目前的步骤中会执行两次——分别被不同的CustomClassLoaders加载并执行。如果类Target被两个CustomClassLoaders加载并创建两个实例Target1和Target2，如图一显示，它们不是类型兼容的。换句话说，在JVM中无法执行以下代码：<br />
<br />
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc">
    <tbody>
        <tr>
            <td>Target target3 = (Target)
            target2;</td>
        </tr>
    </tbody>
</table>
<br />
以上代码会抛出一个ClassCastException。这是因为JVM把他们视为分别不同的类，因为他们被不同的类加载器所定义。这种情况当我们不是使用两个不同的类加载器CustomClassLoader1
和
CustomClassLoader2，而是使用同一个类加载器CustomClassLoader的不同实例时，也会出现同样的错误。这些会在本文后边用具体代码说明。<br />
<br />
<table width="90%" align="center" border="0">
    <tbody>
        <tr>
            <td>
            <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/364n0268z3zb.JPG" width="449" height="566" /><br />
            <br />
            图1. 在同一个JVM中多个类加载器加载同一个目标类</div>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p align="center">&nbsp;</p>
<p align="center">&lt;三&gt;<br />
<strong>为什么我们需要我们自己的类加载器<br />
<br />
</strong>　　原因之一为开发者写自己的类加载器来控制JVM中的类加载行为，java中的类靠其包名和类名来标识，对于实现了java.io.Serializable接口的类，serialVersionUID扮演了一个标识类版本的重要角色。这个唯一标识是一个类名、接口名、成员方法及属性等组成的一个64位的哈希字段，而且也没有其他快捷的方式来标识一个类的版本。严格说来，如果以上的都匹配，那么则属于同一个类。<br />
<br />
但是让我们思考如下情况：我们需要开发一个通用的执行引擎。可以执行实现某一特定接口的任何任务。当任务被提交到这个引擎，首先需要加载这个任务的代码。假设不同的客户对此引擎提交了不同的任务，凑巧，这些所有的任务都有一个相同的类名和包名。现在面临的问题就是这个引擎是否可以针对不同的用户所提交的信息而做出不同的反应。这一情况在下文的参考一节有可供下载的代码样例，samepath
和 differentversions，这两个目录分别演示了这一概念。 图2 显示了文件目录结构，有三个子目录samepath,
differentversions, 和 differentversionspush，里边是例子：<br />
<br />
<table width="90%" align="center" border="0">
    <tbody>
        <tr>
            <td>
            <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/9l33653u08js.JPG" width="446" height="461" /><br />
            图2.
            文件夹结构组织示例</div>
            </td>
        </tr>
    </tbody>
</table>
<br />
在samepath
中，类version.Version保存在v1和v2两个子目录里，两个类具有同样的类名和包名，唯一不同的是下边这行：<br />
<br />
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc">
    <tbody>
        <tr>
            <td>public void fx(){ log("this = " + this + "; Version.fx(1).");
            }</td>
        </tr>
    </tbody>
</table>
<br />
V1中，日志记录中有Version.fx(1)，而在v2中则是Version.fx(2)。把这个两个存在细微不同的类放在一个classpath下，然后运行Test类：<br />
<br />
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc">
    <tbody>
        <tr>
            <td>set CLASSPATH=.;%CURRENT_ROOT%\v1;%CURRENT_ROOT%\v2<br />
            %JAVA_HOME%\bin\java
            Test</td>
        </tr>
    </tbody>
</table>
<br />
图3显示了控制台输出。我们可以看到对应着Version.fx(1)的代码被执行了，因为类加载器在classpath首先看到此版本的代码。<br />
<br />
<table width="90%" align="center" border="0">
    <tbody>
        <tr>
            <td>
            <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/spb0js0651u8.JPG" width="428" height="193" /><br />
            图3.
            在类路径中samepath测试排在最前面的version
            1</div>
            </td>
        </tr>
    </tbody>
</table>
<br />
再次运行，类路径做如下微小改动。 <br />
<br />
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc">
    <tbody>
        <tr>
            <td>set CLASSPATH=.;%CURRENT_ROOT%\v2;%CURRENT_ROOT%\v1<br />
            %JAVA_HOME%\bin\java
            Test</td>
        </tr>
    </tbody>
</table>
<br />
控制台的输出变为图4。对应着Version.fx(2)的代码被加载，因为类加载器在classpath中首先找到它的路径。<br />
<br />
<table width="90%" align="center" border="0">
    <tbody>
        <tr>
            <td>
            <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/wb8py2r57509.JPG" width="428" height="192" /><br />
            图4.
            在类路径中samepath测试排在最前面的version
            2</div>
            </td>
        </tr>
    </tbody>
</table>
<br />
根据以上例子可以很明显地看出，类加载器加载在类路径中被首先找到的元素。如果我们在v1和v2中删除了version.Version，做一个非version.Version形式的.jar文件，如myextension.jar，把它放到对应java.ext.dirs的路径下，再次执行后看到version.Version不再被AppClassLoader加载，而是被扩展类加载器加载。如图5所示。<br />
<br />
<table width="90%" align="center" border="0">
    <tbody>
        <tr>
            <td>
            <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/rm118409yo66.JPG" width="429" height="158" /><br />
            图5.
            AppClassLoader及ExtClassLoader</div>
            </td>
        </tr>
    </tbody>
</table>
<br />
继续这个例子，文件夹differentversions包含了一个RMI执行引擎，客户端可以提供给执行引擎任何实现了common.TaskIntf接口的任务。子文件夹client1
和 client2包含了类client.TaskImpl有个细微不同的两个版本。两个类的区别在以下几行：<br />
<br />
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc">
    <tbody>
        <tr>
            <td>static<br />
            {<br />
            log("client.TaskImpl.class.getClassLoader (v1) : " +
            TaskImpl.class.getClassLoader());<br />
            }<br />
            <br />
            public void execute(){ log("this =
            " + this + "; execute(1)");
            }</td>
        </tr>
    </tbody>
</table>
<br />
在client1和client2里分别有getClassLoader(v1) 与
execute(1)和getClassLoader(v2) 与
execute(2)的的log语句。并且，在开始执行引擎RMI服务器的代码中，我们随意地将client2的任务实现放在类路径的前面。<br />
<br />
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc">
    <tbody>
        <tr>
            <td>CLASSPATH=%CURRENT_ROOT%\common;%CURRENT_ROOT%\server;<br />
            %CURRENT_ROOT%\client2;%CURRENT_ROOT%\client1<br />
            %JAVA_HOME%\bin\java
            server.Server</td>
        </tr>
    </tbody>
</table>
<br />
如图6，7，8的屏幕截图，在客户端VM，各自的client.TaskImpl类被加载、实例化，并发送到服务端的VM来执行。从服务端的控制台，可以明显看到client.TaskImpl代码只被服务端的VM执行一次，这个单一的代码版本在服务端多次生成了许多实例，并执行任务。<br />
<br />
<table width="90%" align="center" border="0">
    <tbody>
        <tr>
            <td>
            <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/511b346uj8rr.JPG" width="429" height="252" /><br />
            图6.
            执行引擎服务器控制台</div>
            </td>
        </tr>
    </tbody>
</table>
<br />
图6显示了服务端的控制台，加载并执行两个不同的客户端的请求，如图7、8所示。需要注意的是，代码只被加载了一次（从静态初始化块的日志中也可以明显看出），但对于客户端的调用这个方法被执行了两次。<br />
<br />
<table width="90%" align="center" border="0">
    <tbody>
        <tr>
            <td>
            <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/806698qpznjf.JPG" width="429" height="169" /><br />
            图7.
            执行引擎客户端
            1控制台　</div>
            </td>
        </tr>
    </tbody>
</table>
<br />
图7中，客户端VM加载了含有client.TaskImpl.class.getClassLoader(v1)的日志内容的类TaskImpl的代码，并提供给服务端的执行引擎。图8的客户端VM加载了另一个TaskImpl的代码，并发送给服务端。<br />
<br />
<table width="90%" align="center" border="0">
    <tbody>
        <tr>
            <td>
            <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/75d4v3u7sq8y.JPG" width="428" height="169" /><br />
            图8.
            执行引擎客户端
            2控制台　</div>
            </td>
        </tr>
    </tbody>
</table>
<br />
在客户端的VM中，类client.TaskImpl被分别加载，初始化，并发送到服务端执行。图6还揭示了client.TaskImpl的代码只在服务端的VM中加载了一次，但这&#8220;唯一的一次&#8221;却在服务端创造了许多实例并执行。或许客户端1该不高兴了因为并不是它的client.TaskImpl(v1)的方法调用被服务端执行了，而是其他的一些代码。如何解决这一问题？答案就是实现定制的类加载器。<br />
</p>
<p align="center">&lt;四&gt;</p>
<p align="center"><strong>定制类加载器<br />
<br />
</strong>　　要较好地控制类的加载，就要实现定制的类加载器。所有自定义的类加载器都应继承自java.lang.ClassLoader。而且在构造方法中，我们也应该设置父类加载器。然后重写findClass()方法。differentversionspush文件夹包含了一个叫做FileSystemClassLoader的自订制的类加载器。其结构如图9所示。<br />
<br />
<table width="90%" align="center" border="0">
    <tbody>
        <tr>
            <td>
            <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/r5ji48er1w43.JPG" width="400" height="630" /><br />
            图9.
            定制类加载器关系</div>
            </td>
        </tr>
    </tbody>
</table>
<br />
以下是在common.FileSystemClassLoader实现的主方法：<br />
<br />
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc">
    <tbody>
        <tr>
            <td>public byte[] findClassBytes(String
            className)<br />
            {<br />
            try<br />
            {<br />
            String pathName = currentRoot +
            File.separatorChar + className. replace(&#8217;.&#8217;, File.separatorChar) +
            ".class";<br />
            FileInputStream inFile = new FileInputStream(pathName);
            <br />
            byte[] classBytes = new
            byte[inFile.available()];<br />
            inFile.read(classBytes); <br />
            return classBytes;
            <br />
            }<br />
            catch (java.io.IOException ioEx)<br />
            {<br />
            return null;
            <br />
            }<br />
            }<br />
            <br />
            public Class findClass(String name)throws
            ClassNotFoundException<br />
            {<br />
            byte[] classBytes = findClassBytes(name);
            <br />
            if (classBytes==null)<br />
            {<br />
            throw new ClassNotFoundException();<br />
            }
            else{<br />
            return defineClass(name, classBytes, 0,
            classBytes.length);<br />
            }<br />
            }<br />
            <br />
            public Class findClass(String name, byte[]
            classBytes)throws ClassNotFoundException<br />
            {<br />
            if
            (classBytes==null)<br />
            {<br />
            throw new ClassNotFoundException(
            "(classBytes==null)"); <br />
            } else{<br />
            return defineClass(name, classBytes, 0,
            classBytes.length);<br />
            }<br />
            }<br />
            <br />
            public void execute(String codeName,
            byte[] code)<br />
            {<br />
            Class klass = null;<br />
            try<br />
            {<br />
            klass =
            findClass(codeName, code);<br />
            TaskIntf task = (TaskIntf)
            klass.newInstance();<br />
            task.execute();<br />
            } catch(Exception
            exception){<br />
            exception.printStackTrace();<br />
            }<br />
            }</td>
        </tr>
    </tbody>
</table>
<br />
这个类供客户端把client.TaskImpl(v1)转换成字节数组，之后此字节数组被发送到RMI服务端。在服务端，一个同样的类用来把字节数组的内容转换回代码。客户端代码如下：<br />
<br />
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc">
    <tbody>
        <tr>
            <td>public class Client<br />
            {<br />
            public static void main (String[]
            args)<br />
            {<br />
            try{ byte[] code = getClassDefinition ("client.TaskImpl");
            <br />
            serverIntf.execute("client.TaskImpl",
            code);<br />
            }<br />
            catch(RemoteException
            remoteException)<br />
            {<br />
            remoteException.printStackTrace();<br />
            }<br />
            }<br />
            <br />
            private
            static byte[] getClassDefinition (String codeName)<br />
            {<br />
            String userDir =
            System.getProperties(). getProperty("BytePath");<br />
            FileSystemClassLoader fscl1
            = null; <br />
            try<br />
            {<br />
            fscl1 = new FileSystemClassLoader
            (userDir);<br />
            }<br />
            catch(FileNotFoundException
            fileNotFoundException)<br />
            {<br />
            fileNotFoundException.printStackTrace();
            <br />
            }<br />
            return
            fscl1.findClassBytes(codeName);<br />
            }<br />
            }</td>
        </tr>
    </tbody>
</table>
<br />
在执行引擎中，从客户端收到的代码被送到定制的类加载器中。定制的类加载器把其从字节数组定义成类，实例化并执行。需要指出的是，对每一个客户请求，我们用类FileSystemClassLoader的不同实例来定义客户端提交的client.TaskImpl。而且，client.TaskImpl并不在服务端的类路径中。这也就意味着当我们在FileSystemClassLoader调用findClass()方法时，findClass()调用内在的defineClass()方法。类client.TaskImpl被特定的类加载器实例所定义。因此，当FileSystemClassLoader的一个新的实例被使用，类又被重新定义为字节数组。因此，对每个客户端请求类client.TaskImpl被多次定义，我们就可以在相同执行引擎JVM中执行不同的client.TaskImpl的代码。<br />
<br />
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc">
    <tbody>
        <tr>
            <td>public void execute(String codeName, byte[] code)throws
            RemoteException<br />
            {<br />
            FileSystemClassLoader fileSystemClassLoader =
            null;<br />
            try<br />
            {<br />
            fileSystemClassLoader = new
            FileSystemClassLoader();<br />
            fileSystemClassLoader.execute(codeName,
            code);<br />
            }<br />
            catch(Exception exception)<br />
            {<br />
            throw new
            RemoteException(exception.getMessage());
            <br />
            }<br />
            }</td>
        </tr>
    </tbody>
</table>
<br />
示例在differentversionspush文件夹下。服务端和客户端的控制台界面分别如图10，11，12所示：<br />
<br />
<table width="90%" align="center" border="0">
    <tbody>
        <tr>
            <td>
            <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/xt7zup25eyzk.JPG" width="428" height="251" /><br />
            图10.
            定制类加载器执行引擎</div>
            </td>
        </tr>
    </tbody>
</table>
<br />
图10显示的是定制的类加载器控制台。我们可以看到client.TaskImpl的代码被多次加载。实际上针对每一个客户端，类都被加载并初始化。<br />
<br />
<table width="90%" align="center" border="0">
    <tbody>
        <tr>
            <td>
            <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/qjuwm77a3l70.JPG" width="429" height="183" /><br />
            图11.
            定制类加载器，客户端1</div>
            </td>
        </tr>
    </tbody>
</table>
<br />
图11中，含有client.TaskImpl.class.getClassLoader(v1)的日志记录的类TaskImpl的代码被客户端的VM加载，然后送到服务端。图12
另一个客户端把包含有client.TaskImpl.class.getClassLoader(v1)的类代码加载并送往服务端。<br />
<br />
<table width="90%" align="center">
    <tbody>
        <tr>
            <td>
            <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/1dpn2sj8pu1l.JPG" width="427" height="181" /><br />
            图12.
            定制类加载器，客户端1</div>
            </td>
        </tr>
    </tbody>
</table>
<br />
这段代码演示了我们如何利用不同的类加载器实例来在同一个VM上执行不同版本的代码。<br />
<br />
<strong>J2EE的类加载器</strong><br />
<br />
J2EE的服务器倾向于以一定间隔频率，丢弃原有的类并重新载入新的类。在某些情况下会这样执行，而有些情况则不。同样，对于一个web服务器如果要丢弃一个servlet实例，可能是服务器管理员的手动操作，也可能是此实例长时间未相应。当一个JSP页面被首次请求，容器会把此JSP页面翻译成一个具有特定形式的servlet代码。一旦servlet代码被创建，容器就会把这个servlet翻译成class文件等待被使用。对于提交给容器的每次请求，容器都会首先检查这个JSP文件是否刚被修改过。是的话就重新翻译此文件，这可以确保每次的请求都是及时更新的。企业级的部署方案以.ear,
.war,
.rar等形式的文件，同样需要重复加载，可能是随意的也可能是依照某种配置方案定期执行。对所有的这些情况——类的加载、卸载、重新加载&#8230;&#8230;全部都是建立在我们控制应用服务器的类加载机制的基础上的。实现这些需要扩展的类加载器，它可以执行由其自身所定义的类。Brett
Peterson已经在他的文章 Understanding J2EE Application Server Class Loading
Architectures给出了J2EE应用服务器的类加载方案的详细说明，详见网站TheServerSide.com。<br />
<br />
<strong>结束语</strong><br />
<br />
本文探讨了类载入到虚拟机是如何进行唯一标识的，以及类如果存在同样的类名和包名时所产生的问题。因为没有一个直接可用的类版本管理机制，所以如果我们要按自己的意愿来加载类时，需要自己订制类加载器来扩展其行为。我们可以利用许多J2EE服务器所提供的&#8220;热部署&#8221;功能来重新加载一个新版本的类，而不改动服务器的VM。即使不涉及应用服务器，我们也可以利用定制类加载器来控制java应用程序载入类时的具体行为。Ted
Neward的书Server-Based Java Programming中详细阐述java的类加载，J2EE的API以及使用他们的最佳途径。<br />
</p>
<img src ="http://www.blogjava.net/conans/aggbug/251110.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2009-01-13 13:00 <a href="http://www.blogjava.net/conans/articles/251110.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ThreadLocal 的使用</title><link>http://www.blogjava.net/conans/articles/251108.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Tue, 13 Jan 2009 04:58:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/251108.html</guid><description><![CDATA[<p>EasyDBO的数据库连接部分，为了给每个连接提供上下文，程序用到了一个关键的类——ThreadLocal。</p>
<p><strong>什么是ThreadLocal？</strong></p>
<p>顾名思义它是local
variable（线程局部变量）。它的功用非常简单，就是为每一个使用该变量的线程都提供一个变量值的副本，是每一个线程都可以独立地改变自己的副本，而不会和其它线程的副本冲突。从线程的角度看，就好像每一个线程都完全拥有该变量。</p>
<p>使用场景</p>
<ol>
    <li><strong>To keep state with a thread (user-id, transaction-id,
    logging-id)</strong>
    </li>
    <li><strong>To cache objects which you need frequently</strong></li>
</ol>
<p><strong>ThreadLocal类</strong></p>
<p>它主要由四个方法组成initialValue()，get()，set(T)，remove()，其中值得注意的是initialValue()，该方法是一个protected的方法，显然是为了子类重写而特意实现的。该方法返回当前线程在该线程局部变量的初始值，这个方法是一个延迟调用方法，在一个线程第1次调用get()或者set(Object)时才执行，并且仅执行1次。ThreadLocal中的确实实现直接返回一个null：</p>
<p>ThreadLocal的原理</p>
<p>ThreadLocal是如何做到为每一个线程维护变量的副本的呢？其实实现的思路很简单，在ThreadLocal类中有一个Map，用于存储每一个线程的变量的副本。比如下面的示例实现：</p>
<p>public class ThreadLocal<br />
{<br />
private Map values =
Collections.synchronizedMap(new HashMap());<br />
public Object
get()<br />
{<br />
Thread curThread = Thread.currentThread(); <br />
Object o =
values.get(curThread); <br />
if (o == null &amp;&amp;
!values.containsKey(curThread))<br />
{<br />
o =
initialValue();<br />
values.put(curThread, o); <br />
}<br />
return o;
<br />
}</p>
<p>　public void set(Object
newValue)<br />
{<br />
values.put(Thread.currentThread(), newValue);<br />
}</p>
<p>　public Object initialValue()<br />
{<br />
return null; <br />
}<br />
} </p>
<p><strong>ThreadLocal 的使用</strong></p>
<p>使用方法一：</p>
<p>Hibernate的文档时看到了关于使ThreadLocal管理多线程访问的部分。具体代码如下 <br />
<br />
1.&nbsp;&nbsp;public static
final ThreadLocal session = new ThreadLocal(); <br />
2.&nbsp;&nbsp;public static Session
currentSession() { <br />
3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Session s = (Session)session.get();
<br />
4.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//open a new session,if this session has none <br />
5.&nbsp;&nbsp; if(s ==
null){ <br />
6.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s = sessionFactory.openSession(); <br />
7.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.set(s);
<br />
8.&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return s; <br />
9. } <br />
<br />
我们逐行分析 <br />
1。
初始化一个ThreadLocal对象，ThreadLocal有三个成员方法 get()、set()、initialvalue()。
<br />
&nbsp;&nbsp;&nbsp;&nbsp;如果不初始化initialvalue，则initialvalue返回null。
<br />
3。session的get根据当前线程返回其对应的线程内部变量，也就是我们需要的net.sf.hibernate.Session（相当于对应每个数据库连接）.多线程情况下共享数据库链接是不安全的。ThreadLocal保证了每个线程都有自己的s（数据库连接）。
<br />
5。如果是该线程初次访问，自然，s（数据库连接）会是null，接着创建一个Session，具体就是行6。 <br />
6。创建一个数据库连接实例 s
<br />
7。保存该数据库连接s到ThreadLocal中。
<br />
8。如果当前线程已经访问过数据库了，则从session中get()就可以获取该线程上次获取过的连接实例。 </p>
<p>使用方法二</p>
<p>当要给线程初始化一个特殊值时，需要自己实现ThreadLocal的子类并重写该方法，通常使用一个内部匿名类对ThreadLocal进行子类化，EasyDBO中创建jdbc连接上下文就是这样做的：</p>
<p>public class JDBCContext{<br />
&nbsp;private static Logger logger =
Logger.getLogger(JDBCContext.class);<br />
&nbsp;private DataSource ds;<br />
&nbsp;protected
Connection connection;<br />
&nbsp;private boolean isValid = true;<br />
&nbsp;private static
ThreadLocal jdbcContext;<br />
&nbsp;<br />
&nbsp;private JDBCContext(DataSource
ds){<br />
&nbsp;&nbsp;this.ds = ds;<br />
&nbsp;&nbsp;createConnection();&nbsp;&nbsp;<br />
&nbsp;}<br />
&nbsp;public static
JDBCContext getJdbcContext(javax.sql.DataSource
ds)<br />
&nbsp;{&nbsp;&nbsp;<br />
&nbsp;&nbsp;if(jdbcContext==null)jdbcContext=new
JDBCContextThreadLocal(ds);<br />
&nbsp;&nbsp;JDBCContext context = (JDBCContext)
jdbcContext.get();<br />
&nbsp;&nbsp;if (context == null) {<br />
&nbsp;&nbsp;&nbsp;context = new
JDBCContext(ds);<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;return context;<br />
&nbsp;}</p>
<p>&nbsp;private static class JDBCContextThreadLocal extends ThreadLocal
{<br />
&nbsp;&nbsp;public javax.sql.DataSource ds;<br />
&nbsp;&nbsp;public
JDBCContextThreadLocal(javax.sql.DataSource
ds)<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;this.ds=ds;<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;protected synchronized Object
initialValue() {<br />
&nbsp;&nbsp;&nbsp;return new JDBCContext(ds);<br />
&nbsp;&nbsp;}<br />
&nbsp;}<br />
}</p>
<p>使用单例模式，不同的线程调用getJdbcContext()获得自己的jdbcContext，都是通过JDBCContextThreadLocal
内置子类来获得JDBCContext对象的线程局部变量，这个变量是该线程所独有的。</p>
<img src ="http://www.blogjava.net/conans/aggbug/251108.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2009-01-13 12:58 <a href="http://www.blogjava.net/conans/articles/251108.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Classloader 基础</title><link>http://www.blogjava.net/conans/articles/251107.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Tue, 13 Jan 2009 04:56:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/251107.html</guid><description><![CDATA[<p><strong><font face="Verdana">什么是ClassLoader</font></strong></p>
<p>ClassLoader是一个抽象类，我们用它的实例对象来装载类，<font face="宋体">它负责将</font> <span lang="EN-US">Java</span> <span style="font-family: 宋体;">字节码装载到</span>
<span lang="EN-US">JVM</span> <span style="font-family: 宋体;">中，</span>
<span style="font-family: 宋体;">并使其成为</span>
<span lang="EN-US">JVM</span> <span style="font-family: 宋体;">一部分。</span>
<span lang="EN-US">JVM</span> <span style="font-family: 宋体;">的类动态装载技术能够在运行时刻动态地加载或者替换系统的某些功能模块，</span><span style="font-family: 宋体;">而不影响系统其他功能模块的正常运行。</span>一般是通过类名读入一个class文件来装载这个类，（其它加载形式暂时没有研究过）。</p>
<p><strong><font face="Verdana">ClassLoader装载过程</font></strong></p>
<p class="WordPro" style="margin: 5.25pt 0cm 0pt; text-indent: 24pt;"><span style="font-family: 宋体;">类装载就是寻找一个类或是一个接口的字节码文件并通过解析该字节码来构造代表这个类或是这个接口的</span>
<span lang="EN-US">class</span> <span style="font-family: 宋体;">对象的过程。在</span>
<span lang="EN-US">Java</span> <span style="font-family: 宋体;">中，类装载器把一个类装入</span>
<span lang="EN-US">Java</span> <span style="font-family: 宋体;">虚拟机中，要经过三个步骤来完成：装载、链接和初始化，其中链接又可以分成校验、准备和解析三步，除了解析外，其它步骤是严格按照顺序完成的，各个步骤的主要工作如下：</span>
</p>
<p class="WordPro" style="margin: 5.25pt 0cm 0pt 69pt; text-indent: -21pt;"><span lang="EN-US"><span>1.<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><span style="font-family: 宋体;">装载：查找和导入类或接口的字节码；</span>
</p>
<p class="WordPro" style="margin: 5.25pt 0cm 0pt 69pt; text-indent: -21pt;"><span lang="EN-US"><span>2.<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><span style="font-family: 宋体;">链接：执行下面的校验、准备和解析步骤，其中解析步骤是可以选择的；</span>
</p>
<p class="WordPro" style="margin: 5.25pt 0cm 0pt 90pt; text-indent: -21pt;"><span style="font-family: Wingdings;" lang="EN-US"><span>l<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><span style="font-family: 宋体;">校验：检查导入类或接口的二进制数据的正确性；</span>
</p>
<p class="WordPro" style="margin: 5.25pt 0cm 0pt 90pt; text-indent: -21pt;"><span style="font-family: Wingdings;" lang="EN-US"><span>l<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><span style="font-family: 宋体;">准备：给类的静态变量分配并初始化存储空间；</span>
</p>
<p class="WordPro" style="margin: 5.25pt 0cm 0pt 90pt; text-indent: -21pt;"><span style="font-family: Wingdings;" lang="EN-US"><span>l<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><span style="font-family: 宋体;">解析：将符号引用转成直接引用；</span>
</p>
<p class="WordPro" style="margin: 5.25pt 0cm 0pt 69pt; text-indent: -21pt;"><span lang="EN-US"><span>3.<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><span style="font-family: 宋体;">初始化：激活类的静态变量的初始化</span>
<span lang="EN-US">Java</span> <span style="font-family: 宋体;">代码和静态</span>
<span lang="EN-US">Java</span> <span style="font-family: 宋体;">代码块。</span></p>
<p><strong><font face="Verdana">装载的实现</font></strong></p>
<p class="WordPro" style="margin: 5.25pt 0cm 0pt; text-indent: 24pt;"><span lang="EN-US">JVM</span> <span style="font-family: 宋体;">中类的装载是由</span>
<span lang="EN-US">ClassLoader</span> <span style="font-family: 宋体;">和它的子类来实现的。</span>
<span lang="EN-US">Java ClassLoader </span><span style="font-family: 宋体;">是一个重要的</span>
<span lang="EN-US">Java</span> <span style="font-family: 宋体;">运行时系统组件，它负责在运行时查找和装入</span>
<span lang="EN-US">Java</span> <span style="font-family: 宋体;">字节码。</span>
</p>
<p class="WordPro" style="margin: 5.25pt 0cm 0pt; text-indent: 24pt;"><span style="font-family: 宋体;">在</span>
<span lang="EN-US">Java</span> <span style="font-family: 宋体;">中，</span>
<span lang="EN-US">ClassLoader</span> <span style="font-family: 宋体;">是一个抽象类，它在包</span>
<span lang="EN-US">java.lang</span> <span style="font-family: 宋体;">中。可以这样说，只要了解了</span>
<span lang="EN-US">ClassLoader</span> <span style="font-family: 宋体;">中的一些重要的方法，再结合上面所介绍的</span>
<span lang="EN-US">JVM</span> <span style="font-family: 宋体;">中类装载的具体的过程，对动态装载类这项技术就有了一个比较大概的掌握，这些重要的方法包括以下几个：</span>
</p>
<p class="WordPro" style="margin: 5.25pt 0cm 0pt 45pt; text-indent: -21pt;"><span lang="EN-US"><span>1.<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><span lang="EN-US">loadCass</span> <span style="font-family: 宋体;">方法：</span>
<span lang="EN-US">loadClass(String name ,boolean resolve)</span> <span style="font-family: 宋体;">其中</span>
<span lang="EN-US">name</span> <span style="font-family: 宋体;">参数指定了</span>
<span lang="EN-US">JVM</span> <span style="font-family: 宋体;">需要的类的名称</span>
<span lang="EN-US">,</span> <span style="font-family: 宋体;">该名称以类的全限定名表示，如</span>
<span lang="EN-US">Java.lang.Object</span> <span style="font-family: 宋体;">；</span>
<span lang="EN-US">resolve</span> <span style="font-family: 宋体;">参数告诉方法是否需要解析类，在初始化类之前，应考虑类解析，并不是所有的类都需要解析，如果</span>
<span lang="EN-US">JVM</span> <span style="font-family: 宋体;">只需要知道该类是否存在或找出该类的超类，那么就不需要解析。这个方法是</span>
<span lang="EN-US">ClassLoader </span><span style="font-family: 宋体;">的入口点。</span>
</p>
<p class="WordPro" style="margin: 5.25pt 0cm 0pt 45pt; text-indent: -21pt;"><span lang="EN-US"><span>2.<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><span lang="EN-US">defineClass</span> <span style="font-family: 宋体;">方法</span>
<span lang="EN-US"><span>&nbsp; </span></span><span style="font-family: 宋体;">这个方法接受类文件的字节数组并把它转换成</span>
<span lang="EN-US">Class</span> <span style="font-family: 宋体;">对象。字节数组可以是从本地文件系统或网络装入的数据。它把字节码分析成运行时数据结构、校验有效性等等。</span>
</p>
<p class="WordPro" style="margin: 5.25pt 0cm 0pt 45pt; text-indent: -21pt;"><span lang="EN-US"><span>3.<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><span lang="EN-US">findSystemClass</span> <span style="font-family: 宋体;">方法</span>
<span lang="EN-US"><span>&nbsp; </span>findSystemClass</span>
<span style="font-family: 宋体;">方法从本地文件系统装入</span>
<span lang="EN-US">Java</span> <span style="font-family: 宋体;">字节码。它在本地文件系统中寻找类文件，如果存在，就使用</span>
<span lang="EN-US">defineClass</span> <span style="font-family: 宋体;">将字节数组转换成</span>
<span lang="EN-US">Class</span> <span style="font-family: 宋体;">对象。当运行</span>
<span lang="EN-US">Java</span> <span style="font-family: 宋体;">应用程序时</span>
<span lang="EN-US">,</span> <span style="font-family: 宋体;">这是</span>
<span lang="EN-US">JVM </span><span style="font-family: 宋体;">正常装入类的缺省机制。</span>
</p>
<p class="WordPro" style="margin: 5.25pt 0cm 0pt 45pt; text-indent: -21pt;"><span lang="EN-US"><span>4.<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><span lang="EN-US">resolveClass</span> <span style="font-family: 宋体;">方法</span>
<span lang="EN-US">resolveClass(Class c)</span> <span style="font-family: 宋体;">方法解析装入的类，如果该类已经被解析过那么将不做处理。当调用</span>
<span lang="EN-US">loadClass</span> <span style="font-family: 宋体;">方法时</span>
<span lang="EN-US">,</span> <span style="font-family: 宋体;">通过它的</span>
<span lang="EN-US">resolve </span><span style="font-family: 宋体;">参数决定是否要进行解析。</span>
</p>
<p class="WordPro" style="margin: 5.25pt 0cm 0pt 45pt; text-indent: -21pt;"><span lang="EN-US"><span>5.<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><span lang="EN-US">findLoadedClass</span> <span style="font-family: 宋体;">方法</span>
<span lang="EN-US"><span>&nbsp; </span></span><span style="font-family: 宋体;">当调用</span>
<span lang="EN-US">loadClass</span> <span style="font-family: 宋体;">方法装入类时</span>
<span lang="EN-US">,</span> <span style="font-family: 宋体;">调用</span>
<span lang="EN-US">findLoadedClass </span><span style="font-family: 宋体;">方法来查看</span>
<span lang="EN-US">ClassLoader</span> <span style="font-family: 宋体;">是否已装入这个类</span>
<span lang="EN-US">,</span> <span style="font-family: 宋体;">如果已装入</span>
<span lang="EN-US">,</span> <span style="font-family: 宋体;">那么返回</span>
<span lang="EN-US">Class</span> <span style="font-family: 宋体;">对象</span>
<span lang="EN-US">,</span> <span style="font-family: 宋体;">否则返回</span>
<span lang="EN-US">NULL</span> <span style="font-family: 宋体;">。如果强行装载已存在的类</span>
<span lang="EN-US">,</span> <span style="font-family: 宋体;">将会抛出链接错误。</span>
</p>
<p><strong><font face="Verdana">java.lang.Class类</font></strong></p>
<p>某个类的所有实例内部都有一个引用，指向该类对应的Class的实例的位置，每个java类对应的Class实例可以当作是类在内存中的代理人。所以当要获得类的信息(如有哪些类变量,有哪些方法)时，都可以让类对应的Class的实例代劳.java的Reflection机制就大量的使用这种方法来实现。但是Class类无法手工实例化，当载入任意类的时候自动创建一个该类对应的Class的实例。每个java类都是由某个classLoader(ClassLoader的实例)来载入的，因此Class类别的实例中都会他的ClassLoader的实例的引用。可以通过getClass.getClassLoader()得到CLassLoader的实例。</p>
<p><strong><font face="Verdana">java动态载入class的两种方式:</font></strong>
<br />
1)implicit隐式,即利用实例化才载入的特性来动态载入class <br />
2)explicit显式方式,又分两种方式:
<br />
a)java.lang.Class的forName()方法 <br />
b)java.lang.ClassLoader的loadClass()方法</p>
<p><strong><font face="Verdana">各种java类由哪些classLoader加载?</font></strong> </p>
<p>1)java类可以通过实例.getClass.getClassLoader()得到<br />
2)接口由AppClassLoader(SystemClassLoader)载入
，SystemClassLoader：可以由ClassLoader.getSystemClassLoader()获得实例<br />
3)ClassLoader类由bootstrap
loader载入</p>
<p><strong><font face="Verdana">ClassLoader hierachy:</font></strong> </p>
<p>1)jvm初始化产生bootstrap loader。并设定它的父ClassLoader为null</p>
<p>2)bootstrap loader建立AppClassLoader,载入 运行java.exe时
的-cp或-classpath中的类（每个运行中的线程都有一个成员contextClassLoader，用来在运行时动态地载入其它类系统默认的contextClassLoader是systemClassLoader）</p>
<p><shape id="_x0000_i1026" style="width: 331.5pt; height: 148.5pt;" type="#_x0000_t75"><imagedata src="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtml1%3C%21--%20%7E%20Value_txtContent%20%7E%20--%3E3%5Cclip_image003.gif" o:href="http://www.yesky.com/image20010518/159569.gif"><img src="http://www.yesky.com/image20010518/159569.gif"  alt="" /> </imagedata></shape></p>
<p class="a" style="margin: 5.25pt 0cm 0pt;" align="center"><span lang="EN-US">Java</span> <span style="font-family: 宋体;">类装载的代理结构</span>
</p>
<p class="WordPro" style="margin: 5.25pt 0cm 0pt; text-indent: 24pt;"><span style="font-family: 宋体;">根</span>
<span lang="EN-US">(Bootstrap) </span><span style="font-family: 宋体;">装载器：该装载器没有父装载器，它是</span>
<span lang="EN-US">JVM</span> <span style="font-family: 宋体;">实现的一部分，从</span>
<span lang="EN-US">sun.boot.class.path</span> <span style="font-family: 宋体;">装载运行时库的核心代码。</span>
</p>
<p>
</p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;">
</p>
<p>
</p>
<p class="WordPro" style="margin: 5.25pt 0cm 0pt; text-indent: 24pt;"><span style="font-family: 宋体;">扩展</span>
<span lang="EN-US">(Extension) </span><span style="font-family: 宋体;">装载器：继承的父装载器为根装载器，不像根装载器可能与运行时的操作系统有关，这个类装载器是用纯</span>
<span lang="EN-US">Java</span> <span style="font-family: 宋体;">代码实现的，它从</span>
<span lang="EN-US">java.ext.dirs (</span> <span style="font-family: 宋体;">扩展目录</span>
<span lang="EN-US">)</span> <span style="font-family: 宋体;">中装载代码。</span>
</p>
<p>
</p>
<p class="WordPro" style="margin: 5.25pt 0cm 0pt; text-indent: 24pt;"><span style="font-family: 宋体;">系统</span>
<span lang="EN-US">(System or Application) </span><span style="font-family: 宋体;">装载器：装载器为扩展装载器，我们都知道在安装</span>
<span lang="EN-US">JDK</span> <span style="font-family: 宋体;">的时候要设置环境变量</span>
<span lang="EN-US">(CLASSPATH )</span> <span style="font-family: 宋体;">，这个类装载器就是从</span>
<span lang="EN-US">java.class.path(CLASSPATH </span><span style="font-family: 宋体;">环境变量</span>
<span lang="EN-US">)</span> <span style="font-family: 宋体;">中装载代码的，它也是用纯</span>
<span lang="EN-US">Java</span> <span style="font-family: 宋体;">代码实现的，同时还是用户自定义类装载器的缺省父装载器。</span>
</p>
<p class="WordPro" style="margin: 5.25pt 0cm 0pt; text-indent: 24pt;"><span style="font-family: 宋体;">小应用程序</span>
<span lang="EN-US">(Applet) </span><span style="font-family: 宋体;">装载器：父装载器为系统装载器，它从用户指定的网络上的特定目录装载小应用程序代码。</span>
</p>
<p class="WordPro" style="margin: 5.25pt 0cm 0pt; text-indent: 24pt;">java中的<font face="宋体">代理结构</font>是自上而下查找类的，这与很多web装载器不同。</p>
<p>
</p>
<p><strong><font face="Verdana">tomcat中的实现的子ClassLoader的结构</font></strong></p>
<p>Tomcat Server在启动的时候将构造一个ClassLoader树，以保证模块的类库是私有的 <br />
Tomcat
Server的ClassLoader结构如下： <br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img style="vertical-align: middle;" src="http://www.yculblog.com/images/emotions/010.gif" border="0"  alt="" />---------------------------+ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Bootstrap &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|
<br />
&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;| <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| <br />
&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;| <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Common &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| <br />
&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;|
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| &nbsp;&nbsp;&nbsp;&nbsp;Catalina &nbsp;Shared &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| <br />
&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;| <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WebApp1 &nbsp;WebApp2 &nbsp;&nbsp;| <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img style="vertical-align: middle;" src="http://www.yculblog.com/images/emotions/010.gif" border="0"  alt="" />---------------------------+ <br />
<br />
其中： <br />
- Bootstrap -
载入JVM自带的类和$JAVA_HOME/jre/lib/ext/*.jar <br />
- System - 载入$CLASSPATH/*.class <br />
-
Common - 载入$CATALINA_HOME/common/...，它们对TOMCAT和所有的WEB APP都可见 <br />
- Catalina -
载入$CATALINA_HOME/server/...，它们仅对TOMCAT可见，对所有的WEB APP都不可见 <br />
- Shared -
载入$CATALINA_HOME/shared/...，它们仅对所有WEB APP可见，对TOMCAT不可见（也不必见） <br />
- WebApp? -
载入ContextBase?/WEB-INF/...，它们仅对该WEB APP可见 </p>
<p>ClassLoader被组织成树形，一般的工作原理是： <br />
1) 线程需要用到某个类，于是contextClassLoader被请求来载入该类
<br />
2) contextClassLoader请求它的父ClassLoader来完成该载入请求 <br />
3)
如果父ClassLoader无法载入类，则contextClassLoader试图自己来载入
<br />
<br />
<br />
注意：WebApp?ClassLoader的工作原理和上述有少许不同：
<br />
它先试图自己载入类（在ContextBase?/WEB-INF/...中载入类），如果无法载入，再请求父ClassLoader完成 </p>
<img src ="http://www.blogjava.net/conans/aggbug/251107.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2009-01-13 12:56 <a href="http://www.blogjava.net/conans/articles/251107.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>闭包的概念、形式与应用</title><link>http://www.blogjava.net/conans/articles/214469.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Sat, 12 Jul 2008 11:22:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/214469.html</guid><description><![CDATA[<blockquote>随着硬件性能的提升以及编译技术和虚拟机技术的改进，一些曾被性能问题所限制的动态语言开始受到关注，Python、Ruby 和 Lua 等语言都开始在应用中崭露头角。动态语言因其方便快捷的开发方式成为很多人喜爱的编程语言，伴随动态语言的流行，我们经常听到一个名词——闭包，很多人会问闭包是什么？闭包是用来做什么的？本文汇集了有关闭包的概念、应用及其在一些编程语言中的表现形式，以供参考。</blockquote><!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--end RESERVED FOR FUTURE USE INCLUDE FILES-->
<p><a name="1.什么是闭包？"><span class="atitle">什么是闭包？</span></a></p>
<p>闭包并不是什么新奇的概念，它早在高级语言开始发展的年代就产生了。闭包（Closure）是词法闭包（Lexical Closure）的简称。对闭包的具体定义有很多种说法，这些说法大体可以分为两类：</p>
<ul>
    <li>一种说法认为闭包是符合一定条件的函数，比如<a href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#resource" cmimpressionsent="1">参考资源</a>中这样定义闭包：闭包是在其<strong>词法上下文</strong>中引用了<strong>自由变量</strong>(<a href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#note_1" cmimpressionsent="1">注</a> <a href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#note_1" cmimpressionsent="1">1</a>)的函数。
    <li>另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。比如<a href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#resource" cmimpressionsent="1">参考资源</a>中就有这样的的定义：在实现<strong>深约束</strong>(<a href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#note_2" cmimpressionsent="1">注</a> <a href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#note_2" cmimpressionsent="1">2</a>)时，需要创建一个能显式表示<strong>引用环境</strong>的东西，并将它与相关的子程序捆绑在一起，这样捆绑起来的整体被称为闭包。 </li>
</ul>
<p>这两种定义在某种意义上是对立的，一个认为闭包是函数，另一个认为闭包是函数和引用环境组成的整体。虽然有些咬文嚼字，但可以肯定第二种说法更确切。闭包只是在形式和表现上像函数，但实际上不是函数。函数是一些可执行的代码，这些代码在函数被定义后就确定了，不会在执行时发生变化，所以一个函数只有一个实例。闭包在运行时可以有多个实例，不同的引用环境和相同的函数组合可以产生不同的实例。所谓引用环境是指在程序执行中的某个点所有处于活跃状态的约束所组成的集合。其中的约束是指一个变量的名字和其所代表的对象之间的联系。那么为什么要把引用环境与函数组合起来呢？这主要是因为在支持嵌套作用域的语言中，有时不能简单直接地确定函数的引用环境。这样的语言一般具有这样的特性：</p>
<ul>
    <li>函数是一阶值（First-class value），即函数可以作为另一个函数的返回值或参数，还可以作为一个变量的值。
    <li>函数可以嵌套定义，即在一个函数内部可以定义另一个函数。 </li>
</ul>
<p>这些概念上的解释很难理解，显然一个实际的例子更能说明问题。Lua 语言的语法比较接近伪代码，我们来看一段 Lua 的代码：</p>
<br />
<a name="N100A9"><strong>清单 1. 闭包示例1</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">
            function make_counter()
            local count = 0
            function inc_count()
            count = count + 1
            return count
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>end<br />
return inc_countendc1 = make_counter()c2 = make_counter()print(c1())print(c2())</p>
<p>在这段程序中，函数 inc_count 定义在函数 make_counter 内部，并作为 make_counter 的返回值。变量 count 不是 inc_count 内的局部变量，按照最内嵌套作用域的规则，inc_count 中的 count 引用的是外层函数中的局部变量 count。接下来的代码中两次调用 make_counter() ，并把返回值分别赋值给 c1 和 c2 ，然后又依次打印调用 c1 和 c2 所得到的返回值。</p>
<p>这里存在一个问题，当调用 make_counter 时，在其执行上下文中生成了局部变量 count 的实例，所以函数 inc_count 中的 count 引用的就是这个实例。但是 inc_count 并没有在此时被执行，而是作为返回值返回。当 make_counter 返回后，其执行上下文将失效，count 实例的生命周期也就结束了，在后面对 c1 和 c2 调用实际是对 inc_count 的调用，而此处并不在 count 的作用域中，这看起来是无法正确执行的。</p>
<p>上面的例子说明了把函数作为返回值时需要面对的问题。当把函数作为参数时，也存在相似的问题。下面的例子演示了把函数作为参数的情况。</p>
<br />
<a name="N100C1"><strong>清单 2. 闭包示例2</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">
            function do10times(fn)
            for i = 0,9 do
            fn(i)
            end
            end
            sum = 0
            function addsum(i)
            sum = sum + i
            end
            do10times(addsum)
            print(sum)
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>这里我们看到，函数 addsum 被传递给函数 do10times，被并在 do10times 中被调用10次。不难看出 addsum 实际的执行点在 do10times 内部，它要访问非局部变量 sum，而 do10times 并不在 sum 的作用域内。这看起来也是无法正常执行的。</p>
<p>这两种情况所面临的问题实质是相同的。在这样的语言中，如果按照作用域规则在执行时确定一个函数的引用环境，那么这个引用环境可能和函数定义时不同。要想使这两段程序正常执行，一个简单的办法是在函数定义时捕获当时的引用环境，并与函数代码组合成一个整体。当把这个整体当作函数调用时，先把其中的引用环境覆盖到当前的引用环境上，然后执行具体代码，并在调用结束后恢复原来的引用环境。这样就保证了函数定义和执行时的引用环境是相同的。这种由引用环境与函数代码组成的实体就是闭包。当然如果编译器或解释器能够确定一个函数在定义和运行时的引用环境是相同的(<a href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#note_3" cmimpressionsent="1">注</a> <a href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#note_3" cmimpressionsent="1">3</a>)，那就没有必要把引用环境和代码组合起来了，这时只需要传递普通的函数就可以了。现在可以得出这样的结论：闭包不是函数，只是行为和函数相似，不是所有被传递的函数都需要转化为闭包，只有引用环境可能发生变化的函数才需要这样做。</p>
<p>再次观察上面两个例子会发现，代码中并没有通过名字来调用函数 inc_count 和 addsum，所以他们根本不需要名字。以第一段代码为例，它可以重写成下面这样：</p>
<br />
<a name="N100DC"><strong>清单 3. 闭包示例3</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">
            function make_counter()
            local count = 0
            return function()
            count = count + 1
            return count
            end
            end
            c1 = make_counter()
            c2 = make_counter()
            print(c1())
            print(c2())
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>这里使用了匿名函数。使用匿名函数能使代码得到简化，同时我们也不必挖空心思地去给一个不需要名字的函数取名字了。</p>
<p>上面简单地介绍了闭包的原理，更多的闭包相关的概念和理论请参考<a href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#resource" cmimpressionsent="1">参考资源</a>中的"名字，作用域和约束"一章。</p>
<p>一个编程语言需要哪些特性来支持闭包呢，下面列出一些比较重要的条件：</p>
<ul>
    <li>函数是一阶值；
    <li>函数可以嵌套定义；
    <li>可以捕获引用环境，并
    <li>把引用环境和函数代码组成一个可调用的实体；
    <li>允许定义匿名函数； </li>
</ul>
<p>这些条件并不是必要的，但具备这些条件能说明一个编程语言对闭包的支持较为完善。另外需要注意，有些语言使用与函数定义不同的语法来定义这种能被传递的"函数"，如 Ruby 中的 Block。这实际上是语法糖，只是为了更容易定义匿名函数而已，本质上没有区别。</p>
<p>借用一个非常好的说法来做个总结(<a href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#note_4" cmimpressionsent="1">注</a> <a href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#note_4" cmimpressionsent="1">4</a>)：对象是附有行为的数据，而闭包是附有数据的行为。</p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="2.闭包的表现形式"><span class="atitle">闭包的表现形式</span></a></p>
<p>虽然建立在相似的思想之上，各种语言所实现的闭包却有着不同的表现形式，下面我们来看一下闭包在一些常用语言中的表现形式。</p>
<p><a name="N10119"><span class="smalltitle">JavaScript 中的闭包</span></a></p>
<p>JavaScript（ECMAScript）不是通用编程语言，但却拥有较大的用户群体，而 Ajax 的流行也使更多的人关注 JavaScript。虽然在进行 DOM 操作时容易引发循环引用问题，但 JavaScript 语言本身对闭包的支持还是很好的，下面是一个简单的例子：</p>
<br />
<a name="N10125"><strong>清单 4. JavaScript</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">
            function addx(x) {
            return function(y) {return x+y;};
            }
            add8 = addx(8);
            add9 = addx(9);
            alert(add8(100));
            alert(add9(100));
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p><a name="N1012C"><span class="smalltitle">Ruby 中的闭包</span></a></p>
<p>随着 Ruby on Rails 的走红，Ruby 无疑是时下炙手可热的语言之一，Ruby 吸取了很多其他语言的优点，是非常优秀的语言，从这一点来看，很难说清是 Rails 成就了 Ruby 还是 Ruby 成就了 Rails。</p>
<p>Ruby 使用 Block 来定义闭包，Block 在 Ruby 中十分重要，几乎到处都可以看到它的身影，下面的代码就展示了一个 Block：</p>
<br />
<a name="N1013B"><strong>清单 5. Ruby</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">
            sum = 0
            10.times{|n| sum += n}
            print sum
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>10.times 表示调用对象10的 times 方法(<a href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#note_5" cmimpressionsent="1">注</a> <a href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#note_5" cmimpressionsent="1">5</a>)，紧跟在这个调用后面的大括号里面的部分就是Block。所谓 Block 是指紧跟在函数调用之后用大括号或 do/end 括起来的代码，Block 的开始部分（左大括号或 do）必须和函数调用在同一行。Block 也可以接受参数，参数列表必须用两个竖杠括起来放在最前面。Block 会被作为它前面的函数调用的参数，而在这个函数中可以使用关键字 yield 来调用该 Block。在这个例子中，10.times 会以数字0到9为参数调用 Block 10次。</p>
<p>Block 实际上就是匿名函数，它可以被调用，可以捕获上下文。由于语法上要求 Block 必须出现在函数调用的后面，所以 Block 不能直接作为函数的的返回值。要想从一个函数中返回 Block，必须使用 proc 或 lambda 函数把 Block 转化为对象才行。详细内容请参考<a href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#resource" cmimpressionsent="1">参考资源</a>和<a href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#resource_3" cmimpressionsent="1">3</a>。</p>
<p><a name="N10158"><span class="smalltitle">Python 中的闭包</span></a></p>
<p>Python 因其简单易学、功能强大而拥有很多拥护者，很多企业和组织在使用这种语言。Python 使用缩进来区分作用域的做法也十分有特点。下面是一个 Python 的例子：</p>
<br />
<a name="N10164"><strong>清单 6. Python 1</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">
            def addx(x):
            def adder (y): return x + y
            return adder
            add8 = addx(8)
            add9 = addx(9)
            print add8(100)
            print add9(100)
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>在 Python 中使用 def 来定义函数时，是必须有名字的，要想使用匿名函数，则需要使用lambda 语句，象下面的代码这样：</p>
<br />
<a name="N10171"><strong>清单 7. Python 2</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">
            def addx(x):
            return lambda y: x + y
            add8 = addx(8)
            add9 = addx(9)
            print add8(100)
            print add9(100)
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>Python 简单易用且功能强大，关于 Python 的更多信息请参考<a href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#resource" cmimpressionsent="1">参考资源</a>。</p>
<p><a name="N1017F"><span class="smalltitle">Perl 中的闭包</span></a></p>
<p>Perl 是老牌文本处理语言了，在 WEB 开发方面也有一席之地。不过 Perl6 的开发进行比较慢，也许一些用户开始转投其它语言了。下面是一个 Perl 的例子。</p>
<br />
<a name="N1018B"><strong>清单 8. Perl</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">
            sub addx {
            my $x = shift;
            return sub { shift() + $x };
            }
            $add8 = addx(8);
            $add9 = addx(9);
            print $add8-&gt;(100);
            print $add9-&gt;(100);
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p><a name="N10192"><span class="smalltitle">Lua 中的闭包</span></a></p>
<p>Lua 以其小巧和快速的特点受到游戏开发者的青睐，被一些游戏用来定制 UI 或作为插件语言，如果你玩过《魔兽世界》，那你对 Lua 一定不会感到陌生。前面在说明闭包原理时就使用了 Lua，这里就不再给出其他的例子了。更多的内容请参考<a href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#resource" cmimpressionsent="1">参考资源</a>。</p>
<p><a name="N1019F"><span class="smalltitle">Scheme 中的闭包</span></a></p>
<p>Scheme 是 Lisp 的一种方言，被 MIT 用作教学语言。Scheme 属于函数语言，虽然不像命令语言那么流行，却是很多黑客喜欢的语言。很多编程思想起源于函数语言，闭包就是其中之一。一般认为 Scheme 是第一个提供完整闭包支持的语言。下面是一个 Scheme 的例子：</p>
<br />
<a name="N101AB"><strong>清单 9. Scheme</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">
            (define (addx x)
            (lambda (y) (+ y x)))
            (define add8 (addx 8))
            (define add9 (addx 9))
            (add8 100)
            (add9 100)
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>Scheme 的语法非常简单，只是有人觉得写法看起来比较古怪。有关 Scheme 更多信息请参<a href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#resource" cmimpressionsent="1">考参考资源</a>。</p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="3.闭包的应用"><span class="atitle">闭包的应用</span></a></p>
<p>闭包可以用优雅的方式来处理一些棘手的问题，有些程序员声称没有闭包简直就活不下去了。这虽然有些夸张，却从侧面说明闭包有着强大的功能。下面列举了一些闭包应用。</p>
<p><a name="N101C2"><span class="smalltitle">加强模块化</span></a></p>
<p>闭包有益于模块化编程，它能以简单的方式开发较小的模块，从而提高开发速度和程序的可复用性。和没有使用闭包的程序相比，使用闭包可将模块划分得更小。比如我们要计算一个数组中所有数字的和，这只需要循环遍历数组，把遍历到的数字加起来就行了。如果现在要计算所有元素的积呢？要打印所有的元素呢？解决这些问题都要对数组进行遍历，如果是在不支持闭包的语言中，我们不得不一次又一次重复地写循环语句。而这在支持闭包的语言中是不必要的，比如对数组求和的操作在 Ruby 中可以这样做：</p>
<br />
<a name="N101CE"><strong>清单 10. 加强模块化</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">
            nums = [10,3,22,34,17]
            sum = 0
            nums.each{|n| sum += n}
            print sum
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>这种处理方法多少有点像我们熟悉的回调函数，不过要比回调函数写法更简单，功能更强大。因为在闭包里引用环境是函数定义时的环境，所以在闭包里改变引用环境中变量的值，直接就可以反映到它定义时的上下文中，这是通常的回调函数所不能做到的。这个例子说明闭包可以使我们把模块划分得更小。</p>
<p><a name="N101D8"><span class="smalltitle">抽象</span></a></p>
<p>闭包是数据和行为的组合，这使得闭包具有较好抽象能力，下面的代码通过闭包来模拟面向对象编程。函数 make_stack 用来生成 stack 对象，它的返回值是一个闭包，这个闭包作为一个 Dispatcher，当以 &#8220;push&#8221; 或 &#8220;pop&#8221; 为参数调用时，返回一个与函数 push 或 pop 相关联的闭包，进而可以操作 data 中的数据。</p>
<br />
<a name="N101E4"><strong>清单 11. 抽象</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">
            function make_stack()
            local data = {};
            local last = -1;
            local function push(e)
            last = last + 1;
            data[last] = e;
            end
            local function pop()
            if last == -1 then
            return nil
            end
            last = last - 1
            return data[last+1]
            end
            return function (index)
            local tb = {push=push, pop=pop}
            return tb[index]
            end
            end
            s = make_stack()
            s("push")("test0")
            s("push")("test1")
            s("push")("test2")
            s("push")("test3")
            print(s("pop")())
            print(s("pop")())
            print(s("pop")())
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>如果加入一些方便调用&#8220;对象方法&#8221;的语法糖，这看起来很像是面向对象的语法。当然 Lua 中有自己的面向对象语法和机制，所以几乎看不到有人写这样的 Lua 代码，但是对于 Scheme 等没有内建面向对象支持也没有内建复杂数据抽象机制的语言，使用闭包来进行抽象是非常重要的手段。</p>
<p><a name="N101EE"><span class="smalltitle">简化代码</span></a></p>
<p>我们来考虑一个常见的问题。在一个窗口上有一个按钮控件，当点击按钮时会产生事件，如果我们选择在按钮中处理这个事件，那就必须在按钮控件中保存处理这个事件时需要的各个对象的引用。另一种选择是把这个事件转发给父窗口，由父窗口来处理这个事件，或是使用监听者模式。无论哪种方式，编写代码都不太方便，甚至要借助一些工具来帮助生成事件处理的代码框架。用闭包来处理这个问题则比较方便，可以在生成按钮控件的同时就写下事件处理代码。比如在 Ruby 中可以这样写：</p>
<br />
<a name="N101FA"><strong>清单 12. 简化代码</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">
            song = Song.new
            start_button = MyButton.new("Start") { song.play }
            stop_button = MyButton.new("Stop") { song.stop }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p><a name="N10201"><span class="smalltitle">更多</span></a></p>
<p>闭包的应用远不止这些，这里列举的只能算是冰山一角而已，并且更多的用法还不断发现中。要想了解更多的用法，多看一些代码应该是个不错的选择。</p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="4.总结"><span class="atitle">总结</span></a></p>
<p>闭包能优雅地解决很多问题，很多主流语言也顺应潮流，已经或将要引入闭包支持。相信闭包会成为更多人爱不释手的工具。闭包起源于函数语言，也许掌握一门函数语言是理解闭包的最佳途径，而且通过学习函数语言可以了解不同的编程思想，有益于写出更好的程序。</p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/linux/l-cn-closure/?ca=drs-tp2708#main" cmimpressionsent="1"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="5.注解"><span class="atitle">注解</span></a></p>
<ol type="1">
    <li><a name="note_1">自由变量是指除局部变量以外的变量。
    <li><a name="note_2">英文原词是 binding，也有人把它翻译为绑定。
    <li><a name="note_3">一个函数中没有自由变量时，引用环境不会发生变化。
    <li><a name="note_4">出自 Python 社区。
    <li><a name="note_5">在Ruby中一切都是对象，数字也是对象。 </li>
</ol>
</a>
<img src ="http://www.blogjava.net/conans/aggbug/214469.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-12 19:22 <a href="http://www.blogjava.net/conans/articles/214469.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>面试的时候爱问的两道题 </title><link>http://www.blogjava.net/conans/articles/214468.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Sat, 12 Jul 2008 11:21:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/214468.html</guid><description><![CDATA[<p>好久不写技术贴了，决定换一下思维，写个算法相关的。<br />
<br />
最近面试的时候，很喜欢问两个算法问题。<br />
问题1：阿拉伯数字的金额转换为中国传统的汉字形式。<br />
问题2：不增加变量，交换两个数值变量的值。<br />
<br />
先说问题2，因为问题2最简单。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 很显然，要想不增加变量，交换两个变量的值，只可能做加减乘除运算。用对应的加减法或者乘除法都可以做到。举例：a=5；b=8。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;加减： a=a+b=5+8=13；b=a-b=13-8=5；a=a-b=13-5=8；<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a=a-b=5-8=-3；b=a+b=-3+8=5；a=b-a=5-(-3)=8；<br />
&nbsp;&nbsp; 同理，乘除。<br />
我觉得此题主要是考一个人的思维。但是面试的人，大部分都不会做。<br />
<br />
再说问题1：还是大部分人不会做。现提供本人思路如下：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 分析问题：a、小数点之前为整数，小数点后只有两位，为角分。<br />
&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; b、小数点之前个位单位为元，依次为元，十，百，千，万，十万，百万，千万，亿&#8230;&#8230;<br />
&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; c、每位的数字对应为：零、壹、贰、叁、肂、伍、陆、柒、捌、镹。<br />
&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; d、在操作中，数值运算和数组操作性能最快。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 思路：a、用两个数组，array1[10]、array2[]按下标为0、1、&#8230;&#8230;的顺序分别存储零、壹、贰、叁、肂、伍、陆、柒、捌、镹。和元，十，百，千，万，十万，百万，千万，亿&#8230;&#8230;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b、针对整数部分，从十开始除，余数转换为汉字，取对应余数值得数组array1[余数]所对应的值。取得到的商，并记录除的次数。次数对应为array[次数]的汉字。拼接。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c、反复第二步，直道商为0。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; d、其中余位为0时特殊处理。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e、小数点后统一处理两次。不做讲述。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 举例：234.12。整数为234。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 234/10&nbsp; 商23 余4&nbsp; 除次数为0&nbsp; array1[4]+array2[0]=肆元<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 23/10&nbsp;&nbsp;&nbsp; 商2&nbsp;&nbsp; 余3&nbsp; 除次数为1&nbsp; array1[3]+array2[1]=叁拾<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2/10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 商0&nbsp;&nbsp; 余2&nbsp; 除次数为2&nbsp; array1[2]+array2[2]=贰佰<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 合起来就是贰佰叁拾肆元。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;此题考的是拿到问题后的分析思路和基本功。可能每个人的实现方法不一样。可能是紧张吧，面试的时候，大部分人都答不出来。<br />
<br />
</p>
<img src ="http://www.blogjava.net/conans/aggbug/214468.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-12 19:21 <a href="http://www.blogjava.net/conans/articles/214468.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>再次握手log4j </title><link>http://www.blogjava.net/conans/articles/214166.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Fri, 11 Jul 2008 01:13:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/214166.html</guid><description><![CDATA[<span style="color: #003366; font-family: "><span style="font-family: "><span style="font-family: ">由于自己工作性质发生了些变化，人随境迁，回首时，发现真的是岁月如梭，时光如水。弹指间，从研发到维护，从总部到出差已经是四月有余了。</span></span></span>
<p><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体">&nbsp;&nbsp;&nbsp; </span></span><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体">在维护系统时，难免会时不时地跟代码再次打些交道。今天想再操刀做个小工具时，居然不太记得了log4j的配置，不得不从apache再重新down了相关的jar与DOC，匆匆看看了一下，快</span>点写下来，日后肯定还用得着，同时也希望对网友们有用。</span></span></span><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体">&nbsp;</span></span></p>
<p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;&nbsp;&nbsp; Log4j</span></span></span><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">基本上已经是java里的首选日志工具了，它主要由三部分组成：Loggers, Appenders和Layouts (注意后面都加了s啦，顾名思义一个配置中可以分别允许有多个此类对象存在，后面将详细介绍)。<br />
</span></span></span></p>
<p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;&nbsp;&nbsp; Loggers</span></span></span><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">－用来定义日志消息的类型及级别；<br />
</span></span></span></p>
<p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;&nbsp;&nbsp; Appenders</span></span></span><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">－用来定义日志消息的输出终端；<br />
</span></span></span></p>
<p><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp;&nbsp; Layouts</span><span style="color: #003366; font-family: 宋体">－用来定义日志消息的输出格式。</span></span></span></p>
<p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体">&nbsp;&nbsp;</span></span><span style="color: #003366; font-family: 宋体"><br />
&nbsp;&nbsp;&nbsp; </span><strong><span style="font-size: 15pt; color: #003366; font-family: 宋体">Logger</span></strong></p>
<p><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp;&nbsp; <strong>Loggers</strong></span><strong><span style="color: #003366; font-family: 宋体">层次：<br />
</span></strong></p>
<p><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体"><span style="color: #003366; font-family: "><span style="font-size: 10pt; font-family: ">对<span style="font-family: ">logger的名字是大小写敏感。</span></span></span></span></span></p>
<p>
<table style="border-right: medium none; border-top: medium none; background: #b3b3b3; border-left: medium none; border-bottom: medium none; border-collapse: collapse" cellspacing="0" cellpadding="0" border="1">
    <tbody>
        <tr>
            <td style="border-right: windowtext 1pt solid; padding-right: 5.4pt; border-top: windowtext 1pt solid; padding-left: 5.4pt; padding-bottom: 0cm; border-left: windowtext 1pt solid; width: 426.1pt; padding-top: 0cm; border-bottom: windowtext 1pt solid" valign="top" width="568">
            <p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">规则－如果类P的名字是另一个类C的名字的前缀，且P与C之间以&#8220;.&#8221;号连接起来，那么称P为祖先层次；如果层次A与其子层次之间没有任何父层次，则认为层次A为父层次。</span></span></span></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #003366; font-family: 宋体">例如，org.apache.log4j是org.apache.log4j.Logger的父层次；而org.apache是org.apache.log4j与org.apache.log4j.Logger的祖先层次。</span></span></span></p>
<p><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #003366; font-family: 宋体">另外，注意log4j中有个默认的root级别的logger，在所有logger中，它是最高级别，其它所有logger均继承于root，root有以下二个特性：</span></span></span></p>
<p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;&nbsp;&nbsp; 1. </span></span></span><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">它总是存在的。<br />
</span></span></span></p>
<p><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp;&nbsp; 2. </span><span style="color: #003366; font-family: 宋体">它不能通过名字直接获取其实例(root实例可以通过类Logger的静态方法Logger.getRootLogger获得，而其它logger则可以直接通过名字来获取Logger.getLogger)。</span></span></span></p>
<p><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><strong><span style="color: #003366; font-family: 宋体">关于Loggers中的级别：</span></strong></p>
<p><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp;&nbsp;</span><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">对每个logger，可以指定其级别，在系统org.apache.log4j.Level中，已经定义了五个级别，分别为debug, info, warn, error, fatal。</span></span></span></p>
<p>
<table style="border-right: medium none; border-top: medium none; background: #b3b3b3; border-left: medium none; border-bottom: medium none; border-collapse: collapse" cellspacing="0" cellpadding="0" border="1">
    <tbody>
        <tr>
            <td style="border-right: windowtext 1pt solid; padding-right: 5.4pt; border-top: windowtext 1pt solid; padding-left: 5.4pt; padding-bottom: 0cm; border-left: windowtext 1pt solid; width: 426.1pt; padding-top: 0cm; border-bottom: windowtext 1pt solid" valign="top" width="568">
            <p style="margin-left: 5.25pt; text-indent: -5.25pt"><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">规则－设当前logger为X，从X开始往X的父类方向开始算(包括X本身)，直到名为root的logger，第一个不为null的级别值就是X的级别值。</span></span></span></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><strong><span style="color: #003366; font-family: 宋体">日志显示：</span></strong><span style="color: #003366; font-family: 宋体">&nbsp;<span style="font-family: 宋体">&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span></span><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">级别的定义是为了过滤性地选择日志。</span></span></span></p>
<p>
<table style="border-right: medium none; border-top: medium none; background: #b3b3b3; border-left: medium none; border-bottom: medium none; border-collapse: collapse" cellspacing="0" cellpadding="0" border="1">
    <tbody>
        <tr>
            <td style="border-right: windowtext 1pt solid; padding-right: 5.4pt; border-top: windowtext 1pt solid; padding-left: 5.4pt; padding-bottom: 0cm; border-left: windowtext 1pt solid; width: 426.1pt; padding-top: 0cm; border-bottom: windowtext 1pt solid" valign="top" width="568">
            <p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">规则－若当前请方式级别为P，而当前的logger的级别为Q，当且仅当在P&gt;=Q的情况下，日志信息才能显示。</span></span></span></p>
            </td>
        </tr>
    </tbody>
</table>
<span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366; font-family: 宋体"><br />
&nbsp;&nbsp;&nbsp; </span><span style="color: #003366; font-family: 宋体">关于日志中级别的关系为：</span><code><span style="color: #003366">DEBUG &lt; INFO &lt; WARN &lt; ERROR &lt; FATAL</span></code><code><span style="color: #003366">。<br />
</span></code></span></span><span style="font-family: 宋体"><code><span style="color: #003366">&nbsp;&nbsp;&nbsp; </span></code><code><span style="color: #003366">关于此规则的说明，有以下代码为实例：</span></code></span><code><span style="color: #003366">&nbsp;&nbsp;&nbsp; </span></code></p>
<p>
<table style="border-right: medium none; border-top: medium none; background: #b3b3b3; border-left: medium none; border-bottom: medium none; border-collapse: collapse" cellspacing="0" cellpadding="0" border="1">
    <tbody>
        <tr>
            <td style="border-right: windowtext 1pt solid; padding-right: 5.4pt; border-top: windowtext 1pt solid; padding-left: 5.4pt; font-size: 10pt; padding-bottom: 0cm; border-left: windowtext 1pt solid; width: 426.1pt; padding-top: 0cm; border-bottom: windowtext 1pt solid; font-family: Verdana" valign="top" width="568">
            <p style="text-align: left; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt" align="left"><span style="color: #003366; font-family: 宋体">// get a logger instance named "com.foo"</span></p>
            <p style="text-align: left; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt" align="left"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp; Logger&nbsp;logger = Logger.getLogger(<strong>"com.foo"</strong>);</span></p>
            <p style="text-align: left; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt" align="left"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp; // Now set its level. Normally you do not need to set the</span></p>
            <p style="text-align: left; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt" align="left"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp; // level of a logger programmatically. This is usually done</span></p>
            <p style="text-align: left; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt" align="left"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp; // in configuration files.</span></p>
            <p style="text-align: left; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt" align="left"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp; <strong>logger</strong>.setLevel(<strong>Level.INFO</strong>);</span></p>
            <p style="text-align: left; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt" align="left"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp; Logger barlogger = Logger.getLogger(<strong>"com.foo.Bar"</strong>);</span></p>
            <p style="text-align: left; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt" align="left"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp; // This request is enabled, because <strong>WARN</strong> &gt;= <strong>INFO</strong>.</span></p>
            <p style="text-align: left; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt" align="left"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp;logger.<strong>warn</strong>("Low fuel level.");</span></p>
            <p style="text-align: left; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt" align="left"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp; // This request is disabled, because <strong>DEBUG</strong> &lt; <strong>INFO</strong>.</span></p>
            <p style="text-align: left; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt" align="left"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp; logger.<strong>debug</strong>("Starting search for nearest gas station.");</span></p>
            <p style="text-align: left; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt" align="left"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp; // The logger instance barlogger, named "com.foo.Bar",</span></p>
            <p style="text-align: left; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt" align="left"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp; // will inherit its level from the logger named</span></p>
            <p style="text-align: left; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt" align="left"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp; // "com.foo" Thus, the following request is enabled</span></p>
            <p style="text-align: left; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt" align="left"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp; // because <strong>INFO</strong> &gt;= <strong>INFO</strong>.</span></p>
            <p style="text-align: left; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt" align="left"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp; barlogger.<strong>info</strong>("Located nearest gas station.");</span></p>
            <p style="text-align: left; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt" align="left"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp; // This request is disabled, because <strong>DEBUG</strong> &lt; <strong>INFO</strong>.</span></p>
            <p><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp; barlogger.<strong>debug</strong>("Exiting gas station search");</span></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p><strong><span style="font-size: 15pt; color: #003366; font-family: 宋体">Appenders</span></strong><strong><span style="font-size: 15pt; color: #003366; font-family: 宋体">与Layouts</span></strong></p>
<p style="text-indent: 21pt"><span style="font-size: 10pt; font-family: 宋体"><span style="color: #003366; font-family: 宋体">Appender</span><span style="color: #003366; font-family: 宋体">正如前面所述，是用来定义日志信息的输出终端，最觉的输出终端有console与file了，另外还有其它如GUI components, JMS, NT Event Loggers, remote socket servers等等。</span></span></p>
<p><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp;&nbsp; Appender</span><span style="color: #003366; font-family: 宋体">也有类似继承的原则，即当前logger的appender包括其它父类的appender。这样就会出现一个logger可能拥有多个appender了，在现实中看来，就是log4j的日志信息可以同进输出到console, file等等终端了。当然，为了不使此appender恶性叠加，可以通过设置additivity标志来阻止继承。</span></span></span></p>
<p><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #003366; font-family: 宋体">规则－若当前logger为C，则C拥有包括其自己及其父类的所有appender。另外，若C的父logger为P，且P的additivity标志已经设置成为false，则C只拥有自己及P的appender了，而P则只能拥有本身的appender。</span></span></span></p>
<p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体">&nbsp;&nbsp;&nbsp; </span></span><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt; color: #003366; font-family: "><span style="font-family: ">以下表格可以清晰说明此规则：</span><br style="font-family: " />
</span></span></span>&nbsp;&nbsp;&nbsp;&nbsp;
<table cellpadding="10" align="center" border="3">
    <tbody>
        <tr rowspan="2">
            <th style="color: #003366">Logger<br />
            Name
            <th style="color: #003366">Added<br />
            Appenders
            <th style="color: #003366">Additivity<br />
            Flag
            <th style="color: #003366">Output Targets
            <th style="color: #003366">Comment
            <tr>
                <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">root </span></span></span>
                <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">A1 </span></span></span>
                <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">not applicable </span></span></span>
                <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">A1 </span></span></span>
                <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">The root logger is anonymous but can be accessed with the Logger.getRootLogger() method. There is no default appender attached to root. </span></span></span>
                <tr>
                    <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">x </span></span></span>
                    <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">A-x1, A-x2 </span></span></span>
                    <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">true </span></span></span>
                    <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">A1, A-x1, A-x2 </span></span></span>
                    <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">Appenders of "x" and root. </span></span></span>
                    <tr>
                        <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">x.y </span></span></span>
                        <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">none </span></span></span>
                        <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">true </span></span></span>
                        <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">A1, A-x1, A-x2 </span></span></span>
                        <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">Appenders of "x" and root. </span></span></span>
                        <tr>
                            <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">x.y.z </span></span></span>
                            <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">A-xyz1 </span></span></span>
                            <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">true </span></span></span>
                            <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">A1, A-x1, A-x2, A-xyz1 </span></span></span>
                            <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">Appenders in "x.y.z", "x" and root. </span></span></span>
                            <tr>
                                <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">security </span></span></span>
                                <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">A-sec </span></span></span>
                                <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">false </span></span></span>
                                <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">A-sec </span></span></span>
                                <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">No appender accumulation since the additivity flag is set to <code>false</code>. </span></span></span>
                                <tr>
                                    <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">security.access </span></span></span>
                                    <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">none </span></span></span>
                                    <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">true </span></span></span>
                                    <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">A-sec </span></span></span>
                                    <td><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366">Only appenders of "security" because the additivity flag in "security" is set to <code>false</code>.</span></span></span> </td>
                                </tr>
                            </tbody>
                        </table>
                        </span><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;<br />
                        </span><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;对于layout，也正如前面所述，是用来定义日志信息的输出格式，它的与C语言中</span><code><span style="color: #003366">printf</span></code><code><span style="color: #003366">函数的格式定义基本相似，本人对printf中的格式参数不太熟悉，总感觉有些复杂，一般是平时看到自己认为有用的格式就记一下，到时直接搬过来。如<br />
                        </span></code></span></span></p>
                        <p><span style="font-family: 宋体"><span style="font-size: 10pt"><code><span style="color: #003366">log4j.appender.R.layout.ConversionPattern=---&gt;%-d{yyyy-MM-dd HH:mm:ss} [%5p]%l - %m%n<br />
                        </span></code><code><span style="color: #003366"><br />
                        时，日志信息格式为：</span></code></span></span></p>
                        <p><code><span style="color: #003366"><span style="font-family: 宋体"><span style="font-size: 10pt">---&gt;2008-07-11 01:13:40 [ INFO]com.test.Log4jTest.main(Log4jTest.java:27) - Exiting application.</span></span></span></code></p>
                        <p><span style="font-family: 宋体"><span style="font-size: 10pt"><code><span style="color: #003366">&nbsp;&nbsp;&nbsp;&nbsp;<br />
                        </span></code><code><span style="color: #003366">&nbsp;&nbsp;&nbsp;&nbsp;好啦，现在log4j的理论很肤浅地扯了一下，现在可以开始配置了。</span></code></span></span></p>
                        <p><span style="font-family: 宋体"><span style="font-size: 10pt"><code><span style="color: #003366">&nbsp;&nbsp;&nbsp;<span style="font-size: 18pt"><span style="font-family: 宋体"><code><span style="color: #003366"></code><code><span style="color: #003366"><strong>配置：</strong></code></span></span></span></span></span></code></span></span><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp;&nbsp;<br />
                        <br />
                        &nbsp;&nbsp;&nbsp;&nbsp;Log4j</span><span style="color: #003366; font-family: 宋体">的配置可以通过加载Java的properties配置文件或者XML文件来完成。<br />
                        </span></span></span></p>
                        <p><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp;&nbsp; Log4j</span><span style="color: #003366; font-family: 宋体">默认的配置为，通过读取系统变量log4j.configuration来找到配置文件，当然变量的默认值为log4j.properties，所以若没有设置此系统变量，可以直接将配置文件命名为log4j.properties，然后放到类路径下即可。另外，若想引用通过其它配置文件，则可以通过</span></span></span></p>
                        <p style="font-size: 10pt; font-family: 宋体"><span style="font-family: 宋体"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;Loader.getResource(java.lang.String)</span><span style="color: #003366; font-family: 宋体">来读取指定的配置文件。</span></span></p>
                        <p><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><strong><span style="font-size: 15pt; color: #003366; font-family: 宋体">其它：</span></strong></p>
                        <span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span>
                        <p><span style="font-family: 宋体"><span style="font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;1. 由于有了log4j中的级别继承机制，所以可以很方便地过滤信息了，不仅可以很方便地限制日志的输出量，也可以同时将日志输出到不同的终端。<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;另外，因为在java文件中，文件的物理层次关系也是直接通过&#8220;.&#8221;符号来控制的，且在很在程度上这个物理层次也决定了文件的逻辑层次，所以我们在当前文件中获取logger时，可以直接通过当前文件的类名来获取，如：<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;static Logger logger = Logger.getLogger(MyApp.class);<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;这样，在过滤消息时就很简单了，简单示例如下：<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;在配置文件中有<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;log4j.rootLogger=ERROR,stdout,R<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;log4j.category.com.db=DEBUG<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;log4j.category.com.i18n=INFO<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;log4j.category.com.zyx=fatal</span></span></p>
                        <p><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;默认的root logger的日志级别为Error，根据级别关系这个级别也相当高了，这样可以减少系统中日志的输出量，但有些地方可能得输出更详细信息，如数据库部分，所以可以将com.db设置成了debug。另外，我在com.zyx下，我只想看到类型为fatal的日志，也可以如上所设。</span></span></span></p>
                        </span></span></span>
                        <p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体">&nbsp;</span></span></p>
                        <p><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;&nbsp;&nbsp;&nbsp;2. log4j.rootLogger=ERROR,stdout, ROLLING_FILE</span></span></span><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体">这个定义表</span>示root logger的日志级别为Error，后面的stdout, ROLLING_FILE表示此root有二个appender，通常可以通过这样来定义日志可以同时向多个终端输出，因为子logger可以继承所有父logger的appender.</span></span></span></p>
                        <p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;&nbsp;&nbsp;&nbsp;如我可以通过以下定义将日志同时往console及file输出：</span></span></span></p>
                        <p>
                        <table style="border-right: medium none; border-top: medium none; background: #b3b3b3; border-left: medium none; border-bottom: medium none; border-collapse: collapse" cellspacing="0" cellpadding="0" border="1">
                            <tbody>
                                <tr>
                                    <td style="border-right: windowtext 1pt solid; padding-right: 5.4pt; border-top: windowtext 1pt solid; padding-left: 5.4pt; font-size: 10pt; padding-bottom: 0cm; border-left: windowtext 1pt solid; width: 426.1pt; padding-top: 0cm; border-bottom: windowtext 1pt solid; font-family: Verdana" valign="top" width="568">
                                    <p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">log4j.appender.stdout=org.apache.log4j.ConsoleAppender</span></span></span></p>
                                    <p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">log4j.appender.stdout.layout=org.apache.log4j.PatternLayout</span></span></span></p>
                                    <p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">log4j.appender.stdout.layout.ConversionPattern=---&gt;%-d{yyyy-MM-dd HH:mm:ss} [%5p]%l - %m%n</span></span></span></p>
                                    <p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体">&nbsp;</span></span></p>
                                    <p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender</span></span></span></p>
                                    <p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">log4j.appender.ROLLING_FILE.File=myapp.log</span></span></span></p>
                                    <p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">log4j.appender.ROLLING_FILE.Append=true</span></span></span></p>
                                    <p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">log4j.appender.ROLLING_FILE.MaxFileSize=1024KB</span></span></span></p>
                                    <p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">log4j.appender.ROLLING_FILE.MaxBackupIndex=10</span></span></span></p>
                                    <p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout</span></span></span></p>
                                    <p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">log4j.appender.ROLLING_FILE.layout.ConversionPattern==[slf5s.start]%d{DATE}[slf5s.DATE]%n"</span></span></span></p>
                                    <p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;&nbsp; %p[slf5s.PRIORITY]%n%x[slf5s.NDC]%n%t[slf5s.THREAD]%n"</span></span></span></p>
                                    <p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;&nbsp; %c[slf5s.CATEGORY]%n%l[slf5s.LOCATION]%n%m[slf5s.MESSAGE]%n%n</span></span></span></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        </p>
                        <p><span style="color: #003366; font-family: 宋体"><span style="font-family: 宋体">&nbsp;</span></span></p>
                        <p><span style="font-family: 宋体"><span style="font-size: 10pt"><span style="color: #003366; font-family: 宋体">&nbsp;&nbsp;&nbsp; </span><span style="color: #003366; font-family: 宋体">马马虎虎总结了一下，但也花费了二个多小时，呵呵！</span></span></span></p>
<img src ="http://www.blogjava.net/conans/aggbug/214166.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-11 09:13 <a href="http://www.blogjava.net/conans/articles/214166.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一批不错的BUG跟踪系统，值得大家采纳使用 </title><link>http://www.blogjava.net/conans/articles/214087.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Thu, 10 Jul 2008 11:26:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/214087.html</guid><description><![CDATA[<div class="t_msgfont" id="message8876"><img height="14" alt="" src="http://www.open-open.com/image/item.gif" width="13" border="0" /> <a href="http://www.open-open.com/open37963.htm" target="_blank"><font color="#0000ff">ITracker</font></a> ITracker基于J2EE的issue/bug跟踪系统，支持多用户、多项目、邮件通知等.<br />
<br />
<img height="14" alt="" src="http://www.open-open.com/image/item.gif" width="13" border="0" /> <a href="http://www.open-open.com/open71963.htm" target="_blank"><font color="#0000ff">Scarab</font></a>&nbsp;&nbsp;<font face="宋体 "><font size="2">Scarab是一个非常灵活的issue管理系统.它具有以下特点:<br />
1.其它系统一样都具有的特点:数据的输入,查询,报告,通知到相关的当事人,注释的协作积累,依赖追踪等.<br />
2.Scarab通过一组管理页面可无限制地,自由地定制模块的数量,Artifact类型,(Attribute)属性(比如:操作系统,状态,优先权等),(Attribute)属性选择权等.<br />
3.多语言支持(包括中文zh)<br />
4.Scarab采用turbine框架实现,安装容易,速度快,具备可伸缩性和可维护性.<br />
5.通过XML提供导入/导出接口以便从其它追踪系统(如:Bugzilla)移植过来.<br />
6.模块化代码设计<br />
7.可以很容易地更改用户界面外观.<br />
8.Scarab可与较大的系统相结合.</font></font><br />
<img height="14" alt="" src="http://www.open-open.com/image/item.gif" width="13" border="0" /> <a href="http://www.open-open.com/open101663.htm" target="_blank"><font color="#0000ff">ELIPS</font></a>&nbsp; &nbsp;ELIPS是一个能够让用户管理不同类别问题(issues)的Bug追踪工具.这些问题(issues)包括:bug修改请求,任务处理请求,工作处理请求,增进请求.Elips采用java与jsp技术开发,到目前为止可运行在Tomcat/Jetty,MySQL/SqlServer/Oracle/Postgresql和Windows/Linux/MacOs X 平台上.ELIPS安装与配置都很容易.<br />
<br />
<img height="14" alt="" src="http://www.open-open.com/image/item.gif" width="13" border="0" /> <a href="http://www.open-open.com/open101763.htm" target="_blank"><font color="#0000ff">Bugtracker</font></a>&nbsp; &nbsp;Bugtracker是一个完整的bug/issue管理系统.它使用Java Servlet作为web前台,MySQL数据库作为后台.<br />
<br />
<img height="14" alt="" src="http://www.open-open.com/image/item.gif" width="13" border="0" /> <a href="http://www.open-open.com/open103163.htm" target="_blank"><font color="#0000ff">BugRat</font></a>&nbsp; &nbsp;BugRat是一个免费的Java软件它提供一个成熟的,灵活的Bug报告与跟踪系统。它利用关系数据来存储数据，既可以通过web来报告Bug也可以通过email报告Bug,可通过web来浏览和查询Bug.BugRat还包括一个Java客户端来管理数据库。<br />
<br />
<img height="14" alt="" src="http://www.open-open.com/image/item.gif" width="13" border="0" /> <a href="http://www.open-open.com/open103263.htm" target="_blank"><font color="#0000ff">Abuky</font></a>&nbsp;&nbsp;Abuky利用Jsp开发的Bug追踪系统。<br />
<br />
<img height="14" alt="" src="http://www.open-open.com/image/item.gif" width="13" border="0" /> <a href="http://www.open-open.com/open105963.htm" target="_blank"><font color="#0000ff">TrackIt</font></a>&nbsp; &nbsp;TrackIt是一个基于Web的项目追踪工具.对开发人员来它整体都设计得很灵活,无限制定义工程项目类型而且很实用.它内置支持XP极限编程构建而且可以很好地与CVS，Subversion相结合. TrackIt通过HQL支持简单列表并通过SQL来支持高级报表。<br />
<br />
<img height="14" alt="" src="http://www.open-open.com/image/item.gif" width="13" border="0" /> <a href="http://www.open-open.com/open106463.htm" target="_blank"><font color="#0000ff">jTrac</font></a>&nbsp; &nbsp;jTrac是一个基于Web的issue追踪系统内置工作流.你可自定义字段来追究项目和分配任务等.jTrac采用Spring MVC, Spring AOP和Spring JDBC/DAO框架,JSP/JSTL作为视图.<br />
<br />
<img height="14" alt="" src="http://www.open-open.com/image/item.gif" width="13" border="0" /> <a href="http://www.open-open.com/open119763.htm" target="_blank"><font color="#0000ff">Bugzilla</font></a>&nbsp; &nbsp;Bugzilla是一个Bug追踪系统设计用来帮助你管理软件开发。<br />
<br />
<img height="14" alt="" src="http://www.open-open.com/image/item.gif" width="13" border="0" /> <a href="http://www.open-open.com/open150463.htm" target="_blank"><font color="#0000ff">JTrac</font></a>&nbsp; &nbsp;JTrac是一个基于Spring,Spring WebFlow,Acegi和Hibernate开发的缺陷跟踪Web应用程序。它的特性包括：自定义工作流，权限控制，e-mail集成，文件附件，详细历史记录查询。<br />
<br />
<img height="14" alt="" src="http://www.open-open.com/image/item.gif" width="13" border="0" /> <a href="http://www.open-open.com/open182363.htm" target="_blank"><font color="#0000ff">Project Dune</font></a>&nbsp; &nbsp;Project Dune是一个集成源代码控制系统(能够用浏览器检查源代码)，基于Web的Bug跟踪系统。该项目的目标是使整个开发过程从评估到发布变成自动化。</div>
<br style="clear: both" />
<img src ="http://www.blogjava.net/conans/aggbug/214087.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-10 19:26 <a href="http://www.blogjava.net/conans/articles/214087.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDK 6 Update 7 携手 VisualVM 1.0 发布 </title><link>http://www.blogjava.net/conans/articles/214077.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Thu, 10 Jul 2008 11:15:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/214077.html</guid><description><![CDATA[VisualVM伴随着JDK 6 Update 7发布了，JDK中又内置了一个不可多的实用工具。VisualVM简单说是一个整合了几个JDK命令行工具的可视化工具，具有一定的profiling能力，针对生产环境和开发环境设计，提供了远程和本地访问途径，帮助监控Java SE平台并提供性能分析的能力。通过执行&lt;jdk-home&gt;/bin/jvisualvm可以启动VisualVM。<br />
<br />
监控内存使用情况。<br />
<img height="393" alt="" src="https://visualvm.dev.java.net/images/monitor.png" width="600" /><br />
<br />
<img src ="http://www.blogjava.net/conans/aggbug/214077.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-10 19:15 <a href="http://www.blogjava.net/conans/articles/214077.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> JAVA操作大型文本文件</title><link>http://www.blogjava.net/conans/articles/213757.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Wed, 09 Jul 2008 11:14:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/213757.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;在前面的废话不想看的可以skip-----由于工作需要，经常需要打开和查询250M左右的文本文件（总行数超过250万行）分析日志，公司发的笔记本内存才512M，地球人都知道，这样的电脑根本不能胜任。不知道有没有人和我一样倒霉，面对这么庞大的文件，曾经让我很无奈，很彷徨。从寻找优秀的类似notepad这样的文本工具，企图通过工具来提高下速度，其中JIURL这个记事本工具，我个人觉得很好，...&nbsp;&nbsp;<a href='http://www.blogjava.net/conans/articles/213757.html'>阅读全文</a><img src ="http://www.blogjava.net/conans/aggbug/213757.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-09 19:14 <a href="http://www.blogjava.net/conans/articles/213757.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>分享J2EE学习的20个网站 </title><link>http://www.blogjava.net/conans/articles/213753.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Wed, 09 Jul 2008 11:09:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/213753.html</guid><description><![CDATA[<p style="text-indent: 21pt"><span style="font-family: 宋体">前人栽树，后人乘凉。想当初自己初学</span>Java<span style="font-family: 宋体">时为了解决一个很基础的问题，好多的朋友热心的回复我，帮我分析错误。现在为了方便那些</span>Java<span style="font-family: 宋体">新手，特给出自己感觉比较好的学习网站和论坛，希望对朋友们能有点帮助。</span><span><br />
1,<a href="http://www.javaeye.com/">http://www.javaeye.com/</a>&nbsp;&nbsp; &nbsp;</span><span style="font-family: 宋体">由</span>Robbin<span style="font-family: 宋体">创建发起的技术网站，人气相当旺，有不少牛人。最初是以讨论</span>Java<span style="font-family: 宋体">技</span>&nbsp;&nbsp; &nbsp;<span style="font-family: 宋体">术和</span>Hibernate<span style="font-family: 宋体">技术开始的技术论坛，现在已经成为一个涵盖整个软件开发领域的综合性网站，</span>2005<span style="font-family: 宋体">年被选为中国十佳技术网站之一。</span><span><br />
2,<a href="http://www.ibm.com/developerworks/cn/java/">http://www.ibm.com/developerworks/cn/java/</a>&nbsp;&nbsp; </span><span style="font-family: 宋体">著名的</span>IBM Developer Works<span style="font-family: 宋体">。涵盖各种技术。</span><span><br />
3,<a href="http://dev2dev.bea.com.cn/">http://dev2dev.bea.com.cn/</a>&nbsp;&nbsp; &nbsp;IBM</span><span style="font-family: 宋体">和</span>BEA<span style="font-family: 宋体">都在主推</span>Java<span style="font-family: 宋体">应用。它们的技术网站中有不少关于</span>Java<span style="font-family: 宋体">的好文章。</span><span><br />
4,<a href="http://java.csdn.net/">http://java.csdn.net/</a>&nbsp;&nbsp; &nbsp;CSDN</span><span style="font-family: 宋体">，名气大到不需介绍。</span><span><br />
5,<a href="http://www.blogjava.net/creasure/archive/2008/">http://www.blogjava.net/</a>&nbsp;&nbsp; &nbsp;</span><span style="font-family: 宋体">这个地方集聚了不少好的</span>Java<span style="font-family: 宋体">博客。</span><span><br />
6,<a href="http://www.j2medev.com/">http://www.j2medev.com/</a>&nbsp;&nbsp; &nbsp;</span><span style="font-family: 宋体">这个网站主要关注</span>J2ME<span style="font-family: 宋体">，是目前国内</span>J2ME<span style="font-family: 宋体">较活跃的社区。</span><span><br />
7,<a href="http://www.javaresearch.org/">http://www.javaresearch.org/</a>&nbsp;&nbsp; &nbsp;</span><span style="font-family: 宋体">有很多不错的文章和资源。</span><span><br />
8,<a href="http://www.matrix.org.cn/">http://www.matrix.org.cn</a>&nbsp;&nbsp; JSP/Servlet</span><span style="font-family: 宋体">集中营！</span><span><br />
9,<a href="http://www.javaworld.com.tw/jute/">http://www.javaworld.com.tw/jute/</a>&nbsp;&nbsp; JavaWorld</span><span style="font-family: 宋体">台湾论坛。</span></p>
<p><span>10,<a href="http://bbs.chinajavaworld.com/index.jspa">http://bbs.chinajavaworld.com/index.jspa</a> </span><span style="font-family: 宋体">中国</span>javaWorld<span style="font-family: 宋体">论坛。</span></p>
<p><span>11,<a href="http://www.java-cn.com/">http://www.java-cn.com/</a> Java</span><span style="font-family: 宋体">中文站，资料比较全而丰富。</span></p>
<p><span>12,<a href="http://www.eclipseworld.org/bbs/index.php"> http://www.eclipseworld.org/bbs/index.php</a> &nbsp;</span><span style="font-family: 宋体">中国</span>eclipse<span style="font-family: 宋体">社区。如果</span>eclipse<span style="font-family: 宋体">都用不好的话，怎么能更有效地开发出好东西呢？工欲善其事，必先利其器嘛。</span></p>
<p><span>13, <a href="http://jboss.csdn.net/">http://jboss.csdn.net/</a> &nbsp;Jboss</span><span style="font-family: 宋体">依托</span>csdn<span style="font-family: 宋体">的中文社区。</span>Jboss<span style="font-family: 宋体">前段时间在中国力挺</span>Jboss<span style="font-family: 宋体">，上边有很多人的分享心得，值得一看。</span></p>
<p><span>14,<a href="http://www.cnpaf.net/">http://www.cnpaf.net/</a> &nbsp;</span><span style="font-family: 宋体">不懂网络协议怎么能精通网络开发？协议方面不懂或者有什么不明白的问题就上这里吧。</span></p>
<p>15,<a href="http://www.ourjava.net/index.php">http://www.ourjava.net/index.php</a> &nbsp;<span style="font-family: 宋体">一个众多资料分享的论坛。还包含了很多游戏，源码等。</span></p>
<p>16, <a href="http://www.pconline.com.cn/pcedu/empolder/gj/java/index.html">http://www.pconline.com.cn/pcedu/empolder/gj/java/index.html</a>&nbsp;</p>
<p style="text-indent: 21pt"><span style="font-family: 宋体">太平洋电脑网上的</span>java<span style="font-family: 宋体">学习专区。值得推荐的是不用注册不用付费，所有的文本资料和视频资料都是免费的！并且视频资料都做成了</span>flash,<span style="font-family: 宋体">容量更小！下载很方便哦</span></p>
<p><span>17,<a href="http://www.chinaitlab.com/www/techspecial/struts/"> http://www.chinaitlab.com/www/techspecial/struts/</a> </span><span style="font-family: 宋体">中国</span>IT<span style="font-family: 宋体">实验室的</span>struts<span style="font-family: 宋体">学习版块，类容精而全！学习</span>struts<span style="font-family: 宋体">的好地方。</span></p>
<p>18, <a href="http://developers.sun.com.cn/">http://developers.sun.com.cn/</a>&nbsp;Sun<span style="font-family: 宋体">技术社区，</span>java<span style="font-family: 宋体">出自</span>sun,<span style="font-family: 宋体">人气可想而之，气氛很活跃。</span></p>
<p><span>19, <a href="http://www.pgsqldb.org/mwiki/index.php">http://www.pgsqldb.org/mwiki/index.php </a>&nbsp;postgre</span><span style="font-family: 宋体">的官方维基百科。</span><span><br />
20, </span><span style="font-family: 宋体">针对教育网朋友，推荐名校的</span>BBS<span style="font-family: 宋体">。学生刚起步，讨论的知识虽然比较基础，但是气氛很热烈，有问题回复速度很快。</span><span><br />
</span></p>
<img src ="http://www.blogjava.net/conans/aggbug/213753.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-09 19:09 <a href="http://www.blogjava.net/conans/articles/213753.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一次Java垃圾收集调优实战</title><link>http://www.blogjava.net/conans/articles/213752.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Wed, 09 Jul 2008 11:07:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/213752.html</guid><description><![CDATA[<h3>1 资料</h3>
<ul>
    <li><span class="nobr"><a title="Visit page outside Confluence" href="http://calvin.javaeye.com/blog/91905" rel="nofollow" mce_href="http://calvin.javaeye.com/blog/91905" linktype="raw" linktext="JDK5.0垃圾收集优化之--Don't Pause(花钱的年华)|http://calvin.javaeye.com/blog/91905">JDK5.0垃圾收集优化之--Don't Pause(花钱的年华)<sup><img class="rendericon" height="7" alt="" src="http://wiki.springside.org.cn/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" mce_src="http://www.blogjava.net/images/icons/linkext7.gif" /></sup></a></span>&#8201;
    <li><span class="nobr"><a title="Visit page outside Confluence" href="http://calvin.javaeye.com/blog/91903" rel="nofollow" mce_href="http://calvin.javaeye.com/blog/91903" linktype="raw" linktext="编写对GC友好，又不泄漏的代码(花钱的年华)|http://calvin.javaeye.com/blog/91903">编写对GC友好，又不泄漏的代码(花钱的年华)<sup><img class="rendericon" height="7" alt="" src="http://wiki.springside.org.cn/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" mce_src="http://www.blogjava.net/images/icons/linkext7.gif" /></sup></a></span>&#8201;
    <li><span class="nobr"><a title="Visit page outside Confluence" href="http://pengjiaheng.spaces.live.com/blog/cns%212DAA368B386E6AEA%21770.entry" rel="nofollow" mce_href="http://pengjiaheng.spaces.live.com/blog/cns%212DAA368B386E6AEA%21770.entry" linktype="raw" linktext="JVM调优总结|http://pengjiaheng.spaces.live.com/blog/cns!2DAA368B386E6AEA!770.entry">JVM调优总结<sup><img class="rendericon" height="7" alt="" src="http://wiki.springside.org.cn/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" mce_src="http://www.blogjava.net/images/icons/linkext7.gif" /></sup></a></span>&#8201;
    <li><span class="nobr"><a title="Visit page outside Confluence" href="http://www.md.pp.ru/%7Eeu/jdk6options.html" rel="nofollow" mce_href="http://www.md.pp.ru/%7Eeu/jdk6options.html" linktype="raw" linktext="JDK 6所有选项及默认值|http://www.md.pp.ru/~eu/jdk6options.html">JDK 6所有选项及默认值<sup><img class="rendericon" height="7" alt="" src="http://wiki.springside.org.cn/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" mce_src="http://www.blogjava.net/images/icons/linkext7.gif" /></sup></a></span>&#8201; </li>
</ul>
<h3>2 GC日志打印</h3>
<p>&nbsp; GC调优是个很实验很伽利略的活儿，GC日志是先决的数据参考和最终验证：</p>
<div class="macro" macrotext="{code}" command="code">
<div class="code">
<div class="codeContent">
<pre class="code-java">-XX:+PrintGCDetails -XX:+PrintGCTimeStamps(GC发生的时间) -XX:+PrintGCApplicationStoppedTime(GC消耗了多少时间) -XX:+PrintGCApplicationConcurrentTime(GC之间运行了多少时间)</pre>
</div>
</div>
</div>
<p>&#8201;</p>
<h3><a class="" style="background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&file=anchor.gif); width: 20px; text-indent: 20px; background-repeat: no-repeat; height: 20px" name="JavaPerformance-1.3收集器选择"></a>3 收集器选择</h3>
<h4><a class="" style="background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&file=anchor.gif); width: 20px; text-indent: 20px; background-repeat: no-repeat; height: 20px" name="JavaPerformance-CMS收集器：暂停时间优先"></a>CMS收集器：暂停时间优先</h4>
<p>&nbsp;&nbsp; 配置参数：-XX:+UseConcMarkSweepGC<br />
&nbsp;&nbsp; 已默认无需配置的参数：-XX:+UseParNewGC(Parallel收集新生代) -XX:+CMSPermGenSweepingEnabled(CMS收集持久代) -XX:UseCMSCompactAtFullCollection(FullGC时压缩年老代)</p>
<p>&nbsp;&nbsp; 初始效果：1G堆内存的新生代约60m，minor gc约5-20毫秒，full gc约130毫秒。</p>
<h4><a class="" style="background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&file=anchor.gif); width: 20px; text-indent: 20px; background-repeat: no-repeat; height: 20px" name="JavaPerformance-Parallel收集器：吞吐量优先"></a>Parallel收集器：吞吐量优先</h4>
<p>&nbsp;&nbsp;&nbsp; 配置参数： -XX:+UseParallelGC -XX:+UseParallelOldGC(Parallel收集年老代，从JDK6.0开始支持)</p>
<p>&nbsp;&nbsp;&nbsp; 已默认无需配置的参数： -XX:+UseAdaptiveSizePolicy(动态调整新生代大小)</p>
<p>&nbsp;&nbsp;&nbsp; 初始效果：1G堆内存的新生代约90-110m(动态调整)，minor gc约5-20毫秒，full gc没有UseParallelOldGC 参数约 1.3秒，有UseParallelOldGC参数约1.06秒，差别不大。</p>
<p>&nbsp;&nbsp;&nbsp; 另外-XX:MaxGCPauseMillis=100 设置期望minor gc的最大时间，JVM会以此来调整新生代的大小，但在此测试环境中对象死的太快，此参数作用不大。</p>
<h3><a class="" style="background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&file=anchor.gif); width: 20px; text-indent: 20px; background-repeat: no-repeat; height: 20px" name="JavaPerformance-1.4调优实战"></a>4 调优实战</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Parallel收集高达1秒的暂停时间基本不可忍受，所以选择CMS收集器。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不知为何在被压的Mule 2.0应用里，每秒都有大约400M的海量短命对象产生：</p>
<ol>
    <li>因为默认60M的新生代太小了，频繁发生minor gc，大约0.2秒就进行一次。
    <li>因为CMS收集器中MaxTenuringThreshold(生代对象撑过过多少次minor gc才进入年老代的设置)默认0，存活的临时对象不经过Survivor区直接进入年老代，不久就占满年老代发生full gc。 </li>
</ol>
<p>&nbsp; &nbsp;&nbsp; 对这两个参数进行调优，既要改善上面两种情况，又要避免新生代过大，复制次数过多造成minor gc的暂停时间过长。</p>
<ol>
    <li>使用-Xmn调到1/3 总内存。比较后设置-Xmn500m，新生代实际约460m。(-XX:NewRatio参数无效)。
    <li>添加-XX:+PrintTenuringDistribution 参数观察各个Age的对象总大小，观察后设置-XX:MaxTenuringThreshold=5。 </li>
</ol>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 优化后，大约1.1秒才发生一次minor GC，同时年老代的增长速度大大减缓，预计几个小时才会发生一次GC，而minor gc速度依然保持在15-20ms之间。</p>
<p>&nbsp; &nbsp; &nbsp; 参数定稿：</p>
<div class="macro" macrotext="{code}" command="code">
<div class="code">
<div class="codeContent">
<pre class="code-java">&nbsp;-Xms1024m -Xmx1024m -Xmn500m -XX:+UseConcMarkSweepGC&nbsp;  -XX:MaxTenuringThreshold=5&nbsp; -XX:+ExplicitGCInvokesConcurrent</pre>
</div>
</div>
</div>
<p>&#8201;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最后服务处理速度从1180 tps 上升到1380 tps，调整两个参数提升17%的性能还是笔很划算的买卖。</p>
<img src ="http://www.blogjava.net/conans/aggbug/213752.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-09 19:07 <a href="http://www.blogjava.net/conans/articles/213752.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用cucurrent 的Callable 改进方法调用性能</title><link>http://www.blogjava.net/conans/articles/213464.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Tue, 08 Jul 2008 15:02:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/213464.html</guid><description><![CDATA[在有些方法里， 比如登陆，一般需要顺序调用多个系统功能才能完成初始化操作.<br />
比如 安全校验-》获取用户权限-》获取用户设置信息-》获取系统字典 等等， 在某些EAI模式的应用里，这些调用可能都是远程调用，每个调用时间可能从0.5秒到数秒不等， 这样累计下来用户一个登陆操作，在后台处理时间可能就有3，4秒，加上网络传输延时，会主观上给用户造成系统很慢的感觉。<br />
<br />
在单个方法调用效率无法改进的前提下，一个简单的办法是将调用方式由串行改为并行，即以多个thread分别去完成方法调用，最后汇总。<br />
<br />
在java 5以前，因为线程的特性限制，必须手工编码实现线程完成状态的调用检查。<br />
<br />
比如<br />
&nbsp;// thread&nbsp;<br />
public void run() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;......<br />
&nbsp;&nbsp;&nbsp;finished = true;<br />
&nbsp;}<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;public boolean isFinished() {<br />
&nbsp;&nbsp;&nbsp;return finished;<br />
&nbsp;&nbsp;}<br />
<br />
<br />
// 以阻塞循环的方式检查是否执行完毕<br />
while(!remoteCall.isFinished()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;try {<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(100);<br />
&nbsp;&nbsp;&nbsp;} catch (InterruptedException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
<br />
这样的代码是繁琐，较低效率，也容易出错的，尤其在线程多于2个的时候。而在服务器方代码中过多的线程使用又可能会导致内存溢出和资源泄露。 <br />
<br />
今天翻书的时候发现java 5中的cucurrent包对此进行了改进 继承自Callable 的类有能力将执行结果返回，并且可以自行检查执行是否结束。<br />
<br />
&nbsp; public class RandomPrimeSearch implements Callable&lt;BigInteger&gt; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public BigInteger call( ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // do&nbsp;operation here<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return BigInteger.probablePrime(bitSize, prng);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp; }<br />
<br />
&nbsp; FutureTask&lt;BigInteger&gt; task = &nbsp;&nbsp;&nbsp; new FutureTask&lt;BigInteger&gt;(new RandomPrimeSearch(512));&nbsp; //需要利用泛型模板返回处理结果<br />
&nbsp;&nbsp;new Thread(task).start( );<br />
<br />
&nbsp; BigInteger result = task.get( );&nbsp; //此处会自动判断是否执行结束，未结束会继续等待。也可以设定最大等待时间<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; //为了提高效率 也可以使用service方式调用<br />
&nbsp;&nbsp;&nbsp; ExecutorService service = Executors.newFixedThreadPool(5);<br />
<br />
&nbsp;&nbsp;&nbsp; Future&lt;BigInteger&gt; prime1 = service.submit(new RandomPrimeSearch(512));<br />
<br />
<br />
这样一来，使用这种并发模式处理代码就容易多了。程序可以简单的修改为这样的结构<br />
remoateCall1 = doRemoteCall1();&nbsp; // 启动线程1 将方法处理以封装到线程中<br />
remoateCall2 = doRemoteCall2();&nbsp; // 启动线程2 <br />
<br />
remoteCall1.get().getUserSetting() ;<br />
remoteCall2.get().getDictionaryList();&nbsp;<br />
....<br />
<br />
呵呵，基本和顺序执行时差不多，代码修改量比较小。<br />
<br />
java 5中引入了线程执行服务ExecutorService 的概念以后， 如果以线程池的方式执行线程调用，资源消耗会大幅度减少，所以不用太担心并发处理会产生过多的系统负荷。<br />
<br />
<img src ="http://www.blogjava.net/conans/aggbug/213464.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-08 23:02 <a href="http://www.blogjava.net/conans/articles/213464.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>持续集成工具hudson </title><link>http://www.blogjava.net/conans/articles/213462.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Tue, 08 Jul 2008 15:01:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/213462.html</guid><description><![CDATA[<h4>一.什么是持续集成</h4>
<h4><span class="atitle"><span style="font-family: 宋体">持续集成的核心概念</span></span></h4>
<h4><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">CI 过程会经常构建软件组件；在许多情况下，每当源代码存储库（比如 Subversion 或 ClearCase）中的代码发生变化时，都要构建软件组件。CI 的好处是：经常构建软件可以确保尽早遇到问题（比如代码缺陷），避免问题在软件开发周期晚期变复杂时才被发现。</span></span></span></span></h4>
<h4><a name="N10122"><span class="smalltitle"><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">工具与过程</span></span></span></span></span></a></h4>
<h4><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">尽管 CI 实际上是一个过程，但是<em>持续集成</em> 这个词常常与一个或多个工具相关联。在本教程中，讲解如何安装、配置和使用 Hudson 作为 CI 服务器，但是要记住，CI 远不只是个工具。实际上，使用的工具可能是 CI 比较次要的方面，因为 CI 工具所做的仅仅是在代码存储库中探测到修改时运行构建。构建过程本身比用来运行它的工具重要得多。</span></span></span></span></h4>
<h4><a name="N1012F"><span class="smalltitle"><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">开始使用 CI</span></span></span></span></span></a></h4>
<h4><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">开始使用 CI 需要三个组件： </span></span></span></span></h4>
<ul>
    <li><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt"><strong>用 Ant 或 Maven 等工具建立的自动构建过程 </strong></span></span></span></span>
    <li><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt"><strong>一个代码存储库，比如 CVS 或 Subversion </strong></span></span></span></span>
    <li><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt"><strong>一个 CI 服务器，比如 Hudson，但是 cron 作业也可以满足需要</strong> </span></span></span></span></li>
</ul>
<h4><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">我们来详细讨论这些组件。</span></span></span></span></h4>
<h4><a name="N10147"><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">自动的构建</span></span></span></span></a></h4>
<h4><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">CI 过程会经常集成软件，这需要通过构建来完成。在 Java 环境中，Ant 是常用的构建平台。可以使用 Ant 可靠地自动执行编译、测试等任务，甚至可以执行软件检查和部署。在掌握了 CI 的所有组件之后，您会发现构建策略是成功的 CI 过程最重要的方面。如果缺少适当的构建过程，CI 就难以发挥作用。</span></span></span></span></h4>
<h4><a name="N10150"><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">源代码管理</span></span></span></span></a></h4>
<h4><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">为了让 CI 正确地发挥作用，需要一个源代码管理（SCM）系统或存储库，比如 Subversion 或 CVS。CI 服务器向 SCM 存储库查询代码修改。在找到修改时，CI 服务器执行签出（即更新本地沙箱）并执行构建。除了执行得更频繁之外，构建过程与在本地环境中执行的构建相同。 </span></span></span></span></h4>
<h4><a name="N10159"><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">CI 服务器</span></span></span></span></a></h4>
<h4><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">对于成功的 CI 过程，需要用一个自动的过程监视 SCM 存储库并在探测到修改时运行构建，这也非常重要。对于 Java 平台，有许多可用的 CI 服务器，包括开放源码软件和商业产品。它们的基本配置都很相似，适合监视特定的 SCM 并在探测到修改时运行构建。所有 CI 服务器都有自己的优缺点。Hudson 尤其让人感兴趣，因为它容易配置而且具有强大的插件，这些插件可以显示测试结果趋势等信息。<br />
<p><span class="atitle">二.Hudson 简介</span></p>
<p><span style="font-size: 10pt">Hudson 是一种革命性的开放源码 CI 服务器，它从以前的 CI 服务器吸取了许多经验教训。Hudson 最吸引人的特性之一是它很容易配置：很难找到更容易设置的 CI 服务器，也很难找到开箱即用特性如此丰富的 CI 服务器。Hudson 容易使用的第二个原因是它具有强大的插件框架，所以很容易添加特性。例如，一个 Hudson 插件可以随时间的推移跟踪 FindBugs 和代码覆盖。它还可以报告测试结果的趋势（来自 JUnit 或 TestNG）以及构建结果和对应的执行时间。 </span></p>
<p><span style="font-size: 10pt">Hudson 需要运行 Java 5。如果需要使用 Hudson 附带的嵌入式容器（Winstone）之外的其他容器，那么只需使用一种 Servlet 2.4 容器。对于大多数情况，Winstone 就足够了。<br />
</span></p>
<p><span class="atitle">三.Hudson使用</span></p>
<p><span style="font-size: 10pt">CI 过程的最后一个方面是 CI 服务器本身。CI 服务器在整个开发过程中的主要作用是控制者：当服务器在代码存储库中探测到修改时，它将运行构建的任务委托给构建过程本身。如果构建失败了，那么 CI 服务器将通知相关方面，然后继续监视存储库。它的角色看起来是被动的；但是，它是快速反映问题的关键。</span></p>
<p><a name="N10326"><span class="smalltitle"><span style="font-size: 10pt">安装 Hudson</span></span></a></p>
<p><span style="font-size: 10pt">使用 Hudson 的主要好处之一是它的设置很简单。在最简单的情况下，Hudson 只需要两个步骤：</span></p>
<ol>
    <li><span style="font-size: 10pt">下载最新的版本（它打包为一个 WAR 文件）。 hudson官方网址:https://hudson.dev.java.net/</span>
    <li><span style="font-size: 10pt">运行 <code>java -jar hudson.war</code>。 </span></li>
</ol>
<p><span style="font-size: 10pt">这样就可以了。因为下载的是一个 WAR 文件，所以如果愿意，可以将它部署在 Tomcat 或 JBoss 等容器中。这完全由您自己决定。当然，Hudson 假设在安装它的机器上运行着 Java 5，而且如果定义了 <code>JAVA_HOME</code> 环境变量，Hudson 就会使用它。（正如前面提到的，Hudson 需要 Java 5。）</span></p>
<p><span style="font-size: 10pt">在安装并运行 Hudson 之后（将 WAR 文件部署到 servlet 容器或从命令行执行 <code>java -jar hudson.war</code>），启动浏览器并访问默认安装位置。如果通过命令行运行 Hudson 而且您在本地机器上，那么可以访问 <code>http://localhost:8080/</code>。</span></span></span></span></span></p>
</h4>
<img alt="" src="http://www.blogjava.net/images/blogjava_net/xiaodu/d.JPG" border="0" /><br />
<strong><span style="font-size: 10pt">如果一切正常（实际上不太可能出问题），应该会看到图 2 所示的 Hudson 启动页面。</span><br />
</strong>
<p><a name="N10360"><span class="smalltitle"><span style="font-size: 10pt"><strong>配置 Hudson</strong></span></span></a></p>
<p><span style="font-size: 10pt"><strong>如果访问 Hudson 主页的本地实例并单击左上角的 Manage Hudson 链接，应该会看到图 3 所示的可配置选项列表。</strong></span></p>
<a name="figure3"><strong><span style="font-size: 10pt">图 3. 配置 Hudson 非常容易</span></strong></a><br />
<img height="625" alt="" src="http://www.blogjava.net/images/blogjava_net/xiaodu/e.JPG" width="1000" border="0" /><br />
<p><span style="font-size: 10pt"><strong>参数说明:<br />
system.message 填写一些说明信息<br />
Quiet period:hudson定时构建工程的时间(秒)<br />
&nbsp;<label class="attach-previous">Enable security</label>:设置hudson登陆的规则(默认为匿名登陆)<br />
TCP port for JNLP slave agents:不了解JNLP不敢胡写总之就是三种方式:固定(fixed) 随机(Radom) 不使用(disabled),使用固定时可以填入JNLP信息</strong></span></p>
<span style="font-size: 10pt"><strong>security realm:可以使用中间件容器,数据库,LDAP来验证安全,具体怎样用法没用过,以后会有更新,研究中.<br />
authorized:可以设置身份的验证方法:系统用户,匿名用户,自定义用户,还有继承用户(此处也在研究中,建议使用匿名用户)<br />
JDK installations:设置JDK的安装路径<br />
Shell executable:设置window shell命令<br />
Ant installation:设置ant 的安装路径<br />
mave installation设置mave的安装路径<br />
cvs executable:设置cvsnt执行进程的路径(cvs.exe)<br />
.cvspass file:设置cvsnt管理员文件的路径(passwd文件)<br />
e-mail notification:设置当发生错误时发送的邮箱地址<br />
hudson url:就是hudson的默认地址<br />
</strong></span>
<p><span style="font-size: 10pt"><strong>还可以配置服务器的其他几个方面，比如向 Hudson 提供一个电子邮件服务器的位置，以便在构建失败时接收电子邮件。根据您的组织设置电子邮件的方式，可能需要让系统管理员帮助设置这个特性。设置电子邮件并不是必需的；Hudson 还支持以 RSS 作为通知机制，对于某些人来说，这种方式比电子邮件更好。究竟选择哪些通知机制完全取决于您。（注意，这里说的是 &#8220;哪些&#8221;，也就是说，可以同时使用多种通知机制！）</strong></span></p>
<span style="font-size: 10pt">
<p><a name="N103A5"><span class="smalltitle"><span style="font-size: 10pt"><strong>在 Hudson 中配置项目</strong></span></span></a></p>
<span style="font-size: 10pt">
<p><span style="font-size: 10pt"><strong>既然 Hudson 已经能够与 SCM 存储库通信了，就该配置项目了。这个示例所用的项目称为 <code>solar-ci</code>。在 Hudson 主页上单击左上角的 New Job 链接。这时会看到图 5 所示的屏幕：</strong> </span></p>
<img alt="" src="http://www.blogjava.net/images/blogjava_net/xiaodu/f.JPG" border="0" /><br />
<br />
<p class="MsoNormal"><strong><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">该页面可以使我们通过</span><span lang="EN-US">hudson</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">来管理</span><span lang="EN-US">cvs</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">里的一个对应的工程</span></strong></p>
<p class="MsoNormal"><strong><span lang="EN-US">Project name:</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">工程名称</span></strong></p>
<p class="MsoNormal"><strong><span lang="EN-US">Description:</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">描述信息</span></strong></p>
<p class="MsoNormal"><strong><span lang="EN-US">Discard build:</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如果选择此项可以设置</span><span lang="EN-US">build</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">记录保存的天数</span><span lang="EN-US">,</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">或者</span><span lang="EN-US">build</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">记录保存的数理</span><span lang="EN-US">,</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">或者只保存最新的</span><span lang="EN-US">build</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">记录</span><span lang="EN-US">,</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">一般不需填写</span></strong></p>
<p class="MsoNormal"><strong><span lang="EN-US">Advance project options:</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">可以设置</span><span lang="EN-US">hudson</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">定时检查</span><span lang="EN-US">cvs</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">工程的时间间隔</span><span lang="EN-US">,</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">还可以指定</span><span lang="EN-US">cvs</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">工程</span><span lang="EN-US">check out</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">到本地的工程路径</span><span lang="EN-US">,</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">一般不需要填写</span></strong></p>
<p class="MsoNormal"><strong><span lang="EN-US">Source code management:</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">我们选择</span><span lang="EN-US">cvs</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">将出现以下参数</span><span lang="EN-US">:</span></strong></p>
<strong><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">Cvsroot:</span><span style="font-size: 10.5pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'">将写</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">cvs</span><span style="font-size: 10.5pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'">登陆字符串</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">,</span><span style="font-size: 10.5pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'">格式</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">(</span><tt><span lang="EN-US" style="font-size: 12pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">:protocol:user:password@host:path),</span><span style="font-size: 12pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">例如<span lang="EN-US">:</span></span></tt><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"> </span><tt><span lang="EN-US" style="font-size: 12pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">:pserver:cvsadmin:1@127.0.0.1:2401:/CVSNT/Repository,</span><span style="font-size: 12pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">使用<span lang="EN-US">cvs</span>必填</span></tt><br />
&nbsp; </strong>
<p class="MsoNormal" style="mso-outline-level: 1"><a name="_Toc203280766"><tt><span lang="EN-US" style="font-size: 12pt"><strong>Modules:</strong></span></tt></a><strong><span style="mso-bookmark: _Toc203280766"><tt><span style="font-size: 12pt">填写<span lang="EN-US">cvs</span>仓库下的具体工程名<span lang="EN-US">, </span>使用<span lang="EN-US">cvs</span>必填</span></tt></span><tt><span lang="EN-US" style="font-size: 12pt"><O:P></O:P></span></tt></strong></p>
<strong><tt><span lang="EN-US" style="font-size: 12pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">Branch:</span><span style="font-size: 12pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">填写分支名称<span lang="EN-US">,</span>也可以勾选<span lang="EN-US">this is a tag,no a branch</span>指定标记名称</span></tt><br />
&nbsp; </strong>
<p class="MsoNormal"><tt><span style="font-size: 12pt"><strong>选择<span lang="EN-US">subversion</span>可以进行相应的<span lang="EN-US">subversion</span>设置<span lang="EN-US"><O:P></O:P></span></strong></span></tt></p>
<p class="MsoNormal"><strong><tt><span lang="EN-US" style="font-size: 12pt">Build trigger</span></tt><tt><span style="font-size: 12pt">可以设置<span lang="EN-US">hudson</span>自动执行的一些动作<span lang="EN-US">,build after others projects are built</span>指定<span lang="EN-US">hudson</span>构建完成后需要继续构建的工程名<span lang="EN-US"><O:P></O:P></span></span></tt></strong></p>
<p class="MsoNormal"><strong><tt><span lang="EN-US" style="font-size: 12pt">Build periodically </span></tt><tt><span style="font-size: 12pt">根据<span lang="EN-US">hudson</span>定义的语法规则来设定自动构建工程的时间间隔<span lang="EN-US"><O:P></O:P></span></span></tt></strong></p>
<p class="MsoNormal" style="mso-outline-level: 1"><a name="_Toc203280767"><tt><span lang="EN-US" style="font-size: 12pt"><strong>Post-build actions</strong></span></tt></a><tt><span lang="EN-US" style="font-size: 12pt"><strong> <O:P></O:P></strong></span></tt></p>
<p class="MsoNormal"><tt><span style="font-size: 12pt"><strong>设置一些构建完成后的动作<span lang="EN-US">,</span>如放邮件<span lang="EN-US">,</span>打包<span lang="EN-US">,</span>产生测试报告<span lang="EN-US">,</span>产生<span lang="EN-US">java doc </span>等<span lang="EN-US">.<O:P></O:P></span></strong></span></tt></p>
<p class="MsoNormal"><tt><span style="font-size: 12pt"><strong>点击<span lang="EN-US">ok</span>保存设置<span lang="EN-US"><O:P></O:P></span></strong></span></tt></p>
<strong>使用hudson<br />
<tt><span style="font-size: 12pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">进入刚配置的项目<span lang="EN-US">,</span>可以在左侧<span lang="EN-US">build history</span>看到历史的<span lang="EN-US">build</span>记录<span lang="EN-US">,</span>点击<span lang="EN-US">build now </span>可以手动执行构建动作<span lang="EN-US">,</span>完成后可以通过记录标记的颜色来看是否出错<span lang="EN-US">,</span>红色有错<span lang="EN-US">,</span>蓝色成功<span lang="EN-US">.</span>点击记录查看详细信息<span lang="EN-US">,</span>如果有变化<span lang="EN-US">hudson</span>将列出类信息</span></tt></strong></span></span> <br />
<br />
<strong>elipse插件应用<br />
eclipse updatesite:http://code.google.com/p/hudson-eclipse/<br />
重新打开eclipse在windows-&gt;preferences下将出现hudson选项,设置默认的hudson url保存.<br />
然后选择windows-&gt;open view打开hudson view<br />
如果你己经配置hudson项目将列出hudson的项目名称,右键菜单可以看到所有的执行菜单,使用还是很方便的,希望大家来完善这篇文章.<br />
</strong>
<img src ="http://www.blogjava.net/conans/aggbug/213462.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-08 23:01 <a href="http://www.blogjava.net/conans/articles/213462.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>面试时候经常会问的一些问题(不断补充中) </title><link>http://www.blogjava.net/conans/articles/212426.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Thu, 03 Jul 2008 12:44:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/212426.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转自：http://www.blogjava.net/beansoft/archive/2007/03/09/102812.html面试必备基础题目(虽然不一定常用, 仅用于面试, 面试就是把人搞的都不会然后砍价, 当然您可以讲我可以查资料完成, 但是面试的时候就是没道理的, 起码我是经常看到这些题).如何把一段逗号分割的字符串转换成一个数组?request.getAttribut...&nbsp;&nbsp;<a href='http://www.blogjava.net/conans/articles/212426.html'>阅读全文</a><img src ="http://www.blogjava.net/conans/aggbug/212426.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-03 20:44 <a href="http://www.blogjava.net/conans/articles/212426.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>BeanSoft 整理的资料FTP集中下载，感谢网友王先生 </title><link>http://www.blogjava.net/conans/articles/212425.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Thu, 03 Jul 2008 12:41:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/212425.html</guid><description><![CDATA[<div class="posttitle"><a class="singleposttitle" id="viewpost1_TitleUrl" href="http://www.blogjava.net/beansoft/archive/2008/03/23/188084.html">BeanSoft 整理的资料FTP集中下载，感谢网友王先生</a> </div>
<p>&nbsp;</p>
<p>长期以来，许多朋友反映本站资料下载困难（原来的是放在微软网盘上的<a title="http://cid-519b3f7aa2172030.skydrive.live.com/browse.aspx/Public/" href="http://cid-519b3f7aa2172030.skydrive.live.com/browse.aspx/Public/">http://cid-519b3f7aa2172030.skydrive.live.com/browse.aspx/Public/</a>，国内下载比较慢），今天特别感谢网友王先生的帮助，才得到这个FTP服务，和大家更好的share我整理的一部分资料（鉴于版权原因，部分资料无法上传），包括原创视频等。</p>
<p>&nbsp;</p>
<p><a title="ftp://beansoftdown:1234@219.141.70.147" href="ftp://beansoftdown:1234@219.141.70.147/">ftp://beansoftdown:1234@219.141.70.147</a> </p>
<p>IP：219.141.70.147</p>
<p>用户：beansoftdown</p>
<p>密码：1234</p>
<p>限速：200K/人</p>
<p>欢迎下载测试！</p>
<p>&nbsp;</p>
<p>现有的目录结构：</p>
<p><a href="http://www.blogjava.net/images/blogjava_net/beansoft/WindowsLiveWriter/BeanSoft_12CBA/image_2.png"><img height="361" alt="image" src="http://www.blogjava.net/images/blogjava_net/beansoft/WindowsLiveWriter/BeanSoft_12CBA/image_thumb.png" width="211" border="0" /> </a></p>
<p>另外，以前有读者寻找 M7 NitroX Studio 3.0.0 M1 这个软件（说实话，这是一款不可多得的真正完全支持可视化JSP，Struts, JSF，Hibernate开发的软件，比MyEclipse棒多了，可惜只能配合Eclipse 3.0，它现在被 BEA 收购，叫做BEA Workshop，由于太贵了，不如MyEclipse普及），现在您可以下载它了，在 软件/Java/开发工具 下，Eclipse 3.0 版本下配套的还有个很好用的UML工具叫 Borland&#174; Together&#174; Edition for Eclipse 6.3，当时是免费的.</p>
<table cellspacing="0" cellpadding="2" width="400" border="0">
    <tbody>
        <tr>
            <td valign="top" width="200"><a href="http://www.blogjava.net/images/blogjava_net/beansoft/WindowsLiveWriter/BeanSoft_12CBA/NitroXStudio_2.png"><img height="213" alt="NitroXStudio" src="http://www.blogjava.net/images/blogjava_net/beansoft/WindowsLiveWriter/BeanSoft_12CBA/NitroXStudio_thumb.png" width="295" border="0" /> </a></td>
            <td valign="top" width="200"><a href="http://www.blogjava.net/images/blogjava_net/beansoft/WindowsLiveWriter/BeanSoft_12CBA/NitroXStudioHibernate_2.png"><img height="198" alt="NitroXStudioHibernate" src="http://www.blogjava.net/images/blogjava_net/beansoft/WindowsLiveWriter/BeanSoft_12CBA/NitroXStudioHibernate_thumb.png" width="295" border="0" /> </a></td>
        </tr>
        <tr>
            <td valign="top" width="200">图1 可视化Struts开发</td>
            <td valign="top" width="200">图2 让人抓狂的2005年的时候就出现的Hibernate反向工程以及实体编辑器，即使放到现在也比MyEclipse 6 做的细致</td>
        </tr>
    </tbody>
</table>
<p>&nbsp;</p>
<p>新版本的BEA Workshop（<a title="http://www.bea.com.cn/products/workshop/index.jsp" href="http://www.bea.com.cn/products/workshop/index.jsp">http://www.bea.com.cn/products/workshop/index.jsp</a>）没用过，看介绍还带有Flex Builder 2，因为个头太大了（500 多MB），而且感觉可能集成的东西太多，运行速度明显很慢。还有个免费的BEA Workshop for JSP（300多MB）。。。</p>
<img src ="http://www.blogjava.net/conans/aggbug/212425.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-03 20:41 <a href="http://www.blogjava.net/conans/articles/212425.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Effective Java读书笔记 </title><link>http://www.blogjava.net/conans/articles/212422.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Thu, 03 Jul 2008 12:36:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/212422.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 终于翻开这本James都称赞的java经典书籍了，发现比一般的英语书籍要难懂一些。但是里面的Item都是非常实用的，是java程序员应该理解的。Creating and Destroying ObjectItem 1:考虑用静态工厂方法替代构造器例如：public static Boolean valueOf(boolean b)&nbsp;&nbsp;&nbsp;&nbsp;&n...&nbsp;&nbsp;<a href='http://www.blogjava.net/conans/articles/212422.html'>阅读全文</a><img src ="http://www.blogjava.net/conans/aggbug/212422.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-03 20:36 <a href="http://www.blogjava.net/conans/articles/212422.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>3 款 SQL INJECTION 攻击检测工具</title><link>http://www.blogjava.net/conans/articles/210663.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Wed, 25 Jun 2008 11:48:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/210663.html</guid><description><![CDATA[写道 "随着 <a href="http://blogs.zdnet.com/security/?p=1059">SQL INJECTION</a> 攻击的<a href="http://blogs.zdnet.com/security/?p=1122">明显增多</a>，<a href="http://blogs.zdnet.com/security/?p=1336">微软近日发布了三个免费工具</a>，帮助网站管理员和检测存在的风险并对可能的攻击进行拦截。
<div class="full"><a href="http://www.communities.hp.com/securitysoftware/blogs/spilabs/archive/2008/06/23/finding-sql-injection-with-scrawlr.aspx"><strong>Scrawlr</strong> </a><br />
<br />
下载地址：<a href="https://download.spidynamics.com/Products/scrawlr/">https://download.spidynamics.com/Products/scrawlr/</a> <br />
<br />
这个微软和 HP合作开发的工具，会在网站中爬行，对所有网页的查询字符串进行分析并发现其中的 SQL INJECTION 风险。Scrawlr 使用了部分 HP WebInspect 相同的技术，但只检测 SQL INJECTION 风险。Scrawlr 从一个起始 URL 入口，爬遍整个网站，并对站点中所有网页进行分析以找到可能存在的漏洞。 <br />
<br />
<br />
<a href="http://support.microsoft.com/kb/954476"><strong>Microsoft Source Code Analyzer for SQL Injection</strong> </a><br />
<br />
下载地址：<a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=58A7C46E-A599-4FCB-9AB4-A4334146B6BA&amp;displaylang=en">http://www.microsoft.com/downloads/details.aspx?FamilyId=58A7C46E-A599-4FCB-9AB4-A4334146B6BA&amp;displaylang=en</a> <br />
<br />
这款被称作 MSCASI 的工具可以检测 ASP 代码并发现其中的 SQL INJECTION 漏洞（ASP 代码以 SQL INJECTION 漏洞著称），你需要向 MSCASI 提供原始代码，MSCASI 会帮你找到存在风险的代码位置。 <br />
<br />
<strong><br />
<a href="http://learn.iis.net/page.aspx/473/using-urlscan">URLScan 3.0</a> </strong><br />
<br />
下载地址： <a href="http://www.iis.net/downloads/default.aspx?tabid=34&amp;g=6&amp;i=1697">http://www.iis.net/downloads/default.aspx?tabid=34&amp;g=6&amp;i=1697</a> <br />
<br />
该工具会让 IIS 限制某些类型的 HTTP 请求，通过对特定 HTTP 请求进行限制，可以防止某些有害的请求在服务器端执行。UrlScan 通过一系列关键词发现恶意请求，并阻止恶意请求的执行。 </div>
 <img src ="http://www.blogjava.net/conans/aggbug/210663.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-06-25 19:48 <a href="http://www.blogjava.net/conans/articles/210663.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>为什么ORM性能比iBATIS好？</title><link>http://www.blogjava.net/conans/articles/210658.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Wed, 25 Jun 2008 11:41:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/210658.html</guid><description><![CDATA[<div class="blog_content">缓存是有很多层次的，有web server前端缓存，有动态页面静态化，有页面片断缓存，有查询缓存，也有对象缓存。不同层面的缓存适用于不同的应用场景，作用也各自不同，如果可以，你全部一起用上，他们不矛盾，但这个话题比较大，现在不展开谈。 <br />
<br />
针对OLTP类型的web应用，只要代码写的质量没有问题，最终的性能瓶颈毫无疑问还是数据库查询。应用服务器层面可以水平扩展，但是数据库是单点的，很难水平扩展，所以如何有效降低数据库查询频率，减轻数据库压力，是web应用性能问题的根源。 <br />
<br />
以上所有的缓存方式都可以直接或者间接的降低数据库访问，但缓存是有应用场景的，虽然新闻网站非常适合使用动态页面静态化技术，但是例如电子商务网站就不适合动态页面静态化，而页面缓存和查询缓存可以使用的场景也不多。但是对象缓存是所有缓存技术当中适用场景最广泛的，任何OLTP应用，即使实时性要求很高，你也可以使用对象缓存，而且好的ORM实现，对象缓存是完全透明的，不需要你的程序代码进行硬编码。 <br />
<br />
用不用对象缓存，怎么用对象缓存，不是一个调优的技巧问题，而是整个应用的架构问题。在你开发一个应用之前，你就要想清楚，这个应用最终的场景是什么？会有多大的用户量和数据量。你将采用什么方式来架构这个应用： <br />
<br />
OK，也许你偏爱SQL，那么你选择iBATIS，数据库设计当中大表有很多冗余字段，会尽量消除大表之间的关联关系，最终用户量和访问量很高以后，你会选择使用Oracle，雇佣资深的DBA，进行数据库调优和SQL调优，这是大多数公司走的路。 <br />
<br />
但是我告诉你，你还有另外一条路可以走。你可以选择ORM(不见得一定是Hibernate)，数据库设计当中避免出现大表，比较多的表关联关系，通过ORM以对象化方式操作。当用户量和访问量很高以后，除了数据库端本身的优化，你还有对象缓存这条途径。对象缓存是怎样提高性能的呢？随便举个例子： <br />
<br />
论坛的列表页面，需要显示topic的分页列表，topic作者的名字，topic最后回复帖子的作者，如果是iBATIS，你准备怎么做？ <br />
<br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Sql代码 <a title="复制代码" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" href="http://robbin.javaeye.com/blog/77338#"><img alt="复制代码" src="http://robbin.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-sql">
    <li><span><span class="keyword">select</span><span>&nbsp;...&nbsp;</span><span class="keyword">from</span><span>&nbsp;topic&nbsp;</span><span class="func">left</span><span>&nbsp;</span><span class="op">join</span><span>&nbsp;</span><span class="func">user</span><span>&nbsp;</span><span class="func">left</span><span>&nbsp;</span><span class="op">join</span><span>&nbsp;post&nbsp;.....&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="sql" style="display: none" name="code">select ... from topic left join user left join post .....</pre>
<br />
<br />
你需要通过join user表来取得topic作者的名字，然后你还需要join post表取得最后回复的帖子，post再join user表取得最后回贴作者名字。 <br />
<br />
也许你说，我可以设计表冗余，在topic里面增加username，在post里面增加username，所以通过大表冗余字段，消除了复杂的表关联： <br />
<br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Sql代码 <a title="复制代码" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" href="http://robbin.javaeye.com/blog/77338#"><img alt="复制代码" src="http://robbin.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-sql">
    <li><span><span class="keyword">select</span><span>&nbsp;...&nbsp;</span><span class="keyword">from</span><span>&nbsp;topic&nbsp;</span><span class="func">left</span><span>&nbsp;</span><span class="op">join</span><span>&nbsp;post...&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="sql" style="display: none" name="code">select ... from topic left join post...</pre>
<br />
<br />
OK，且不说冗余字段的维护问题，现在仍然是两张大表的关联查询。然后让我们看看ORM怎么做？ <br />
<br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Sql代码 <a title="复制代码" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" href="http://robbin.javaeye.com/blog/77338#"><img alt="复制代码" src="http://robbin.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-sql">
    <li><span><span class="keyword">select</span><span>&nbsp;*&nbsp;</span><span class="keyword">from</span><span>&nbsp;topic&nbsp;</span><span class="keyword">where</span><span>&nbsp;...&nbsp;</span><span class="comment">--分页条件</span><span>&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="sql" style="display: none" name="code">select * from topic where ... --分页条件</pre>
<br />
<br />
就这么一条SQL搞定，比上面的关联查询对数据库的压力小多了。 <br />
<br />
也许你说，不对阿，作者信息呢？回贴作者信息呢？这些难道不会发送SQL吗？如果发送SQL，这不就是臭名昭著的n+1条问题吗？ <br />
<br />
你说的对，最坏情况下，会有很多条SQL： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Sql代码 <a title="复制代码" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" href="http://robbin.javaeye.com/blog/77338#"><img alt="复制代码" src="http://robbin.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-sql">
    <li><span><span class="keyword">select</span><span>&nbsp;*&nbsp;</span><span class="keyword">from</span><span>&nbsp;</span><span class="func">user</span><span>&nbsp;</span><span class="keyword">where</span><span>&nbsp;id&nbsp;=&nbsp;topic_id...; &nbsp;&nbsp;</span></span></li>
    <li><span>.... &nbsp;&nbsp;</span></li>
    <li><span class="keyword">select</span><span>&nbsp;*&nbsp;</span><span class="keyword">from</span><span>&nbsp;</span><span class="func">user</span><span>&nbsp;</span><span class="keyword">where</span><span>&nbsp;id&nbsp;=&nbsp;topic_id...; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="keyword">select</span><span>&nbsp;*&nbsp;</span><span class="keyword">from</span><span>&nbsp;post&nbsp;</span><span class="keyword">where</span><span>&nbsp;id&nbsp;=&nbsp;last_topic_id...; &nbsp;&nbsp;</span></span></li>
    <li><span>.... &nbsp;&nbsp;</span></li>
    <li><span class="keyword">select</span><span>&nbsp;*&nbsp;</span><span class="keyword">from</span><span>&nbsp;post&nbsp;</span><span class="keyword">where</span><span>&nbsp;id&nbsp;=&nbsp;last_topic_id...; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="keyword">select</span><span>&nbsp;*&nbsp;</span><span class="keyword">from</span><span>&nbsp;</span><span class="func">user</span><span>&nbsp;</span><span class="keyword">where</span><span>&nbsp;id&nbsp;=&nbsp;post_id...; &nbsp;&nbsp;</span></span></li>
    <li><span>.... &nbsp;&nbsp;</span></li>
    <li><span class="keyword">select</span><span>&nbsp;*&nbsp;</span><span class="keyword">from</span><span>&nbsp;</span><span class="func">user</span><span>&nbsp;</span><span class="keyword">where</span><span>&nbsp;id&nbsp;=&nbsp;post_id...;&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="sql" style="display: none" name="code">select * from user where id = topic_id...;
....
select * from user where id = topic_id...;
select * from post where id = last_topic_id...;
....
select * from post where id = last_topic_id...;
select * from user where id = post_id...;
....
select * from user where id = post_id...;</pre>
<br />
<br />
事实上何止n+1，根本就是3n+1条SQL了。那你怎么还说ORM性能高呢？ <br />
<br />
<span style="color: red">因为对象缓存在起作用，你可以观察到后面的3n条SQL语句全部都是基于主键的单表查询，这3n条语句在理想状况下(比较繁忙的web网站)，全部都可以命中缓存。</span>所以事实上只有一条SQL，就是： <br />
<br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Sql代码 <a title="复制代码" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" href="http://robbin.javaeye.com/blog/77338#"><img alt="复制代码" src="http://robbin.javaeye.com/images/icon_copy.gif" _counted="undefined" /></a></div>
</div>
<ol class="dp-sql">
    <li><span><span class="keyword">select</span><span>&nbsp;*&nbsp;</span><span class="keyword">from</span><span>&nbsp;topic&nbsp;</span><span class="keyword">where</span><span>&nbsp;...</span><span class="comment">--分页条件</span><span>&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="sql" style="display: none" name="code">select * from topic where ...--分页条件</pre>
<br />
<br />
这条单表的条件查询和iBATIS通过字段冗余简化过后的大表关联查询相比，当数据量大到一定程度以后(十几万条)，查询的速度会差至少一个数量级，而且对数据库的压力很小，这就是对象缓存的真正威力！ <br />
<br />
<span style="color: red">更进一步分析，使用ORM，我们不考虑缓存的情况，那么就是3n+1条SQL。但是这3n+1条SQL的执行速度一定比iBATIS的大表关联查询慢吗？不一定！</span>因为使用ORM的情况下，第一条SQL是单表的条件查询，在有索引的情况下，速度很快，后面的3n条SQL都是单表的主键查询，在繁忙的数据库系统当中，3n条SQL几乎可以全部命中数据库的data buffer。但是使用iBATIS的大表关联查询，很可能会造成全表扫描，这样性能是非常差的。 <br />
<br />
<span style="color: red">所以结论就是：即使不使用对象缓存，ORM的n+1条SQL性能仍然很有可能超过iBATIS的大表关联查询，而且对数据库造成的压力要小很多。这个结论貌似令人难以置信，但经过我的实践证明，就是事实。前提是数据量和访问量都要比较大，否则看不出来这种效果</span> <br />
<br />
还是拿上面这个例子的应用场景来说，由于JavaEye网站用RoR的ActiveRecord，所以这个场景事实上就会发送3n+1条SQL语句。我从log里面看到这密密麻麻的SQL，着实非常担忧性能，所以尝试使用了find的:include选项去eager fetch，迫使ActiveRecord发送单条复杂的关联查询。但非常不幸的是，在网站服务器的production.log里面经过前后对比，发现使用:include以后，单条复杂关联查询耗时更多，数据库压力更大。 <br />
<br />
在使用memcached之后，比3n+1条的性能进一步明显提升。所以性能对比就是这样的： <br />
<br />
ORM + Cache &gt; ORM n+1 &gt; iBATIS 关联查询 <br />
<br />
那为什么应用Cache可以进一步提高性能，是因为访问Cache的开销比访问数据库小的得多造成的。 <br />
<br />
应用程序根据主键key去Cache Server取value，是非常简单的算法，开销极小。 <br />
而发送一条主键查询的SQL到数据库，要经过非常复杂的过程，有SQL的解析，执行计划的优化，占位符参数的代入，只读事务的保护和隔离等等，最终虽然也命中了数据库的data buffer，但是开销确实很大。 <br />
<br />
BerkeleyDB就是一个极好的证明，它号称其查询速度是Oracle的1000倍，不是因为它做的比Oracle牛，而是因为它本质上就是一个大Cache，查询没有额外的开销。 </div>
<img src ="http://www.blogjava.net/conans/aggbug/210658.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-06-25 19:41 <a href="http://www.blogjava.net/conans/articles/210658.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>应该如何正确使用Quartz</title><link>http://www.blogjava.net/conans/articles/210657.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Wed, 25 Jun 2008 11:41:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/210657.html</guid><description><![CDATA[对于Web容器来说，最忌讳应用程序私自启动线程，自行进行线程调度，像Quartz这种在web容器内部默认就自己启动了10个线程进行异步job调度的框架本身就是很危险的事情，很容易造成servlet线程资源回收不掉，所以我一向排斥使用quartz。 <br />
<br />
quartz还有一个问题就是不支持cluster。导致使用quartz的应用都没有办法做群集。 <br />
<br />
那么应该如何正确的使用quartz的同时，又不影响web容器自身的线程调度呢？ <br />
<br />
办法就是自己单独启动一个Job Server，来quartz跑job，不要部署在web容器中。 <br />
<br />
其他web节点当需要启动异步任务的时候，可以通过种种方式(DB, JMS, Web Service, etc)通知Job Server，而Job Server收到这个通知之后，把异步任务加载到自己的任务队列中去。 <br />
<br />
其实想改造当前已经集成quartz的web应用也不算困难： <br />
<br />
例如可以使用数据库的表来记录和维护任务队列和状态，把quartz部分完全从web应用中剥离出去，自己写一个Java Main程序把配置quartz的spring容器跑起来，这样Job Server就启动了(注意这个Job Server完全脱离tomcat)。此外这个Main程序应该再启动一个子线程，定期扫描数据库的任务队列表： <br />
有新的任务就加入quartz的任务调度； <br />
把当前任务的执行状态写入任务表； <br />
看到删除任务的表字段状态以后，删除相应的任务。 <br />
<br />
然后web应用去掉quartz部分配置，把原来的调用quartz任务的代码改写为读写数据库的任务表，这样就把job部分完全从web容器剥离掉了，甚至web容器做cluster也没有问题了，并且多个web节点在同时读写任务表的时候，还有数据库的事务来确保操作的一致性，实在是很棒。 <br />
<br />
另外还可以单独做一个job管理界面，可以通过web界面手工添加任务，查看任务状态，删除任务等等。
<img src ="http://www.blogjava.net/conans/aggbug/210657.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-06-25 19:41 <a href="http://www.blogjava.net/conans/articles/210657.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java程序员的推荐阅读书籍</title><link>http://www.blogjava.net/conans/articles/210656.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Wed, 25 Jun 2008 11:39:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/210656.html</guid><description><![CDATA[作为Java程序员来说，最痛苦的事情莫过于可以选择的范围太广，可以读的书太多，往往容易无所适从。我想就我自己读过的技术书籍中挑选出来一些，按照学习的先后顺序，推荐给大家，特别是那些想不断提高自己技术水平的Java程序员们。 <br />
<br />
<span style="font-size: 18pt">一、Java编程入门类</span> <br />
<br />
对于没有Java编程经验的程序员要入门，随便读什么入门书籍都一样，这个阶段需要你快速的掌握Java基础语法和基本用法，宗旨就是&#8220;囫囵吞枣不求甚解&#8221;，先对Java熟悉起来再说。用很短的时间快速过一遍Java语法，连懵带猜多写写代码，要&#8220;知其然&#8221;。 <br />
<br />
1、《Java编程思想》 <br />
<img src="http://www.douban.com/lpic/s1959358.jpg" _counted="undefined"  alt="" /> <br />
在有了一定的Java编程经验之后，你需要&#8220;知其所以然&#8221;了。这个时候《Java编程思想》是一本让你知其所以然的好书，它对于基本的面向对象知识有比较清楚的交待，对Java基本语法，基本类库有比较清楚的讲解，可以帮你打一个良好的Java编程基础。这本书的缺点是实在太厚，也比较罗嗦，不适合现代人快节奏学习，因此看这本书要懂得取舍，不是每章每节都值得一看的，挑重点的深入看就可以了。 <br />
<br />
2、《Agile Java》中文版 <br />
<img src="http://www.douban.com/lpic/s2008093.jpg" _counted="undefined"  alt="" /> <br />
这本书是出版社送给我的，我一拿到就束之高阁，放在书柜一页都没有翻过，但是前两天整理书柜的时候，拿出来一翻，竟然发现这绝对是一本好书！这本书一大特点是以单元测试和TDD来贯穿全书的，在教你Java各种重要的基础知识的过程中，潜移默化的影响你的编程思维走向敏捷，走向TDD。另外这本书成书很新，以JDK5.0的语法为基础讲解，要学习JDK5.0的新语法也不错。还有这本书对于内容取舍也非常得当，Java语言毕竟类库庞大，可以讲的内容太多，这本书选择的内容以及内容的多寡都很得当，可以让你以最少的时间掌握Java最重要的知识，顺便培养出来优秀的编程思路，真是一本不可多得的好书。 <br />
<br />
虽然作者自己把这本书定位在入门级别，但我不确定这本书用来入门是不是稍微深了点，我自己也准备有空的时候翻翻这本书，学习学习。 <br />
<br />
<br />
<span style="font-size: 18pt">二、Java编程进阶类</span> <br />
<br />
打下一个良好的Java基础，还需要更多的实践经验积累，我想没有什么捷径。有两本书值得你在编程生涯的这个阶段阅读，培养良好的编程习惯，提高你的代码质量。 <br />
<br />
1、《重构 改善既有代码的设计》 <br />
<img src="http://www.douban.com/lpic/s1826359.jpg" _counted="undefined"  alt="" /> <br />
这本书名气很大，不用多介绍，可以在闲暇的时候多翻翻，多和自己的实践相互印证。这本书对你产生影响是潜移默化的。 <br />
<br />
2、《测试驱动开发 by Example》 <br />
<img src="http://www.douban.com/lpic/s1441607.jpg" _counted="undefined"  alt="" /> <br />
本书最大特点是很薄，看起来没有什么负担。你可以找一个周末的下午，一边看，一边照做，一个下午就把书看完，这本书的所有例子跑完了。这本书的作用是通过实战让你培养TDD的思路。 <br />
<br />
<br />
<span style="font-size: 18pt">三、Java架构师之路</span> <br />
<br />
到这个阶段，你应该已经非常娴熟的运用Java编程，而且有了一个良好的编程思路和习惯了，但是你可能还缺乏对应用软件整体架构的把握，现在就是你迈向架构师的第一步。 <br />
<br />
1、《Expert One-on-One J2EE Design and Development》 <br />
<img src="http://www.douban.com/lpic/s1501574.jpg" _counted="undefined"  alt="" /> <br />
这本书是Rod Johnson的成名著作，非常经典，从这本书中的代码诞生了springframework。但是好像这本书没有中译本。 <br />
<br />
2、《Expert One-on-One J2EE Development without EJB》 <br />
<img src="http://www.douban.com/lpic/s1496227.jpg" _counted="undefined"  alt="" /> <br />
这本书由gigix组织翻译，多位业界专家参与，虽然署名译者是JavaEye，其实JavaEye出力不多，实在是忝居译者之名。 <br />
<br />
以上两本书都是Rod Johnson的经典名著，Java架构师的必读书籍。在我所推荐的这些书籍当中，是我看过的最仔细，最认真的书，我当时读这本书几乎是废寝忘食的一气读完的，有小时候挑灯夜读金庸武侠小说的劲头，书中所讲内容和自己的经验知识一一印证，又被无比精辟的总结出来，读完这本书以后，我有种被打通经脉，功力爆增的感觉。 <br />
<br />
但是后来我看过一些其他人的评价，似乎阅读体验并没有我那么high，也许是因为每个人的知识积累和经验不同导致的。我那个时候刚好是经验知识积累已经足够丰富，但是还没有系统的整理成型，让这本书一梳理，立刻形成完整的知识体系了。 <br />
<br />
3、《企业应用架构模式》 <br />
<img src="http://www.douban.com/lpic/s1607804.jpg" _counted="undefined"  alt="" /> <br />
Martin的又一本名著，但这本书我只是泛泛的看了一遍，并没有仔细看。这本书似乎更适合做框架的人去看，例如如果你打算自己写一个ORM的话，这本书是一定要看的。但是做应用的人，不看貌似也无所谓，但是如果有空，我还是推荐认真看看，会让你知道框架为什么要这样设计，这样你的层次可以晋升到框架设计者的角度去思考问题。Martin的书我向来都是推崇，但是从来都没有像Rod Johnson的书那样非常认真去看。 <br />
<br />
4、《敏捷软件开发 原则、模式与实践》 <br />
<img src="http://www.douban.com/lpic/s1671095.jpg" _counted="undefined"  alt="" /> <br />
Uncle Bob的名著，敏捷的经典名著，这本书比较特别，与其说是讲软件开发过程的书，不如说讲软件架构的书，本书用了很大篇幅讲各种面向对象软件开发的各种模式，个人以为看了这本书，就不必看GoF的《设计模式》了。 <br />
<br />
<br />
<span style="font-size: 18pt">四、软件开发过程</span> <br />
<br />
了解软件开发过程不单纯是提高程序员个人的良好编程习惯，也是增强团队协作的基础。 <br />
<br />
1、《UML精粹》 <br />
<img src="http://www.douban.com/lpic/s1648691.jpg" _counted="undefined"  alt="" /> <br />
UML其实和软件开发过程没有什么必然联系，却是软件团队协作沟通，撰写软件文档需要的工具。但是UML真正实用的图不多，看看这本书已经足够了，完全没有必要去啃《UML用户指南》之类的东西。要提醒大家的是，这本书的中译本翻译的非常之烂，建议有条件的看英文原版。 <br />
<br />
2、《解析极限编程 拥抱变化》XP <br />
<img src="http://www.douban.com/lpic/s2008432.jpg" _counted="undefined"  alt="" /> <br />
这是Kent Beck名著的第二版，中英文对照。没什么好说的，必读书籍。 <br />
<br />
3、《统一软件开发过程》UP <br />
<img src="http://www.douban.com/lpic/s1843342.jpg" _counted="undefined"  alt="" /> <br />
其实UP和敏捷并不一定冲突，UP也非常强调迭代，测试，但是UP强调的文档和过程驱动却是敏捷所不取的。不管怎么说，UP值得你去读，毕竟在中国真正接受敏捷的企业很少，你还是需要用UP来武装一下自己的，哪怕是披着UP的XP。 <br />
<br />
4、《敏捷建模》AM <br />
<img src="http://www.douban.com/lpic/s1264986.jpg" _counted="undefined"  alt="" /> <br />
Scott Ambler的名著，这本书非常的progmatic，告诉你怎么既敏捷又UP，把敏捷和UP统一起来了，又提出了很多progmatic的建议和做法。你可以把《解析极限编程 拥抱变化》、《统一软件开发过程》和《敏捷建模》这三本书放在一起读，看XP和UP的不同点，再看AM是怎么统一XP和UP的，把这三种理论融为一炉，形成自己的理论体系，那么你也可以去写书了。 <br />
<br />
<br />
<span style="font-size: 18pt">五、软件项目管理</span> <br />
<br />
如果你突然被领导提拔为项目经理，而你完全没有项目管理经验，你肯定会心里没底；如果你觉得自己管理项目不善，很想改善你的项目管理能力，那么去考PMP肯定是远水不解近渴的。 <br />
<br />
1、《快速软件开发》 <br />
<img src="http://www.douban.com/lpic/s1696681.jpg" _counted="undefined"  alt="" /> <br />
这也是一本名著。可以这样说，有本书在手，你就有了一个项目管理的高级参谋给你出谋划策，再也不必担心自己不能胜任的问题了。这本书不是讲管理的理论的，在实际的项目管理中，讲这些理论是不解决问题的，这本书有点类似于&#8220;软件项目点子大全&#8221;之类的东西，列举了种种软件项目当中面临的各种问题，以及应该如何解决问题的点子，你只需要稍加变通，找方抓药就行了。 <br />
<br />
<br />
<span style="font-size: 18pt">六、总结</span> <br />
<br />
在这份推荐阅读书籍的名单中，我没有列举流行的软件框架类学习书籍，例如Struts，Hibernate，Spring之类，也没有列举AJAX方面的书籍。是因为这类书籍容易过时，而上述的大半书籍的生命周期都足够长，值得你去购买和收藏。
<img src ="http://www.blogjava.net/conans/aggbug/210656.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-06-25 19:39 <a href="http://www.blogjava.net/conans/articles/210656.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>