﻿<?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-VincentChen‘s Blog-文章分类-Java</title><link>http://www.blogjava.net/Vencent/category/6999.html</link><description>&lt;font color='orange'&gt;本博客仅为收集所用。在此对原作者表示感谢。&lt;/font&gt;
&lt;center&gt;
&lt;script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
&lt;/script&gt;&lt;div class="custom"&gt;
&lt;script type="text/javascript"&gt;&lt;!--
google_ad_client = "pub-6256612161572960";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text";
google_ad_channel ="";
google_page_url = document.location;
google_color_border = ["FFDDAA","FFDDAA","FFDDAA","FFDDAA"];
google_color_bg = ["EEEEEE","EEEEEE","EEEEEE","EEEEEE"];
google_color_link = ["FFDDAA","0033FF","00008B","99CC33"];
google_color_url = ["999999","0033FF","00008B","FFCC00"];
google_color_text = ["0033FF","AA9999","0033FF","AA9999"];
//--&gt;&lt;/script&gt;
&lt;script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
&lt;/script&gt;&lt;/div&gt;&lt;/center&gt;
&lt;!--bgsound src="http://www.blogjava.net/Files/Vencent/The%20Mass%20Era.zip" volume="10" loop="10"/--&gt;</description><language>zh-cn</language><lastBuildDate>Wed, 20 Jun 2007 02:12:49 GMT</lastBuildDate><pubDate>Wed, 20 Jun 2007 02:12:49 GMT</pubDate><ttl>60</ttl><item><title>整合weblogic cluster ＋ apache</title><link>http://www.blogjava.net/Vencent/articles/125027.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Mon, 18 Jun 2007 17:02:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/125027.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/125027.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/125027.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/125027.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/125027.html</trackback:ping><description><![CDATA[1. 在Weblogic安装目录中找到For Apache的Plug-ins<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 位于$WL_HOME/bin目录下，其中：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mod_wl128_20.so：用于Standard Apache Version 2.0.x（Regular Strength Encryption）<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mod_wl_20.so：用于Standard Apache Version 2.0.x（128-bit Encryption）<br><br>2. 确认需要的Apache版本<br><br>3. 确认在Apache中支持Plug-ins<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 执行:$APACHE_HOME/bin/apache -l，如果没有列出来mod_so.c，则需要重新<br>Build。<br><br>4. 安装Apache HTTP Server Plug-In module<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将mod_wl_20.so复制到$APACHE_HOME/modules目录下；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 修改$APACHE_HOME/conf/httpd.conf配置文件，增加如下行：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LoadModule weblogic_module&nbsp;&nbsp;&nbsp;&nbsp; modules/mod_wl_20.so<br><br>5. 在httpd.conf中配置其它参数<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;</span><span style="color: #800000;">IfModule&nbsp;</span><span style="color: #ff0000;">mod_weblogic.c</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WebLogicCluster&nbsp;localhost:90,localhost:91<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MatchExpression&nbsp;*.jsp<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">IfModule</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">Location&nbsp;</span><span style="color: #ff0000;">/weblogic</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetHandler&nbsp;weblogic-handler<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PathTrim&nbsp;/<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">Location</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;">IfModule&nbsp;</span><span style="color: #ff0000;">mod_weblogic.c</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WebLogicCluster&nbsp;localhost:7003,localhost:7005,localhost:7007<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MatchExpression&nbsp;*<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">IfModule</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">Location&nbsp;</span><span style="color: #ff0000;">/DizzyTixWeb</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetHandler&nbsp;weblogic-handler<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PathTrim&nbsp;/<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">Location</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">Location&nbsp;</span><span style="color: #ff0000;">/DizzySupplies</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetHandler&nbsp;weblogic-handler<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PathTrim&nbsp;/<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">Location</span><span style="color: #0000ff;">&gt;</span></div>
<br>检查httpd.conf配置是否正确：APACHE_HOME\bin\Apache -t<br><br>6. 重启Weblogic Server<br>7. 启动Apache HTTP Server<br>8. 测试插件 http://localhost/weblogic/<br><br><br><img src ="http://www.blogjava.net/Vencent/aggbug/125027.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2007-06-19 01:02 <a href="http://www.blogjava.net/Vencent/articles/125027.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 关于SAX，DOM，JAXP，JDOM，DOM4J的一些理解【转载】</title><link>http://www.blogjava.net/Vencent/articles/124856.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Sun, 17 Jun 2007 15:26:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/124856.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/124856.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/124856.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/124856.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/124856.html</trackback:ping><description><![CDATA[<p>第一：首先介绍一下SAX，DOM，JAXP，JDOM，DOM4J的基本知识：<br>（注意：至于 JAXP&nbsp; |&nbsp;&nbsp; JAXB&nbsp; |&nbsp;&nbsp; JAXM&nbsp; |&nbsp;&nbsp; JAXR&nbsp; |&nbsp;&nbsp; JAX-RPC 分别指什么，查看<a  href="http://gceclub.sun.com.cn/staticcontent/html/xml/faq/#jaxr">http://gceclub.sun.com.cn/staticcontent/html/xml/faq/#jaxr</a>_）</p>
<p>1、sax、dom是两种对xml文档进行分析的方法（没有具体的实现，只有接口）<br>所以不是解释器，如果光有他们，你是完成不了对xml文档的处理的。<br>sax的包是org.xml.sax<br>dom的包是org.w3c.dom<br>包的名称很重要，它有助于你理解他们之间的关系。</p>
<p>2、jaxp是api，他封装了sax\dom两种接口。并在sax\dom的基础之上，作了一套比较简单的api以供开发人员使用。<br>jaxp的包是javax.xml.parsers<br>可以看看jaxp的源文件，它的文件中包含了对sax或者dom的引用（import）<br>jaxp也不是具体的实现，他只是一套api。如果你仅仅有jaxp那是无法工作的<br>（其实jaxp只是完成对sax、dom的包装，生成了DocumentBuilderFactory\DocumentBuilder<br>和SAXParserFactory SAXParser。也就是设计模式中的工厂模式，他的好处就是具体的对象（ 解释器）建立由子类完成）</p>
<p>3、xerces解释器（号称地球上最快的xml解释器）<br>在xerces
中对jaxp中定义的SAXParser SAXParserFactory DocumentBuilder
DocumentBuilderFactory进行了继承（extends）对应SAXParserImpl
SAXParserFactoryImpl DocumentBuilderImpl DocumentBuilderFactoryImpl<br>这就是为什么你的classpath中只要有xerces.jar（其中包含了sax dom jaxp ）和 xercesImpl.jar就可以的原因了.</p>
<p>4、什么时候可以用别的解释器 比如crimson呢<br>他也是和xerces一样 是解释器，很简单，用crimson.jar 替代xercesImpl.jar</p>
<p>5、jdom和dom4j<br>&nbsp;<br>W3C
的DOM标准API难用的让人想撞墙，于是有一帮人开发Java专用的XML
API目的是为了便于使用，这就是jdom的由来，开发到一半的时候，另一部分人又分了出来，他们有自己的想法，于是他们就去开发dom4j，形成了今天
这样两个API，至于他们之间的性能，jdom全面惨败，dom4j大获全胜。我觉得jdom和dom4j就相当于sax/dom+jaxp，具体的解释
器可以选择。</p>
<p>第二：再介绍一下，dom,sax,jdom,dom4j的技术特点：</p>
<p>1: DOM<br>DOM
是用与平台和语言无关的方式表示 XML 文档的官方 W3C 标准。DOM
是以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中寻找特定信息。分析该结构通常需要加载整个文档和构造层次结构，然后才能做任何
工作。由于它是基于信息层次的，因而 DOM 被认为是基于树或基于对象的。DOM
以及广义的基于树的处理具有几个优点。首先，由于树在内存中是持久的，因此可以修改它以便应用程序能对数据和结构作出更改。它还可以在任何时候在树中上下
导航，而不是像 SAX 那样是一次性的处理。DOM 使用起来也要简单得多。<br>　　另一方面，对于特别大的文档，解析和加载整个文档可能很慢且很耗资源，因此使用其他手段来处理这样的数据会更好。这些基于事件的模型，比如 SAX。</p>
<p>2:SAX<br>
这种处理的优点非常类似于流媒体的优点。分析能够立即开始，而不是等待所有的数据被处理。而且，由于应用程序只是在读取数据时检查数据，因此不需要将数
据存储在内存中。这对于大型文档来说是个巨大的优点。事实上，应用程序甚至不必解析整个文档；它可以在某个条件得到满足时停止解析。一般来说，SAX
还比它的替代者 DOM 快许多。</p>
<p>3:　选择 DOM 还是选择 SAX ？<br>　　对于需要自己编写代码来处理 XML 文档的开发人员来说，选择 DOM 还是 SAX 解析模型是一个非常重要的设计决策。 <br>　　DOM 采用建立树形结构的方式访问 XML 文档，而 SAX 采用的事件模型。 <br>
DOM 解析器把 XML 文档转化为一个包含其内容的树，并可以对树进行遍历。用 DOM
解析模型的优点是编程容易，开发人员只需要调用建树的指令，然后利用navigation
APIs访问所需的树节点来完成任务。可以很容易的添加和修改树中的元素。然而由于使用 DOM 解析器的时候需要处理整个 XML
文档，所以对性能和内存的要求比较高，尤其是遇到很大的 XML 文件的时候。由于它的遍历能力，DOM 解析器常用于 XML
文档需要频繁的改变的服务中。 <br>　　SAX 解析器采用了基于事件的模型，它在解析 XML
文档的时候可以触发一系列的事件，当发现给定的tag的时候，它可以激活一个回调方法，告诉该方法制定的标签已经找到。SAX
对内存的要求通常会比较低，因为它让开发人员自己来决定所要处理的tag。特别是当开发人员只需要处理文档中所包含的部分数据时，SAX
这种扩展能力得到了更好的体现。但用 SAX 解析器的时候编码工作会比较困难，而且很难同时访问同一个文档中的多处不同数据。 </p>
<p>4:jdom <a  href="http://www.jdom.org/">http://www.jdom.org</a><br>JDOM
的目的是成为 Java 特定文档模型，它简化与 XML 的交互并且比使用 DOM 实现更快。由于是第一个 Java 特定模型，JDOM
一直得到大力推广和促进。正在考虑通过&#8220;Java 规范请求 JSR-102&#8221;将它最终用作&#8220;Java 标准扩展&#8221;。从 2000 年初就已经开始了
JDOM 开发。<br>　　JDOM 与 DOM 主要有两方面不同。首先，JDOM 仅使用具体类而不使用接口。这在某些方面简化了 API，但是也限制了灵活性。第二，API 大量使用了 Collections 类，简化了那些已经熟悉这些类的 Java 开发者的使用。<br>
JDOM 文档声明其目的是&#8220;使用 20%（或更少）的精力解决 80%（或更多）Java/XML 问题&#8221;（根据学习曲线假定为
20%）。JDOM 对于大多数 Java/XML 应用程序来说当然是有用的，并且大多数开发者发现 API 比 DOM 容易理解得多。JDOM
还包括对程序行为的相当广泛检查以防止用户做任何在 XML 中无意义的事。然而，它仍需要您充分理解 XML
以便做一些超出基本的工作（或者甚至理解某些情况下的错误）。这也许是比学习 DOM 或 JDOM 接口都更有意义的工作。<br>　　JDOM
自身不包含解析器。它通常使用 SAX2 解析器来解析和验证输入 XML 文档（尽管它还可以将以前构造的 DOM
表示作为输入）。它包含一些转换器以将 JDOM 表示输出成 SAX2 事件流、DOM 模型或 XML 文本文档。JDOM 是在 Apache
许可证变体下发布的开放源码。</p>
<p>5: DOM4J&nbsp;&nbsp; <a  href="http://dom4j.sourceforge.net/">http://dom4j.sourceforge.net/</a><br>
虽然 DOM4J 代表了完全独立的开发结果，但最初，它是 JDOM 的一种智能分支。它合并了许多超出基本 XML 文档表示的功能，包括集成的
XPath 支持、XML Schema 支持以及用于大文档或流化文档的基于事件的处理。它还提供了构建文档表示的选项，它通过 DOM4J API
和标准 DOM 接口具有并行访问功能。从 2000 下半年开始，它就一直处于开发之中。<br>　　为支持所有这些功能，DOM4J
使用接口和抽象基本类方法。DOM4J 大量使用了 API 中的 Collections
类，但是在许多情况下，它还提供一些替代方法以允许更好的性能或更直接的编码方法。直接好处是，虽然 DOM4J 付出了更复杂的 API
的代价，但是它提供了比 JDOM 大得多的灵活性。<br>　　在添加灵活性、XPath 集成和对大文档处理的目标时，DOM4J 的目标与
JDOM 是一样的：针对 Java 开发者的易用性和直观操作。它还致力于成为比 JDOM 更完整的解决方案，实现在本质上处理所有
Java/XML 问题的目标。在完成该目标时，它比 JDOM 更少强调防止不正确的应用程序行为。<br>　　DOM4J
是一个非常非常优秀的Java XML
API，具有性能优异、功能强大和极端易用使用的特点，同时它也是一个开放源代码的软件。如今你可以看到越来越多的 Java 软件都在使用
DOM4J 来读写 XML，特别值得一提的是连 Sun 的 JAXM 也在用 DOM4J。</p>
<p>最后：我建议用dom4j</p>
JDOM
和 DOM 在性能测试时表现不佳，在测试 10M 文档时内存溢出。在小文档情况下还值得考虑使用 DOM 和 JDOM。虽然 JDOM
的开发者已经说明他们期望在正式发行版前专注性能问题，但是从性能观点来看，它确实没有值得推荐之处。另外，DOM 仍是一个非常好的选择。DOM
实现广泛应用于多种编程语言。它还是许多其它与 XML 相关的标准的基础，因为它正式获得 W3C 推荐（与基于非标准的 Java
模型相对），所以在某些类型的项目中可能也需要它（如在 javascript 中使用 DOM）。<br>　　SAX表现较好，这要依赖于它特定的解析方式。一个 SAX 检测即将到来的XML流，但并没有载入到内存（当然当XML流被读入时，会有部分文档暂时隐藏在内存中）。<br>　　无疑，DOM4J是最好的，目前许多开源项目中大量采用 DOM4J，例如大名鼎鼎的 Hibernate 也用 DOM4J 来读取 XML 配置文件。如果不考虑可移植性，那就采用DOM4J吧！<img src ="http://www.blogjava.net/Vencent/aggbug/124856.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2007-06-17 23:26 <a href="http://www.blogjava.net/Vencent/articles/124856.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>给编程狂热者的ant task笔记</title><link>http://www.blogjava.net/Vencent/articles/68400.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Thu, 07 Sep 2006 16:18:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/68400.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/68400.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/68400.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/68400.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/68400.html</trackback:ping><description><![CDATA[
		<p>   这篇文档是专门写给那些编程狂热者，在Ant里编程时要留意的重要Task。<br /><br />    不知为何，老外的各种脚本都写得格外漂亮。从Appfuse里学到很多，在编写<a href="http://wiki.javascud.org/display/springs/Home" _fcksavedurl="http://wiki.javascud.org/display/springs/Home">SpringSide2.0</a><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" />的构件安装脚本时又被迫自学了不少，这里作下总结。</p>
		<p>    如果只说一样最重要的事情，就是<span class="nobr"><a title="Visit page outside Confluence" href="http://ant-contrib.sourceforge.net/tasks/index.html" rel="nofollow" _fcksavedurl="http://ant-contrib.sourceforge.net/tasks/index.html">ant-contrib<sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a></span>的&lt;if&gt; 和 &lt;for&gt;节点，使Ant 拥有了完整的编程能力。</p>
		<p>
				<b>
				</b>
				<font size="5">
						<strong>1. 变量</strong>
				</font>
		</p>
		<p>   Ant里的变量有个诡异的特性----一旦被赋值就不会改变，这个特性有时候帮助很大，有时候让人很苦恼，一定要注意。另一样要注意的是，Ant里的变量和其他语言的变量一样，有可效范围。</p>
		<p>
				<b>
				</b>
				<font size="4">
						<strong> 1.由命令行赋值</strong>
				</font>
		</p>
		<p>      ant build.xml -Dtomcat.home=foo</p>
		<p>
				<b>
				</b>
				<font size="4">
						<strong>2.与用户交互输入--<span class="nobr"><a title="Visit page outside Confluence" href="http://ant.apache.org/manual/CoreTasks/input.html" rel="nofollow" _fcksavedurl="http://ant.apache.org/manual/CoreTasks/input.html">Input task<sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a></span></strong>
				</font>
		</p>
		<p>      &lt;input message="请选择一个Target "<br />               validargs="compile,jar,test"<br />               addproperty="my.input"/&gt;</p>
		<p>
				<b>
				</b>
				<font size="4">
						<strong> 3.从propertis文件读取并存盘 -- </strong>
				</font>
				<span class="nobr">
						<a title="Visit page outside Confluence" href="http://ant.apache.org/manual/OptionalTasks/propertyfile.html" rel="nofollow" _fcksavedurl="http://ant.apache.org/manual/OptionalTasks/propertyfile.html">
								<font size="4">
										<strong>propertyfile task</strong>
								</font>
								<sup>
										<img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" />
								</sup>
						</a>
				</span>
		</p>
		<p>      &lt;propertyfile file="my.properties"&gt;<br />              &lt;entry key="springside.home" default="."/&gt;<br />      &lt;/propertyfile&gt;</p>
		<p>      如果my.properties 不存在，生成my.properties文件，springside.home=.。有一个特别有用的地方：有些properties文件的属性每个开发者都不同，不想放入svn，但又想初始化数值，可以用该命令。</p>
		<p>     &lt;propertyfile file="my.properties"&gt;<br />              &lt;entry key="springside.home" value="....."/&gt;<br />      &lt;/propertyfile&gt;</p>
		<p>      重新写入配置文件。</p>
		<p>
				<b>
				</b>
				<font size="5">
						<strong>2. 流程控制</strong>
				</font>
		</p>
		<p>     如果没有ant-contrib 贡献的&lt;if&gt; 和&lt;for&gt;节点，Ant的可编程性是极低极低的。</p>
		<p>
				<b>
				</b>
				<font size="4">
						<strong> 2.1 <span class="nobr"><a title="Visit page outside Confluence" href="http://ant-contrib.sourceforge.net/tasks/tasks/if.html" rel="nofollow" _fcksavedurl="http://ant-contrib.sourceforge.net/tasks/tasks/if.html">if task<sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a></span></strong>
				</font>
		</p>
		<p> ant原来可以在target级进行if判断(unless,if 属性)，但实在太不方便了。</p>
		<p>
				<b>
				</b>
				<font size="4">
						<strong>2.2 <span class="nobr"><a title="Visit page outside Confluence" href="http://ant.apache.org/manual/CoreTasks/conditions.html" rel="nofollow" _fcksavedurl="http://ant.apache.org/manual/CoreTasks/conditions.html">Conditions<sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a></span></strong>
				</font>
		</p>
		<p>但Ant预先封装的一堆condition很是很方便的。这些condition完全从实际出发，包括文件是否存在，<span class="nobr"><a title="Visit page outside Confluence" href="http://localhost:8080/" rel="nofollow" _fcksavedurl="http://localhost:8080/">http://localhost:8080<sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a></span>是否连通都可以作为条件，见<span class="nobr"><a title="Visit page outside Confluence" href="http://ant.apache.org/manual/CoreTasks/conditions.html" rel="nofollow" _fcksavedurl="http://ant.apache.org/manual/CoreTasks/conditions.html">Ant的参考手册<sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a></span>。</p>
		<p>
				<b>
				</b>
				<font size="4">
						<strong>2.3 <span class="nobr"><a title="Visit page outside Confluence" href="http://ant-contrib.sourceforge.net/tasks/tasks/for.html" rel="nofollow" _fcksavedurl="http://ant-contrib.sourceforge.net/tasks/tasks/for.html">For task<sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a></span></strong>
				</font>
		</p>
		<p>支持"a,b,c,d" 字符串数组的循环与文件目录，Fileset的循环。</p>
		<p>
				<b>
				</b>
				<font size="4">
						<strong>2.4 <span class="nobr"><a title="Visit page outside Confluence" href="http://ant.apache.org/manual/CoreTasks/parallel.html" rel="nofollow" _fcksavedurl="http://ant.apache.org/manual/CoreTasks/parallel.html">Parallel task<sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a></span></strong>
				</font>
		</p>
		<p>Parallel非常有用，比如我想一边开tomcat，一边做别的，就需要使用它，否则就只有用spawn=true属性把tomcat放在后台运行。spawn有很多不好的地方，比如不能即时在console看到信息，停止ant运行不能把tomcat关掉等。</p>
		<p>Parallel相当于一个容器，放在里面的每个task都会被并行执行。如果想把某几个task顺序执行，用相当于()的<span class="nobr"><a title="Visit page outside Confluence" href="http://ant.apache.org/manual/CoreTasks/sequential.html" rel="nofollow" _fcksavedurl="http://ant.apache.org/manual/CoreTasks/sequential.html">Sequential task<sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a></span> 包起来。</p>
		<p>
				<b>
				</b>
				<font size="4">
						<strong>2.5 <span class="nobr"><a title="Visit page outside Confluence" href="http://ant.apache.org/manual/CoreTasks/waitfor.html" rel="nofollow" _fcksavedurl="http://ant.apache.org/manual/CoreTasks/waitfor.html">Waitfor task<sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a></span></strong>
				</font>
		</p>
		<p>暂停ant执行直到条件符合，比如&lt;waitfor&gt;&lt;http url=<span class="nobr"><a title="Visit page outside Confluence" href="http://localhost:8080/" rel="nofollow" _fcksavedurl="http://localhost:8080/">http://localhost:8080/<sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a></span>&gt;&lt;/waitfor&gt;就会等待tomcat启动后才会继续往下执行。<span class="nobr"><a title="Visit page outside Confluence" href="http://ant.apache.org/manual/CoreTasks/macrodef.html" rel="nofollow" _fcksavedurl="http://ant.apache.org/manual/CoreTasks/macrodef.html">Macrodef task<sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a></span></p>
		<p>
				<b>
				</b>
				<font size="5">
						<strong>3. 代码封装</strong>
				</font>
		</p>
		<p> ant 代码最基本的封装是</p>
		<p> 1. ant  task：调用其他脚本的任务，可设定dir 与是否继承本脚本的变量。</p>
		<p> 2. antcall task：调用本脚本内其他task，可设置参数。</p>
		<p> 3. import task ：就像其他语言的include一样，引入其他脚本内容到本脚本里。</p>
		<p>
				<b>
				</b>
				<font size="4">
						<strong>1. <span class="nobr"><a title="Visit page outside Confluence" href="http://ant-contrib.sourceforge.net/tasks/tasks/antfetch_task.html" rel="nofollow" _fcksavedurl="http://ant-contrib.sourceforge.net/tasks/tasks/antfetch_task.html">AntFetch<sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a></span>,  <span class="nobr"><a title="Visit page outside Confluence" href="http://ant-contrib.sourceforge.net/tasks/tasks/antcallback_task.html" rel="nofollow" _fcksavedurl="http://ant-contrib.sourceforge.net/tasks/tasks/antcallback_task.html">AntCallBack task<sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a></span></strong>
				</font>
		</p>
		<p>   ant-contrib贡献，对应于Ant 与 AntCall。原版只能向被调用函数传递变量，函数执行后没办法return 值。antcallback的语法如下<br />   &lt;antcallback target="mytarget" return="myresult1,myresult2"/&gt;</p>
		<p>
				<b>
				</b>
				<font size="4">
						<strong>2. <span class="nobr"><a title="Visit page outside Confluence" href="http://ant.apache.org/manual/CoreTasks/macrodef.html" rel="nofollow" _fcksavedurl="http://ant.apache.org/manual/CoreTasks/macrodef.html">Macrodef task<sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a></span></strong>
				</font>
		</p>
		<p>   作为最小的封装单位，与以&lt;target&gt;封装再&lt;antcall target="xxx"&gt;调用差不太远，细微之处自行体验了。个人比较喜欢用macrodef。</p>
		<p>
				<b>
				</b>
				<font size="4">
						<strong>3. <span class="nobr"><a title="Visit page outside Confluence" href="http://ant.apache.org/manual/CoreTasks/java.html" rel="nofollow" _fcksavedurl="http://ant.apache.org/manual/CoreTasks/java.html">Java task<sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a></span> 与 <span class="nobr"><a title="Visit page outside Confluence" href="http://ant.apache.org/manual/CoreTasks/exec.html" rel="nofollow" _fcksavedurl="http://ant.apache.org/manual/CoreTasks/exec.html">Exec task<sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a></span> 直接执行Java类或程序</strong>
				</font>
		</p>
		<p>   注意执行目录的定义。另在Windows下如果要直接运行dos窗口中的命令，以下指令启动默认浏览器访问localhost：</p>
		<p>   &lt;exec executable="cmd.exe"&gt;<br />      &lt;arg line="/c start <span class="nobr"><a title="Visit page outside Confluence" href="http://localhost:8080/" rel="nofollow" _fcksavedurl="http://localhost:8080/">http://localhost:8080<sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a></span>"/&gt;<br />   &lt;/exec&gt;   </p>
		<p>
				<b>
				</b>
				<font size="5">
						<strong>4. 扩展Ant的Task</strong>
				</font>
		</p>
		<p>   扩展ant task很简单，实现execute() 方法执行task，实现setter接口让ant框架执行属性注入。继承Task 获得一些ant的能力，比如查询某个变量的值。</p>
		<p>   稍微有点麻烦的是多层嵌套属性的注入。详细请看<span class="nobr"><a title="Visit page outside Confluence" href="http://ant.apache.org/manual/developlist.html" rel="nofollow" _fcksavedurl="http://ant.apache.org/manual/developlist.html">http://ant.apache.org/manual/developlist.html<sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a></span></p>
		<p>   SpringSide 2.0 里很简单的实现了一个XML File Merge的task，见XmlMergeTask.java。<br /><br /><a href="http://blog.sina.com.cn/u/1223801382" target="_blank" rel="nofollow">蛋蛋</a> 说扩展Ant的最方便的方法还是在ANT里嵌套脚本。导入BSF库以后，你就可以用BSF支持的脚本语言了(见<a href="http://ant.apache.org/manual/OptionalTasks/script.html" _fcksavedurl="http://ant.apache.org/manual/OptionalTasks/script.html">Script Task</a>)。接下来有机会尝试一下。<br /></p>
		<p>
				<br />
				<b>
				</b>
				<font size="5">
						<strong>5. 文件操作</strong>
				</font>
		</p>
		<p>  刚好springside里进行了比较多的文件操作，随便记一下。</p>
		<p>
				<span class="nobr">
						<a title="Visit page outside Confluence" href="http://ant.apache.org/manual/CoreTasks/replace.html" rel="nofollow" _fcksavedurl="http://ant.apache.org/manual/CoreTasks/replace.html">replace <sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a>
				</span>与 copy 时加入<span class="nobr"><a title="Visit page outside Confluence" href="http://ant.apache.org/manual/CoreTasks/filter.html" rel="nofollow" _fcksavedurl="http://ant.apache.org/manual/CoreTasks/filter.html">filter<sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a></span>, 都可以进行字符串替换.</p>
		<p>
				<span class="nobr">
						<a title="Visit page outside Confluence" href="http://ant.apache.org/manual/CoreTasks/concat.html" rel="nofollow" _fcksavedurl="http://ant.apache.org/manual/CoreTasks/concat.html">concat<sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _fcksavedurl="http://wiki.javascud.org/images/icons/linkext7.gif" /></sup></a>
				</span>在文件末添加其他文件的内容。</p>
		<p>  好困，很多东西没写详细，明天再补充。<br /><br />  题外话，Ant 完整演示了如何编写XML式的代码，虽然对于开发人员来说XML编码非常麻烦，远远没有Ruby的rake以ruby代码本身来构建系统清晰，但对于IDE，特别是希望图形化编程的IDE来说，XML比普通代码要容易渲染得多，所以普元EOS的图形化编程也是序列成XML代码。再另外，Ant的task 和 普元的构件也有相似。</p>
<img src ="http://www.blogjava.net/Vencent/aggbug/68400.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-09-08 00:18 <a href="http://www.blogjava.net/Vencent/articles/68400.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Iterator vs Visitor, Pull vs Push</title><link>http://www.blogjava.net/Vencent/articles/58381.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Sat, 15 Jul 2006 17:47:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/58381.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/58381.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/58381.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/58381.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/58381.html</trackback:ping><description><![CDATA[
		<h1>
				<span lang="EN-US">Iterator vs Visitor, Pull vs Push</span>
		</h1>
		<h2>
				<span style="font-family: 黑体;">名词界定</span>
		</h2>
		<p class="MsoNormal">
				<span lang="EN-US">Iterator Pattern</span>
				<span style="font-family: 宋体;">也叫做</span>
				<span lang="EN-US">Generator, Sequence, Stream</span>
				<span style="font-family: 宋体;">等。</span>
				<span lang="EN-US">Java</span>
				<span style="font-family: 宋体;">里面有</span>
				<span lang="EN-US">Iterator Interface</span>
				<span style="font-family: 宋体;">，大家应该比较熟悉，不再赘述。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">完整的具有</span>
				<span lang="EN-US">Visitor</span>
				<span style="font-family: 宋体;">和</span>
				<span lang="EN-US">Visited (Visitable) </span>
				<span style="font-family: 宋体;">两个部分的</span>
				<span lang="EN-US">Visitor Pattern</span>
				<span style="font-family: 宋体;">的使用并不广泛。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">简单的只有</span>
				<span lang="EN-US">Visitor</span>
				<span style="font-family: 宋体;">部分的</span>
				<span lang="EN-US">Simple Visitor Pattern</span>
				<span style="font-family: 宋体;">比较常见，比如</span>
				<span lang="EN-US">Callback, Interceptor, Filter</span>
				<span style="font-family: 宋体;">，</span>
				<span lang="EN-US">Functor, Selector, Extractor</span>
				<span style="font-family: 宋体;">等，都可以看作是</span>
				<span lang="EN-US">Simple Visitor Pattern</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">它们都只有</span>
				<span lang="EN-US">Visitor</span>
				<span style="font-family: 宋体;">部分，而没有</span>
				<span lang="EN-US">Visited</span>
				<span style="font-family: 宋体;">部分。或者说他们的</span>
				<span lang="EN-US">Visitor</span>
				<span style="font-family: 宋体;">需要处理的</span>
				<span lang="EN-US">Visited Object</span>
				<span style="font-family: 宋体;">通常只有一种通用数据类型，所以不需要专门提出来一个</span>
				<span lang="EN-US">Visited
Interface -- accept(visitor)</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">这种情况和</span>
				<span lang="EN-US">Observer
Pattern</span>
				<span style="font-family: 宋体;">很相似。不过这也不奇怪，很多</span>
				<span lang="EN-US">Design
Pattern</span>
				<span style="font-family: 宋体;">都是非常类似的，有的几乎只有名字不同。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">为了避免不必要的口舌之争后，这么说吧，</span>
				<span lang="EN-US">Visitor</span>
				<span style="font-family: 宋体;">和</span>
				<span lang="EN-US">Observer</span>
				<span style="font-family: 宋体;">的侧重点不同。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">Visitor</span>
				<span style="font-family: 宋体;">一般来说是</span>
				<span lang="EN-US">Visit</span>
				<span style="font-family: 宋体;">一个集合，通常在一个遍历算法中密集完成，获取的信息（</span>
				<span lang="EN-US">Node Object</span>
				<span style="font-family: 宋体;">）之间一般都有密切关联，比如父子关系，兄弟关系。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">而</span>
				<span lang="EN-US">Observer
Patten</span>
				<span style="font-family: 宋体;">则是监听一个长期运行的系统，零零散散地不定期地运行，获取的信息之间不存在密切联系，或者说，没什么关系。比如订阅的报纸到了，订购的牛奶到了。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">费了半天口舌，澄清各种可能的误会，我们继续</span>
				<span lang="EN-US">Iterator vs Visitor</span>
				<span style="font-family: 宋体;">之旅。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">Iterator Pattern</span>
				<span style="font-family: 宋体;">和</span>
				<span lang="EN-US">Simple Visitor Pattern</span>
				<span style="font-family: 宋体;">处理的问题领域几乎是重合的。它们面对的共同问题模型的组成部分如下：</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">(1)</span>
				<span style="font-family: 宋体;">有一个算法</span>
				<span lang="EN-US">Algorithm</span>
				<span style="font-family: 宋体;">，通常是遍历算法（</span>
				<span lang="EN-US">Traversal</span>
				<span style="font-family: 宋体;">）。而且通常是复杂的数据结构，</span>
				<span lang="EN-US">Tree</span>
				<span style="font-family: 宋体;">、</span>
				<span lang="EN-US">Graph</span>
				<span style="font-family: 宋体;">等结构的遍历算法。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">(2)</span>
				<span style="font-family: 宋体;">算法的使用者，需要和算法的每一步遇到的</span>
				<span lang="EN-US">Node Object</span>
				<span style="font-family: 宋体;">进行交流。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">所不同的是，</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">是一种主动模型，</span>
				<span lang="EN-US">Pull</span>
				<span style="font-family: 宋体;">模型，</span>
				<span lang="EN-US">Ask and Get</span>
				<span style="font-family: 宋体;">。</span>
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">听候用户的调遣。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">Vistor</span>
				<span style="font-family: 宋体;">是一种被动模型，</span>
				<span lang="EN-US">Push</span>
				<span style="font-family: 宋体;">模型，</span>
				<span lang="EN-US">Plugin /
callback</span>
				<span style="font-family: 宋体;">模型，</span>
				<span lang="EN-US">Push and
Pray and Wait</span>
				<span style="font-family: 宋体;">。</span>
				<span lang="EN-US">Visitor</span>
				<span style="font-family: 宋体;">听候算法的调遣。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">相当于算法公司的一名业务人员，代表公司和用户打交道。用户并不需要深入到算法公司内部。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">而</span>
				<span lang="EN-US">Visitor</span>
				<span style="font-family: 宋体;">相当于用户派出的代表，深入到算法公司内部，由算法公司安排访问行程。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">的典型使用方法是：</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">iterator = traversal.getIterator();</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">item = iterator.next();</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">do some thing with item</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">Vistor</span>
				<span style="font-family: 宋体;">的典型使用方法是</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">visitor = new Visitor(){</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<span style="">  </span>..
visit(item) { do something with item }</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">};</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">traversal.traverse(visitor);</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">一个典型的例子是</span>
				<span lang="EN-US">StAX</span>
				<span style="font-family: 宋体;">和</span>
				<span lang="EN-US">SAX</span>
				<span style="font-family: 宋体;">和两种操作</span>
				<span lang="EN-US">XML</span>
				<span style="font-family: 宋体;">的方式。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">（参见</span>
				<span lang="EN-US">
						<a href="http://www.xmlpull.org/">http://www.xmlpull.org/</a>
				</span>
				<span style="font-family: 宋体;">，关于</span>
				<span lang="EN-US">StAX</span>
				<span style="font-family: 宋体;">的典型用法，网上有些经典文章，本文不再赘述。请使用</span>
				<span lang="EN-US">StAX
XMLPull XML</span>
				<span style="font-family: 宋体;">等关键字进行搜索）</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">StAX</span>
				<span style="font-family: 宋体;">就是一个典型的</span>
				<span lang="EN-US">Pull Model, Iterator Pattern</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">而</span>
				<span lang="EN-US">SAX</span>
				<span style="font-family: 宋体;">是</span>
				<span lang="EN-US">Push Model, Simple Visitor Pattern
(Event Listener)</span>
				<span style="font-family: 宋体;">。（如果较真，你当然可以把它叫做</span>
				<span lang="EN-US">Oberver Pattern</span>
				<span style="font-family: 宋体;">）。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">另外一个有趣的例子是</span>
				<span lang="EN-US">DOM
Traversal</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">W3</span>
				<span style="font-family: 宋体;">的</span>
				<span lang="EN-US">DOM Level 2</span>
				<span style="font-family: 宋体;">规范定义了</span>
				<span lang="EN-US">DOM Traversal</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<a href="http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113/traversal.html">http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113/traversal.html</a>
				</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">DocumentTraversal, TreeWalker,
NodeIterator, NodeFilter</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">DOM Traversal</span>
				<span style="font-family: 宋体;">主要是一个</span>
				<span lang="EN-US">Iterator Pattern</span>
				<span style="font-family: 宋体;">，</span>
				<span lang="EN-US">TreeWalker, NodeIterator</span>
				<span style="font-family: 宋体;">都是</span>
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">；但</span>
				<span lang="EN-US">DOM Traversal</span>
				<span style="font-family: 宋体;">同时也是一个简单的</span>
				<span lang="EN-US">Visitor Pattern </span>
				<span style="font-family: 宋体;">——</span>
				<span lang="EN-US">NodeFiter</span>
				<span style="font-family: 宋体;">可以作为简单的</span>
				<span lang="EN-US">Visitor</span>
				<span style="font-family: 宋体;">被注入到</span>
				<span lang="EN-US">Traversal</span>
				<span style="font-family: 宋体;">算法里面，对遇到的每个</span>
				<span lang="EN-US">Node</span>
				<span style="font-family: 宋体;">进行过滤。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">不过，这个</span>
				<span lang="EN-US">NodeFiter</span>
				<span style="font-family: 宋体;">的</span>
				<span lang="EN-US">method name</span>
				<span style="font-family: 宋体;">比较有意思，叫做</span>
				<span lang="EN-US">accept</span>
				<span style="font-family: 宋体;">。而我们知道</span>
				<span lang="EN-US">Visitor Pattern</span>
				<span style="font-family: 宋体;">的</span>
				<span lang="EN-US">Visited Object</span>
				<span style="font-family: 宋体;">具有一个</span>
				<span lang="EN-US">accept</span>
				<span style="font-family: 宋体;">方法。不过，不要误会。这个</span>
				<span lang="EN-US">NodeFilter</span>
				<span style="font-family: 宋体;">仍然是一个</span>
				<span lang="EN-US">Visitor</span>
				<span style="font-family: 宋体;">。这里的</span>
				<span lang="EN-US">Accept</span>
				<span style="font-family: 宋体;">的意思就是</span>
				<span lang="EN-US">Intercept, Filter</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">用法是这样。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">NodeIterator iterator =
DocumentTraversal.createNodeIterator(…NodeFilter …)</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">按照我的设想，这个</span>
				<span lang="EN-US">API</span>
				<span style="font-family: 宋体;">设计，还可以有另外的思路。把</span>
				<span lang="EN-US">Filter</span>
				<span style="font-family: 宋体;">加在</span>
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">身上，而不是加在</span>
				<span lang="EN-US">Traversal</span>
				<span style="font-family: 宋体;">算法身上。因为</span>
				<span lang="EN-US">Iterator Pattern</span>
				<span style="font-family: 宋体;">很容易地做到这一点。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">NodeIterator iterator = New
FilteredIterator(</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<span style="">  
</span>DocumentTraversal().createNodeIterator() , … NodeFilter …);</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">这样，</span>
				<span lang="EN-US">DOM
Traversal</span>
				<span style="font-family: 宋体;">就是一个纯粹的</span>
				<span lang="EN-US">Iterater
Pattern</span>
				<span style="font-family: 宋体;">了。</span>
		</p>
		<h2>
				<span style="font-family: 黑体;">特性比较</span>
		</h2>
		<p class="MsoNormal">
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">属于问答模式，或者说消费者</span>
				<span lang="EN-US">/</span>
				<span style="font-family: 宋体;">生产者模式。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">如果消费者不问不要，生产者就不答不给。</span>
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">的使用者完全掌握了主动权，是控制舞步节奏的领舞者，随时可以中止这场问答游戏。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">的用法本身就是</span>
				<span lang="EN-US">Lazy</span>
				<span style="font-family: 宋体;">的，一问一答，遍历算法停在那里恭候</span>
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">使用者的调遣。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">Visitor</span>
				<span style="font-family: 宋体;">则完全是被动的，</span>
				<span lang="EN-US">Visitor</span>
				<span style="font-family: 宋体;">的提供者</span>
				<span lang="EN-US">/</span>
				<span style="font-family: 宋体;">使用者把</span>
				<span lang="EN-US">Visitor</span>
				<span style="font-family: 宋体;">扔到</span>
				<span lang="EN-US">Traversal</span>
				<span style="font-family: 宋体;">算法里面，然后运行算法，同时祈祷并等候算法的完成（</span>
				<span lang="EN-US">Push and Wait</span>
				<span style="font-family: 宋体;">），完全失去了控制权，只能等待算法整个完成或者中止，才能重新拿到控制权。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">Vistor</span>
				<span style="font-family: 宋体;">的用法很难做到</span>
				<span lang="EN-US">Lazy</span>
				<span style="font-family: 宋体;">，算法必须提供一些机制，接受</span>
				<span lang="EN-US">Visitor</span>
				<span style="font-family: 宋体;">每一步调用发出的指令，进行相应的策略选择。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">换句话说，</span>
				<span lang="EN-US">Visitor
Pattern</span>
				<span style="font-family: 宋体;">里面的算法必须做出相应的</span>
				<span lang="EN-US">Lazy</span>
				<span style="font-family: 宋体;">支持，而且</span>
				<span lang="EN-US">Visitor</span>
				<span style="font-family: 宋体;">必需积累前面步骤的状态，然后判断这次调用中发出什么样的指令。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">比如，有这样一个需求：遍历一棵树，搜集到前</span>
				<span lang="EN-US">5</span>
				<span style="font-family: 宋体;">个名字是</span>
				<span lang="EN-US">Apple</span>
				<span style="font-family: 宋体;">的</span>
				<span lang="EN-US">Node</span>
				<span style="font-family: 宋体;">。然后返回这</span>
				<span lang="EN-US">5</span>
				<span style="font-family: 宋体;">个</span>
				<span lang="EN-US">Node</span>
				<span style="font-family: 宋体;">。假设树遍历算法已经有了。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">这时候采用</span>
				<span lang="EN-US">Iterator
Pattern</span>
				<span style="font-family: 宋体;">视线起来很容易。不再多说。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">Visitor Pattern</span>
				<span style="font-family: 宋体;">则需要：</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">Vistor</span>
				<span style="font-family: 宋体;">使用一个集合来保存每次遇到的名字是</span>
				<span lang="EN-US">Apple</span>
				<span style="font-family: 宋体;">的</span>
				<span lang="EN-US">Node</span>
				<span style="font-family: 宋体;">，每次都判断是否已经找到了</span>
				<span lang="EN-US">5</span>
				<span style="font-family: 宋体;">个，如果已经找到，那么发出一个</span>
				<span lang="EN-US">Stop Signal</span>
				<span style="font-family: 宋体;">给算法。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">如果遍历算法不接受这种指令怎么办？</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">只好等待算法完成。或者实在等不及，预计到后面还有上万个</span>
				<span lang="EN-US">Node</span>
				<span style="font-family: 宋体;">需要遍历，那么就干脆</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">throw new RuntimeException(),<span style="">  </span>throw new Throwable()</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">也许算法并没有聪明到捕获这些</span>
				<span lang="EN-US">Exception</span>
				<span style="font-family: 宋体;">。那么这个</span>
				<span lang="EN-US">Trick</span>
				<span style="font-family: 宋体;">就成功了。外面使用一个</span>
				<span lang="EN-US">Try Catch</span>
				<span style="font-family: 宋体;">捕获这个</span>
				<span lang="EN-US">Exception</span>
				<span style="font-family: 宋体;">。不过，这是</span>
				<span lang="EN-US">Very Very Bad Smell</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">的应用场景是这样：</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">我
在商品定购目录上看到一个公司有我感兴趣的产品系列。于是我打电话给该公司，要求派一个销售代表来。销售代表上门之后，从包里拿出一个一个的产品给你看，
我看了几个，没什么满意的，于是打了个哈欠说，今天就先到这里吧，下次再说。打发了销售代表，我就转身去做自己的事情了。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">我的地盘，我做主。这就是</span>
				<span lang="EN-US">Iterator
Pattern</span>
				<span style="font-family: 宋体;">的理念。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">Vistior</span>
				<span style="font-family: 宋体;">的应用场景是这样：</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">我
在商品定购目录上看到一个公司有我感兴趣的产品系列。于是我上门拜访该公司，公司给我安排了一场产品性能展示，我看了几个之后，没有什么满意的，于是我
说，我肚子疼，想先回去了。遇到好心的公司代表，当然说，身体要紧，慢走。遇到固执的公司代表，一定会说，对不起，我们公司有自己的工作流程，完成产品演
示之前，产品厅的门锁是打不开的。我只好勃然大怒，吵吵嚷嚷（</span>
				<span lang="EN-US">throw exception</span>
				<span style="font-family: 宋体;">），期待能够杀出重围，这时候，假设该公司的保安系统反映比较灵敏（</span>
				<span lang="EN-US">try catch every visitor exception</span>
				<span style="font-family: 宋体;">），就会有几个保安跑过来，把我按在椅子上继续听讲。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">入乡随俗，客随主便。别人的地盘，别人做主。这就是</span>
				<span lang="EN-US">Visitor Pattern</span>
				<span style="font-family: 宋体;">的理念。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">Iterator Pattern</span>
				<span style="font-family: 宋体;">的优势当然不仅如此。这只是个特殊的例子。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">更常见的是，</span>
				<span lang="EN-US">Iterator
Pattern</span>
				<span style="font-family: 宋体;">能够支持基于</span>
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">的很多算法。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">比如，</span>
				<span lang="EN-US">Functional
Programming</span>
				<span style="font-family: 宋体;">的</span>
				<span lang="EN-US">Map, Reduce,
Filter</span>
				<span style="font-family: 宋体;">等函数都是接受一个</span>
				<span lang="EN-US">Iterator
(Sequence, List, Stream</span>
				<span style="font-family: 宋体;">等</span>
				<span lang="EN-US">)</span>
				<span style="font-family: 宋体;">。</span>
				<span lang="EN-US">Map, Filter</span>
				<span style="font-family: 宋体;">等函数还可以组合成一个新的</span>
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">。这个组合可以一直下去。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">当然，</span>
				<span lang="EN-US">Visitor</span>
				<span style="font-family: 宋体;">也是可以组合的。但是限制严格，缺乏扩展性。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">比如这样一个需求：</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">有</span>
				<span lang="EN-US">T1</span>
				<span style="font-family: 宋体;">和</span>
				<span lang="EN-US">T2</span>
				<span style="font-family: 宋体;">两棵树。首先遍历</span>
				<span lang="EN-US">T1</span>
				<span style="font-family: 宋体;">的</span>
				<span lang="EN-US">10</span>
				<span style="font-family: 宋体;">个</span>
				<span lang="EN-US">Node</span>
				<span style="font-family: 宋体;">，如果发现</span>
				<span lang="EN-US">Apple</span>
				<span style="font-family: 宋体;">，那么摘下来，然后继续遍历，如果</span>
				<span lang="EN-US">10</span>
				<span style="font-family: 宋体;">步都没有发现</span>
				<span lang="EN-US">Apple</span>
				<span style="font-family: 宋体;">，那么切换到</span>
				<span lang="EN-US">T2</span>
				<span style="font-family: 宋体;">；遍历</span>
				<span lang="EN-US">T2</span>
				<span style="font-family: 宋体;">的规则也是如此，</span>
				<span lang="EN-US">10</span>
				<span style="font-family: 宋体;">步之内发现目标，就继续，否则就切换到</span>
				<span lang="EN-US">T1</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">Iterator Pattern</span>
				<span style="font-family: 宋体;">实现起来很简单。相当于我是买方，情势是买方市场，我可以让两个公司的销售代表同时到我的公司来，我可以同时接待他们，让他们各自按顺序展示自己的产品。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">Visitor Pattern</span>
				<span style="font-family: 宋体;">怎么做？情势是卖方市场，我巴巴地跑上门去，看</span>
				<span lang="EN-US">T1</span>
				<span style="font-family: 宋体;">公司的产品展示，看了</span>
				<span lang="EN-US">10</span>
				<span style="font-family: 宋体;">个之后说，请送我到</span>
				<span lang="EN-US">T2</span>
				<span style="font-family: 宋体;">公司的产品展示现场，我看</span>
				<span lang="EN-US">10</span>
				<span style="font-family: 宋体;">个之后，再回来。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">一个用户可以同时使用多个算法的</span>
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">；但是用户的一个</span>
				<span lang="EN-US">Visitor</span>
				<span style="font-family: 宋体;">只能同时进入一个算法。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">这就是两者核心理念的不同。</span>
		</p>
		<h2>
				<span style="font-family: 黑体;">实现难度</span>
		</h2>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">读者说了，</span>
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">这么方便，你就使用</span>
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">好了，说这么多干什么。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">如果别人提供了</span>
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">，我当然会使用。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">现在的问题是，假设你是算法公司的成员。你是提供</span>
				<span lang="EN-US">Visitor Pattern</span>
				<span style="font-family: 宋体;">的</span>
				<span lang="EN-US">API</span>
				<span style="font-family: 宋体;">，还是</span>
				<span lang="EN-US">Iterator
Pattern</span>
				<span style="font-family: 宋体;">的</span>
				<span lang="EN-US">API</span>
				<span style="font-family: 宋体;">？</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">Visitor Pattern</span>
				<span style="font-family: 宋体;">的实现比较简单。自己知道自己公司的内部组织结构，一个一个的遍历，并传递给</span>
				<span lang="EN-US">Visitor</span>
				<span style="font-family: 宋体;">就行了。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">Iterator Pattern</span>
				<span style="font-family: 宋体;">的实现难度，可以说，那是相当的大。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">内部数据结构简单的数组、链表好说，做一个类似于</span>
				<span lang="EN-US">Closure, Context, Continuation</span>
				<span style="font-family: 宋体;">的保存了当前调用步骤（数组索引，或者当前指针）和调用环境（内部数据集）的结构，返回给用户就可以了。用户每次调用</span>
				<span lang="EN-US">iterator.next</span>
				<span style="font-family: 宋体;">，</span>
				<span lang="EN-US">iterator</span>
				<span style="font-family: 宋体;">就把索引或指针向后移动一下。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">如果是内部数据复杂的</span>
				<span lang="EN-US">Tree,
Graph</span>
				<span style="font-family: 宋体;">结构，就相当复杂了。比如是遍历一棵树，而且这棵树的</span>
				<span lang="EN-US">Node</span>
				<span style="font-family: 宋体;">里面没有</span>
				<span lang="EN-US">Parent</span>
				<span style="font-family: 宋体;">引用，那么</span>
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">必须自己维护一个栈把前面的所有的</span>
				<span lang="EN-US">Parent Node</span>
				<span style="font-family: 宋体;">都保存起来。当用户调用</span>
				<span lang="EN-US">iterator.next</span>
				<span style="font-family: 宋体;">的时候，</span>
				<span lang="EN-US">iterator</span>
				<span style="font-family: 宋体;">就必须检查自己当前的状态，如果所有的</span>
				<span lang="EN-US">Child Node</span>
				<span style="font-family: 宋体;">都走完了，那么就要返回到上面的</span>
				<span lang="EN-US">Parent</span>
				<span style="font-family: 宋体;">，继续检查。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">而在</span>
				<span lang="EN-US">Visitor
Pattern</span>
				<span style="font-family: 宋体;">里面，这个算法的实现简直是小菜一碟，只要一个简单的递归就够了。计算机会自动帮你分配和管理运行栈，保存前面的</span>
				<span lang="EN-US">Parent Node</span>
				<span style="font-family: 宋体;">，执行返回的时候，这个</span>
				<span lang="EN-US">Parent Node</span>
				<span style="font-family: 宋体;">又自动交还给你。</span>
		</p>
		<h2>
				<span lang="EN-US">Coroutine</span>
		</h2>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">有没有简单的方法来实现</span>
				<span lang="EN-US">Iterator
Pattern API</span>
				<span style="font-family: 宋体;">呢？如同实现</span>
				<span lang="EN-US">Visitor
Pattern API</span>
				<span style="font-family: 宋体;">那样容易？</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">幸福得象花儿一样。简单得像</span>
				<span lang="EN-US">Visitor</span>
				<span style="font-family: 宋体;">一样。能不能那样？</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">聪明的人们把目光转向了</span>
				<span lang="EN-US">Coroutine</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">Coroutine</span>
				<span style="font-family: 宋体;">本来是一个通用的概念。表示几个协同工作的程序。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">比如，消费者</span>
				<span lang="EN-US">/</span>
				<span style="font-family: 宋体;">生产者，你走几步，我走几步；下棋对弈，你一步我一步。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">由于协同工作的程序通常只有</span>
				<span lang="EN-US">2</span>
				<span style="font-family: 宋体;">个，而且这两个程序交换的数据通常只有一个。于是人们就很容易想到用</span>
				<span lang="EN-US">Coroutine</span>
				<span style="font-family: 宋体;">来实现</span>
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">这里面</span>
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">就是</span>
				<span lang="EN-US">Coroutine</span>
				<span style="font-family: 宋体;">里面的生产者</span>
				<span lang="EN-US">Producer</span>
				<span style="font-family: 宋体;">角色，数据提供者。所以，也叫做</span>
				<span lang="EN-US">Generator</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">每次</span>
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">程序就是等在那里，一旦用户（消费者</span>
				<span lang="EN-US">Consumer</span>
				<span style="font-family: 宋体;">角色）调用了</span>
				<span lang="EN-US">iterator.next, Iterator</span>
				<span style="font-family: 宋体;">就继续向下执行一步，然后把当前遇到的内部数据的</span>
				<span lang="EN-US">Node</span>
				<span style="font-family: 宋体;">放到一个消费者用户能够看到的公用的缓冲区（比如，直接放到消费者线程栈里面的局部变量）里面，然后自己就停下来（</span>
				<span lang="EN-US">wait</span>
				<span style="font-family: 宋体;">）。然后消费者用户就从缓冲区里面获得了那个</span>
				<span lang="EN-US">Node</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">这样</span>
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">就可以自顾自地进行递归运算，不需要自己管理一个栈，而是迫使计算机帮助它分配和管理运行栈。于是就实现了幸福得像花儿一样，简单得像</span>
				<span lang="EN-US">Visitor</span>
				<span style="font-family: 宋体;">一样的梦想。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">比如，这样一段代码，遍历一棵二叉树。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">public class TreeWalker : Coroutine {<br />
    private TreeNode _tree;<br />
    public TreeWalker(TreeNode tree) { _tree = tree; }<br />
    protected override Execute() {<br />
        Walk(_tree);<br />
    }<br />
    private void Walk(TreeNode tree) {<br />
        if (tree != null) {<br />
           
Walk(tree.Left);<br /><span style="color: red;">           
Yield(tree);<br /></span>           
Walk(tree.Right);<br />
        }<br />
    }<br />
}</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: &quot;Courier New&quot;;" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">其中的</span>
				<span lang="EN-US">Yield</span>
				<span style="font-family: 宋体;">指令是关键。意思是，首先把当前</span>
				<span lang="EN-US">Node</span>
				<span style="font-family: 宋体;">甩到用户的数据空间，然后自己暂停运行（类似于</span>
				<span lang="EN-US">java</span>
				<span style="font-family: 宋体;">的</span>
				<span lang="EN-US">thread yield</span>
				<span style="font-family: 宋体;">方法或者</span>
				<span lang="EN-US">object.wait</span>
				<span style="font-family: 宋体;">方法），把自己当前运行的线程挂起来，这样虚拟机就为自己保存了当前的运行栈（</span>
				<span lang="EN-US">context</span>
				<span style="font-family: 宋体;">）。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">有人说，这不就是</span>
				<span lang="EN-US">continuation</span>
				<span style="font-family: 宋体;">吗？</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">对。只是</span>
				<span lang="EN-US">Coroutine</span>
				<span style="font-family: 宋体;">这里多了一个产生并传递数据的动作。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">实现原理如果用</span>
				<span lang="EN-US">Java
Thread</span>
				<span style="font-family: 宋体;">表示大概就是这样。当然下面的代码只是一个示意。网上有具体的</span>
				<span lang="EN-US">Java Coroutine</span>
				<span style="font-family: 宋体;">实现，具体代码我也没有看过，想来实现原理大致如此。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">public class TreeIterator implements
Iterator{</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<span style="">  
</span>TreeWalker walker;</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<span style="">   
</span>// start the walker thread ..</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<span style="">  
</span>Object next(){</span>
		</p>
		<p class="MsoNormal">
				<span style="color: red;" lang="EN-US">
						<span style="">     </span>walker.notify();<o:p></o:p></span>
		</p>
		<p class="MsoNormal">
				<span style="color: red;" lang="EN-US">
						<span style="">     </span>// wait for a while so that walker can
continue run<o:p></o:p></span>
		</p>
		<p class="MsoNormal">
				<span style="color: red;" lang="EN-US">
						<span style="">     </span>return walker.currentNode;<o:p></o:p></span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<span style="">   </span>}</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">}</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">class TreeWalker implements Runnable{</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">    TreeNode currentNode;<br />
   </span>
		</p>
		<p class="MsoNormal" style="text-indent: 10.5pt;">
				<span lang="EN-US">TreeWarker(root){<span style="">  </span></span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<span style="">  </span>
						<span style="">  </span>currentNode = root;</span>
		</p>
		<p class="MsoNormal" style="text-indent: 10.5pt;">
				<span lang="EN-US">}</span>
		</p>
		<p class="MsoNormal" style="text-indent: 10.5pt;">
				<span lang="EN-US">void run(){</span>
		</p>
		<p class="MsoNormal" style="text-indent: 10.5pt;">
				<span lang="EN-US">
						<span style="">  </span>walk(curentNode);</span>
		</p>
		<p class="MsoNormal" style="text-indent: 10.5pt;">
				<span lang="EN-US">}</span>
		</p>
		<p class="MsoNormal" style="text-indent: 10.5pt;">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="text-indent: 14.25pt;">
				<span lang="EN-US">private void
Walk(TreeNode tree) {<br />
        if (tree != null) {<br />
           
Walk(tree.Left);</span>
		</p>
		<p class="MsoNormal" style="text-indent: 34.85pt;">
				<span style="color: red;" lang="EN-US">currentNode = tree;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="text-indent: 34.85pt;">
				<span style="color: red;" lang="EN-US">this.wait();<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="text-indent: 34.85pt;">
				<span lang="EN-US">Walk(tree.Right);<br />
        }<br />
    }<br />
}</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">我们看到，</span>
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">本身是一个</span>
				<span lang="EN-US">Thread</span>
				<span style="font-family: 宋体;">，用户也是一个</span>
				<span lang="EN-US">Thread</span>
				<span style="font-family: 宋体;">。</span>
				<span lang="EN-US">Iterator Thread</span>
				<span style="font-family: 宋体;">把数据传递给</span>
				<span lang="EN-US">User Thread</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">说实话，我宁可自己维护一个</span>
				<span lang="EN-US">Stack</span>
				<span style="font-family: 宋体;">，也不愿意引入</span>
				<span lang="EN-US">Coroutine</span>
				<span style="font-family: 宋体;">这类</span>
				<span lang="EN-US">Thread Control</span>
				<span style="font-family: 宋体;">的方式来实现</span>
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<h2>
				<span style="font-family: 黑体;">总结</span>
		</h2>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">千言万语一句话。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-US">Iterator</span>
				<span style="font-family: 宋体;">是好的，但不是免费的。</span>
		</p>
<img src ="http://www.blogjava.net/Vencent/aggbug/58381.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-07-16 01:47 <a href="http://www.blogjava.net/Vencent/articles/58381.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> Web  显示层技术评估  </title><link>http://www.blogjava.net/Vencent/articles/58380.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Sat, 15 Jul 2006 17:46:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/58380.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/58380.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/58380.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/58380.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/58380.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Web				显示层技术评估								名词界定								显示层的意思就是				PresentationLayer				，也翻译成表现层、展现层、展示层。								本文讨论的范围只包括采用				HTMLTemplate				的显示层技术，不包括				Echo				，				GWT(google ...&nbsp;&nbsp;<a href='http://www.blogjava.net/Vencent/articles/58380.html'>阅读全文</a><img src ="http://www.blogjava.net/Vencent/aggbug/58380.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-07-16 01:46 <a href="http://www.blogjava.net/Vencent/articles/58380.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>log4j配置简要说明</title><link>http://www.blogjava.net/Vencent/articles/42244.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Thu, 20 Apr 2006 16:11:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/42244.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/42244.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/42244.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/42244.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/42244.html</trackback:ping><description><![CDATA[
		<font color="#000000" face="宋体" size="3">虽然以前一直在用log4j,但是对其配置不甚了了，突然间因为需解决某些问题，要理解log4j的配置，<br />然而用google搜了一下，却发现网上没有一个简单直观的说明，于是只好看log4j的官方介绍,终于<br />理解了log4j的配置用法，以下是我对log4j配置的一点认识，如有谬误还请不吝赐教.<br /><br />首先我们搞清楚log4j能干什么，简单来说就是提供一个记录不同级别信息内容的日志工具，<br />可以把不同级别，不同包路径的信息，以指定格式输出到多种设备（控制台，文件等）<br />在程序中，可以以以下方式来使用<br />   Log log = org.apache.commons.logging.LogFactory.LogFactory.getLog(yourClassName.class);<br />  log.debug("debug message -------------------");<br />  log.info("info message ******************");<br />  log.warn("warn message +++++++++++++++");<br />  log.error("error msg=================");<br />  <br />本文主要讲的是如何配置log4j，先让我们先看看一个典型的log4j配置：  <br /><br />==========log4j.properties==================<br /><br />log4j.appender.stdout=org.apache.log4j.ConsoleAppender<br />log4j.appender.stdout.layout=org.apache.log4j.PatternLayout<br />log4j.appender.stdout.layout.ConversionPattern=%d{MM-dd HH\:mm\:ss.SSS} %-5p [%F\:%L]%x %m%n<br /><br />log4j.appender.fileout=org.apache.log4j.RollingFileAppender<br />log4j.appender.fileout.File=D:/workspace/log4jtest/log/application.log<br />log4j.appender.fileout.MaxFileSize=10000KB<br />log4j.appender.fileout.MaxBackupIndex=10<br />log4j.appender.fileout.layout=org.apache.log4j.PatternLayout<br />log4j.appender.fileout.layout.ConversionPattern=%d{MM-dd HH:mm:ss.SSS}[%24F:%-3L:%-5p]%x %m%n<br /><br />log4j.rootCategory=INFO, stdout, fileout<br />log4j.logger.com.wolfsquare.log2=DEBUG,stdout<br />===================================<br /><br />这个文件可以划为三小块<br /><br />===========第一块定义了一个名为 stdout 的appender和layout (appender,layout的概念后面再解释，目前先记着有这样两个名词)：<br /><br />log4j.appender.stdout=org.apache.log4j.ConsoleAppender<br />定义stdout的实际输出实现类，从这个appender实现类名可以猜到，这个类是负责控制台输出的。<br />log4j.appender.stdout.layout=org.apache.log4j.PatternLayout<br />定义stdout的输出装饰器<br />log4j.appender.stdout.layout.ConversionPattern=%d{MM-dd HH\:mm\:ss.SSS} %-5p [%F\:%L]%x %m%n<br />装饰器参数配置<br /><br /><br />============第二块定义了一个名为 fileout 的appender和layout:<br />log4j.appender.fileout=org.apache.log4j.RollingFileAppender<br />同理可猜这个实现类是输出到文件的<br />log4j.appender.fileout.File=D:/workspace/log4jtest/log/application.log<br />log4j.appender.fileout.MaxFileSize=10000KB<br />log4j.appender.fileout.MaxBackupIndex=10<br />log4j.appender.fileout.layout=org.apache.log4j.PatternLayout<br />log4j.appender.fileout.layout.ConversionPattern=%d{MM-dd HH:mm:ss.SSS}[%24F:%-3L:%-5p]%x %m%n<br /><br />============第三块定义了名字分别为rootCategory,log4j.logger.com.wolfsquare.log2的两个logger<br />log4j.rootCategory=INFO, stdout, fileout<br />log4j.logger.com.wolfsquare.log2=DEBUG,stdout<br /><br />rootCategory logger是缺省的logger，记录所有的包的信息输出。<br />第二个logger是只输出指定包com.wolfsquare.log2下的日志信息。<br />那么INFO,DEBUG又是什么意思呢，他们是信息的分级标识，通过继承实现这个实现自定义级别的分级。<br />第三块配置两句的意思是这样的：<br />rootCategory 把所有类的INFO级别以上的信息输出到stdout和fileout两个appender中，<br />logger.com.wolfsquare.log2，把com.wolfsquare.log2包中的所有类（包括子包）DEBUG级别（含）以上的信息输出到stdout 中<br />一个logger可以输出到很多个设备中（appender）,如果需要增加输出设备则用分号分隔开appender名称即可。<br /><br />输出信息的分类级别是DEBUG &gt; INFO &gt; WARN &gt; ERROR,信息细节由细到粗，指定输出某一级别的信息时，<br />过细的信息输出将会被忽略<br /><br />如果一个配置中有多个logger，他们之间会有什么关系呢？答案是，在输出上，他们没有任何关系，都是独立运作的，<br />不相关的，但是在配置上，父包的配置会传给子包，如果子包没有另外定义配置的话。<br />例如上面配置文件中的两个logger：<br />log4j.logger.com.wolfsquare<br />log4j.logger.com.wolfsquare.log2<br /><br />这里认为 log4j.logger.com.wolfsquare.log2 继承自 log4j.logger.com.wolfsquare，他们的配置声明如下：<br />log4j.rootCategory=INFO, stdout, fileout<br />log4j.logger.com.wolfsquare.log2=,stdout<br />注意第二句没有指定输出级别,那么根据配置继承规则会继承父logger的配置，在这里就是INFO。<br /><br />同时需要强调的是，如果两个logger有继承关系，且输出到同一个appender，根据输出独立原则，那么将会出现两行一样的信息，<br />例如上面的两个logger定义会导致这样的情况。<br />最后以一幅图来概括：</font>
		<font face="Times New Roman" size="3">
		</font>
		<font color="#000000" face="Courier New">
		</font>
		<br />
		<p>
				<b>
						<img src="http://java.mblogger.cn/upimgs/java.mblogger.cn/wolfsquare/2006-4/2006_420273.gif" />
				</b>
		</p>
<img src ="http://www.blogjava.net/Vencent/aggbug/42244.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-04-21 00:11 <a href="http://www.blogjava.net/Vencent/articles/42244.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[TDD开发的全过程] 二、开发PhoneManager等类</title><link>http://www.blogjava.net/Vencent/articles/40990.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Thu, 13 Apr 2006 15:15:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/40990.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/40990.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/40990.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/40990.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/40990.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 一、前言今天我把文章的名称改了一下，想把它写成关于TDD实践的一系列文章。前一篇是设计，这一篇开始是开发。TDD我是闻名已久，在过去实际开发中也经常用junit来写单元测试，但真正的TDD却从来没有尝试过。不过单元测试写得久了，发现TDD确实有它诱人的地方，也许它真的可以带我领略一个新的编程世界。于是，又再次翻开BOB的那本〈敏捷**开发〉（去年只看了一半），现在就学用结合吧。在BOB...&nbsp;&nbsp;<a href='http://www.blogjava.net/Vencent/articles/40990.html'>阅读全文</a><img src ="http://www.blogjava.net/Vencent/aggbug/40990.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-04-13 23:15 <a href="http://www.blogjava.net/Vencent/articles/40990.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JMS入门(转自dev2dev)</title><link>http://www.blogjava.net/Vencent/articles/40864.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Thu, 13 Apr 2006 04:47:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/40864.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/40864.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/40864.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/40864.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/40864.html</trackback:ping><description><![CDATA[
		<a id="viewpost1_TitleUrl" class="postTitle2" href="../../loocky/archive/2006/04/13/40797.html">
		</a>
		<div class="postTitle">
				<span class="h1b">BEA WebLogic Server8.1 JMS入门</span>
				<br />
		</div>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td height="64">时间：2003-11-28<br />作者：<a href="http://dev2dev.bea.com.cn/author/67.html">周海根</a><br />浏览次数：
<script language="JavaScript" src="http://203.81.25.103/cgi-bin/beadevcount.cgi?d_id=547" type="text/JavaScript"></script>
 2831 2728 <br />本文关键字：<a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=JMS">JMS</a>, <a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=%E5%9F%BA%E7%A1%80">基础</a>, <a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=%E6%95%99%E7%A8%8B">教程</a>, <a href="http://dev2dev.bea.com.cn/products/search.jsp?searchtype=keywords&amp;keywords=%E6%A6%82%E5%BF%B5">概念</a></td>
								<td>
										<table class="box_content" border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td>
																		<span class="h2b">文章工具</span>
																		<br />
																		<img alt="推荐给朋友" src="http://dev2dev.bea.com.cn/images/letter001.gif" align="absmiddle" height="10" width="19" /> <a href="javascript:sendmail()">推荐给朋友</a><br /><img alt="打印文章" src="http://dev2dev.bea.com.cn/images/print001.gif" align="absmiddle" height="18" width="19" /> <a href="javascript:window.print()">打印文章</a></td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<!-- 提取技术文章 -->
		<div class="beas">
				<img alt="" src="http://dev2dev.bea.com.cn/images/dot6B6B6B.gif" height="1" width="100%" />
		</div>
		<p>
				<b>一. JMS简介<br />1. JMS基本概念</b>
				<br />JMS(Java Message Service)是访问企业消息系统的标准API,它便于消息系<br />统中的Java应用程序进行消息交换,并且通过提供标准的产生、发送、接收消息的接口简化企业应用的开发。<br /><img src="http://dev2dev.bea.com.cn/images/school/server031128/image001.gif" height="167" width="318" /><br /><b>2. JMS基本功能</b><br />JMS
是用于和面向消息的中间件相互通信的应用程序接口。它既支持点对点(point-to-point)的域，又支持发布/订阅
(publish/subscribe)类型的域，并且提供对下列类型的支持：经认可的消息传递,事务型消息的传递，一致性消息和具有持久性的订阅者支
持。JMS还提供了另一种方式来对您的应用与旧的后台系统相集成。<br /><b>3. WebLogic JMS Server介绍</b><br />WebLogic Server8.1符合JAVA规范,并通过Sun Microsystems J2EE 1.3认<br />证.
作为WebLogic的一部分,当然WebLogic JMS
Server也完全遵从JMS规范,还支持集群,并可以应用于实际企业系统.下图是WebLogic JMS
Server体系结构.图中可以看到WebLogic JMS Server主要组件有: WebLogic JMS
servers(用于消息通信),Java客户端,JNDI(用于域名查找), 后备存储(用于持久消息存储,基于文件或者JDBC数据库).<br /><img src="http://dev2dev.bea.com.cn/images/school/server031128/image002.jpg" height="400" width="448" /><br /><b>二. WebLogic JMS特性</b><br />1. 消息通信模型<br />JMS 支持两种消息通信模型：点到点（point-to-point）（PTP）模型和发布/订阅（Pub/Sub）模型。除了下列不同之外，这两种消息通信模型非常地相似：<br />PTP 模型规定了一个消息只能有一个接收者;Pub/Sub 模型允许一个消息可以有多个接收者。<br />2. 消息组成<br />消息传递系统的中心就是消息。<br />一条 Message 分为三个组成部分： <br />· 头（header）是个标准字段集，客户机和供应商都用它来标识和路由消息。<br />·
属性（property）支持把可选头字段添加到消息。如果您的应用程序需要不使用标准头字段对消息编目和分类，您就可以添加一个属性到消息以实现这个编
目和分类。提供 set&lt;Type&gt;Property(...) 和 get&lt;Type&gt;Property(...)
方法以设置和获取各种 Java 类型的属性，包括 Object。JMS 定义了一个供应商选择提供的标准属性集。<br />· 消息的主体（body）包含要发送给接收应用程序的内容。每个消息接口特定于它所支持的内容类型。 <br />JMS 为不同类型的内容提供了它们各自的消息类型，但是所有消息都派生自 Message 接口。<br />· StreamMessage：包含 Java 基本数值流，用标准流操作来顺序的填充和读取。<br />· MapMessage：包含一组名/值对；名称为 string 类型，而值为 Java 的基本类型。<br />· TextMessage：包含一个 String。<br />· ObjectMessage：包含一个 Serializable Java 对象；能使用 JDK 的集合类。<br />· BytesMessage：包含未解释字节流: 编码主体以匹配现存的消息格式。<br />· XMLMessage: 包含XML内容。扩展TextMessage,XMLMessage 类型的使用，使得消息过滤非常便利。<br />3. 消息确认模式<br />非事务性会话中，应用程序创建的会话有5 种确认模式,而在事务性会话中，确认模式被忽略。<br />五种确认模式说明:<br />· AUTO_ACKNOWLEDGE：自动确认模式。一旦接收方应用程序的方法调用从处理消息处返回，会话对象就会确认消息的接收。<br />·
CLIENT_ACKNOWLEDGE：客户端确认模式。会话对象依赖于应用程序对被接收的消息调用一个acknowledge()方法。一旦这个方法被
调用，会话会确认最后一次确认之后所有接收到的消息。这种模式允许应用程序以一个调用来接收，处理并确认一批消息。注意：在管理控制台中，如果连接工厂的
Acknowledge
Policy（确认方针）属性被设置为"Previous"（提前），但是你希望为一个给定的会话确认所有接收到的消息，那么就用最后一条消息来调用
acknowledge()方法。<br />·
DUPS_OK_ACKNOWLEDGE：允许副本的确认模式。一旦接收方应用程序的方法调用从处理消息处返回，会话对象就会确认消息的接收；而且允许重
复确认。在需要考虑资源使用时，这种模式非常有效。注意：如果你的应用程序无法处理重复的消息的话，你应该避免使用这种模式。如果发送消息的初始化尝试失
败，那么重复的消息可以被重新发送。<br />·
NO_ACKNOWLEDGE：不确认模式。不确认收到的消息是需要的。消息发送给一个NO_ACKNOWLEDGE
会话后，它们会被WebLogic 服务器立即删除。在这种模式下，将无法重新获得已接收的消息，而且可能导致下面的结果：1.
消息可能丢失；和（或者）另一种情况：2. 如果发送消息的初始化尝试失败，会出现重复消息被发送的情况。<br />·
MULTICAST_NO_ACKNOWLEDGE：IP组播下的不确认模式，同样无需确认。发送给一个
MULTICAST_NO_ACKNOWLEDGE会话的消息， 会共享之前所述的NO_ACKNOWLEDGE
确认模式一样的特征。这种模式支持希望通过IP
组播方式进行消息通信的应用程序，而且无需依赖会话确认提供的服务质量。注意：如果你的应用程序无法处理消息的丢失或者重复，那么你应该避免使用这种模
式。如果发送消息的初始化尝试失败的话，重复的消息可能会被再次发送。<br />注：在上表的5 种确认模式中，AUTO_ACKNOWLEDGE ，DUPS_OK_ACKNOWLEDGE 和<br />CLIENT_ACKNOWLEDGE 是JMS 规范定义的，NO_ACKNOWLEDGE 和MULTICAST_NO_ACKNOWLEDGE是WebLogic JMS 提供的。<br /><b>三. 配置JMS</b><br />1. 创建连接工厂<br />(1) 启动WebLogic Server8.1,登录控制台,选中JMS Connection Factories节点,点击右边的" Configure a new JMS Connection Factory...";<br /><img src="http://dev2dev.bea.com.cn/images/school/server031128/image004.jpg" height="415" width="554" /><br />(2) 填写连接工厂的名称SendJMSFactory和JNDI名称SendJMSFactory,点击"Create";<br /><img src="http://dev2dev.bea.com.cn/images/school/server031128/image006.jpg" height="415" width="554" /><br />(3) 勾上"myserver",将SendJMSFactory应用到myserver;<br /><img src="http://dev2dev.bea.com.cn/images/school/server031128/image008.jpg" height="415" width="554" /><br />2. 定义后备存储<br />(1) 选中JMS Stores节点,点击右边的" Configure a new JMS Connection Factory...";<br /><img src="http://dev2dev.bea.com.cn/images/school/server031128/image010.jpg" height="415" width="554" /><br />(2) 填写文件后备存储的名称SendFileStore和目录Directionary E:\BEA\user_projects\domains\mydomain\sendfilestore,点击"Create".<br /><img src="http://dev2dev.bea.com.cn/images/school/server031128/image012.jpg" height="415" width="554" /><br />3. 创建JMS服务器<br />(1) 选中JMS Servers节点,点击右边的" Configure a new JMSServer...";<br /><img src="http://dev2dev.bea.com.cn/images/school/server031128/image014.jpg" height="415" width="554" /><br />(2) 填写JMS服务器的名称SendJMSServer和Paging Store设为" SendFileStore",点击"Create"; <br /><img src="http://dev2dev.bea.com.cn/images/school/server031128/image016.jpg" height="415" width="554" /><br />(3) Target选中"myserver",将SendJMSServer应用到myserver.<br /><img src="http://dev2dev.bea.com.cn/images/school/server031128/image018.jpg" height="415" width="554" /><br />4. 创建消息队列<br />(1) 展开"SendJMSServer"节点,点击" Configure a new JMS Queue...";<br /><img src="http://dev2dev.bea.com.cn/images/school/server031128/image020.jpg" height="415" width="554" /><br />(2) 填写消息队列的名称SendJMSQueue和JNDI名称SendJMSQueue,点击"Create"; <br /><img src="http://dev2dev.bea.com.cn/images/school/server031128/image022.jpg" height="415" width="554" /><br />四. JMS应用程序<br />一个 JMS 应用程序由下列元素组成： <br />· JMS 客户机。 用 JMS API 发送和接收消息的 Java 程序。<br />· 非 JMS（Non-JMS）客户机。 认识到这一点很重要 - 旧的程序经常成为整个 JMS 应用程序的一部分，而且它们的包含应该在设计时预先考虑。<br />· 消息。 在 JMS 和非 JMS 客户机之间交换的消息的格式和内容是 JMS 应用程序设计所必须考虑的部分。<br />· JMS 供应商。供应商必须提供特定于其 MOM 产品的具体的实现。<br />· 受管对象。 消息传递系统供应商的管理员创建了一个对象，它独立于供应商专有的技术。包括连接工厂ConnectionFactory和目的Destination。<br />一种典型的 JMS 程序需要经过下列步骤才能开始消息产生和使用:<br />· 通过 JNDI 查找 ConnectionFactory。<br />· 通过 JNDI 查找一个或多个 Destination。 <br />· 用 ConnectionFactory 创建一个 Connection。 <br />· 用 Connection 创建一个或多个 Session。 <br />· 用 Session 和 Destination 创建所需的 MessageProducer 和 MessageConsumer。 <br />· 启动 Connection。 <br />下面利用上面配置的JMS资源演示点对点消息发送和接收的过程。<br />五. 设计消息发送端<br />1. 使用的JMS资源<br />服务器URL: t3://localhost:80<br />连接工厂: SendJMSFactory<br />队列: SendJMSQueue<br />2. 设计步骤<br />· 初始化JNDI Tree<br />Hashtable env = new Hashtable();<br />env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);<br />env.put(Context.PROVIDER_URL, PROVIDER_URL);<br />return new InitialContext(env);<br />· lookup ConnectionFactory<br />qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY);<br />· lookup Destination<br />queue = (Queue) ctx.lookup(queueName);<br />· 用 ConnectionFactory 创建Connection <br />qcon = qconFactory.createQueueConnection();<br />· 用 Connection 创建一个Session<br />qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);<br />· 用 Session 和 Destination 创建MessageProducer<br />qsender = qsession.createSender(queue);<br />· 启动 Connection。<br />qcon.start();<br />· 发送消息<br />msg = qsession.createTextMessage();<br />msg.setText(message);<br />qsender.send(msg);<br />3. 源代码<br />package jmssample;</p>
		<p>import java.util.Hashtable;<br />import javax.jms.*;<br />import javax.naming.Context;<br />import javax.naming.InitialContext;<br />import javax.naming.NamingException;<br />import java.io.BufferedReader;<br />import java.io.IOException;<br />import java.io.InputStreamReader;</p>
		<p>/** This example shows how to establish a connection<br />* and send messages to the JMS queue. The classes in this<br />* package operate on the same JMS queue. Run the classes together to<br />* witness messages being sent and received, and to browse the queue<br />* for messages. The class is used to send messages to the queue.<br />*<br />* @author Copyright (c) 1999-2003 by BEA Systems, Inc. All Rights Reserved.<br />*/<br />public class QueueSend<br />{<br />// Defines the JNDI context factory.<br />public final static String JNDI_FACTORY="weblogic.jndi.WLInitialContextFactory";</p>
		<p>// Defines the JNDI provider url.<br />public final static String PROVIDER_URL=" t3://localhost:80";</p>
		<p>// Defines the JMS connection factory for the queue.<br />public final static String JMS_FACTORY="SendJMSFactory";</p>
		<p>// Defines the queue.<br />public final static String QUEUE="SendJMSQueue";</p>
		<p>
				<br />private QueueConnectionFactory qconFactory;<br />private QueueConnection qcon;<br />private QueueSession qsession;<br />private QueueSender qsender;<br />private Queue queue;<br />private TextMessage msg;</p>
		<p>/**<br />* Creates all the necessary objects for sending<br />* messages to a JMS queue.<br />*<br />* @param ctx JNDI initial context<br />* @param queueName name of queue<br />* @exception NamingException if operation cannot be performed<br />* @exception JMSException if JMS fails to initialize due to internal error<br />*/<br />public void init(Context ctx, String queueName)<br />throws NamingException, JMSException<br />{<br />qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY);<br />qcon = qconFactory.createQueueConnection();<br />qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);<br />queue = (Queue) ctx.lookup(queueName);<br />qsender = qsession.createSender(queue);<br />msg = qsession.createTextMessage();<br />qcon.start();<br />}</p>
		<p>/**<br />* Sends a message to a JMS queue.<br />*<br />* @param message message to be sent<br />* @exception JMSException if JMS fails to send message due to internal error<br />*/<br />public void send(String message) throws JMSException {<br />msg.setText(message);<br />qsender.send(msg);<br />}</p>
		<p>/**<br />* Closes JMS objects.<br />* @exception JMSException if JMS fails to close objects due to internal error<br />*/<br />public void close() throws JMSException {<br />qsender.close();<br />qsession.close();<br />qcon.close();<br />}<br />/** main() method.<br />*<br />* @param args WebLogic Server URL<br />* @exception Exception if operation fails<br />*/<br />public static void main(String[] args) throws Exception {<br />InitialContext ic = getInitialContext();<br />QueueSend qs = new QueueSend();<br />qs.init(ic, QUEUE);<br />readAndSend(qs);<br />qs.close();<br />}</p>
		<p>private static void readAndSend(QueueSend qs)<br />throws IOException, JMSException<br />{<br />BufferedReader msgStream = new BufferedReader(new InputStreamReader(System.in));<br />String line=null;<br />boolean quitNow = false;<br />do {<br />System.out.print("Enter message (\"quit\" to quit): ");<br />line = msgStream.readLine();<br />if (line != null &amp;&amp; line.trim().length() != 0) {<br />qs.send(line);<br />System.out.println("JMS Message Sent: "+line+"\n");<br />quitNow = line.equalsIgnoreCase("quit");<br />}<br />} while (! quitNow);</p>
		<p>}</p>
		<p>private static InitialContext getInitialContext()<br />throws NamingException<br />{<br />Hashtable env = new Hashtable();<br />env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);<br />env.put(Context.PROVIDER_URL, PROVIDER_URL);<br />return new InitialContext(env);<br />}</p>
		<p>}</p>
		<p>六. 设计消息接收端<br />1. 使用的JMS资源<br />服务器URL: t3://localhost:80<br />连接工厂: SendJMSFactory<br />队列: SendJMSQueue<br />2. 设计步骤<br />· 初始化JNDI Tree<br />Hashtable env = new Hashtable();<br />env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);<br />env.put(Context.PROVIDER_URL, PROVIDER_URL);<br />return new InitialContext(env);<br />· lookup ConnectionFactory<br />qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY);<br />· lookup Destination<br />queue = (Queue) ctx.lookup(queueName);<br />· 用 ConnectionFactory 创建Connection <br />qcon = qconFactory.createQueueConnection();<br />· 用 Connection 创建一个Session<br />qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);<br />· 用 Session 和 Destination 创建MessageConsumer<br />qreceiver = qsession.createReceiver(queue);<br />· 设置监听<br />qreceiver.setMessageListener(this);<br />· 启动 Connection<br />qcon.start();<br />3. 源代码<br />package jmssample;</p>
		<p>import java.util.Hashtable;<br />import javax.jms.*;<br />import javax.naming.Context;<br />import javax.naming.InitialContext;<br />import javax.naming.NamingException;<br />import java.util.Hashtable;<br />import javax.jms.*;<br />import javax.naming.Context;<br />import javax.naming.InitialContext;<br />import javax.naming.NamingException;</p>
		<p>/**<br />* This example shows how to establish a connection to<br />* and receive messages from a JMS queue. The classes in this<br />* package operate on the same JMS queue. Run the classes together to<br />* witness messages being sent and received, and to browse the queue<br />* for messages. This class is used to receive and remove messages<br />* from the queue.<br />*<br />* @author Copyright (c) 1999-2003 by BEA Systems, Inc. All Rights Reserved.<br />*/<br />public class QueueReceive implements MessageListener<br />{<br />// Defines the JNDI context factory.<br />public final static String JNDI_FACTORY="weblogic.jndi.WLInitialContextFactory";</p>
		<p>// Defines the JNDI provider url.<br />public final static String PROVIDER_URL=" t3://localhost:80";</p>
		<p>// Defines the JMS connection factory for the queue.<br />public final static String JMS_FACTORY="SendJMSFactory";</p>
		<p>// Defines the queue.<br />public final static String QUEUE="SendJMSQueue";</p>
		<p>private QueueConnectionFactory qconFactory;<br />private QueueConnection qcon;<br />private QueueSession qsession;<br />private QueueReceiver qreceiver;<br />private Queue queue;<br />private boolean quit = false;</p>
		<p>/**<br />* Message listener interface.<br />* @param msg message<br />*/<br />public void onMessage(Message msg)<br />{<br />try {<br />String msgText;<br />if (msg instanceof TextMessage) {<br />msgText = ((TextMessage)msg).getText();<br />} else {<br />msgText = msg.toString();<br />}</p>
		<p>System.out.println("Message Received: "+ msgText );</p>
		<p>if (msgText.equalsIgnoreCase("quit")) {<br />synchronized(this) {<br />quit = true;<br />this.notifyAll(); // Notify main thread to quit<br />}<br />}<br />} catch (JMSException jmse) {<br />jmse.printStackTrace();<br />}<br />}</p>
		<p>/**<br />* Creates all the necessary objects for receiving<br />* messages from a JMS queue.<br />*<br />* @param ctx JNDI initial context<br />* @param queueName name of queue<br />* @exception NamingException if operation cannot be performed<br />* @exception JMSException if JMS fails to initialize due to internal error<br />*/<br />public void init(Context ctx, String queueName)<br />throws NamingException, JMSException<br />{<br />qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY);<br />qcon = qconFactory.createQueueConnection();<br />qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);<br />queue = (Queue) ctx.lookup(queueName);<br />qreceiver = qsession.createReceiver(queue);<br />qreceiver.setMessageListener(this);<br />qcon.start();<br />}</p>
		<p>/**<br />* Closes JMS objects.<br />* @exception JMSException if JMS fails to close objects due to internal error<br />*/<br />public void close()throws JMSException<br />{<br />qreceiver.close();<br />qsession.close();<br />qcon.close();<br />}<br />/**<br />* main() method.<br />*<br />* @param args WebLogic Server URL<br />* @exception Exception if execution fails<br />*/</p>
		<p>public static void main(String[] args) throws Exception {</p>
		<p>InitialContext ic = getInitialContext();<br />QueueReceive qr = new QueueReceive();<br />qr.init(ic, QUEUE);</p>
		<p>System.out.println("JMS Ready To Receive Messages (To quit, send a \"quit\" message).");</p>
		<p>// Wait until a "quit" message has been received.<br />synchronized(qr) {<br />while (! qr.quit) {<br />try {<br />qr.wait();<br />} catch (InterruptedException ie) {}<br />}<br />}<br />qr.close();<br />}</p>
		<p>private static InitialContext getInitialContext()<br />throws NamingException<br />{<br />Hashtable env = new Hashtable();<br />env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);<br />env.put(Context.PROVIDER_URL, PROVIDER_URL);<br />return new InitialContext(env);<br />}</p>
		<p>
				<br />}<br />七. 测试消息发送和接收<br />1. 设置WebLogic Classpath;<br /></p>
		<img src="http://dev2dev.bea.com.cn/images/school/server031128/image023.png" height="600" width="664" />
		<br />2. 转到发送接收程序目录编译文件;<br /><img src="http://dev2dev.bea.com.cn/images/school/server031128/image025.png" height="431" width="668" /><br />3. 执行接受程序;<br />4. 打开另一窗口,执行发送程序;<br /><p><img src="http://dev2dev.bea.com.cn/images/school/server031128/image027.png" height="431" width="668" /><br />5. 输入发送消息"quit",接收程序结束. <br /><img src="http://dev2dev.bea.com.cn/images/school/server031128/image029.png" height="431" width="668" /><br /><br /><b>总结</b><br />本
文先简要介绍了JMS的一些基本概念,继而引入了WebLogic JMS
Server的体系结构和相关特性。在此基础之上,图文并茂地讲述了JMS在WebLogic Server
8.1上的配置。最后在解剖JMS应用程序框架的同时,以点对点为例演示了JMS的发送接收消息流程。<br /><br /></p><!--文章其他信息--><div class="dot001"><img alt="" src="http://dev2dev.bea.com.cn/images/_.gif" height="1" width="100%" /></div><table border="0" cellpadding="3" cellspacing="0" width="100%"><tbody><tr valign="bottom"><td colspan="2" height="20"> <span class="h2b">作者简介</span></td></tr><tr><td align="center" valign="top" width="0"><br /></td><td>周海根是（dev2dev论坛id：zhouhg） 长城软件系统有限公司 J2EE架构设计师， 项目经理</td></tr></tbody></table><img src ="http://www.blogjava.net/Vencent/aggbug/40864.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-04-13 12:47 <a href="http://www.blogjava.net/Vencent/articles/40864.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用java打造任意形状窗口和透明窗口</title><link>http://www.blogjava.net/Vencent/articles/39120.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Tue, 04 Apr 2006 04:35:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/39120.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/39120.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/39120.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/39120.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/39120.html</trackback:ping><description><![CDATA[
		<div class="postcontent">
				<p>
						<font color="#800080">
						</font>
						<img src="../../images/blogjava_net/dyerac/9435/r_butterflu.JPG" onload="if(this.width" border="0" />
						<br />
						<br />图形界面开发对于Java来说并非它的长项，开发者经常会碰到各种各样的限制，比如，<font color="#800080">如何打造一款任意形状的窗口</font>？<font color="#800080">如何可以透过窗口显示它覆盖下的内容</font>？</p>
				<p>考虑到Java并没有被设计成支持以上的功能，所以，你能得到的永远是方方正正的窗口，毫无新意，当然，我们可以通过JNI调用本地代码来完成，但是这就失去了java可移植性的意义，那么，用纯粹的java代码如何实现以上两种功能呢？</p>
				<p>下文提供了一个实现的参考</p>
				<p>
						<font color="#ff0000">预备知识</font>：<br />1.java.awt.Robot，这个类是一个功能非常强大的类，通过它我们可以控制鼠标和键盘的响应，不过这里，我们只需要用到它的一个功能－－截屏，也就是得到当前屏幕的快照（screenshot）<br />2.我们可以通过调用一个swing组件的paintComponent(Graphics g)方法用特定的Graphics为其定制特殊的外观<br /></p>
				<p>首
先声明的一点是，本文中的实现方法只是一个欺骗的手法，因为要想实现前文中的功能，我们几乎的重写一套Swing出来，这里，简便的做法是，我们通过
robot类来获得当前屏幕的快照，然后贴在我们需要的窗口上，这样，不就实现了透明的功能了吗？顺便提一下，几年前日本发明的隐形衣也是依靠这种机制，
这种衣服在身后附带一套摄像机，然后即时的将拍下的内容显示在衣服的正面，因此，当别人看过来时，仿佛就通过人和衣服看到了身后的场景^_^</p>
				<p>另外，还要感谢Joshua Chris leniz的Swing Hack一书，以上充满创新的方法正来自他的书中</p>
				<p>好咯，让我们具体看一下细节的处理：<br /><font color="#ff1493">第一</font>，我们要得到当前屏幕的快照，保存到一个Image对象[color=Red]background[/color]中：<br />  public void updateBackground() {<br />  try {<br />   Robot rbt = new Robot();<br />   Toolkit tk = Toolkit.getDefaultToolkit();<br />   Dimension dim = tk.getScreenSize();<br />   [color=Red]background [/color]= rbt.createScreenCapture(new Rectangle(0, 0, (int) dim<br />     .getWidth(), (int) dim.getHeight()));<br />  } catch (Exception ex) {<br />   }<br /> }<br /><br /><font color="#006400">第二</font>，我们需要让窗口显示这个图像，也就是说，让窗口的背景图像是这副图像，以达到透明的欺骗效果：</p>
				<p>public void paintComponent(Graphics g) {<br />  Point pos = this.getLocationOnScreen();<br />  Point offset = new Point(-pos.x, -pos.y);<br />  g.drawImage([color=Red]background[/color], offset.x, offset.y, null);<br /> }</p>
				<p>在swing
hack一书中，作者也给出了他的实现，然而，运行结果表明该实现存在很大的问题：窗口经常无法即时更新，往往背景变了，窗口里显示的却还是以前的背景。
仔细研究了他的代码，我发现了问题的根结，同时也是这种实现技术的关键要素－－如何让窗口在正确的时机里更新显示，下面，我们会讨论这一点</p>
				<p>
						<font color="#ffa500">第三</font>，更新窗口外观<br />前两步的操作，只能得到一副当前屏幕的快照，一旦背景变化了，或者窗口移动了，变化大小了，那么我们制作的窗口将永远无法和和屏幕背景联合成整体，也就失去了透明的效果；同时，我们也不可能每时每刻都调用<br />updateBackground() 方法获得最新的背景，可行的方法是，通过对事件的监听来选择适当的时间来更新外观</p>
				<p>
						<font color="#ff0000">我们应该可以达到这三点共识</font>：<br />1。窗口移动或改变大小时，背景图像一般是不会发生变化的，我们不需要得到新的屏幕快照，只用将以前得到的背景中适当的部分贴到窗口上，调用repaint（）方法就足已<br />2。要获得最新的屏幕快照，必须先将窗口隐藏起来，调用updateBackground() 得到图像后再把窗口显示，我们可以用refresh方法来表示<br /> refresh（）{<br />    frame.hide();<br />    updateBackground() ;<br />   frame.show();<br />}<br />3。如果背景改变了，那么一定是别的windows程序获得了或失去了事件焦点，也就是说我们关注的窗口将触发焦点得失事件，这个时候需要调用refresh() 得到最新的屏幕快照</p>
				<p>
						<br />看到这里，你或许认为已经没有技术难点了，然而，此时才是我们[color=Red]最需要关注的地方[/color]：<br />参
看第三点，我们需要在窗口得失焦点时调用refresh() 方法；参看第一点，我们调用refresh()
方法时需要先将窗口隐藏，然后再显示。于是问题来了，在隐藏和显示窗口时，同样会触发得失焦点事件，得失焦点事件又将触发新的隐藏和显示窗口事件（为了得
到新的屏幕快照），这就使程序陷入了死循环中，我们必须加以控制，使得第二次触发焦点得失事件时不调用refresh（）方法</p>
				<p>作者的办法是加一个线程来控制，通过判断时间间隔长短来决定是否调用refresh（）方法，可是，这个条件是程序非常的不稳定，因为往往调用时间会根据系统繁忙度而改变，使得需要更新时不能更新，不需要更新的时候反而更新了<br />因此，我决定采取新的解决方案，能不能隐藏/显示窗口时不触发得失焦点事件呢？<br />解
决方法很简单，我抛开了传统的setVisible（）或者show（），hide（）方法，而是使用setLocation（）方法，因为调用
setLocation（）方法时窗口不会失去焦点，同时，只要用类似setLocation（－2000，－2000）方法也同样可以轻松的让窗口在屏
幕中消失<br />下面是我的全部代码：</p>
				<p>import java.awt.BorderLayout;<br />import java.awt.Dimension;<br />import java.awt.Graphics;<br />import java.awt.Image;<br />import java.awt.Point;<br />import java.awt.Rectangle;<br />import java.awt.Robot;<br />import java.awt.Toolkit;<br />import java.awt.event.ComponentEvent;<br />import java.awt.event.ComponentListener;<br />import java.awt.event.WindowEvent;<br />import java.awt.event.WindowFocusListener;</p>
				<p>import javax.swing.JButton;<br />import javax.swing.JComponent;<br />import javax.swing.JFrame;<br />import javax.swing.JLabel;<br />import javax.swing.UIManager;</p>
				<p>import org.jvnet.substance.SubstanceLookAndFeel;<br />import org.jvnet.substance.theme.SubstanceLightAquaTheme;</p>
				<p>import ch.randelshofer.quaqua.QuaquaLookAndFeel;</p>
				<p>public class TestEvent extends JComponent implements ComponentListener,<br />  WindowFocusListener {<br /> private JFrame frame;</p>
				<p> private Boolean isHiding = false, isShowing = false, start = false;</p>
				<p> private Image background;</p>
				<p> private Point p;<br />                     <br />                    [color=Red]//获得当前屏幕快照[/color]<br /> public void updateBackground() {<br />  try {<br />   Robot rbt = new Robot();<br />   Toolkit tk = Toolkit.getDefaultToolkit();<br />   Dimension dim = tk.getScreenSize();<br />   background = rbt.createScreenCapture(new Rectangle(0, 0, (int) dim<br />     .getWidth(), (int) dim.getHeight()));<br />  } catch (Exception ex) {<br />   // p(ex.toString());<br />   // 此方法没有申明过 ，因为无法得知上下文 。因为不影响执行效果 ，先注释掉它 ex.printStackTrace();<br />  }</p>
				<p> }</p>
				<p>                   [color=Red]  //将窗口掉离出屏幕以获得纯粹的背景图象[/color]<br /> public void refresh() {<br />  if (start == true) {<br />   this.updateBackground();<br />   frame.setLocation(p);<br />   if (p.x &lt; 0 || p.y &lt; 0)<br />    frame.setLocation(0, 0);<br />   this.repaint();<br />  }<br /> }</p>
				<p> public void componentHidden(ComponentEvent e) {<br />  // TODO Auto-generated method stub<br />  System.out.println("Hidden");<br /> }</p>
				<p>                     [color=Red] //窗口移动时[/color]<br /> public void componentMoved(ComponentEvent e) {<br />  // TODO Auto-generated method stub<br />  System.out.println("moved");<br />  this.repaint();<br /> }</p>
				<p>                    [color=Red] //窗口改变大小时[/color]<br /> public void componentResized(ComponentEvent e) {<br />  // TODO Auto-generated method stub<br />  System.out.println("resized");<br />  this.repaint();<br /> }</p>
				<p> public void componentShown(ComponentEvent e) {<br />  // TODO Auto-generated method stub<br />  System.out.println("shown");<br /> }</p>
				<p>                    [color=Red] //窗口得到焦点后,用refresh()方法更新界面[/color]<br /> public void windowGainedFocus(WindowEvent e) {<br />  // TODO Auto-generated method stub<br />  System.out.println("gainedFocus");<br />  refresh();<br />  start = false;<br /> }</p>
				<p>                    [color=Red] //窗口失去焦点后,将其移出屏幕[/color]<br /> public void windowLostFocus(WindowEvent e) {<br />  // TODO Auto-generated method stub<br />  System.out.println("lostFocus");<br />  if (frame.isShowing() == true) {<br />   System.out.println("visible");<br />  } else {<br />   System.out.println("invisible");<br />  }<br />  start = true;<br />  p = frame.getLocation();<br />  frame.setLocation(-2000, -2000);<br /> }</p>
				<p> public TestEvent(JFrame frame) {<br />  super();<br />  this.frame = frame;<br />  updateBackground();<br />  this.setSize(200, 120);<br />  this.setVisible(true);<br />  frame.addComponentListener(this);<br />  frame.addWindowFocusListener(this);</p>
				<p>  // TODO Auto-generated constructor stub<br /> }</p>
				<p>                    //绘制外观,注意,其中 pos,offset 是为了将特定部分的图象贴到窗口上<br /> public void paintComponent(Graphics g) {<br />  Point pos = this.getLocationOnScreen();<br />  Point offset = new Point(-pos.x, -pos.y);<br />  g.drawImage(background, offset.x, offset.y, null);<br /> }</p>
				<p> /**<br />  * @param args<br />  */<br /> public static void main(String[] args) {<br />  // TODO Auto-generated method stub<br />  try {<br />   // UIManager.setLookAndFeel("org.fife.plaf.Office2003.Office2003LookAndFeel");<br />   // UIManager.setLookAndFeel("org.fife.plaf.OfficeXP.OfficeXPLookAndFeel");<br />   // UIManager.setLookAndFeel("org.fife.plaf.OfficeXP.OfficeXPLookAndFeel");<br />   UIManager.setLookAndFeel(new SubstanceLookAndFeel());<br />   //UIManager.setLookAndFeel(new SmoothLookAndFeel());<br />   //UIManager.setLookAndFeel(new QuaquaLookAndFeel());<br />   UIManager.put("swing.boldMetal", false);<br />   if (System.getProperty("substancelaf.useDecorations") == null) {<br />    JFrame.setDefaultLookAndFeelDecorated(true);<br />    //JDialog.setDefaultLookAndFeelDecorated(true);<br />   }<br />   System.setProperty("sun.awt.noerasebackground", "true");<br />   SubstanceLookAndFeel.setCurrentTheme(new SubstanceLightAquaTheme());</p>
				<p>   // UIManager.setLookAndFeel("org.fife.plaf.VisualStudio2005.VisualStudio2005LookAndFeel");<br />  } catch (Exception e) {<br />   System.err.println("Oops!  Something went wrong!");<br />  }</p>
				<p>  JFrame frame = new JFrame("Transparent Window");<br />  TestEvent t = new TestEvent(frame);<br />  t.setLayout(new BorderLayout());<br />  JButton button = new JButton("This is a button");<br />  t.add("North", button);<br />  JLabel label = new JLabel("This is a label");<br />  t.add("South", label);<br />  frame.getContentPane().add("Center", t);<br />  frame.pack();<br />  frame.setSize(150, 100);<br />  frame.show();<br />  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br />  // t.start=true;<br /> }</p>
				<p>}</p>
				<p>
						<br />当然，以上代码还存在许多不足，比如在移动窗口时性能会有影响，应该可以通过线程来控制其更新的频率来提升效率，希望大家能一起研究一下，改好了记得通知我哦</p>
				<p>ps：你也许还会说，e？怎么没讲任意形状窗口如何打造？<br />       呵呵，其实只要把窗口按上述方法设置成透明，再去掉边框，再换上自己的边框，不就完成了马？<br />     相信聪明的各位一定很容易就办到咯</p>
				<p>另外，我还在下面附带了作者的大论，想了解更多的同学也可以去看看</p>
				<p>
						<a href="http://www.matrix.org.cn/resource/article/44/44186_Swing.html">http://www.matrix.org.cn/resource/article/44/44186_Swing.html</a>
				</p>
		</div>
<img src ="http://www.blogjava.net/Vencent/aggbug/39120.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-04-04 12:35 <a href="http://www.blogjava.net/Vencent/articles/39120.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> BeanUtils 介紹</title><link>http://www.blogjava.net/Vencent/articles/36953.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Wed, 22 Mar 2006 16:12:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/36953.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/36953.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/36953.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/36953.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/36953.html</trackback:ping><description><![CDATA[
		<h3>　BeanUtils 介紹</h3>
		<p>所謂 BeanUtils 為何要開發呢, 每個工程師或許在寫 JavaBean 的時候, 都會乖乖地去寫 getters 和
setters, 就是 getXXX() 及 setXXX() methods, 但是當你的 object 是動態產生的, 也許是用檔案,
也許是其他原因, 那你該如何去存取資料呢 !!</p>
		<p>幾個例子你可能會用到 BeanUtils, 當然, 這是已經存在的專案了</p>
		<ul>
				<li>
						<span class="nobr">
								<a href="http://jakarta.apache.org/bsf/index.html" title="Visit page outside Confluence" rel="nofollow">BSF<sup><img class="rendericon" src="http://www.javaworld.com.tw/confluence/images/icons/linkext7.gif" alt="" align="absmiddle" border="0" height="7" width="7" /></sup></a>
						</span>: Script Language 和 Java Object Model 之間</li>
				<li>
						<span class="nobr">
								<a href="http://jakarta.apache.org/velocity/index.html" title="Visit page outside Confluence" rel="nofollow">Velocity<sup><img class="rendericon" src="http://www.javaworld.com.tw/confluence/images/icons/linkext7.gif" alt="" align="absmiddle" border="0" height="7" width="7" /></sup></a>
						</span>/ <span class="nobr"><a href="http://java.sun.com/products/jsp/" title="Visit page outside Confluence" rel="nofollow">JSP<sup><img class="rendericon" src="http://www.javaworld.com.tw/confluence/images/icons/linkext7.gif" alt="" align="absmiddle" border="0" height="7" width="7" /></sup></a></span>: 使用 template 建立相似的網頁</li>
				<li>
						<span class="nobr">
								<a href="http://jakarta.apache.org/taglibs/index.html" title="Visit page outside Confluence" rel="nofollow">jakarta taglibs<sup><img class="rendericon" src="http://www.javaworld.com.tw/confluence/images/icons/linkext7.gif" alt="" align="absmiddle" border="0" height="7" width="7" /></sup></a>
						</span>/ <span class="nobr"><a href="http://jakarta.apache.org/struts/index.html" title="Visit page outside Confluence" rel="nofollow">Struts<sup><img class="rendericon" src="http://www.javaworld.com.tw/confluence/images/icons/linkext7.gif" alt="" align="absmiddle" border="0" height="7" width="7" /></sup></a></span>/ <span class="nobr"><a href="http://xml.apache.org/cocoon/index.html" title="Visit page outside Confluence" rel="nofollow">Cocoon<sup><img class="rendericon" src="http://www.javaworld.com.tw/confluence/images/icons/linkext7.gif" alt="" align="absmiddle" border="0" height="7" width="7" /></sup></a></span>: 建立自己特殊的 Tag Libraries for JSP 或 XSP</li>
				<li>
						<span class="nobr">
								<a href="http://ant.apache.org/" title="Visit page outside Confluence" rel="nofollow">ant build.xml<sup><img class="rendericon" src="http://www.javaworld.com.tw/confluence/images/icons/linkext7.gif" alt="" align="absmiddle" border="0" height="7" width="7" /></sup></a>
						</span>/ <span class="nobr"><a href="http://jakarta.apache.org/tomcat/index.html" title="Visit page outside Confluence" rel="nofollow">tomcat server.xml<sup><img class="rendericon" src="http://www.javaworld.com.tw/confluence/images/icons/linkext7.gif" alt="" align="absmiddle" border="0" height="7" width="7" /></sup></a></span>: XML-based 的 設定檔案 ( configuration resources )</li>
		</ul>
		<p>你大可以使用 java api 中的 java.lang.reflect 及 java.beans 來達到這些資料交換 ~~ 不過呢, 難度有點高 ,但是, BeanUtils 將會減低你開發的時間 !!</p>
		<p>目前最新的 stable 版本為 1.7.0 (2003/2/18 released), <br />
下載位置為 <span class="nobr"><a href="http://apache.stu.edu.tw/jakarta/commons/beanutils/binaries/commons-beanutils-1.7.0.zip" title="Visit page outside Confluence" rel="nofollow">Binary<sup><img class="rendericon" src="http://www.javaworld.com.tw/confluence/images/icons/linkext7.gif" alt="" align="absmiddle" border="0" height="7" width="7" /></sup></a></span> &amp; <span class="nobr"><a href="http://apache.cdpa.nsysu.edu.tw/jakarta/commons/beanutils/source/commons-beanutils-1.7.0-src.zip" title="Visit page outside Confluence" rel="nofollow">Source<sup><img class="rendericon" src="http://www.javaworld.com.tw/confluence/images/icons/linkext7.gif" alt="" align="absmiddle" border="0" height="7" width="7" /></sup></a></span></p>
		<h3>
				<a name="BeanUtils介紹-　BeanUtilsAPI介紹">
				</a>　BeanUtils API 介紹</h3>
		<p>BeanUtils 的 <span class="nobr"><a href="http://jakarta.apache.org/commons/beanutils/api/index.html" title="Visit page outside Confluence" rel="nofollow">Java API<sup><img class="rendericon" src="http://www.javaworld.com.tw/confluence/images/icons/linkext7.gif" alt="" align="absmiddle" border="0" height="7" width="7" /></sup></a></span> 主要的 package 總共四項</p>
		<ol>
				<li>org.apache.commons.beanutils</li>
				<li>org.apache.commons.beanutils.converters</li>
				<li>org.apache.commons.beanutils.locale</li>
				<li>org.apache.commons.beanutils.locale.converters</li>
		</ol>
		<p>其實除了第一項之外, 其他的都是後來版本才加上去的, converters 就是專門處理不同傳入的 object 該如何轉換, locale 呢, 就是為了國際化的處理, 所以重點我都會擺在第一項!! </p>
		<p>而其中最常用到的 class 是 PropertyUtils 及 ConvertUtils 還有 DynaBeans( 有用 struts dynaform 的應該不陌生 ) </p>
		<h3>
				<a name="BeanUtils介紹-　BeanUtils.PropertyUtils介紹">
				</a>　BeanUtils.PropertyUtils 介紹</h3>
		<p>基本上, 我假設大家對 JavaBean 的開發都沒有問題, 就是 對 getters 及 setters 都了解是什麼. 先假設,</p>
		<div class="code" style="border-style: solid;">
				<div class="codeHeader" style="border-bottom-style: solid;">
						<b>Employee.java</b>
				</div>
				<div class="codeContent">
						<pre class="code-java">
								<span class="code-keyword">public</span> class Employee {<br /><span class="code-keyword">public</span> Address getAddress(<span class="code-object">String</span> type);<br /><span class="code-keyword">public</span> void setAddress(<span class="code-object">String</span> type, Address address);<br /><span class="code-keyword">public</span> Employee getSubordinate(<span class="code-object">int</span> index);<br /><span class="code-keyword">public</span> void setSubordinate(<span class="code-object">int</span> index, Employee subordinate);<br /><span class="code-keyword">public</span><span class="code-object">String</span> getFirstName();<br /><span class="code-keyword">public</span> void setFirstName(<span class="code-object">String</span> firstName);<br /><span class="code-keyword">public</span><span class="code-object">String</span> getLastName();<br /><span class="code-keyword">public</span> void setLastName(<span class="code-object">String</span> lastName);<br />}</pre>
				</div>
		</div>
		<p>在 PropertyUtils 中會區分為三種 method 狀態</p>
		<ul>
				<li>
						<b>Simple</b> - 如果你是用到 primitive 語法, 如 int, String 或其他自行開發的 objects 等等, 只需要單一的物件就可以取得資料
<div class="preformatted"><div class="preformattedContent"><pre>PropertyUtils.getSimpleProperty(Object bean, String name) <br />PropertyUtils.setSimpleProperty(Object bean, String name, Object value)</pre></div></div><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java">Employee employee = ...;<br /><span class="code-object">String</span> firstName = (<span class="code-object">String</span>)<br />    PropertyUtils.getSimpleProperty(employee, <span class="code-quote">"firstName"</span>);<br /><span class="code-object">String</span> lastName = (<span class="code-object">String</span>)<br />    PropertyUtils.getSimpleProperty(employee, <span class="code-quote">"lastName"</span>);<br />.............<br />PropertyUtils.setSimpleProperty(employee, <span class="code-quote">"firstName"</span>, firstName);<br />PropertyUtils.setSimpleProperty(employee, <span class="code-quote">"lastName"</span>, lastName);</pre></div></div></li>
		</ul>
		<ul>
				<li>
						<b>Indexed</b> - 如果你是用到 Collection 或 List 實作出來的 objects , 只需要使用一個 index 數值就可以取得資料的型態
<div class="preformatted"><div class="preformattedContent"><pre>PropertyUtils.getIndexedProperty(Object bean, String name) <br />PropertyUtils.getIndexedProperty(Object bean, String name, int index) <br />PropertyUtils.setIndexedProperty(Object bean, String name, Object value) <br />PropertyUtils.setIndexedProperty(Object bean, String name, int index, Object value)</pre></div></div><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java">Employee employee = ...;<br /><span class="code-object">int</span> index = ...;<br /><span class="code-object">String</span> name = <span class="code-quote">"subordinate["</span> + index + <span class="code-quote">"]"</span>;<br />Employee subordinate = (Employee)<br />    PropertyUtils.getIndexedProperty(employee, name);<br />Employee employee = ...;<br /><span class="code-object">int</span> index = ...;<br />Employee subordinate = (Employee)<br />    PropertyUtils.getIndexedProperty(employee, <span class="code-quote">"subordinate"</span>, index);</pre></div></div></li>
		</ul>
		<ul>
				<li>
						<b>Mapped</b> - 如果你是用到 Map 延伸出來的 objects , 只需要使用一個 key 值就可以取得資料
<div class="preformatted"><div class="preformattedContent"><pre>PropertyUtils.getMappedProperty(Object bean, String name) <br />PropertyUtils.getMappedProperty(Object bean, String name, String key) <br />PropertyUtils.setMappedProperty(Object bean, String name, Object value) <br />PropertyUtils.setMappedProperty(Object bean, String name, String key, Object value)</pre></div></div><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java">Employee employee = ...;<br />Address address = ...;<br />PropertyUtils.setMappedProperty(employee, <span class="code-quote">"address(home)"</span>, address);<br />Employee employee = ...;<br />Address address = ...;<br />PropertyUtils.setMappedProperty(employee, <span class="code-quote">"address"</span>, <span class="code-quote">"home"</span>, address);</pre></div></div></li>
		</ul>
		<p>但是如果你是巢狀(nested)的資料結構, 你該如何取得你要的資料呢</p>
		<div class="preformatted">
				<div class="preformattedContent">
						<pre>PropertyUtils.getNestedProperty(Object bean, String name) <br />PropertyUtils.setNestedProperty(Object bean, String name, Object value)</pre>
				</div>
		</div>
		<p>你只需要簡單地使用 ".", 就可以得到你要的資料了 </p>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
						<pre class="code-java">
								<span class="code-object">String</span> city = (<span class="code-object">String</span>)<br />    PropertyUtils.getNestedProperty(employee, <span class="code-quote">"address(home).city"</span>);</pre>
				</div>
		</div>
		<p>千萬要記住, BeanUtils 是要讓你隨心所欲使用, 所以呢 index , mapped 當然都可以這樣使用</p>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
						<pre class="code-java">Employee employee = ...;<br /><span class="code-object">String</span> city = (<span class="code-object">String</span>) <br />    PropertyUtils.getProperty(employee, <span class="code-quote">"subordinate[3].address(home).city"</span>);</pre>
				</div>
		</div>
		<h3>
				<a name="BeanUtils介紹-　BeanUtils.DynaBeanandBeanUtils.DynaClass介紹">
				</a>　BeanUtils.DynaBean and BeanUtils.DynaClass 介紹</h3>
		<p>所有的 Dynamic JavaBean 都是實作 DynaBean 或 DynaClass 這兩個 interface, 也可能會用到
DynaProperty class 來存取 properties . 我們為何要用到 Dynamic JavaBean 呢, 例如,
你從資料庫撈出來的資料, 有時候可能是三個欄位, 有時候是四個欄位, 如果我們對於每個 Bean 都要去寫一個 class, 就會很累,
所以對於每一種 javabean 我們就設定他的屬性有哪些, 接著就可以使用 PropertyUtils 來將他的數值取出, 如此,
可以減少很多開發工時. 在 Struts 的課程中, 很多人問到我, 請問每一個 ActionForm 都必須寫成 java 檔嗎, 當然,
不需要的, 否則一個網頁一個 ActionForm ( 假設都不一樣 ), 那麼, 這麼浪費時間的工作, 為何還要使用 Struts 來作為
Framework 呢, 所以我們都是使用 org.apache.struts.action.DynaActionForm!!<br />
MutableDynaClass 這是一個 DynaClass, 是為了動態可以調整 properties !</p>
		<ul>
				<li>
						<b>BasicDynaBean and BasicDynaClass</b> - 基本的 Dynamic 型態
<div class="preformatted"><div class="preformattedContent"><pre>BasicDynaClass(java.lang.String name, java.lang.Class dynaBeanClass, DynaProperty[] properties)<br />BasicDynaBean(DynaClass dynaClass)</pre></div></div><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java">DynaProperty[] props = <span class="code-keyword">new</span> DynaProperty[]{<br /><span class="code-keyword">new</span> DynaProperty(<span class="code-quote">"address"</span>, java.util.Map.class),<br /><span class="code-keyword">new</span> DynaProperty(<span class="code-quote">"subordinate"</span>, mypackage.Employee[].class),<br /><span class="code-keyword">new</span> DynaProperty(<span class="code-quote">"firstName"</span>, <span class="code-object">String</span>.class),<br /><span class="code-keyword">new</span> DynaProperty(<span class="code-quote">"lastName"</span>,  <span class="code-object">String</span>.class)<br />};<br />BasicDynaClass dynaClass = <span class="code-keyword">new</span> BasicDynaClass(<span class="code-quote">"employee"</span>, <span class="code-keyword">null</span>, props);<br /><br />DynaBean employee = dynaClass.newInstance();<br />employee.set(<span class="code-quote">"address"</span>, <span class="code-keyword">new</span> HashMap());<br />employee.set(<span class="code-quote">"subordinate"</span>, <span class="code-keyword">new</span> mypackage.Employee[0]);<br />employee.set(<span class="code-quote">"firstName"</span>, <span class="code-quote">"Fred"</span>);<br />employee.set(<span class="code-quote">"lastName"</span>, <span class="code-quote">"Flintstone"</span>);</pre></div></div></li>
				<li>
						<b>ResultSetDynaClass (Wraps ResultSet in DynaBeans)</b> - 使用 ResultSet 的 Dynamic JavaBean
<div class="preformatted"><div class="preformattedContent"><pre>ResultSetDynaClass(java.sql.ResultSet resultSet)<br />ResultSetDynaClass(java.sql.ResultSet resultSet, boolean lowerCase)</pre></div></div><p>如果 lowerCase 設為 false , 回傳的資料欄位名將根據 JDBC 回傳的為準. default 為 true.</p><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java">Connection conn = ...;<br />Statement stmt = conn.createStatement();<br />ResultSet rs = stmt.executeQuery<br />    (<span class="code-quote">"select account_id, name from customers"</span>);<br />Iterator rows = (<span class="code-keyword">new</span> ResultSetDynaClass(rs)).iterator();<br /><span class="code-keyword">while</span> (rows.hasNext()) {<br />    DynaBean row = (DynaBean) rows.next();<br /><span class="code-object">System</span>.out.println(<span class="code-quote">"Account number is "</span> +<br />                    row.get(<span class="code-quote">"account_id"</span>) +<br /><span class="code-quote">" and name is "</span> + row.get(<span class="code-quote">"name"</span>));<br />}<br />rs.close();<br />stmt.close();</pre></div></div></li>
				<li>
						<b>RowSetDynaClass (Disconnected ResultSet as DynaBeans)</b> - 使用 RowSet 的 Dynamic JavaBean
<div class="preformatted"><div class="preformattedContent"><pre>RowSetDynaClass(java.sql.ResultSet resultSet)<br />RowSetDynaClass(java.sql.ResultSet resultSet, boolean lowerCase)</pre></div></div><p>如果 lowerCase 設為 false , 回傳的資料欄位名將根據 JDBC 回傳的為準. default 為 true.</p><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java">Connection conn = ...;  <span class="code-comment">// Acquire connection from pool<br /></span>Statement stmt = conn.createStatement();<br />ResultSet rs = stmt.executeQuery(<span class="code-quote">"SELECT ..."</span>);<br />RowSetDynaClass rsdc = <span class="code-keyword">new</span> RowSetDynaClass(rs);<br />rs.close();<br />stmt.close();<br />...;                    <span class="code-comment">// Return connection to pool<br /></span>List rows = rsdc.getRows();<br />...;                   <span class="code-comment">// <span class="code-object">Process</span> the rows as desired</span></pre></div></div></li>
				<li>
						<b>WrapDynaBean and WrapDynaClass</b> - 包裝過的 Dynamic JavaBean<br />
如果你對於 DynaBean 的功能強大, 非常佩服的同時, 手邊的 JavaBean 又不能隨隨便便就不用 那你就把他包裝起來 ....
<div class="preformatted"><div class="preformattedContent"><pre>WrapDynaClass(java.lang.Class beanClass) <br />WrapDynaBean(java.lang.Object instance) <br />ConvertingWrapDynaBean(java.lang.Object instance)</pre></div></div><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java">MyBean bean = ...;<br />DynaBean wrapper = <span class="code-keyword">new</span> WrapDynaBean(bean);<br /><span class="code-object">String</span> firstName = wrapper.get(<span class="code-quote">"firstName"</span>);</pre></div></div><h3><a name="BeanUtils介紹-　BeanUtils.ConvertUtils介紹"></a>　BeanUtils.ConvertUtils 介紹</h3><p>在很多情況, 例如 struts framework 中, 就常常用到 request.getParameter 的參數, 需要轉換成 正確的資料型態, 所以 ConvertUtils 就是來處理這些動作. </p><div class="preformatted"><div class="preformattedContent"><pre>ConvertUtils().convert(java.lang.Object value) <br />ConvertUtils().convert(java.lang.String[] values, java.lang.Class clazz) <br />ConvertUtils().convert(java.lang.String value, java.lang.Class clazz)</pre></div></div><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java">HttpServletRequest request = ...;<br />MyBean bean = ...;<br />HashMap map = <span class="code-keyword">new</span> HashMap();<br />Enumeration names = request.getParameterNames();<br /><span class="code-keyword">while</span> (names.hasMoreElements()) {<br /><span class="code-object">String</span> name = (<span class="code-object">String</span>) names.nextElement();<br />    map.put(name, request.getParameterValues(name));<br />}<br />BeanUtils.populate(bean, map);<span class="code-comment">// it will use ConvertUtils <span class="code-keyword">for</span> convertings</span></pre></div></div></li>
		</ul>
		<p>目前支援的型態有</p>
		<ul>
				<li>java.lang.BigDecimal</li>
				<li>java.lang.BigInteger</li>
				<li>boolean and java.lang.Boolean</li>
				<li>byte and java.lang.Byte</li>
				<li>char and java.lang.Character</li>
				<li>java.lang.Class</li>
				<li>double and java.lang.Double</li>
				<li>float and java.lang.Float</li>
				<li>int and java.lang.Integer</li>
				<li>long and java.lang.Long</li>
				<li>short and java.lang.Short</li>
				<li>java.lang.String</li>
				<li>java.sql.Date</li>
				<li>java.sql.Time</li>
				<li>java.sql.Timestamp</li>
		</ul>
		<p>也可以建立自己的 converter </p>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
						<pre class="code-java">Converter myConverter =<br /><span class="code-keyword">new</span> org.apache.commons.beanutils.converter.IntegerConverter(); <br />ConvertUtils.register(myConverter, <span class="code-object">Integer</span>.TYPE);    <span class="code-comment">// Native type <br /></span>ConvertUtils.register(myConverter, <span class="code-object">Integer</span>.class);   <span class="code-comment">// Wrapper class</span></pre>
				</div>
		</div>
		<p>　ps :部分內容屬於直接翻譯自 <span class="nobr"><a href="http://jakarta.apache.org/commons/beanutils/" title="Visit page outside Confluence" rel="nofollow">jakarta commons beanutils</a></span></p>
<img src ="http://www.blogjava.net/Vencent/aggbug/36953.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-03-23 00:12 <a href="http://www.blogjava.net/Vencent/articles/36953.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> Commons FileUpload</title><link>http://www.blogjava.net/Vencent/articles/36952.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Wed, 22 Mar 2006 16:11:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/36952.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/36952.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/36952.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/36952.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/36952.html</trackback:ping><description><![CDATA[UUID是Universally Unique
IDentifier,他是一組128bit的數字,定義在http://www.ietf.org/internet-drafts/draft-
mealling-uuid-urn-03.txt .相信有寫過Windows程式的人對他不會太陌生.<br clear="all" /><p>　有時後我們在分散式的系統下,希望要產生唯一的一個ID.如果我們不希望用centralize的方式產生的話,我們可以用UUID來產生Unique ID,這個演算法讓我們幾乎不會產生重複的ID.使用方法也很簡單:<br clear="all" /></p><div class="code"><div class="codeContent"><pre class="code-java">UUID uuid = UUID.randomUUID();        <br /><span class="code-object">System</span>.out.printf(<span class="code-quote">"UUID : %s"</span>, uuid).println();<br />使用瀏覽器進行檔案上傳時，是使用multipart/form-data編碼，然而<br />Servlet容器並不會自動幫我們處理編碼，而必須由程式設計人員自行處理，Jakarta Commons<br />FileUpload可以讓您輕易的處理檔案上傳事務，您可以在這個網頁中找到下載檔案，撰寫本文時最新的版本是1.0，檔名是commons-<br />fileupload-1.0.zip：<br /><br /><span class="nobr"><a href="http://jakarta.apache.org/site/binindex.cgi" title="Visit page outside Confluence" rel="nofollow">http://jakarta.apache.org/site/binindex.cgi<sup><img class="rendericon" src="http://www.javaworld.com.tw/confluence/images/icons/linkext7.gif" alt="" align="absmiddle" border="0" height="7" width="7" /></sup></a></span><br /><br /></pre><p>　將zip檔案解開，將commons-fileupload-1.0.jar放置在WEB-INF/lib下，這邊先提供一個快速入門的例子，首先撰寫上傳的表單：</p><div class="code" style="border-style: solid;"><div class="codeHeader" style="border-bottom-style: solid;"><b>upload.html</b></div><div class="codeContent"><pre class="code-java">&lt;html&gt;<br />&lt;head&gt;<br />&lt;title&gt;檔案上傳&lt;/title&gt;<br />&lt;meta http-equiv=<span class="code-quote">"Content-Type"</span> content=<span class="code-quote">"text/html; charset=big5"</span>&gt;<br />&lt;/head&gt;<br />&lt;body&gt;<br />&lt;b&gt;檔案上傳&lt;/b&gt;&lt;/font&gt;&lt;/p&gt;<br /><br />&lt;form name=<span class="code-quote">"UploadForm"</span> enctype=<span class="code-quote">"multipart/form-data"</span> method=<span class="code-quote">"post"</span> action=<span class="code-quote">"upload.jsp"</span>&gt;<br />    &lt;input type=<span class="code-quote">"file"</span> name=<span class="code-quote">"File1"</span> size=<span class="code-quote">"20"</span> maxlength=<span class="code-quote">"20"</span>&gt; &lt;br&gt;<br />    &lt;input type=<span class="code-quote">"file"</span> name=<span class="code-quote">"File2"</span> size=<span class="code-quote">"20"</span> maxlength=<span class="code-quote">"20"</span>&gt; &lt;br&gt;<br />    &lt;input type=<span class="code-quote">"submit"</span>value=<span class="code-quote">"上傳"</span>&gt;<br />&lt;/form&gt;<br /><br />&lt;/body&gt;<br />&lt;/html&gt;</pre></div></div><p>　要處理上傳的檔案，首先要設定一些儲存檔案所需的資訊，然後處理上傳請求：</p><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java">DiskFileUpload fu = <span class="code-keyword">new</span> DiskFileUpload();<br /><span class="code-comment">// 使用的記憶體容量，超過先寫入暫存檔<br /></span>    fu.setSizeThreshold(4096);<br /><span class="code-comment">// 最大上傳檔案容量<br /></span>    fu.setSizeMax(1000000);<br /><span class="code-comment">// 暫存目錄<br /></span>    fu.setRepositoryPath(application.getRealPath(<span class="code-quote">"/"</span>));<br />    List fileItems = fu.parseRequest(request);</pre></div></div><p>　上面的程式也可以綜合為下面這行程式：</p><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java">DiskFileUpload upload = <span class="code-keyword">new</span> DiskFileUpload();<br />List items = upload.parseRequest(request,<br />        yourMaxMemorySize, yourMaxRequestSize, yourTempDirectory);</pre></div></div><p>parserRequest()傳回的List內含FileItem物件，我們可以取出並寫入檔案，例如：</p><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java">Iterator itr = fileItems.iterator();<br /><span class="code-keyword">while</span>(itr.hasNext()) {<br />        FileItem fi = (FileItem)itr.next();<br /><br />        out.println(<span class="code-quote">"\nNAME: "</span>+fi.getName());<br />        out.println(<span class="code-quote">"SIZE: "</span>+fi.getSize());<br />        File fNew= <span class="code-keyword">new</span> File(application.getRealPath(<span class="code-quote">"/"</span>), fi.getName());<br />        fi.write(fNew);<br />    }</pre></div></div><p>　上面的程式將會將檔案寫入Web應用程式的根目錄，下面的JSP程式是個簡單的檔案上傳範例：</p><div class="code" style="border-style: solid;"><div class="codeHeader" style="border-bottom-style: solid;"><b>upload.jsp</b></div><div class="codeContent"><pre class="code-java">&lt;%@ page <span class="code-keyword">import</span>=<span class="code-quote">"org.apache.commons.fileupload.DiskFileUpload"</span>%&gt;<br />&lt;%@ page <span class="code-keyword">import</span>=<span class="code-quote">"org.apache.commons.fileupload.FileItem"</span>%&gt;<br />&lt;%@ page <span class="code-keyword">import</span>=<span class="code-quote">"java.util.List"</span>%&gt;<br />&lt;%@ page <span class="code-keyword">import</span>=<span class="code-quote">"java.util.Iterator"</span>%&gt;<br />&lt;%@ page <span class="code-keyword">import</span>=<span class="code-quote">"java.io.File"</span>%&gt;<br />&lt;%@page contentType=<span class="code-quote">"text/html;charset=Big5"</span>%&gt;<br />&lt;%<br />    DiskFileUpload fu = <span class="code-keyword">new</span> DiskFileUpload();<br /><span class="code-comment">// 使用的記憶體容量，超過先寫入暫存檔<br /></span>    fu.setSizeThreshold(4096);<br /><span class="code-comment">// 最大上傳檔案容量<br /></span>    fu.setSizeMax(1000000);<br /><span class="code-comment">// 儲存的目錄<br /></span>    fu.setRepositoryPath(application.getRealPath(<span class="code-quote">"/"</span>) + <span class="code-quote">"temp/"</span>);<br />    List fileItems = fu.parseRequest(request);                                           <br /><br />    Iterator itr = fileItems.iterator();<br /><span class="code-keyword">while</span>(itr.hasNext()) {<br />        FileItem fi = (FileItem)itr.next();<br /><br />        out.println(<span class="code-quote">"\nNAME: "</span>+fi.getName());<br />        out.println(<span class="code-quote">"SIZE: "</span>+fi.getSize());<br />        File fNew= <span class="code-keyword">new</span> File(application.getRealPath(<span class="code-quote">"/"</span>), fi.getName());<br />        fi.write(fNew);<br />    }<br />%&gt;</pre></div></div><p>　這邊是以寫入檔案為例，如果有要進行額外的處理，例如取得串流或位元陣列，則可以使用FileItem的getInputStream()或get()來分別取得，詳細的方法可以查詢API文件。</p><p>有時候您會在表單中包括有檔案描述與檔案上傳欄位，例如：</p><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java">&lt;form name=<span class="code-quote">"UploadForm"</span> enctype=<span class="code-quote">"multipart/form-data"</span> method=<span class="code-quote">"post"</span> action=<span class="code-quote">"upload.jsp"</span>&gt;<br />    上傳檔案 1 &lt;input type=<span class="code-quote">"file"</span> name=<span class="code-quote">"File1"</span> size=<span class="code-quote">"20"</span> maxlength=<span class="code-quote">"20"</span>&gt; &lt;br&gt;<br />    檔案描述 1 &lt;input type=<span class="code-quote">"text"</span> name=<span class="code-quote">"File1"</span> size=<span class="code-quote">"30"</span> maxlength=<span class="code-quote">"50"</span>&gt; &lt;br&gt;<br />    上傳檔案 2&lt;input type=<span class="code-quote">"file"</span> name=<span class="code-quote">"File2"</span> size=<span class="code-quote">"20"</span> maxlength=<span class="code-quote">"20"</span>&gt; &lt;br&gt;<br />    檔案描述 2 &lt;input type=<span class="code-quote">"text"</span> name=<span class="code-quote">"File1"</span> size=<span class="code-quote">"30"</span> maxlength=<span class="code-quote">"50"</span>&gt; &lt;br&gt;<br />    &lt;input type=<span class="code-quote">"submit"</span>value=<span class="code-quote">"上傳"</span>&gt;<br />&lt;/form&gt;</pre></div></div><p>這時候在上傳處理時，必須要分別是檔案欄位還是一般的表單欄位，您可以使用FileItem的isFormField()來進行判斷，例如：</p><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java">Iterator iter = items.iterator();<br /><span class="code-keyword">while</span> (iter.hasNext()) {<br />    FileItem item = (FileItem) iter.next();<br /><br /><span class="code-keyword">if</span> (item.isFormField()) {<br /><span class="code-comment">// 處理檔案描述欄位<br /></span>        processFormField(item);<br />    } <span class="code-keyword">else</span> {<br /><span class="code-comment">// 處理上傳的檔案<br /></span>        processUploadedFile(item);<br />    }<br />}</pre></div></div><p>另外上檔檔案瀏覽器傳送檔案名稱時，有的瀏覽器可能會包括檔案路徑資訊，為了處理這種情況，我們可以事先處理一下這個可能性，例如在processUploadedFile()方法中這麼實作：</p><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java"><span class="code-object">String</span> fileName = item.getName();<br /><span class="code-keyword">try</span> {<br /><span class="code-comment">// unix-like 系統<br /></span>    fileName = FileName.substring(FileName.lastIndexOf(<span class="code-quote">"/"</span>)+1);<br /><span class="code-comment">// Windows 系統<br /></span><span class="code-comment">// fileName = FileName.substring(FileName.lastIndexOf(<span class="code-quote">"\\"</span>)+1);<br /></span><br />} <span class="code-keyword">catch</span> (Exception e) {<br />        .....<br />}</pre></div></div>


附帶一提，Struts 1.1中的org.apache.struts.upload套件，就使用了Commons FileUpload，您可以參考這個連接有關於Struts中如何進行檔案上傳：<br /><span class="nobr"><a href="http://www.caterpillar.onlyfun.net/phpBB2/viewtopic.php?t=1315" title="Visit page outside Confluence" rel="nofollow">http://www.caterpillar.onlyfun.net/phpBB2/viewtopic.php?t=1315</a></span><pre class="code-java"><br /></pre></div></div><img src ="http://www.blogjava.net/Vencent/aggbug/36952.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-03-23 00:11 <a href="http://www.blogjava.net/Vencent/articles/36952.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> Proxool - 連線池統計</title><link>http://www.blogjava.net/Vencent/articles/36949.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Wed, 22 Mar 2006 16:05:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/36949.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/36949.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/36949.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/36949.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/36949.html</trackback:ping><description><![CDATA[Proxool 提供了一些方法可以讓您取得連線池的相關統計資料，例如您可以使用org.logicalcobwebs.proxool.admin.SnapshotIF來取得連線池目前使用狀態的資訊：
<div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java">SnapshotIF snapshot = ProxoolFacade.getSnapshot(<span class="code-quote">"example"</span>, <span class="code-keyword">true</span>);<br /><span class="code-object">System</span>.out.println(snapshot.getActiveConnectionCount());<br /><span class="code-object">System</span>.out.println(snapshot.getMaximumConnectionCount());<br />....</pre></div></div><p>　true 表示取得詳細的連線池訊息；您也可以對連線池的資料進行定時統計，這必須在XML或屬性檔中設定統計的時間，例如在XML中增加以下內容：</p><div class="code" style="border-style: solid;"><div class="codeHeader" style="border-bottom-style: solid;"><b>proxool.xml</b></div><div class="codeContent"><pre class="code-java">&lt;proxool&gt;<br />     ....<br />    &lt;statistics&gt;1m,15m,1d&lt;/statistics&gt;<br />&lt;/proxool&gt;</pre></div></div><p>　統計的時隔可以分為s(econds),、m(inutes)、h(ours)與d(ays)，就上面的設定來說，就是依分鐘、五分鐘、一天分別作統計，如果是在屬性檔案中設定，則增加：</p><div class="code" style="border-style: solid;"><div class="codeHeader" style="border-bottom-style: solid;"><b>proxool.properties</b></div><div class="codeContent"><pre class="code-java">jdbc-0.proxool.statistics=1m,15m,1d</pre></div></div><p>　如果要取得統計資訊，可以從org.logicalcobwebs.proxool.admin.StatisticsIF取得，例如取得所有的統計資料：</p><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java">StatisticsIF[] statisticsArray = ProxoolFacade.getStatistics(<span class="code-quote">"example"</span>);</pre></div></div><p>　接下來就可以使用StatisticsIF的getXXX()方法來取得相關的訊息，您也可以指定取回某個時間的統計資訊，例如每15分鐘的統計資料：</p><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java">StatisticsIF statistics = ProxoolFacade.getStatistics(<span class="code-quote">"example"</span>, <span class="code-quote">"15m"</span>);</pre></div></div><p>　如果您使用Web應用程式，則可以直接利用org.logicalcobwebs.proxool.admin.servlet.AdminServlet來取得相關的統計資料，在web.xml中這麼設定：</p><div class="code" style="border-style: solid;"><div class="codeHeader" style="border-bottom-style: solid;"><b>web.xml</b></div><div class="codeContent"><pre class="code-java">&lt;servlet&gt;<br />  &lt;servlet-name&gt;Admin&lt;/servlet-name&gt;<br />  &lt;servlet-class&gt;org.logicalcobwebs.proxool.admin.servlet.AdminServlet&lt;/servlet-class&gt;<br />&lt;/servlet&gt;<br /><br />&lt;servlet-mapping&gt;<br />  &lt;servlet-name&gt;Admin&lt;/servlet-name&gt;<br />  &lt;url-pattern&gt;/admin&lt;/url-pattern&gt;<br />&lt;/servlet-mapping&gt;</pre></div></div><p>　啟動Container，在測試資料庫後，您就可以連接Servlet取得連線統計訊息，例如：</p><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java">http:<span class="code-comment">//網址/Web程式名稱/admin</span></pre></div></div>


　AdminServlet的畫面就像是這樣：<br /><span class="nobr"><a href="http://proxool.sourceforge.net/adminServlet.html" title="Visit page outside Confluence" rel="nofollow">http://proxool.sourceforge.net/adminServlet.html</a></span><img src ="http://www.blogjava.net/Vencent/aggbug/36949.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-03-23 00:05 <a href="http://www.blogjava.net/Vencent/articles/36949.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> Proxool - 組態設定</title><link>http://www.blogjava.net/Vencent/articles/36947.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Wed, 22 Mar 2006 16:04:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/36947.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/36947.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/36947.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/36947.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/36947.html</trackback:ping><description><![CDATA[Proxool 提供許多方式可以設定相關的參數，這邊先介紹三種，另外還可以直接在Web應用程式中進行設定的方法，這在下一個主題中再說明。

<p>　可以直接在Java程式中使用java.util.Properties設定，例如：</p><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java"><span class="code-object">Class</span>.forName(<span class="code-quote">"org.logicalcobwebs.proxool.ProxoolDriver"</span>);<br />Properties info = <span class="code-keyword">new</span> Properties();<br />info.setProperty(<span class="code-quote">"proxool.maximum-connection-count"</span>, <span class="code-quote">"20"</span>);<br />info.setProperty(<span class="code-quote">"proxool.house-keeping-test-sql"</span>, <span class="code-quote">"select CURRENT_DATE"</span>);<br />info.setProperty(<span class="code-quote">"user"</span>, <span class="code-quote">"caterpillar"</span>);<br />info.setProperty(<span class="code-quote">"password"</span>, <span class="code-quote">"123456"</span>);<br />Connection conn = DriverManager.getConnection(<br /><span class="code-quote">"proxool.example:com.mysql.jdbc.Driver:jdbc:mysql:<span class="code-comment">//localhost:3306/GUESTBOOK"</span>, info);</span></pre></div></div><p>　當然這種方式是硬編碼（hard code）在程式中，要改變參數時必須修改原始檔案並重新編譯，我們也可以使用XML檔案或屬性檔來進行設定，使用XML檔案的方式如下：</p><div class="code" style="border-style: solid;"><div class="codeHeader" style="border-bottom-style: solid;"><b>proxool.xml</b></div><div class="codeContent"><pre class="code-java">&lt;?xml version=<span class="code-quote">"1.0"</span> encoding=<span class="code-quote">"ISO-8859-1"</span>?&gt;<br />&lt;something-<span class="code-keyword">else</span>-entirely&gt;<br />  &lt;proxool&gt;<br />    &lt;alias&gt;example&lt;/alias&gt;<br />    &lt;driver-url&gt;jdbc:mysql:<span class="code-comment">//localhost:3306/GUESTBOOK&lt;/driver-url&gt;<br /></span>    &lt;driver-class&gt;com.mysql.jdbc.Driver&lt;/driver-class&gt;<br />    &lt;driver-properties&gt;<br />      &lt;property name=<span class="code-quote">"user"</span> value=<span class="code-quote">"caterpillar"</span>/&gt;<br />      &lt;property name=<span class="code-quote">"password"</span> value=<span class="code-quote">"123456"</span>/&gt;<br />    &lt;/driver-properties&gt;<br />    &lt;maximum-connection-count&gt;10&lt;/maximum-connection-count&gt;<br />    &lt;house-keeping-test-sql&gt;select CURRENT_DATE&lt;/house-keeping-test-sql&gt;<br />  &lt;/proxool&gt;<br />&lt;/something-<span class="code-keyword">else</span>-entirely&gt;</pre></div></div><p>　其中example是連接池的別名（Alias），我們使用org.logicalcobwebs.proxool.configuration.JAXPConfigurator來讀取XML，以下的示範如何取得連線：</p><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java"><span class="code-object">Class</span>.forName(<span class="code-quote">"org.logicalcobwebs.proxool.ProxoolDriver"</span>);<br />JAXPConfigurator.configure(<span class="code-quote">"proxool.xml"</span>, <span class="code-keyword">false</span>); <span class="code-comment">// <span class="code-keyword">false</span> 表示不驗證 XML<br /></span>Connection conn = DriverManager.getConnection(<span class="code-quote">"proxool.example"</span>);</pre></div></div><p>　我們也可以使用屬性檔來配置Proxool，屬性檔的內容如下：</p><div class="code" style="border-style: solid;"><div class="codeHeader" style="border-bottom-style: solid;"><b>proxool.properties</b></div><div class="codeContent"><pre class="code-java">jdbc-0.proxool.alias=example<br />jdbc-0.proxool.driver-url=jdbc:mysql:<span class="code-comment">//localhost:3306/GUESTBOOK<br /></span>jdbc-0.proxool.driver-class=com.mysql.jdbc.Driver<br />jdbc-0.user=caterpillar<br />jdbc-0.password=123456<br />jdbc-0.proxool.maximum-connection-count=10<br />jdbc-0.proxool.house-keeping-test-sql=select CURRENT_DATE</pre></div></div><p>　我們使用org.logicalcobwebs.proxool.configuration.PropertyConfigurator來讀取屬性檔，下面示範如何取得連線：</p><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java"><span class="code-object">Class</span>.forName(<span class="code-quote">"org.logicalcobwebs.proxool.ProxoolDriver"</span>);<br />org.logicalcobwebs.proxool.configuration.PropertyConfigurator.configure(<span class="code-quote">"proxool.properties"</span>);<br />Connection conn = DriverManager.getConnection(<span class="code-quote">"proxool.example"</span>);</pre></div></div><!--
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns:dc="http://purl.org/dc/elements/1.1/"
         xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
<rdf:Description
    rdf:about="http://www.javaworld.com.tw/confluence/pages/viewpage.action?pageId=708"
    dc:identifier="http://www.javaworld.com.tw/confluence/pages/viewpage.action?pageId=708"
    dc:title="Proxool - 組態設定"
    trackback:ping="http://www.javaworld.com.tw/confluence/rpc/trackback/708"/>
</rdf:RDF>
--><!--
    Root decorator: all decisions about how a page is to be decorated via the
                    inline decoration begins here.
--><!--
    Switch based upon the context. However, for now, just delegate to a decorator
    identified directly by the context.
--><p style="clear: both;"><!-- comments should always display underneath the content. we should have a 'clear:both' here just in case there are floats or aligned images in the content --></p><div class="tabletitle" style="border: 0px none ;"><a name="comments">Comments</a><span class="smalltext"> (<a href="http://www.javaworld.com.tw/confluence/pages/viewpage.action?pageId=708&amp;showComments=false">Hide</a>)</span></div><a name="comment-3192"></a><div class="commentblock"><p>我碰到一个大问题，在数据库连接最大活动时间设置为：5 分钟，最大存活时间 10 分钟，可是 连接超时后没有被杀死，而且都是红色不可用。如何解决呀？ 我使用 oracle 9i ，配置了两个连接池。 </p><p>我还试着执行下面这个清除语句：org.logicalcobwebs.proxool.ProxoolFacade.killAllConnections("btcn");<br />
 org.logicalcobwebs.proxool.ProxoolFacade.shutdown(0);                  // 关闭所有连接池</p><p>不起作用，死连接一大片，没有被清除，请指教</p></div><img src ="http://www.blogjava.net/Vencent/aggbug/36947.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-03-23 00:04 <a href="http://www.blogjava.net/Vencent/articles/36947.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> Proxool - Servlet 組態設定</title><link>http://www.blogjava.net/Vencent/articles/36948.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Wed, 22 Mar 2006 16:04:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/36948.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/36948.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/36948.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/36948.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/36948.html</trackback:ping><description><![CDATA[除了直接使用JAXPConfigurator從XML或屬性檔讀取組態設定之外，如果您正在運行Web
應用程式，您可以透過org.logicalcobwebs.proxool.configuration.ServletConfigurator，將
之設定為Servlet，並於Container一啟始時就載入Proxool以初始連接池，要這麼作，請將proxool-0.8.3.jar放到
WEB/lib目錄中。

<p>　使用ServletConfigurator時，您有三種方式可以設定相關參數給它，透過XML、透過屬性檔、透過設定Servlet初始參數。</p><p>　首先是透過XML檔案，XML檔案的設定請參考前一個<span class="nobr"><a href="http://www.javaworld.com.tw/confluence/pages/viewpage.action?pageId=708" title="Visit page outside Confluence" rel="nofollow">主題<sup><img class="rendericon" src="http://www.javaworld.com.tw/confluence/images/icons/linkext7.gif" alt="" align="absmiddle" border="0" height="7" width="7" /></sup></a></span>，在web.xml中，您可以這麼設定：</p><div class="code" style="border-style: solid;"><div class="codeHeader" style="border-bottom-style: solid;"><b>web.xml</b></div><div class="codeContent"><pre class="code-java">&lt;servlet-name&gt;ServletConfigurator&lt;/servlet-name&gt;<br />  &lt;servlet-class&gt;org.logicalcobwebs.proxool.configuration.ServletConfigurator&lt;/servlet-class&gt;<br />  &lt;init-param&gt;<br />    &lt;param-name&gt;xmlFile&lt;/param-name&gt;<br />    &lt;param-value&gt;WEB-INF/proxool.xml&lt;/param-value&gt;<br />  &lt;/init-param&gt;<br />  &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;<br />&lt;/servlet&gt;</pre></div></div><p>　再來是透過屬性檔，屬性檔的設定請參考前一個<span class="nobr"><a href="http://www.javaworld.com.tw/confluence/pages/viewpage.action?pageId=708" title="Visit page outside Confluence" rel="nofollow">主題<sup><img class="rendericon" src="http://www.javaworld.com.tw/confluence/images/icons/linkext7.gif" alt="" align="absmiddle" border="0" height="7" width="7" /></sup></a></span>，在web.xml中，您可以這麼設定：</p><div class="code" style="border-style: solid;"><div class="codeHeader" style="border-bottom-style: solid;"><b>web.xml</b></div><div class="codeContent"><pre class="code-java">&lt;servlet&gt;<br />  &lt;servlet-name&gt;ServletConfigurator&lt;/servlet-name&gt;<br />  &lt;servlet-class&gt;org.logicalcobwebs.proxool.configuration.ServletConfigurator&lt;/servlet-class&gt;<br />  &lt;init-param&gt;<br />    &lt;param-name&gt;propertyFile&lt;/param-name&gt;<br />    &lt;param-value&gt;WEB-INF/proxool.properties&lt;/param-value&gt;<br />  &lt;/init-param&gt;<br />&lt;/servlet&gt;</pre></div></div><p>　上面兩種作法，其實ServletConfigurator也各是委託JAXPConfigurator或
PropertyConfigurator來讀取組態設定；您也可以不透過檔案設定組態，而直接在web.xml中透過Servlet初始參數的設定來指
定相關參數：</p><div class="code" style="border-style: solid;"><div class="codeHeader" style="border-bottom-style: solid;"><b>web.xml</b></div><div class="codeContent"><pre class="code-java">&lt;servlet&gt;<br />  &lt;servlet-name&gt;ServletConfigurator&lt;/servlet-name&gt;<br />  &lt;servlet-class&gt;org.logicalcobwebs.proxool.configuration.ServletConfigurator&lt;/servlet-class&gt;<br />  &lt;init-param&gt;<br />    &lt;param-name&gt;jdbc-0.proxool.alias&lt;/param-name&gt;<br />    &lt;param-value&gt;example&lt;/param-value&gt;<br />  &lt;/init-param&gt;<br />  &lt;init-param&gt;<br />    &lt;param-name&gt;jdbc-0.proxool.driver-url&lt;/param-name&gt;<br />    &lt;param-value&gt;jdbc:mysql:<span class="code-comment">//localhost:3306/GUESTBOOK&lt;/param-value&gt;<br /></span>  &lt;/init-param&gt;<br />  &lt;init-param&gt;<br />    &lt;param-name&gt;jdbc-0.proxool.driver-class&lt;/param-name&gt;<br />    &lt;param-value&gt;com.mysql.jdbc.Driver&lt;/param-value&gt;<br />  &lt;/init-param&gt;<br />  &lt;init-param&gt;<br />    &lt;param-name&gt;jdbc-0.user&lt;/param-name&gt;<br />    &lt;param-value&gt;caterpillar&lt;/param-value&gt;<br />  &lt;/init-param&gt;<br />  &lt;init-param&gt;<br />    &lt;param-name&gt;jdbc-0.password&lt;/param-name&gt;<br />    &lt;param-value&gt;123456&lt;/param-value&gt;<br />  &lt;/init-param&gt;<br />  &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;<br />&lt;/servlet&gt;</pre></div></div><p>　取得連線的方式只要下面這句就行了：</p><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java">Connection conn = DriverManager.getConnection(<span class="code-quote">"proxool.example"</span>);</pre></div></div><p>　下面這個JSP簡單的測試一下是否可以取得連線：</p><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java">&lt;%@page <span class="code-keyword">import</span>=<span class="code-quote">"java.sql.*"</span>%&gt;<br />&lt;%@page contentType=<span class="code-quote">"text/html;charset=Big5"</span>%&gt;<br />&lt;%<br /><span class="code-keyword">try</span> {<br />        Connection conn = DriverManager.getConnection(<span class="code-quote">"proxool.example"</span>);<br /><span class="code-keyword">if</span>(!conn.isClosed())<br />            out.println(<span class="code-quote">"資料庫連線測試成功！"</span>);<br /><br />        conn.close();<br />    }<br /><span class="code-keyword">catch</span>(SQLException e) {<br />        out.println(e.toString());<br />    }<br />%&gt;</pre></div></div><img src ="http://www.blogjava.net/Vencent/aggbug/36948.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-03-23 00:04 <a href="http://www.blogjava.net/Vencent/articles/36948.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> Proxool - 快速入門</title><link>http://www.blogjava.net/Vencent/articles/36946.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Wed, 22 Mar 2006 16:03:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/36946.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/36946.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/36946.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/36946.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/36946.html</trackback:ping><description><![CDATA[在資料庫應用程式中，資料庫連線的取得是一個耗費時間的動作，為了避免花費時間在連線的取得與關閉上，我們會將連線資源放置在一個池中，有需要連線時就從池中取得，不需要連線時就將之放回池中，以求重複利用連線，連線池也擔任連線數量、連線時間的控制等等動作。

<p>　Proxool 是一個開放原始碼的連線池管理套件，在使用與設定上都十分的方便，撰寫此文的同時，Proxool 最新的版本是0.8.3，您可以在以下的網址下載：<br /><span class="nobr"><a href="http://proxool.sourceforge.net/index.html" title="Visit page outside Confluence" rel="nofollow">http://proxool.sourceforge.net/index.html<sup><img class="rendericon" src="http://www.javaworld.com.tw/confluence/images/icons/linkext7.gif" alt="" align="absmiddle" border="0" height="7" width="7" /></sup></a></span></p><p>　網站上的User Guide提供相當簡明的入門文件，您可以直接先從這些文件開始下手，而這篇文件則先提供您一個快速入門的範例，讓您知道如何透過Proxool取得資料庫連線，這邊所使用的是MySQL資料庫。</p><p>　為了要使用Java來進行連線，首先您所需要的是當然是JDBC驅動程式，如果您不知道如何使用JDBC，請先參考這邊有關於JDBC的介紹：<br /><span class="nobr"><a href="http://www.caterpillar.onlyfun.net/phpBB2/viewforum.php?f=21" title="Visit page outside Confluence" rel="nofollow">http://www.caterpillar.onlyfun.net/phpBB2/viewforum.php?f=21<sup><img class="rendericon" src="http://www.javaworld.com.tw/confluence/images/icons/linkext7.gif" alt="" align="absmiddle" border="0" height="7" width="7" /></sup></a></span></p><p>　接下來請在Proxool網址上取得proxool-0.8.3.zip這個檔案，解開後，將lib下的proxool-0.8.3.jar放至
您的 CLASSPATH可以存取的位置，如果是Web應用程式的話，您可以放置在WEB/lib目錄下，如果是桌面應用程式，您可以將之加入環境變數
CLASSPATH中。</p><p>　要使用Proxool，首先是載入Proxool驅動程式：</p><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java"><span class="code-object">Class</span>.forName(<span class="code-quote">"org.logicalcobwebs.proxool.ProxoolDriver"</span>);</pre></div></div><p>　接著我們在透過DriverManager取得連線時，必須告知連接池別名、JDBC驅動程式、JDBC URL等相關訊息：</p><div class="code" style="border-style: solid;"><div class="codeContent"><pre class="code-java">Connection conn =<br />DriverManager.getConnection(<span class="code-quote">"proxool.example:com.mysql.jdbc.Driver:jdbc:mysql:<span class="code-comment">//localhost:3306/GUESTBOOK"</span>,<br /></span><span class="code-quote">"caterpillar"</span>,<br /><span class="code-quote">"123456"</span>);</pre></div></div><p>　其中example是連接池的別名（alias），是一個用來參考至連接池的名稱，取得連接，接下來就按照JDBC的操作來使用即可，在不使用連線的時候，可以關閉它將連線放回連接池。</p><p>　下面這個程式是個簡單測試Proxool連線取得的範例：</p><div class="code" style="border-style: solid;"><div class="codeHeader" style="border-bottom-style: solid;"><b>DBTest.java</b></div><div class="codeContent"><pre class="code-java"><span class="code-keyword">import</span> java.sql.*;<br /><br /><span class="code-keyword">public</span> class DBTest {<br /><span class="code-keyword">static</span> {<br /><span class="code-keyword">try</span> {<br /><span class="code-object">Class</span>.forName(<span class="code-quote">"org.logicalcobwebs.proxool.ProxoolDriver"</span>);<br />        }<br /><span class="code-keyword">catch</span>(ClassNotFoundException e) {<br /><span class="code-object">System</span>.out.println(<span class="code-quote">"找不到驅動程式類別"</span>);<br />            e.printStackTrace();<br />        }<br />    }<br /><br /><span class="code-keyword">public</span><span class="code-keyword">static</span> void main(<span class="code-object">String</span>[] args) {<br /><span class="code-keyword">try</span> {<br />            Connection conn = DriverManager.getConnection(<br /><span class="code-quote">"proxool.example:com.mysql.jdbc.Driver:jdbc:mysql:<span class="code-comment">//localhost:3306/GUESTBOOK"</span>,<br /></span><span class="code-quote">"caterpillar"</span>, <span class="code-quote">"123456"</span>);<br /><span class="code-keyword">if</span>(!conn.isClosed())<br /><span class="code-object">System</span>.out.println(<span class="code-quote">"資料庫連線測試成功！"</span>);<br />            conn.close();<br />        }<br /><span class="code-keyword">catch</span>(SQLException e) {<br />            e.printStackTrace();<br />        }<br />    }<br />}<a name="comments"><br /></a><span class="smalltext"></span></pre></div></div><!--
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns:dc="http://purl.org/dc/elements/1.1/"
         xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
<rdf:Description
    rdf:about="http://www.javaworld.com.tw/confluence/pages/viewpage.action?pageId=703"
    dc:identifier="http://www.javaworld.com.tw/confluence/pages/viewpage.action?pageId=703"
    dc:title="Proxool - 快速入門"
    trackback:ping="http://www.javaworld.com.tw/confluence/rpc/trackback/703"/>
</rdf:RDF>
--><!--
    Root decorator: all decisions about how a page is to be decorated via the
                    inline decoration begins here.
--><!--
    Switch based upon the context. However, for now, just delegate to a decorator
    identified directly by the context.
--><p style="clear: both;"><!-- comments should always display underneath the content. we should have a 'clear:both' here just in case there are floats or aligned images in the content --></p><img src ="http://www.blogjava.net/Vencent/aggbug/36946.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-03-23 00:03 <a href="http://www.blogjava.net/Vencent/articles/36946.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 使用 DBCP 作 DB Connection pooling</title><link>http://www.blogjava.net/Vencent/articles/36945.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Wed, 22 Mar 2006 16:02:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/36945.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/36945.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/36945.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/36945.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/36945.html</trackback:ping><description><![CDATA[
		<p> 一般來說，在多人使用的系統中，應用程式若沒有運用 Connection pooling
的機制，會造成很大的效能問題，Connection 開開關關，除了慢，也會耗損資料庫伺服器的資源。大部分的 AP Server 都有提供
Connection pooling 的機制，程式設計師並無須去顧慮這個機制是如何運作的，只要懂得設定相關的參數即可。</p>
		<p> 假如說，某種狀況下，我們必須自行建置 Connection pooling
的機制時，該如何進行呢？自己寫當然是非常不划算的，況且也不一定寫的好，在這裡，我們使用 jakata project 裡的一個子專案
DBCP，來快速的建置一個隨處可用的 Connection pooling 機制。</p>
		<p>  在 Tomcat 裡，DBCP 是內建的，用來管理 DB Connection pooling。這個機制是可移植且可獨立出來使用的，要在你的運用程式中加上 DBCP 的功能，你必須至 <span class="nobr"><a href="http://jakarta.apache.org/commons/index.html" title="Visit page outside Confluence" rel="nofollow">http://jakarta.apache.org/commons/index.html<sup><img class="rendericon" src="http://www.javaworld.com.tw/confluence/images/icons/linkext7.gif" alt="" align="absmiddle" border="0" height="7" width="7" /></sup></a></span>
這個網址，找到該網頁內的 Components，共有三個必須下載：Collections 、 DBCP 、 Pool 。DBCP 是運用
Collections 及 Pool 這二個基礎的 Components 所設計出來的。當然，如果你有安裝 Tomcat
server，最佳的方式是至 $TOMCAT_HOME/common/lib/ 目錄下去取得，保證版本的配合度不會出現問題。在 Tomcat
server 裡，以 Tomcat 5.0.19 版內附的最新版本，這三個 Components 的檔名分別是
commons-collections.jar 、 commons-pool-1.1.jar 及 commons-dbcp-1.1.jar。</p>
		<p> 取得使用 DBCP 必備的 jar 檔後，請記得將這些 jar 檔，放置到 CLASSPATH 中，或直接放至
$JAVA_HOME/jre/lib/ext/ 目錄內。不過，由於 DBCP 有運用到 DataSource 的功能，而這功能是 J2EE
才有的，所以你還必須去下載 J2EE 的一個 javax.jar 檔。</p>
		<p>  環境建置好之後，接下來就可以開始設計 Connection Pooling 的機制，在這兒，我們介紹最簡單的作法，只要幾行指令就可以完成了，請看範例區裡的程式及其說明。</p>
		<p>範例：</p>
		<div class="code">
				<div class="codeContent">
						<pre class="code-java">01 <span class="code-keyword">package</span> util;<br />02 <br />03 <span class="code-keyword">import</span> java.sql.*;<br />04 <span class="code-keyword">import</span> javax.naming.*;<br />05 <span class="code-keyword">import</span> javax.sql.*;<br />06 <br />07 <span class="code-keyword">import</span> org.apache.commons.dbcp.BasicDataSource;<br />08 <br />09 <span class="code-keyword">public</span> class DBConnect {<br />10   <span class="code-keyword">static</span> DataSource dataSource = <span class="code-keyword">null</span>;<br />11 <br />12   <span class="code-keyword">public</span><span class="code-keyword">static</span> DataSource setupDataSource( <span class="code-object">String</span> sDrvName, <span class="code-object">String</span> sUserName,<br />13       <span class="code-object">String</span> sPwd, <span class="code-object">String</span> connectURI ) {<br />14       BasicDataSource ds = <span class="code-keyword">new</span> BasicDataSource();<br />15       ds.setDriverClassName( sDrvName );<br />16       ds.setUsername( sUserName );<br />17       ds.setPassword( sPwd );<br />18       ds.setUrl( connectURI );<br />19       ds.setMaxActive( 50 );<br />20       ds.setMaxIdle( 10 );<br />21       ds.setMaxWait( 10000 ); <span class="code-comment">// 10 seconds<br /></span>22       <span class="code-keyword">return</span> ds;<br />23   }<br />24 <br />25 <br />26   <span class="code-comment">// <span class="code-keyword">static</span> init of the class<br /></span>27   <span class="code-keyword">static</span> {<br />28     <span class="code-keyword">try</span> {<br />29       <span class="code-object">System</span>.setProperty( <span class="code-quote">"jdbc.drivers"</span>, <span class="code-quote">"oracle.jdbc.driver.OracleDriver"</span> );<br />30       <span class="code-object">Class</span>.forName( <span class="code-quote">"oracle.jdbc.driver.OracleDriver"</span> );<br />31 <br />32       dataSource = setupDataSource( <span class="code-quote">"oracle.jdbc.driver.OracleDriver"</span>, <span class="code-quote">"username"</span>,<br />33         <span class="code-quote">"password"</span>, <span class="code-quote">"jdbc:oracle:thin:@192.168.0.1:1521:SID"</span> );<br />34     }<br />35     <span class="code-keyword">catch</span> (Exception e) {<br />36       <span class="code-object">System</span>.out.println( <span class="code-quote">"DBConnect.java =&gt; Unable to load driver."</span>  + e.getMessage() );<br />37     }<br />38   }<br />39 <br />40   /**<br />41    * 空的建構元，不作任何處理動作。<br />42    */<br />43   <span class="code-keyword">public</span> DBConnect() {}<br />44 <br />45   /**<br />46    * 取得 DB Connection.<br />47    */<br />48   <span class="code-keyword">public</span><span class="code-keyword">static</span> Connection getConnection() <span class="code-keyword">throws</span> SQLException,ClassNotFoundException {<br />49     BasicDataSource bds = (BasicDataSource) dataSource;<br />50     <span class="code-object">System</span>.out.println(<span class="code-quote">"NumActive: "</span> + bds.getNumActive() + <span class="code-quote">","</span><br />51       + <span class="code-quote">"NumIdle: "</span> + bds.getNumIdle() );<br />52     <span class="code-keyword">return</span> dataSource.getConnection();<br />53   }<br />54 }</pre>
				</div>
		</div>
		<p>完成這個程式後，接下來在你的應用程式裡，用 DBConnect.getConnection() 來取得 DB Connection，就能享受到 Connection Pooling 的功能了。</p>
		<p>在實際的運作中，這個範例有加上偵錯指令，會顯示出目前 Connection Pool 裡，有多少個 Idle 的 Connection 及多少個 Active 的 Connection，可供作為系統運作的參數調整依據。</p>
<img src ="http://www.blogjava.net/Vencent/aggbug/36945.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-03-23 00:02 <a href="http://www.blogjava.net/Vencent/articles/36945.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 如何有效率地使用字串</title><link>http://www.blogjava.net/Vencent/articles/36944.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Wed, 22 Mar 2006 16:00:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/36944.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/36944.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/36944.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/36944.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/36944.html</trackback:ping><description><![CDATA[
		<p>原文刊登在 2002/09/26 Java 週報上</p>
		<p>看完上篇（請參考九月十二日的Java週報）筆者所講解的物件的比較之後，<br />
既然講到了字串，筆者就再來跟大家討論一下，如何有效率地使用字串。<br />
你也許會有疑問說，字串就這樣用啊，什麼叫有效率的使用字串呢？我們<br />
先來確定一件事情，Java API說明文件上有這麼一行字：</p>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
						<pre class="code-java">“Strings are constant; their values cannot be changed after they are created.<br /><span class="code-object">String</span> buffers support mutable strings. Because <span class="code-object">String</span> objects<br />are immutable they can be shared.”。</pre>
				</div>
		</div>
		<p>意思是字串是個常數，是不可<br />
更改的，也就是說你對一個字串物件做任何的修改，像是加上另一個串、<br />
把字母變大寫等等，都會產生一個新的字串物件。我們做個小小的測試，<br />
來証明這件事情。</p>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
						<pre class="code-java">
								<span class="code-object">String</span> str1 = <span class="code-keyword">new</span><span class="code-object">String</span>(“hello”);<br /><span class="code-object">String</span> str2 = str2;<br /><span class="code-object">boolean</span> b1 = str1 == str2;</pre>
				</div>
		</div>
		<p>還記得上週筆者講解的字串之間比較嗎？b1得到的結果是true，代表str1<br />
和str2參考到同一個字串物件，忘記或是不清楚的讀者，再回去翻翻週報<br />
的內容。如果現在我們把str2加上“java”這個字串：</p>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
						<pre class="code-java">str2 = str2 + “java”;<br /><span class="code-object">boolean</span> b2 = str1 == str2;</pre>
				</div>
		</div>
		<p>你會發現b2的結果是false，代表str1和str2所參考的字串物件已經不是同<br />
一個了！現在在系統中就有三個字串物件，一個是“hello”，第二個是“<br />
java”，第三個是“hellojava”。因為在Java中，字串有這樣一個不可修<br />
改的特性，所以才會引發出如何有效地使用字串這個問題出來。</p>
		<p>字串是每個應用程式都會用到的物件，常常有些程式中會對字串做大量的<br />
運算，尤其是兩個字串的相加，例如我們寫了一個從網路上讀取網頁資料<br />
的程式，跑個迴圈，用BufferedReader物件一次讀一行進來，然後把每一<br />
行再加在一起。像這種很直覺、很簡單的程式，兩行就搞定了，可是JVM中<br />
所做的事情可多了。 假設我們寫個一程式，要把一個字串一直加上“a”<br />
一百次，很直覺得我們會這樣寫：</p>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
						<pre class="code-java">
								<span class="code-object">String</span> str = “”;<br /><span class="code-keyword">for</span> (<span class="code-object">int</span> i=0; i&lt;100; i++)<br />str += “a”;</pre>
				</div>
		</div>
		<p>可是你知道在記憶體中會產生多少的垃圾出來嗎？總共會有a、aa、aaa、<br />
aaa….，無疑的，上述的程式雖然簡單，但浪費了不少的記憶體，而且產<br />
生物件和物件的存取也會花掉不少的時間，我們加上幾行程式碼來測試所<br />
花的時間和記憶體：</p>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
						<pre class="code-java">
								<span class="code-object">long</span> startTime = <span class="code-object">System</span>.currentTimeMillis();<br /><span class="code-object">long</span> startMem = <span class="code-object">Runtime</span>.getRuntime().freeMemory();<br /><br /><span class="code-keyword">for</span> (<span class="code-object">int</span> i=0; i&lt;1000; i++)<br />str += <span class="code-quote">"a"</span>;<br /><br /><span class="code-object">long</span> endMem = <span class="code-object">Runtime</span>.getRuntime().freeMemory();<br /><span class="code-object">System</span>.out.println(<span class="code-quote">"Use memory: "</span>+ (startMem - endMem));<br /><span class="code-object">long</span> endTime = <span class="code-object">System</span>.currentTimeMillis();<br /><span class="code-object">System</span>.out.println(<span class="code-quote">"Use Time: "</span>+ (endTime – startTime));</pre>
				</div>
		</div>
		<p>上面的程式在筆者的PIII-800的電腦上跑，平均花了50 ms和151256 bytes<br />
的記憶體，時間還好，但記憶體使用量算蠻大的了。那我們要如何來改進<br />
讓程式更有效率呢？因為String物件是不可修改的，可是程式中又常需要<br />
這樣的一個動作，所以Java提供了另外一個類別，專門來處理字串運算用<br />
的，這個類別就叫作StringBuffer。StringBuffer類別提供了很多方法來<br />
做字串的運算，但如附加、刪除、插入、反轉、替換等等…。我們就用<br />
StringBuffer類別所提供的附加(append)方法來做到跟上面那個例子同樣<br />
的結果：</p>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
						<pre class="code-java">
								<span class="code-object">StringBuffer</span> sb = <span class="code-keyword">new</span><span class="code-object">StringBuffer</span>();<br /><span class="code-object">long</span> startTime = <span class="code-object">System</span>.currentTimeMillis();<br /><span class="code-object">long</span> startMem = <span class="code-object">Runtime</span>.getRuntime().freeMemory();<br /><br /><span class="code-keyword">for</span> (<span class="code-object">int</span> i=0; i&lt;1000; i++)<br />sb.append(“a”);<br /><br /><span class="code-object">long</span> endMem = <span class="code-object">Runtime</span>.getRuntime().freeMemory();<br /><span class="code-object">System</span>.out.println(<span class="code-quote">"Use memory: "</span>+ (startMem - endMem));<br /><span class="code-object">long</span> endTime = <span class="code-object">System</span>.currentTimeMillis();</pre>
				</div>
		</div>
		<p>修改過的程式在筆者電腦上跑，平均花了0 ms和4854 bytes的記憶體。<br />
0 ms？！多跑幾次有時會到10 ms，要看你電腦CPU目前的負載如何，不<br />
過跟前面的例子比較起來，已經算是快了，而且記憶體也使用的非常少<br />
。這只是個小小的例子，如果字串量再大一點，兩者的差異會更明顯。</p>
		<p>所以結論就是，如果你的程式中會對字串做大量的修改時，請改用<br />
StringBuffer類別，它會明顯示改進你程式的效率。至於StringBuffer<br />
類別所提供的方法詳細的使用說明，就請自行參閱Java API。</p>
		<p>
				<br clear="all" />
		</p>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
				</div>
		</div>
		<p>
				<br clear="all" />
		</p>
		<table class="confluenceTable">
				<tbody>
						<tr>
								<th class="confluenceTh">作者：</th>
								<td class="confluenceTd">hkdennis2k</td>
						</tr>
				</tbody>
		</table>
		<p> JDK 5.0 加入了 StringBuilder<br />
和 StringBuffer 主要不同的時, 它不是 synconized 的, 省回了一點 overhead</p>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
						<pre class="code-java">javac -target 1.4<br /><span class="code-object">String</span> b=a+<span class="code-quote">"a"</span>;</pre>
				</div>
		</div>
		<p>會被 compile 為</p>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
						<pre class="code-java">
								<span class="code-object">String</span> b=<span class="code-keyword">new</span><span class="code-object">StringBuffer</span>(a).append(<span class="code-quote">"a"</span>).toString();</pre>
				</div>
		</div>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
						<pre class="code-java">javac -target 1.5<br /><span class="code-object">String</span> b=a+<span class="code-quote">"a"</span>;</pre>
				</div>
		</div>
		<p>會被 compile 為</p>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
						<pre class="code-java">
								<span class="code-object">String</span> b=<span class="code-keyword">new</span> StringBuilder(a).append(<span class="code-quote">"a"</span>).toString();</pre>
				</div>
		</div>
		<p>因為 1.4 沒有 StringBuilder, 所以 javac -target 1.5 是不可以在 jvm 1.4 上運行的</p>
		<p>另外....</p>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
						<pre class="code-java">
								<span class="code-keyword">static</span>
								<span class="code-keyword">final</span>
								<span class="code-object">int</span> x=10000;<br /><br /><span class="code-object">StringBuffer</span> sb = <span class="code-keyword">new</span><span class="code-object">StringBuffer</span>();<br /><span class="code-keyword">for</span> (<span class="code-object">int</span> i=0; i&lt;x; i++)<br />sb.append(“a”);<br /><br /><span class="code-object">StringBuffer</span> sb = <span class="code-keyword">new</span><span class="code-object">StringBuffer</span>(x);<br /><span class="code-keyword">for</span> (<span class="code-object">int</span> i=0; i&lt;x; i++)<br />sb.append(“a”);</pre>
				</div>
		</div>
		<p>也是相差很遠的...<br />
好像大約 20%</p>
		<p>想想 String b=new StringBuilder(a).append("a").toString(); 吧<br />
在大型的 loop 中, 這是突破 preformenace 的一個關口....</p>
		<p>
				<br clear="all" />
		</p>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
				</div>
		</div>
		<p>
				<br clear="all" />
		</p>
		<table class="confluenceTable">
				<tbody>
						<tr>
								<th class="confluenceTh">作者：</th>
								<td class="confluenceTd">hkdennis2k</td>
						</tr>
				</tbody>
		</table>
		<p> StringBuilder 內部是用 char[] 實作, 而 default 只是用 char<span class="error">[16]</span>,<br />
似類似 ArrayList, 當 char[] 長度不足就會用 System.arraycopy 移到另一個新的使用</p>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
						<pre class="code-java">
								<span class="code-object">StringBuffer</span> sb = <span class="code-keyword">new</span><span class="code-object">StringBuffer</span>();<br /><span class="code-keyword">for</span> (<span class="code-object">int</span> i=0; i&lt;x; i++)<br />sb.append(<span class="code-quote">"a"</span>);</pre>
				</div>
		</div>
		<p>而這段 code, 會出現大當 arraycopy, new char[] 等等浪費時間的動作<br />
連 GC 做的份也少省了下來</p>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
						<pre class="code-java">
								<span class="code-object">StringBuffer</span> sb = <span class="code-keyword">new</span><span class="code-object">StringBuffer</span>(x);</pre>
				</div>
		</div>
		<p>而這個, 一開始就準備了一個剛好足夠大小的 char[]</p>
		<p>也就是, 和 ArrayList, HashMap 之類的, 利用 init 一個比較大/剛好的 array 來減少 rehash / overhead的原理一樣, 不過 StringBuffer 沒法字去更改 resize factor 就是了....</p>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
						<pre class="code-java">void expandCapacity(<span class="code-object">int</span> minimumCapacity) {<br /><span class="code-object">int</span> newCapacity = (value.length + 1) * 2;<br /><span class="code-keyword">if</span> (newCapacity &lt; 0) {<br />            newCapacity = <span class="code-object">Integer</span>.MAX_VALUE;<br />        } <span class="code-keyword">else</span><span class="code-keyword">if</span> (minimumCapacity &gt; newCapacity) {<br />      newCapacity = minimumCapacity;<br />  }  <br /><span class="code-object">char</span> newValue[] = <span class="code-keyword">new</span><span class="code-object">char</span>[newCapacity];<br /><span class="code-object">System</span>.arraycopy(value, 0, newValue, 0, count);<br />  value = newValue;<br />    }<br /><span class="code-keyword">public</span><span class="code-object">StringBuffer</span> append(<span class="code-object">String</span> str) {<br /><span class="code-keyword">if</span> (str == <span class="code-keyword">null</span>) str = <span class="code-quote">"<span class="code-keyword">null</span>"</span>;<br /><span class="code-object">int</span> len = str.length();<br /><span class="code-keyword">if</span> (len == 0) <span class="code-keyword">return</span><span class="code-keyword">this</span>;<br /><span class="code-object">int</span> newCount = count + len;<br /><span class="code-keyword">if</span> (newCount &gt; value.length)<br />      expandCapacity(newCount);<br />  str.getChars(0, len, value, count);<br />  count = newCount;<br /><span class="code-keyword">return</span><span class="code-keyword">this</span>;<br />    }</pre>
				</div>
		</div>
		<p>
				<br clear="all" />
		</p>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
				</div>
		</div>
		<p>
				<br clear="all" />
		</p>
		<table class="confluenceTable">
				<tbody>
						<tr>
								<th class="confluenceTh">作者：</th>
								<td class="confluenceTd">老陳</td>
						</tr>
				</tbody>
		</table>
		<p> 另外再提供一個技巧,就是比對空字串的時候,一般人會這樣比</p>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
						<pre class="code-java">a.equals("")</pre>
				</div>
		</div>
		<p>但如果改用下列的方式效率會更好</p>
		<div class="code" style="border-style: solid;">
				<div class="codeContent">
						<pre class="code-java">a.length() == 0</pre>
				</div>
		</div>
		<p>雖然""是直接去String pool裡面拿的,不用再去create一個新的String Object,但是Object的比對總是要比原生型態的效率差一點</p>
		<p>以上提供給大家參考. 歡迎大大指較</p>
<img src ="http://www.blogjava.net/Vencent/aggbug/36944.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-03-23 00:00 <a href="http://www.blogjava.net/Vencent/articles/36944.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>AOP@Work: 用 AspectJ 和 Spring 进行依赖项插入::面向方面开发人员可以采用的高级技术</title><link>http://www.blogjava.net/Vencent/articles/35989.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Sat, 18 Mar 2006 13:32:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/35989.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/35989.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/35989.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/35989.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/35989.html</trackback:ping><description><![CDATA[
		<p>级别: 中级</p>
		<p>
				<a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#author">Adrian Colyer</a>, 首席科学家, Interface21<br /></p>
		<p>2006 年  1 月  23 日</p>
		<blockquote>依赖项插入和面向方面编程是互补的技术，所以想把它们结合在一起使用是很自然的。请跟随 Adrian Colyer 一起探索两者之间的关系，并了解怎样才能把它们组合在一起，来促进高级的依赖项插入场景。</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>依赖项插入和面向方面编程
（AOP）是两个关键的技术，有助于在企业应用程序中简化和纯化域模型和应用程序分层。依赖项插入封装了资源和协调器发现的细节，而方面可以（在其他事情
中）封装中间件服务调用的细节 —— 例如，提供事务和安全性管理。因为依赖项插入和 AOP
都会形成更简单、更容易测试的基于对象的应用程序，所以想把它们结合在一起使用是很自然的。方面可以帮助把依赖项插入的能力带到更广的对象和服务中，而依
赖项插入可以用来对方面本身进行配置。</p>
		<p>在这篇文章中，我将介绍如何把 Spring 框架的依赖项插入与用 AspectJ 5 编写的方面有效地结合在一起。我假设您拥有基本的 AOP 知识（如果没有这方面知识 ，可以在 <a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#resources">参考资料</a>
中找到一些良好的起点），所以我的讨论将从对基于依赖项插入的解决方案中包含的关键角色和职责的分析开始。从这里，我将介绍如何通过依赖项插入配置单体
（singleton）方面。因为配置非单体方面与配置域对象共享许多公共内容，所以后面我会研究一个应用于这两者的简单解决方案。总结这篇文章时，我会
介绍如何为多个高级依赖项插入场景使用方面，其中包括基于接口的插入和重复插入。</p>
		<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
				<tbody>
						<tr>
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td>
										<table border="1" cellpadding="5" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N10068">
																				<b>关于这个系列</b>
																		</a>
																		<br />
																		<p>
																				<a href="http://www.ibm.com/developerworks/views/java/libraryview.jsp?search_by=AOP@work:">
																						<i>AOP@Work</i>
																				</a>系列面对的是在面向方面编程上有些基础，想扩展或加深了解的开发人员。同 developerWorks 的大多数文章一样，这个系列高度实用：读完每篇介绍新技术的文章，都可以立即投入实用。</p>
																		<p>这个系列每个作者的选择，都是因为他们在面向方面编程领域具有领袖地位或专家水平。许多作者都是系列中介绍的项目和工具的参与者。每篇文章都力图提供一个中立的评述，以确保这里表达的观点的公正与正确。</p>
																		<p>如果有对每个作者文章的评论或问题，请分别与他们联系。要对这个系列整体进行评论，可以与系列的负责人 <a href="mailto:ndlesiecki@yahoo.com">Nicholas
Lesiecki</a> 联系。请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#resources">参考资料</a> 获取关于 AOP 的更多背景资料。</p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#downloads">下载</a> 获得文章的源代码，参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#resources">参考资料</a> 下载 AspectJ 或 Spring 框架，运行示例需要它们。</p>
		<p>
				<a name="N10091">
						<span class="atitle">什么是依赖项插入？</span>
				</a>
		</p>
		<p>在 <i>Domain-Driven Design</i> 一书中，Eric Evans 讨论了如何把对象与建立对象的配置和关联的细节隐藏起来：</p>
		<blockquote>对象的大部分威力在于对象内部复杂的配置和关联。应当对对象进行提炼，直到与对象的意义或者在交互中支持对象的作用无关的东西都不存在为止。这个中间循环的责任很多。如果让复杂对象负责自己的创建，就会出现问题。</blockquote>
		<p>Evans 接着提供了一个汽车引擎的示例：它的众多部件一起协作，执行引擎的职责。虽然可以把引擎块想像成把一组活塞插入气缸，但是这样的设计会把引擎明显地弄复杂。相反，技工或机器人装配引擎，引擎本身只考虑自己的操作。</p>
		<p>虽然这个示例是我从书中介绍用于复杂对象创建的<i>工厂</i> 概念一节中取出的，但是我们也可以用这个概念解释依赖项插入技术的动机。</p>
		<p>
				<a name="N100A9">
						<span class="smalltitle">从协作到合约</span>
				</a>
		</p>
		<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
				<tbody>
						<tr>
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td>
										<table border="1" cellpadding="5" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N100B3">
																				<b>参考读物</b>
																		</a>
																		<br />
关于依赖项插入的经典介绍，请参阅 Martin Fowler 的 “Inversion of Control Containers and
the Dependency Injection Pattern”。关于使用 Spring 的依赖项插入的更多内容，请参阅 <i>Professional Java Development with the Spring Framework</i>。这两者的链接都在
<a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#resources">参考资料</a> 中。 
</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>针对这篇文章的目的，可以把依赖项插入想像成对象和对象的执行环境之间的<i>合约</i>。对象（执行 <code>ResourceConsumer</code>、
<code>Collaborator</code> 和 <code>ServiceClient</code> 的其中一个角色或全部角色）同意不出去搜索自己需要的资源、它与之协作的合作伙伴或它使用的服务。相反，对象提供一种机制，让这些依赖项可以提供给它。接下来，执行环境同意在对象需要它的依赖项之前，向对象提供所有的依赖项。</p>
		<p>解析依赖项的方法在不同的场景中各有不同。例如，在单元测试用例中，对象的执行环境是测试用例本身，所以测试设置代码有责任直接满足依赖项。在集成测试或应用程序在生产环境时，<i>代理</i> 负责寻找满足对象依赖项的资源，并把它们传递给对象。代理的角色通常是由轻量级容器扮演的，例如 Spring 框架。不管依赖项是如何解析的，被配置的对象通常不知道这类细节。在第二个示例中，它可能还不知道代理的存在。</p>
		<p>代理（例如 Spring 框架）有四个关键职责，在整篇文章中我将不断提到这些职责，它们是：</p>
		<ul>
				<li>确定对象需要配置（通常因为对象刚刚创建）</li>
				<li>确定对象的依赖项</li>
				<li>发现满足这些依赖项的对象</li>
				<li>用对象的依赖项对它进行配置</li>
		</ul>
		<p>从下面的各种依赖项插入解决方案可以看出，解决这些职责有多种策略。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N100ED">
						<span class="atitle">使用 Spring 进行依赖项插入</span>
				</a>
		</p>
		<p>在标准的 Spring 部署中，Spring 容器同时负责创建和配置核心应用程序对象（称为 <i>bean</i>）。因为容器既创建对象，又扮演代理的角色，所以对 Spring 容器来说，确定 bean 已经创建而且需要配置是件轻而易举的小事。通过查询应用程序的元模型，可以确定 bean 的依赖项，元模型通常是在 Spring 的配置文件中用 XML 表示的。</p>
		<p>满
足 bean 的依赖项的对象是容器管理的其他 bean。容器充当这些 bean
的仓库，所以可以用名称查询它们（或者在需要的时候创建）。最后，容器用新 bean 的依赖项对其进行配置。这通常是通过 setter
插入完成的（调用新 bean 的 setter 方法，把依赖项作为参数传递进去），虽然 Spring
支持其他形式的插入，例如构造函数插入和查询方法插入（请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#resources">参考资料</a> 学习关于使用 Spring 进行依赖项插入的更多内容。）</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10100">
						<span class="atitle">方面的依赖项插入</span>
				</a>
		</p>
		<p>像其他对象一样，方面可以从通过依赖项插入进行的配置中受益。在许多情况下，把方面实现为轻量级<i>控制器</i> 是良好的实践。在这种情况下，方面确定什么时候应当执行某些行为，但是会委托给协作器去执行实际的工作。例如，可以用异常处理策略对象配置异常处理方面。方面会探测出什么时候抛出了异常，并委托处理器对异常进行处理。清单 1 显示了基本的 <code>RemoteException</code> 处理方面：</p>
		<br />
		<a name="N10114">
				<b>清单 1. RemoteException 处理方面</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />
														<br />public aspect RemoteExceptionHandling {<br />      private RemoteExceptionHandler exceptionHandler;<br /><br />      public void setExceptionHandler(RemoteExceptionHandler aHandler) {<br />        this.exceptionHandler = aHandler;<br />      }<br /><br />      pointcut remoteCall() : call(* *(..) throws RemoteException+);<br /><br />      /**<br />       * Route exception to handler. RemoteException will still <br />       * propagate to caller unless handler throws an alternate <br />       * exception.<br />       */<br />      after() throwing(RemoteException ex) : remoteCall() {<br />        if (exceptionHandler != null)  <br />          exceptionHandler.onRemoteException(ex);<br />      }  <br />    }<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
				<tbody>
						<tr>
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td>
										<table border="1" cellpadding="5" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N1011E">
																				<b>研究源代码</b>
																		</a>
																		<br />
																		<p>如果想查看 <code>RemoteExceptionHandling</code> 方面配置的实际效果，请下载 <a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#downloads">文章源代码</a> 并运行 testsrc 文件夹中的 <code>RemoteExceptionHandlingTest</code> 测试用例。</p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>现
在我要用依赖项插入，用一个特殊的异常处理策略来配置我的方面。对于这个方面，我可以用标准的 Spring
方式，但是有一个警告。一般来说，Spring 既负责创建 bean，也负责配置 bean。但是，AspectJ 方面是由 AspectJ
运行时创建的。我需要 Spring 来配置 AspectJ 创建的方面。对于单体方面最常见的形式，例如上面的 <code>RemoteExceptionHandling</code> 方面，AspectJ 定义了一个 <code>aspectOf()</code> 方法，它返回方面的实例。我可以告诉 Spring 使用 <code>aspectOf()</code> 方法作为工厂方法，获得方面的实例。清单 2 显示了方面的 Spring 配置：</p>
		<br />
		<a name="N10146">
				<b>清单 2. 方面的 Spring 配置</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />
														<br />
														<br />  &lt;beans&gt;      <br />      &lt;bean name="RemoteExceptionHandlingAspect"<br />        class="org.aspectprogrammer.dw.RemoteExceptionHandling"<br />        factory-method="aspectOf"&gt;<br />        &lt;property name="exceptionHandler"&gt;<br />          &lt;ref bean="RemoteExceptionHandler"/&gt;<br />        &lt;/property&gt;<br />      &lt;/bean&gt;<br /><br />      &lt;bean name="RemoteExceptionHandler" <br />        class="org.aspectprogrammer.dw.DefaultRemoteExceptionHandler"&gt;<br />      &lt;/bean&gt;<br />  &lt;/beans&gt;<br /><br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>我想确保我的方面在远程异常抛出之前得到配置。在示例代码中，我用 Spring 的 <code>ApplicationContext</code> 确保了这种情况，因为它会自动地预先实例化所有单体 bean。如果我使用普通的 <code>BeanFactory</code>，然后再调用
<code>preInstantiateSingletons</code>，也会实现同样的效果。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1015B">
						<span class="atitle">域对象的依赖项插入</span>
				</a>
		</p>
		<p>配置单体方面就像在 Spring 容器中配置其他 bean 一样简单，但是对于拥有其他生命周期的方面来说，该怎么办呢？例如 <code>perthis</code>、<code>pertarget</code> 甚至 <code>percflow</code> 方面？生命周期与单体不同的方面实例，不能由 Spring 容器预先实例化；相反，它们是由 AspectJ 运行时根据方面声明创建的。迄今为止，<i>代理</i> （Spring）已经知道了对象需要配置，因为它创建了对象。如果我想执行非单体方面的依赖项插入，就需要用不同的策略来确定需要配置的对象已经创建。</p>
		<p>非单体方面不是能够从外部配置受益的、在 Spring 容器的控制之外创建的惟一对象类型。例如，需要访问仓库、服务和工厂的域实体（请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#resources">参考资料</a>）也会从依赖项插入得到与容器管理的 bean 能得到的同样好处。回忆一下代理的四项职责：</p>
		<ul>
				<li>确定对象需要配置（通常因为对象刚刚创建）</li>
				<li>确定对象的依赖项</li>
				<li>发现满足这些依赖项的对象</li>
				<li>用对象的依赖项对它进行配置</li>
		</ul>
		<p>我
仍然想用 Spring
来确定对象的依赖项，去发现满足这些依赖项的对象，并用对象的依赖项来配置对象。但是，需要另一种方法来确定对象需要配置。具体来说，我需要一个解决方
案，针对那些在 Spring 的容器控制之外，在应用程序执行过程中的任意一点上创建的对象。</p>
		<p>
				<a name="N1018C">
						<span class="smalltitle"> SpringConfiguredObjectBroker</span>
				</a>
		</p>
		<p>我把 Spring 配置的对象叫作 <code>SpringConfigured</code> 对象。创建新的 <code>SpringConfigured</code> 对象之后的需求就是，应当请求 Spring 来配置它。Spring <code>ApplicationContext</code> 支持的 <code>SpringConfiguredObjectBroker</code> 应当做这项工作，如清单 3 所示：</p>
		<br />
		<a name="N101A9">
				<b>清单 3. @SpringConfigured 对象代理</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />
														<br />public aspect SpringConfiguredObjectBroker <br />    implements ApplicationContextAware {<br /><br />      private ConfigurableListableBeanFactory beanFactory;<br /><br />      /**<br />       * This broker is itself configured by Spring DI, which will<br />       * pass it a reference to the ApplicationContext<br />       */<br />      public void setApplicationContext(ApplicationContext aContext) {<br />        if (!(aContext instanceof ConfigurableApplicationContext)) {<br />          throw new SpringConfiguredObjectBrokerException(<br />            "ApplicationContext [" + aContext +<br />            "] does not implement ConfigurableApplicationContext"<br />          );<br />        }<br />        this.beanFactory = <br />          ((ConfigurableApplicationContext)aContext).getBeanFactory();<br />      }<br /><br />      /**<br />       * creation of any object that we want to be configured by Spring<br />       */<br />      pointcut springConfiguredObjectCreation(<br />                  Object newInstance,<br />                  SpringConfigured scAnnotation<br />                  ) <br />        : initialization((@SpringConfigured *).new(..)) &amp;&amp;<br />          this(newInstance) &amp;&amp;<br />          @this(scAnnotation);<br /><br />      /**<br />       * ask Spring to configure the newly created instance<br />       */<br />      after(Object newInstance, SpringConfigured scAnn) returning <br />       : springConfiguredObjectCreation(newInstance,scAnn)<br />      {<br />        String beanName = getBeanName(newInstance, scAnn);<br />        beanFactory.applyBeanPropertyValues(newInstance,beanName);<br />      }<br /><br />      /**<br />       * Determine the bean name to use - if one was provided in<br />       * the annotation then use that, otherwise use the class name.<br />       */<br />      private String getBeanName(Object obj, SpringConfigured ann) {<br />        String beanName = ann.value();<br />        if (beanName.equals(“”)) {<br />          beanName = obj.getClass().getName();<br />        }<br />        return beanName;<br />      }<br />    }<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N101AF">
						<span class="smalltitle">SpringConfiguredObjectBroker 内部</span>
				</a>
		</p>
		<p>我将依次分析 <code>SpringConfiguredObjectBroker</code> 方面的各个部分。首先，这个方面实现了 Spring 的 <code>ApplicationContextAware</code> 接口。代理方面本身是由 Spring 配置的（这是它得到对应用程序上下文的引用的方式）。让方面实现 <code>ApplicationContextAware</code> 接口，确保了 Spring 知道在配置期间向它传递一个到当前 <code>ApplicationContext</code> 的引用。</p>
		<p>切点 <code>springConfiguredObjectCreation()</code> 用 <code>@SpringConfigured</code> 标注与任何对象的初始化连接点匹配。标注和新创建的实例，都在连接点上作为上下文被捕捉到。最后，返回的 after 建议要求 Spring 配置新创建的实例。bean 名称被用来查询实例的配置信息。我可以以 <code>@SpringConfigured</code> 标注的值的形式提供名称，或者也可以默认使用类的名称。</p>
		<p>方面的实现本身可以是标准库的一部分（实际上 Spring 的未来发行版会提供这样的方面），在这种情况下，我需要做的全部工作只是对 Spring 要配置的实例的类型进行标注，如下所示：</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />    @SpringConfigured("AccountBean")<br />    public class Account {<br />      ...<br />    }<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>可以在程序的控制下，创建这一类类型的实例（例如，作为数据库查询的结果），而且它们会把 Spring 为它们配置的全部依赖项自动管理起来。请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#downloads">下载</a> 得到这里使用的 <code>@SpringConfigured</code> 标注的示例。请注意，当我选择为这个示例使用的标注时（因为提供 bean 名称是非常自然的方式），标记器接口使得在 Java™ 1.4 及以下版本上可以使用这种方法。</p>
		<p>就像我在这一节开始时讨论的，<code>SpringConfigured</code> 技术不仅仅适用于域实例，而且适用于在 Spring 容器的控制之外创建的任何对象（对于 Spring 本身创建的对象，不需要添加任何复杂性）。通过这种方式，可以配置任何方面，而不用管它的生命周期。例如，如果定义 <code>percflow</code> 方面，那么每次进入相关的控制流程时，<i>AspectJ</i> 都会创建新的方面实例，而 <i>Spring</i> 会在每个方面创建的时候对其进行配置。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N101FB">
						<span class="atitle">基于接口的插入</span>
				</a>
		</p>
		<p>迄今为止，我使用了 Spring 容器读取的 bean 定义来确定对象的依赖项。这个方案的一个变体采用合约接口，由客户端声明它的要求。假设前一节的 <code>Account</code> 实体要求访问 <code>AccountOperationValidationService</code>。我可以声明一个接口，如清单 4 所示：</p>
		<br />
		<a name="N10210">
				<b>清单 4. 客户端接口</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />
														<br />public interface AccountOperationValidationClient {<br /><br />   public void setAccountOperationValidationService(<br />      AccountOperationValidationService aValidationService);<br /><br />}  <br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>现在，需要访问 <code>AccountOperationValidationService</code>
的对象必须实现这个接口，并把自己声明为客户。使用与前一节开发的方面类似的方面，我可以匹配实现这个接口的客户对象的所有初始化连接点。由它负责第一个
代理职责：确定什么时候需要配置对象。第二个职责在接口中被明确表达：必须满足的依赖项是验证服务依赖项。我将用一个方面插入所有客户验证服务的依赖项。
方面得到合适服务的最简单方法就是把服务插入到方面自身！清单 5 显示了一个示例： </p>
		<br />
		<a name="N10221">
				<b>清单 5. 服务插入器方面</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />
														<br />   /** <br />     * ensure that all clients of the account validation service<br />     * have access to it <br />     */<br />    public aspect AccountOperationValidationServiceInjector {<br /><br />      private AccountOperationValidationService service;<br /><br />      /**<br />       * the aspect itself is configured via Spring DI<br />       */<br />      public void setService(AccountOperationValidationService aService){<br />        this.service = aService;<br />      }<br /><br />      /**<br />       * the creation of any object that is a client of the <br />       * validation service<br />       */<br />      pointcut clientCreation(AccountOperationValidationClient aClient) :<br />        initialization(AccountOperationValidationClient+.new(..)) &amp;&amp;<br />        this(aClient);<br /><br />      /**<br />       * inject clients when they are created<br />       */<br />      after(AccountOperationValidationClient aClient) returning :<br />        clientCreation(aClient) {<br />        aClient.setAccountOperationValidationService(this.service);<br />      }<br /><br />    }<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>这个解决方案提供了两级控制。服务本身实际的定义是在 Spring 的配置文件中提供的，就像清单 6 中的 XML 片段示例一样：</p>
		<br />
		<a name="N1022E">
				<b>清单 6. 服务插入器配置</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />
														<br />
														<br />    &lt;beans&gt;  <br />      &lt;bean name="AccountOperationValidationServiceInjector"<br />        class="org.aspectprogrammer.dw.<br />                  AccountOperationValidationServiceInjector"<br />        factory-method="aspectOf"&gt;<br />        &lt;property name="service"&gt;<br />        &lt;ref bean="AccountOperationValidationService"/&gt;<br />          &lt;/property&gt;<br />      &lt;/bean&gt;<br /><br />      &lt;bean name="AccountOperationValidationService" <br />        class="org.aspectprogrammer.dw.<br />                 DefaultAccountOperationValidationService"&gt;<br />      &lt;/bean&gt;<br />    &lt;/beans&gt; <br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>服务的客户只需要实现 <code>AccountOperationValidationClient</code> 接口，那么就会自动用 Spring 定义的服务的当前实例对它们进行配置。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1023B">
						<span class="atitle">重复插入</span>
				</a>
		</p>
		<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
				<tbody>
						<tr>
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td>
										<table border="1" cellpadding="5" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N10245">
																				<b>在 Spring 中的查询方法插入</b>
																		</a>
																		<br />
																		<p>查
询方法插入是 Spring 容器支持的一种高级特性：由容器覆盖被管理 bean 的抽象或具体方法，返回在容器中查询另一个命名 bean
的结果。查询通常是非单体 bean。查询依赖项的 bean ，用被查询 bean 类型所声明的返回类型，定义查询方法。Spring 配置文件在
bean 的内部使用 <code>&lt;lookup-method&gt;</code> 元素告诉 Spring 在调用查询方法时应当返回什么 bean 实例。请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#resources">参考资料</a> 学习关于这项技术的更多内容。带有 <code>HotSwappable</code> 目标源的 Spring AOP 代理提供了另一种方法。</p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>迄
今为止，我介绍的解决方案都是在对象初始化之后立即配置对象。但是，在某些情况下，客户需要与之协调的对象在运行的时候变化。例如，通过与系统进行交互，
销售团队可以动态地为在线预订应用程序修改报价策略和座位分配策略。与报价策略和座位分配策略交互的预订服务需要的策略实现，应当是预订时的实现，而不是
预订服务第一次初始化的时候实现的版本。在这种情况下，可以把依赖项的插入延迟到客户第一次需要它的时候，并在每次引用依赖项的时候，将依赖项的最新版本
重新插入客户。</p>
		<p>这个场景的基本技术包括字段级插入或 getter 方法覆盖。在进入示例之前，我要再次强调：我要介绍的插入技术所面向的对象，是在 <i>Spring 容器的控制之外</i> 创建的。对于 Spring 创建的对象，Spring 容器已经提供了解决这些需求的简单机制。</p>
		<p>
				<a name="N10263">
						<span class="smalltitle">字段级插入</span>
				</a>
		</p>
		<p>在下面的示例中，可以看出如何为延迟插入或重复插入应用字段级插入。字段的 <code>get</code> 连接点让我可以确定什么时候进行插入，而字段类型可以确定要插入的依赖项。所以，如果客户声明了这样的一个字段：</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />private PricingStrategy pricingStrategy;<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>而在客户的方法中，发现了下面的代码</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />this.pricingStrategy.price(.....);<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>那么代码在运行时的执行会形成 <code>pricingStrategy</code> 字段的  <code>get()</code> 连接点，我可以用它插入当前报价策略实现，如清单 7 所示：</p>
		<br />
		<a name="N1028C">
				<b>清单 7. 字段级插入示例</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />
														<br />    public aspect PricingStrategyInjector {<br /><br />      private PricingStrategy currentPricingStrategy;<br /><br />      public void setCurrentPricingStrategy(PricingStrategy aStrategy) {<br />        this.currentPricingStrategy = aStrategy;<br />      }<br /><br />      /**<br />       * a client is trying to access the current pricing strategy<br />       */<br />      pointcut pricingStrategyAccess() : <br />        get(PricingStrategy *) &amp;&amp;<br />        !within(PricingStrategyInjector);  // don’t advise ourselves!<br /><br />      /**<br />       * whenever a client accesses a pricing strategy field, ensure they<br />       * get the latest...<br />       */<br />      PricingStrategy around() : pricingStrategyAccess() {<br />        return this.currentPricingStrategy;<br />      }<br />    }<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#downloads">下载</a> 获得这个技术的实际效果。</p>
		<p>
				<a name="N10299">
						<span class="smalltitle">服务定位策略</span>
				</a>
		</p>
		<p>重复插入的一个替代就是用更常规的技术，用服务定位策略技术实现插入客户。例如：</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />public interface PricingStrategyLocator {<br />      PricingStrategy getCurrentPricingStrategy();<br />}    <br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>虽然代价是定义一个额外接口，还会使客户代码更长一些，但是这项技术对于代码清晰性来说具有优势。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N102AA">
						<span class="atitle">结束语</span>
				</a>
		</p>
		<p>在这篇文章中，我把依赖项插入看作对象和对象执行的环境之间的合约。对象不愿意外出寻找自己需要的资源、要协作的合作伙伴或者使用的服务。相反，对象提供了一种机制，允许把这些依赖项提供给它。然后，在对象需要依赖项之前，执行环境负责把对象需要的所有依赖项提供给它。 </p>
		<p>我讨论了依赖项插入解决方案的四个关键职责，这些是代理代表对象获取依赖项时必须解决的问题。最后，我介绍了满足这些需求的许多不同的技术。显然，如果<i>能够</i> 用 Spring 容器初始化并配置对象，那么就应当这么做。对于在 Spring 容器的控制之外创建的对象，例如一些使用非单体实例化模型的域对象或方面，我推荐使用 <code>@SpringConfigured</code> 标注或类似的东西。这项技术让您可以把全部配置信息完全转移到外部的 Spring 配置文件中。 </p>
		<p>在编写这篇文章的示例时，我采用了 AspectJ 5 的最新里程碑版（到 2005 年 10 月）和 Spring 1.2.4。请 <a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#downloads">下载</a> 完整的工作示例，开始体验我讨论的想法。<code>testsrc</code> 目录下的测试用例是良好的起点。</p>
		<br />
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<span class="atitle">
						<a name="download">下载</a>
				</span>
		</p>
		<table class="data-table-1" border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<th>描述</th>
								<th>名字</th>
								<th style="text-align: right;">大小</th>
								<th>下载方法</th>
						</tr>
						<tr>
								<td class="tb-row">Source code</td>
								<td nowrap="nowrap">j-aopwork13.zip</td>
								<td style="text-align: right;" nowrap="nowrap">26 KB</td>
								<td nowrap="nowrap">
                               <a class="fbox" href="ftp://www6.software.ibm.com/software/developer/library/j-aopwork13.zip"><b>FTP</b></a></td>
						</tr>
				</tbody>
		</table>
		<table border="0" cellpadding="0" cellspacing="0">
				<tbody>
						<tr valign="top">
								<td colspan="5">
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="12" width="12" />
								</td>
						</tr>
						<tr>
								<td>
										<img alt="" src="http://www.ibm.com/i/v14/icons/fw.gif" height="16" width="16" />
								</td>
								<td>
										<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/whichmethod.html">关于下载方法的信息</a>
								</td>
								<td>
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="50" />
								</td>
								<td>
										<img alt="" src="http://www.ibm.com/i/v14/icons/sout.gif" height="16" width="16" />
								</td>
								<td>
										<a class="fbox" href="http://www.adobe.com/products/acrobat/readstep2.html">Get Adobe® Reader®</a>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="resources">
						<span class="atitle">参考资料 </span>
				</a>
		</p>
		<b>学习</b>
		<br />
		<ul>
				<li>您可以参阅本文在 developerWorks 全球站点上的 <a href="http://www-128.ibm.com/developerworks/java/library/j-aopwork13.html" target="_blank">英文原文</a>。<br /><br /></li>
				<li>“<a href="http://www.ibm.com/developerworks/cn/java/j-aopwork8/">AOP@Work: 介绍 AspectJ 5</a>” （Adrian Colyer，developerWorks，2005 年 7 月）：AspectJ 5 简介。<br /><br /></li>
				<li>“<a href="http://www-128.ibm.com/developerworks/cn/opensource/os-lightweight3/">轻量级开发的成功秘诀，第 3 部分: Spring 露出水面</a>” （Bruce Tate，developerWorks，2005 年 6 月）：Spring 框架概述。<br /><br /></li>
				<li>“<a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork11/">AOP@Work: 对方面进行单元测试</a>”（Nicholas Lesiecki， developerWorks，2005 年 11 月）：用依赖项插入技术对方面进行单元测试。<br /><br /></li>
				<li>“<a href="http://www.martinfowler.com/articles/injection.html">Inversion of Control Containers and the Dependency Injection Pattern</a>” （Martin Fowler，2004 年 1 月）：对依赖项插入的经典介绍。<br /><br /></li>
				<li>
						<i>
								<a href="http://domaindrivendesign.org/book/">Domain-Driven Design: Tackling Complexity in the Heart of Software</a>
						</i> （Eric Evans；Addison-Wesley，2003 年 8 月）：理解依赖性插入技术动机的良好起点。<br /><br /></li>
				<li>
						<i>
								<a href="http://www.wiley.com/WileyCDA/WileyTitle/productCd-0764574833.html">Professional Java Development with the Spring Framework</a>
						</i> （Rod Johnson、Juergen Hoeller、Alef Arendsen、Thomas Risberg、Colin Sampaleanu；Wiley，2005 年 7 月）：学习关于用 Spring 进行依赖项插入的更多内容。<br /><br /></li>
				<li>
						<a href="http://www.springframework.org/docs/reference/beans.html">The Spring Reference Guide</a>：请参阅第 3 章获得关于 Spring 中的查询方法插入的更多内容。<br /><br /></li>
				<li>
						<a href="http://www-128.ibm.com/developerworks/cn/views/java/articles.jsp?view_by=search&amp;search_by=AOP%40Work%3A">
								<i>AOP@Work</i> 系列</a>：请阅读关于 AOP 实际应用的完整系列。<br /><br /></li>
				<li>
						<a href="http://www.ibm.com/developerworks/cn/java/">Java 技术专区</a>：数百篇关于 Java 编程各方面的文章。</li>
		</ul>
		<br />
		<b>获得产品和技术</b>
		<br />
		<ul>
				<li>
						<a href="http://www.springframework.org/"> Spring 主页</a>：请下载 Spring 框架。<br /><br /></li>
				<li>
						<a href="http://www.eclipse.org/aspectj"> AspectJ 主页</a>：请下载最新的 AspectJ 编译器和工具。<br /><br /></li>
				<li>
						<a href="http://www.eclipse.org/ajdt">AJDT 主页</a>：请下载 AspectJ Development Tools for Eclipse。<br /><br /></li>
		</ul>
		<br />
		<b>讨论</b>
		<br />
		<ul>
				<li>
						<a href="http://www.ibm.com/developerworks/blogs/">developerWorks
blogs</a>：加入 developerWorks 社区。<br /><br /></li>
		</ul>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/java/j-aopwork13.html#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="author">
						<span class="atitle">关于作者</span>
				</a>
		</p>
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td colspan="3">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="5" width="100%" />
								</td>
						</tr>
						<tr align="left" valign="top">
								<td>
										<p>
												<img alt="" src="http://www-128.ibm.com/developerworks/i/p-acolyer.jpg" align="left" height="80" width="64" />
										</p>
								</td>
								<td>
										<img alt="" src="http://www.ibm.com/i/c.gif" height="5" width="4" />
								</td>
								<td width="100%">
										<p>Adrian
Colyer 是 Eclipse.org 的 AspectJ 项目的负责人，也是 AJDT 项目的创始人，AJDT 项目在 Eclipse
中为 AspectJ 提供 IDE 支持。在 2005 年 10 月接受 Interface21 的首席科学家一职之前，Adrian
在位于英国 Hursley 的 IBM 软件实验室领导面向方面的软件开发团队。他是 Eclipse AspectJ 图书
Aspect-Oriented Programming with AspectJ and the Eclipse AspectJ
Development Tools 的合作者，还经常针对面向方面编程主题进行演讲。
</p>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/Vencent/aggbug/35989.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-03-18 21:32 <a href="http://www.blogjava.net/Vencent/articles/35989.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JUnit 4 抢先看:即将发布的版本承诺在测试方面有新的进展</title><link>http://www.blogjava.net/Vencent/articles/35979.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Sat, 18 Mar 2006 12:54:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/35979.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/35979.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/35979.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/35979.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/35979.html</trackback:ping><description><![CDATA[
		<p>级别: 中级</p>
		<p>
				<a href="http://www-128.ibm.com/developerworks/cn/java/j-junit4.html#author">Elliotte Harold</a>, 副教授, Polytechnic University<br /></p>
		<p>2005 年  10 月  13 日</p>
		<blockquote>JUnit 是 Java™ 语言<i>事实上的</i>
标准单元测试库。JUnit 4 是该库三年以来最具里程碑意义的一次发布。它的新特性主要是通过采用 Java 5
中的标记（annotation）而不是利用子类、反射或命名机制来识别测试，从而简化测试。在本文中，执着的代码测试人员 Elliotte
Harold 以 JUnit 4 为例，详细介绍了如何在自己的工作中使用这个新框架。注意，本文假设读者具有 JUnit 的使用经验。</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>JUnit 由 Kent
Beck 和 Erich Gamma 开发，几乎毫无疑问是迄今所开发的最重要的第三方 Java 库。正如 Martin Fowler
所说，“在软件开发领域，从来就没有如此少的代码起到了如此重要的作用”。JUnit 引导并促进了测试的盛行。由于 JUnit，Java
代码变得更健壮，更可靠，bug 也比以前更少。JUnit（它本身的灵感来自 Smalltalk 的 SUnit）衍生了许多 xUnit
工具，将单元测试的优势应用于各种语言。nUnit (.NET)、pyUnit (Python)、CppUnit (C++)、dUnit
(Delphi) 以及其他工具，影响了各种平台和语言上的程序员的测试工作。</p>
		<p>然而，JUnit
仅仅是一个工具而已。真正的优势来自于 JUnit 所采用的思想和技术，而不是框架本身。单元测试、测试先行的编程和测试驱动的开发并非都要在
JUnit 中实现，任何比较 GUI 的编程都必须用 Swing 来完成。JUnit
本身的最后一次更新差不多是三年以前了。尽管它被证明比大多数框架更健壮、更持久，但是也发现了 bug；而更重要的是，Java
不断在发展。Java 语言现在支持泛型、枚举、可变长度参数列表和注释，这些特性为可重用的框架设计带来了新的可能。</p>
		<p>JUnit
的停滞不前并没有被那些想要废弃它的程序员所打败。挑战者包括 Bill Venners 的 Artima SuiteRunner 以及
Cedric Beust 的 TestNG 等。这些库有一些可圈可点的特性，但是都没有达到 JUnit
的知名度和市场占有份额。它们都没有在诸如 Ant、Maven 或 Eclipse 之类的产品中具有广泛的开箱即用支持。所以 Beck 和
Gamma 着手开发了一个新版本的 JUnit，它利用 Java 5 的新特性（尤其是注释）的优势，使得单元测试比起用最初的 JUnit
来说更加简单。用 Beck 的话来说，“JUnit 4 的主题是通过进一步简化 JUnit，鼓励更多的开发人员编写更多的测试。”JUnit 4
尽管保持了与现有 JUnit 3.8 测试套件的向后兼容，但是它仍然承诺是自 JUnit 1.0 以来 Java 单元测试方面最重大的改进。</p>
		<p>
				<b>注意：</b>该框架的改进是相当前沿的。尽管 JUnit 4 的大轮廓很清晰，但是其细节仍然可以改变。这意味着本文是对 JUnit 4 抢先看，而不是它的最终效果。</p>
		<p>
				<a name="N10084">
						<span class="atitle">测试方法</span>
				</a>
		</p>
		<p>以前所有版本的 JUnit 都使用命名约定和反射来定位测试。例如，下面的代码测试 1+1 等于 2：</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />import junit.framework.TestCase;<br /><br />public class AdditionTest extends TestCase {<br /><br />  private int x = 1;<br />  private int y = 1;<br /><br />  public void testAddition() {<br />    int z = x + y;<br />    assertEquals(2, z);<br />  }<br /><br />}</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>而在 JUnit 4 中，测试是由 <code>@Test</code> 注释来识别的，如下所示：</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">import org.junit.Test;<br />import junit.framework.TestCase;<br /><br />public class AdditionTest extends TestCase {<br /><br />  private int x = 1;<br />  private int y = 1;<br /><br />  @Test public void testAddition() {<br />    int z = x + y;<br />    assertEquals(2, z);<br />  }<br /><br />}</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>使用注释的优点是不再需要将所有的方法命名为 <code>testFoo()</code>、<code>testBar()</code>，等等。例如，下面的方法也可以工作：</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">import org.junit.Test;<br />import junit.framework.TestCase;<br /><br />public class AdditionTest extends TestCase {<br /><br />  private int x = 1;<br />  private int y = 1;<br /><br />  @Test public void additionTest() {<br />    int z = x + y;<br />    assertEquals(2, z);<br />  }<br /><br />}</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>下面这个方法也同样能够工作：</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">import org.junit.Test;<br />import junit.framework.TestCase;<br /><br />public class AdditionTest extends TestCase {<br /><br />  private int x = 1;<br />  private int y = 1;<br /><br />  @Test public void addition() {<br />    int z = x + y;<br />    assertEquals(2, z);<br />  }<br /><br />}</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>这允许您遵循最适合您的应用程序的命名约定。例如，我介绍的一些例子采用的约定是，测试类对其测试方法使用与被测试的类相同的名称。例如，<code>List.contains()</code> 由 <code>ListTest.contains()</code> 测试，<code>List.add()</code> 由 <code>ListTest.addAll()</code> 测试，等等。</p>
		<p>
				<code>TestCase</code> 类仍然可以工作，但是您不再需要扩展它了。只要您用 <code>@Test</code> 来注释测试方法，就可以将测试方法放到任何类中。但是您需要导入 <code>junit.Assert</code> 类以访问各种 assert 方法，如下所示：</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">import org.junit.Assert;<br /><br />public class AdditionTest {<br /><br />  private int x = 1;<br />  private int y = 1;<br /><br />  @Test public void addition() {<br />    int z = x + y;<br />    Assert.assertEquals(2, z);<br />  }<br /><br />}</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
您也可以使用 JDK 5 中新特性（static import），使得与以前版本一样简单：</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />import static org.junit.Assert.assertEquals;<br /><br />public class AdditionTest {<br /><br />  private int x = 1;<br />  private int y = 1;<br /><br />  @Test public void addition() {<br />    int z = x + y;<br />    assertEquals(2, z);<br />  }<br /><br />}</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
这种方法使得测试受保护的方法非常容易，因为测试案例类现在可以扩展包含受保护方法的类了。 
</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/java/j-junit4.html#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N100E2">
						<span class="atitle">SetUp 和 TearDown</span>
				</a>
		</p>
		<p>
JUnit 3 测试运行程序（test runner）会在运行每个测试之前自动调用 <code>setUp()</code> 方法。该方法一般会初始化字段，打开日志记录，重置环境变量，等等。例如，下面是摘自 XOM 的 <code>XSLTransformTest</code> 中的 <code>setUp()</code> 方法：</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">protected void setUp() {<br /><br />    System.setErr(new PrintStream(new ByteArrayOutputStream()));<br /><br />    inputDir = new File("data");<br />    inputDir = new File(inputDir, "xslt");<br />    inputDir = new File(inputDir, "input");<br /><br />}</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在 JUnit 4 中，您仍然可以在每个测试方法运行之前初始化字段和配置环境。然而，完成这些操作的方法不再需要叫做 <code>setUp()</code>，只要用 <code>@Before</code> 注释来指示即可，如下所示：
</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />@Before protected void initialize() {<br /><br />    System.setErr(new PrintStream(new ByteArrayOutputStream()));<br /><br />    inputDir = new File("data");<br />    inputDir = new File(inputDir, "xslt");<br />    inputDir = new File(inputDir, "input");<br /><br />}</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
甚至可以用 <code>@Before</code> 来注释多个方法，这些方法都在每个测试之前运行：
</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />@Before protected void findTestDataDirectory() {<br />    inputDir = new File("data");<br />    inputDir = new File(inputDir, "xslt");<br />    inputDir = new File(inputDir, "input");<br />}<br /><br /> @Before protected void redirectStderr() {<br />    System.setErr(new PrintStream(new ByteArrayOutputStream()));<br />}</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>清除方法与此类似。在 JUnit 3 中，您使用 <code>tearDown()</code> 方法，该方法类似于我在 XOM 中为消耗大量内存的测试所使用的方法：</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">protected void tearDown() {<br />  doc = null;<br />  System.gc();   <br />} </code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
对于 JUnit 4，我可以给它取一个更自然的名称，并用 <code>@After</code> 注释它：
</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />@After protected void disposeDocument() {<br />  doc = null;<br />  System.gc();   <br />} </code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>与 <code>@Before</code> 一样，也可以用 <code>@After</code> 来注释多个清除方法，这些方法都在每个测试之后运行。</p>
		<p>最后，您不再需要在超类中显式调用初始化和清除方法，只要它们不被覆盖即可，测试运行程序将根据需要自动为您调用这些方法。超类中的 <code>@Before</code> 方法在子类中的 <code>@Before</code> 方法之前被调用（这反映了构造函数调用的顺序）。<code>@After</code> 方法以反方向运行：子类中的方法在超类中的方法之前被调用。否则，多个 <code>@Before</code> 或 <code>@After</code> 方法的相对顺序就得不到保证。</p>
		<p>
				<a name="N1014D">
						<span class="smalltitle">套件范围的初始化</span>
				</a>
		</p>
		<p>JUnit 4 也引入了一个 JUnit 3 中没有的新特性：类范围的 <code>setUp()</code> 和 <code>tearDown()</code> 方法。任何用 <code>@BeforeClass</code> 注释的方法都将在该类中的测试方法运行之前刚好运行一次，而任何用 <code>@AfterClass</code> 注释的方法都将在该类中的所有测试都运行之后刚好运行一次。</p>
		<p>例
如，假设类中的每个测试都使用一个数据库连接、一个网络连接、一个非常大的数据结构，或者还有一些对于初始化和事情安排来说比较昂贵的其他资源。不要在每
个测试之前都重新创建它，您可以创建它一次，并还原它一次。该方法将使得有些测试案例运行起来快得多。例如，当我测试调用第三方库的代码中的错误处理时，
我通常喜欢在测试开始之前重定向 <code>System.err</code>，以便输出不被预期的错误消息打乱。然后我在测试结束后还原它，如下所示：</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />// This class tests a lot of error conditions, which<br />// Xalan annoyingly logs to System.err. This hides System.err <br />// before each test and restores it after each test.<br />private PrintStream systemErr;<br /><br />@BeforeClass protected void redirectStderr() {<br />    systemErr = System.err; // Hold on to the original value<br />    System.setErr(new PrintStream(new ByteArrayOutputStream()));<br />}<br /><br />@AfterClass protected void tearDown() {<br />    // restore the original value<br />    System.setErr(systemErr);<br />}</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>没有必要在每个测试之前和之后都这样做。但是一定要小心对待这个特性。它有可能会违反测试的独立性，并引入非预期的混乱。如果一个测试在某种程度上改变了 <code>@BeforeClass</code>
所初始化的一个对象，那么它有可能会影响其他测试的结果。它有可能在测试套件中引入顺序依赖，并隐藏
bug。与任何优化一样，只在剖析和基准测试证明您具有实际的问题之后才实现这一点。这就是说，我看到了不止一个测试套件运行时间如此之长，以至不能像它
所需要的那样经常运行，尤其是那些需要建立很多网络和数据库连接的测试。（例如，LimeWire
测试套件运行时间超过两小时。）要加快这些测试套件，以便程序员可以更加经常地运行它们，您可以做的就是减少 bug。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/java/j-junit4.html#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10178">
						<span class="atitle">测试异常</span>
				</a>
		</p>
		<p>异常测试是 JUnit 4 中的最大改进。旧式的异常测试是在抛出异常的代码中放入 <code>try</code> 块，然后在 <code>try</code> 块的末尾加入一个 <code>fail()</code> 语句。例如，该方法测试被零除抛出一个 <code>ArithmeticException</code>：</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />public void testDivisionByZero() {<br /><br />    try {<br />        int n = 2 / 0;<br />        fail("Divided by zero!");<br />    }<br />    catch (ArithmeticException success) {<br />        assertNotNull(success.getMessage());<br />    }<br /><br />}</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
该方法不仅难看，而且试图挑战代码覆盖工具，因为不管测试是通过还是失败，总有一些代码不被执行。在 JUnit 4 中，您现在可以编写抛出异常的代码，并使用注释来声明该异常是预期的：
</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />@Test(expected=ArithmeticException.class) <br />  public void divideByZero() {<br />    int n = 2 / 0;<br />}</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
如果该异常没有抛出（或者抛出了一个不同的异常），那么测试就将失败。但是如果您想要测试异常的详细消息或其他属性，则仍然需要使用旧式的 <code>try-catch</code> 样式。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/java/j-junit4.html#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N101A3">
						<span class="atitle">被忽略的测试</span>
				</a>
		</p>
		<p>也
许您有一个测试运行的时间非常地长。不是说这个测试应该运行得更快，而是说它所做的工作从根本上比较复杂或缓慢。需要访问远程网络服务器的测试通常都属于
这一类。如果您不在做可能会中断该类测试的事情，那么您可能想要跳过运行时间长的测试方法，以缩短编译-测试-调试周期。或者也许是一个因为超出您的控制
范围的原因而失败的测试。例如，W3C XInclude 测试套件测试 Java 还不支持的一些 Unicode
编码的自动识别。不必老是被迫盯住那些红色波浪线，这类测试可以被注释为 <code>@Ignore</code>，如下所示：</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />// Java doesn't yet support <br />// the UTF-32BE and UTF32LE encodings<br />    @Ignore public void testUTF32BE() <br />      throws ParsingException, IOException, XIncludeException {<br /><br />        File input = new File(<br />          "data/xinclude/input/UTF32BE.xml"<br />        );<br />        Document doc = builder.build(input);<br />        Document result = XIncluder.resolve(doc);<br />        Document expectedResult = builder.build(<br />          new File(outputDir, "UTF32BE.xml")<br />        );<br />        assertEquals(expectedResult, result);<br /><br />    }</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>测试运行程序将不运行这些测试，但是它会指出这些测试被跳过了。例如，当使用文本界面时，会输出一个“I”（代表 ignore），而不是为通过的测试输出所经历的时间，也不是为失败的测试输出“E”：</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />$ java -classpath .:junit.jar org.junit.runner.JUnitCore <br />  nu.xom.tests.XIncludeTest<br />JUnit version 4.0rc1<br />.....I..<br />Time: 1.149<br /><br />OK (7 tests)</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
但是一定要小心。最初编写这些测试可能有一定的原因。如果永远忽略这些测试，那么它们期望测试的代码可能会中断，并且这样的中断可能不能被检测到。忽略测试只是一个权宜之计，不是任何问题的真正解决方案。
</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/java/j-junit4.html#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N101BE">
						<span class="atitle">时间测试</span>
				</a>
		</p>
		<p>测
试性能是单元测试最为痛苦的方面之一。JUnit 4
没有完全解决这个问题，但是它对这个问题有所帮助。测试可以用一个超时参数来注释。如果测试运行的时间超过指定的毫秒数，则测试失败。例如，如果测试花费
超过半秒时间去查找以前设置的一个文档中的所有元素，那么该测试失败：</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />@Test(timeout=500) public void retrieveAllElementsInDocument() {<br />    doc.query("//*");<br />} </code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>除
了简单的基准测试之外，时间测试也对网络测试很有用。在一个测试试图连接到的远程主机或数据库宕机或变慢时，您可以忽略该测试，以便不阻塞所有其他的测
试。好的测试套件执行得足够快，以至程序员可以在每个测试发生重大变化之后运行这些测试，有可能一天运行几十次。设置一个超时使得这一点更加可行。例如，
如果解析 http://www.ibiblio.org/xml 花费了超过 2 秒，那么下面的测试就会超时：</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />@Test(timeout=2000) <br />  public void remoteBaseRelativeResolutionWithDirectory()<br />   throws IOException, ParsingException {<br />      builder.build("http://www.ibiblio.org/xml");<br />  } </code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/java/j-junit4.html#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N101D2">
						<span class="atitle">新的断言</span>
				</a>
		</p>
		<p>JUnit 4 为比较数组添加了两个 <code>assert()</code> 方法：</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />public static void assertEquals(Object[] expected, Object[] actual)<br />public static void assertEquals(String message, Object[] expected, <br />Object[] actual)<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>这两个方法以最直接的方式比较数组：如果数组长度相同，且每个对应的元素相同，则两个数组相等，否则不相等。数组为空的情况也作了考虑。 
</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/java/j-junit4.html#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N101E6">
						<span class="atitle">需要补充的地方</span>
				</a>
		</p>
		<p>JUnit 4 基本上是一个新框架，而不是旧框架的升级版本。JUnit 3 开发人员可能会找到一些原来没有的特性。 
</p>
		<p>
最明显的删节就是 GUI
测试运行程序。如果您想在测试通过时看到赏心悦目的绿色波浪线，或者在测试失败时看到令人焦虑的红色波浪线，那么您需要一个具有集成 JUnit
支持的 IDE，比如 Eclipse。不管是 Swing 还是 AWT 测试运行程序都不会被升级或捆绑到 JUnit 4 中。
</p>
		<p>
下一个惊喜是，失败（assert 方法检测到的预期的错误）与错误（异常指出的非预期的错误）之间不再有任何差别。尽管 JUnit 3 测试运行程序仍然可以区别这些情况，而 JUnit 4 运行程序将不再能够区分。  
</p>
		<p>
最后，JUnit 4 没有 <code>suite()</code> 方法，这些方法用于从多个测试类构建一个测试套件。相反，可变长参数列表用于允许将不确定数量的测试传递给测试运行程序。 
</p>
		<p>
我对消除了 GUI 测试运行程序并不感到太高兴，但是其他更改似乎有可能增加 JUnit 的简单性。只要考虑有多少文档和 FAQ 当前专门用于解释这几点，然后考虑对于 JUnit 4，您不再需要解释这几点了。 
</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/java/j-junit4.html#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N101FF">
						<span class="atitle">编译和运行 JUnit 4</span>
				</a>
		</p>
		<p>
当前，还没有 JUnit 4 的库版本。如果您想要体验新的版本，那么您需要从 SourceForge 上的 CVS 知识库获取它。分支（branch）是“Version4”（参见 <a href="http://www-128.ibm.com/developerworks/cn/java/j-junit4.html#resources">参考资料</a>）。注意，很多的文档没有升级，仍然是指以旧式的 3.x 方式做事。Java 5 对于编译 JUnit 4 是必需的，因为 JUnit 4 大量用到注释、泛型以及 Java 5 语言级的其他特性。 
</p>
		<p>
自 JUnit 3 以来，从命令行运行测试的语法发生了一点变化。您现在使用 <code>org.junit.runner.JUnitCore</code> 类：</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />$ java -classpath .:junit.jar org.junit.runner.JUnitCore <br />  TestA TestB TestC...<br />JUnit version 4.0rc1<br /><br />Time: 0.003<br /><br />OK (0 tests)</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N10217">
						<span class="smalltitle">兼容性</span>
				</a>
		</p>
		<p>Beck
和 Gamma 努力维持向前和向后兼容。JUnit 4 测试运行程序可以运行 JUnit 3
测试，不用做任何更改。只要将您想要运行的每个测试的全限定类名传递给测试运行程序，就像针对 JUnit 4
测试一样。运行程序足够智能，可以分辨出哪个测试类依赖于哪个版本的 JUnit，并适当地调用它。
</p>
		<p>向后兼容要困难一些，但是也可以在 JUnit 3 测试运行程序中运行 JUnit 4 测试。这一点很重要，所以诸如
Eclipse 之类具有集成 JUnit 支持的工具可以处理 JUnit 4，而不需要更新。为了使 JUnit 4 测试可以运行在 JUnit
3 环境中，可以将它们包装在 <code>JUnit4TestAdapter</code> 中。将下面的方法添加到您的 JUnit 4 测试类中应该就足够了：
</p>
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />public static junit.framework.Test suite() {<br />  return new JUnit4TestAdapter(AssertionTest.class);    <br />}</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>但是由于 Java 比较多变，所以 JUnit 4 一点都不向后兼容。JUnit 4 完全依赖于 Java 5 特性。对于 Java 1.4 或更早版本，它将不会编译或运行。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/java/j-junit4.html#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1022E">
						<span class="atitle">前景</span>
				</a>
		</p>
		<p>JUnit
4 远没有结束。很多重要的方面没有提及，包括大部分的文档。我不推荐现在就将您的测试套件转换成注释和 JUnit
4。即使如此，开发仍在快速进行，并且 JUnit 4 前景非常看好。尽管 Java 2 程序员在可预见的未来仍然需要使用 JUnit
3.8，但是那些已经转移到 Java 5 的程序员则应该很快考虑使他们的测试套件适合于这个新的框架，以便匹配。
</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/java/j-junit4.html#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="resources">
						<span class="atitle">参考资料 </span>
				</a>
		</p>
		<b>学习</b>
		<br />
		<ul>
				<li>您可以参阅本文在 developerWorks 全球站点上的 <a href="http://www.ibm.com/developerworks/java/library/j-junit4.html" target="_blank">英文原文</a>。<br /><br /></li>
				<li>
						<a href="http://www.pragmaticprogrammer.com/starter_kit/utj/index.html">
								<i>Pragmatic Unit Testing in Java with JUnit</i>
						</a>（Andy Hunt 和 Dave Thomas，Pragmatic Programmers，2003 年）：非常好地介绍了单元测试。<br /><br /></li>
				<li>
						<a href="http://www.amazon.com/exec/obidos/ISBN=1932394230/ref=nosim/cafeaulaitA/">
								<i>JUnit Recipes: Practical Methods for Programmer Testing</i>
						</a>（J. B. Rainsberger，Manning，2004 年）：一本最广泛地引用和参考了 JUnit 的书籍。<br /><br /></li>
				<li>
						<a href="http://www.beust.com/testng/">TestNG</a>：Cedric Beust 的框架，基于现在用于 JUnit 4 中的测试样式，最先使用了注释。<br /><br /></li>
				<li>“<a href="http://www-128.ibm.com/developerworks/cn/java/j-testng">TestNG 使 Java 单元测试轻而易举</a>”（Filippo Diotalevi，developerWorks，2005 年 1 月）：介绍了 TestNG。<br /><br /></li>
				<li>“<a href="http://www-128.ibm.com/developerworks/cn/java/j-ant/">利用 Ant 和 JUnit 进行增量开发</a>”（Malcolm Davis，developerWorks，2000 年 11 月）：探讨了单元测试的优势，具体使用了 Ant 和 JUnit，并有示例代码。<br /><br /></li>
				<li>“<a href="http://www-128.ibm.com/developerworks/cn/java/j-xp042203/">揭开极端编程的神秘面纱: 测试驱动的编程</a>”（Roy Miller，developerWorks，2003 年 4 月）：找出测试驱动的编程可以如何提高程序员的生产效率和质量，并学习编写测试的机制。<br /><br /></li>
				<li>“<a href="http://www.ibm.com/developerworks/edu/i-dw-wes-junit-i.html">Keeping critters out of your code</a>”（David Carew 等人，developerWorks，2003 年 6 月）：学习可以如何将 JUnit 与 WebSphere Application Developer 结合起来使用。<br /><br /></li>
				<li>“<a href="http://www-128.ibm.com/developerworks/cn/java/j-cobertura/">用 Cobertura 测量测试覆盖率</a>”（Elliotte Rusty Harold，developerWorks，2005 年 5 月）：学习用这个方便的开放源码工具来识别未测试的代码和查找 bug。<br /><br /></li>
		</ul>
		<br />
		<b>获得产品和技术</b>
		<br />
		<ul>
				<li>
						<a href="http://cvs.sourceforge.net/viewcvs.py/junit/junit/?only_with_tag=Version4">JUnit 4</a>：下载最新版本的 JUnit，即 SourceForge CVS 知识库。确保使用分支“Version4”。<br /><br /></li>
		</ul>
		<br />
		<b>讨论</b>
		<br />
		<ul>
				<li>
						<a href="http://www.ibm.com/developerworks/blogs/">developerWorks blogs</a>：加入 developerWorks 社区。</li>
		</ul>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www-128.ibm.com/developerworks/cn/java/j-junit4.html#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="author">
						<span class="atitle">关于作者</span>
				</a>
		</p>
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td colspan="3">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="5" width="100%" />
								</td>
						</tr>
						<tr align="left" valign="top">
								<td>
										<br />
								</td>
								<td>
										<img alt="" src="http://www.ibm.com/i/c.gif" height="5" width="4" />
								</td>
								<td width="100%">
										<p>Elliotte
Rusty Harold 出生在新奥尔良，现在，他还定期回老家喝一碗美味的秋葵汤。不过目前他与妻子 Beth 定居在纽约临近布鲁克林的
Prospect Heights，与他们住在一起的还有猫咪 Charm（取自夸克）和 Marjorie（按照他岳母的名字）。他是
Polytechnic 大学计算机科学的副教授，讲授 Java 技术和面向对象编程。他的 <a href="http://www.cafeaulait.org/">Cafe au Lait</a> 网站是 Internet 上最受欢迎的独立 Java 站点之一，姊妹站点 <a href="http://www.cafeconleche.org/">Cafe con Leche</a> 是最受欢迎的 XML 站点之一。他的著作包括 <a href="http://www.cafeconleche.org/books/effectivexml/"><i>Effective XML</i></a>、<a href="http://www.cafeconleche.org/books/xmljava/"><i>Processing XML with Java</i></a>、<a href="http://www.cafeaulait.org/books/jnp3/"><i>Java Network Programming</i></a> 和 <a href="http://www.cafeconleche.org/books/bible3/"><i>The XML 1.1 Bible</i></a>。他目前在研究处理 XML 的 <a href="http://www.xom.nu/">XOM</a> API、<a href="http://jaxen.codehaus.org/">Jaxen</a> XPath 引擎和 <a href="http://jester.sourceforge.net/">Jester</a> 测试覆盖工具。
</p>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/Vencent/aggbug/35979.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-03-18 20:54 <a href="http://www.blogjava.net/Vencent/articles/35979.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用面向 Aspect 的编程改进模块性</title><link>http://www.blogjava.net/Vencent/articles/35962.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Sat, 18 Mar 2006 11:01:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/35962.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/35962.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/35962.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/35962.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/35962.html</trackback:ping><description><![CDATA[
		<p>面向 Aspect 的编程（AOP）是一种新的编程技术，它允许程序员对横切关系（crosscutting concerns）（跨越典型职责
界限的行为，例如日志记录）进行模块化。AOP 引进了 Aspect，它将影响多个类的行为封装到一个可重用模块中。使用 Xerox PARC 的
 AspectJ 最新发行版，Java 开发人员现在可以利用 AOP 能够提供的模块化。本文介绍了 AspectJ 并说明了使用它所带来的设计益
处。请通过点击本文顶部或底部的<b>讨论</b>，在论坛中与作者以及其他读者分享您的想法。<br />人们认识到，传统的程序经常表现出一些不能自然地
适合单个程序模块或者几个紧密相关的程序模块的行为，因此面向 Aspect 的编程（AOP）应运而生。Aspect 的先驱将这种行为称为横切，因为
它跨越了给定编程模型中的典型职责界限。例如，在面向对象的编程中，模块性的天然单位是类，横切关系是一种跨越多个类的关系。典型横切关系包括日志记录、
对上下文敏感的错误处理、性能优化以及设计模式。 </p>
		<p>如果使用过用于横切关系的代码，您就会知道缺乏模块性所带来的问题。因为横切行为的实现是分散的，开发人员发现这种行为难以作逻辑思维、实现和更
改。例如，用于日志记录的代码和主要用于其它职责的代码缠绕在一起。根据所解决的问题的复杂程度和作用域的不同，所引起的混乱可大可小。更改一个应用程序
的日志记录策略可能涉及数百次编辑 — 即使可行，这也是个令人头疼的任务。与之形成对比的是面向 Aspect 的编程的基本案例之一。在标题为“<a class="contentlink" href="http://www-900.ibm.com/developerWorks/cn/java/j-aspectj/#resources" target="_blank"><font color="#4455aa">Aspect-Oriented Programming</font></a>”的文章中，一些 AspectJ 作者谈到了性能优化，传统技术可以将程序从 768 行扩充到 35,213 行。用面向 Aspect 技术重写后，代码缩回到 1,039 行，并保持了大多数性能优点。 </p>
		<p>AOP 通过促进另一种模块性补充了面向对象的编程，该模块性将横切关系广泛分布的实现聚拢到一个单元。这种单元称为 Aspect，这就是名称面
向 Aspect 的编程的来历。通过划分 Aspect 代码，横切关系变得容易处理。可以在编译时更改、插入或除去系统的 Aspect，甚至重用系
统的 Aspect。</p>
		<p>通过示例学习<br />为了获得对面向 Aspect 的编程更好的感性认识，让我们看一看来自 Xerox PARC 的面向 Aspect 的
 Java 编程语言扩展 — AspectJ。在示例中，将使用 AspectJ 来做日志记录。示例是从开放源码 Cactus 框架中抽取出来的，
它简化了服务器端 Java 组件的测试。框架的贡献者决定通过对框架内的所有方法调用进行跟踪来辅助调试。Cactus 的 1.2 版本没有使用
 AspectJ 编写，典型方法如下列清单 1 中所示：</p>
		<p>
				<b>清单 1. 日志调用手工插入到每个方法中</b> <br />public void doGet(JspImplicitObjects theObjects) throws ServletException<br />{<br />  logger.entry("doGet(...)");</p>
		<p>  JspTestController controller = new JspTestController();<br />  controller.handleRequest(theObjects);</p>
		<p>  logger.exit("doGet");<br />}</p>
		<p> </p>
		<p>作为该项目代码约定的一部分，要求每个开发人员将这几行代码插入到他或她所编写的任何方法中。还要求开发人员记录每个方法的参数。如果没有对部分项
目监督进行详尽的代码复查，就很难履行这种约定。在 1.2 版本中，大约有 80 个单独的记录日志调用分布在 15 个类中。在框架的 1.3 版本
中，用单一 Aspect 代替了这 80 多个调用，该 Aspect 自动记录参数和返回值以及方法入口和出口。清单 2 包含了这个
 Aspect 的一个作了很大简化的版本（例如，我省略了参数和返回值日志记录）。 </p>
		<p>
				<b>清单 2. 自动应用于每个方法的记录日志调用</b> <br />public aspect AutoLog{<br />  <br />  pointcut publicMethods() : execution(public * org.apache.cactus..*(..));</p>
		<p>  pointcut logObjectCalls() :<br />    execution(* Logger.*(..));<br />    <br />  pointcut loggableCalls() : publicMethods() &amp;&amp; ! logObjectCalls();<br />    <br />  before() : loggableCalls(){<br />    Logger.entry(thisJoinPoint.getSignature().toString());<br />  }<br />    <br />  after() : loggableCalls(){<br />    Logger.exit(thisJoinPoint.getSignature().toString());<br />  }<br />}</p>
		<p>
				<br /> </p>
		<p>让我们分解示例并研究 Aspect 做了什么。您将注意到的第一件事是 Aspect 的声明。Aspect 声明类似于类声明，它们都定义 Java 类型，就象类所做的那样。除了其声明以外，该 Aspect 还包含 Pointcut 和 Advice。 </p>
		<p>Pointcut 和 join point<br />要理解 Pointcut，必需知道 join point 是什么。join point 
表示在程序执行中明确定义的点。AspectJ 中典型的 join point 包括方法调用、对类成员的访问以及异常处理程序块的执行。
join point 可以包含其它 join point。例如，一个方法调用可能在它返回之前引起其它方法调用。那么，Pointcut 就是一种语
言构造，这种构造根据已定义的标准挑选一组 join point。示例中的第一个 Pointcut 称为 publicMethods，选择
 org.apache.cactus 包中的所有公用（public）方法的执行。execution 是一个原始的 Pointcut（就象
 int 是一种原始的 Java 类型）。它选择与其括号中定义的方法说明匹配的任何方法的执行。方法说明允许包含通配符；示例中的一个方法说明包含了
几个通配符。第二个名为 logObjectCalls 的 Pointcut 选择了 Logger 类中的所有方法的执行。第三个
 Pointcut loggableCalls，通过使用 &amp;&amp; ! 合并了前两个 Pointcut，这意味着它选择了除
 Logger 类中的公用方法以外，org.apache.cactus 中所有的公用方法。（记录 log 方法将导致无限递归。） </p>
		<p>Advice<br />既然 Aspect 已经定义了它应该记录的点，它使用 Advice 来完成实际的日志记录。Advice 是在
 join point 之前、之后或周围执行的代码。相对于 Pointcut 来定义 Advice，说类似于“在想要记录的每个方法调用之后运行这
些代码”这样的话。因此 Advice 如下：</p>
		<p>
				<br />before() : loggableCalls(){<br />    Logger.entry(thisJoinPoint.getSignature().toString());<br />}</p>
		<p> </p>
		<p>Advice 使用 Logger 类，其入口和出口方法类似于下列代码：</p>
		<p>
				<br />public static void entry(String message){<br />   System.out.println("entering method " + message);<br />}</p>
		<p> </p>
		<p>在示例中，传递到记录器的 String 是从 thisJoinPoint 派生的，这是一个特殊的反射对象，它允许访问
 join point 执行所处的运行时上下文。在 Cactus 实际使用的 Aspect 中，Advice 使用这种对象来检索传递到每个记录的
方法调用中的方法参数。当日志记录 Aspect 应用于代码时，方法调用的结果如下： </p>
		<p>
				<b>清单 3. AutoLog Aspect 的输出</b> <br />entering method: void test.Logging.main(String[])<br />entering method: void test.Logging.foo()<br />exiting method: void test.Logging.foo()<br />exiting method: void test.Logging.main(String[])</p>
		<p> </p>
		<p>
				<br />Around Advice</p>
		<p>Cactus 示例定义了 before() 和 after() Advice。第三种 Advice 名称是 around()，给予
 Aspect 的编写者一个机会来影响是否以及何时使用特殊 proceed() 语法执行 join point。下列（有点一般）Advice 是
否执行 Hello 类中的 say 方法是随机的：</p>
		<p>
				<br />void around(): call(public void Hello.say()){<br />  if(Math.random() &gt; .5){<br />      proceed();//go ahead with the method call<br />  }<br />  else{<br />      System.out.println("Fate is not on your side.");<br />  }<br />}</p>
		<p>
				<br /> </p>
		<p>使用 AspectJ 进行开发<br />既然您已经对 Aspect 代码的形式特征有了更好的感性认识，让我们暂时把注意力转移到编写 Aspect 的工作上来吧。也就是说，让我们回答这个问题：“如何使上述代码起作用？” </p>
		<p>要让 Aspect 影响正常的基于类的代码，必须将 Aspect 加入到它们要修改的代码中去。要使用 AspectJ 完成这个操作，必须使
用 ajc 编译器来编译类和 Aspect 代码。ajc 既可以作为编译器也可以作为预编译器操作，生成有效的 .class 或 .java 文
件，可以在任何标准 Java 环境（添加一个小的运行时 JAR）中编译和运行这些文件。 </p>
		<p>要使用 AspectJ 进行编译，将需要显式地指定希望在给定编译中包含的源文件（Aspect 和类）— ajc 不象 javac 那样简单
地为相关导入模块搜索类路径。之所以这样做，是因为标准 Java 应用程序中的每个类都是相对分离的组件。为了正确操作，一个类只要求其直接引用的类的
存在。Aspect 表示跨越多个类的行为的聚集。因此，需要将 AOP 程序作为一个单元来编译，而不能每次编译一个类。 </p>
		<p>通过指定包含在给定编译中的文件，您还可以在编译时插入或抽出系统的各种 Aspect。例如，通过在编译中包含或排除先前描述的日志记录 Aspect，应用程序构建器可以在 Cactus 框架中添加或除去方法跟踪。 </p>
		<p>
				<b>AspectJ 是开放源码的</b>
		</p>
		<p>Xerox 使用“Mozilla 公共许可证”（Mozilla Public License）发布了 AspectJ。对于开放源码爱好者来
说，这是个好消息。对于近期将要采用 AspectJ 的人来说，这也是个好消息：产品免费，如果您觉得发现了严重错误，您有权检查源代码。开放的代码库
还意味着在上市之前，AspectJ 的源代码将得到有效的社会评审。 <br /> <br />AspectJ 当前版本的一个重要限制是其编译器只能将
 Aspect 加入到它拥有源代码的代码中。也就是说，不能使用 ajc 将 Advice 添加到预编译类中。AspectJ 团队认为这个限制只是
暂时的，AspectJ 网站承诺未来的版本（正式版 2.0）将允许字节码的修改。 </p>
		<p>工具支持<br />AspectJ 发行版包含了几种开发工具。这预示着 AspectJ 将有美好的前景，因为它表明了那部分作者的一个重要承诺，
使 AspectJ 对于开发人员将是友好的。对于面向 Aspect 的系统工具支持尤其重要，因为程序模块可能受到它们所未知的模块所影响。 </p>
		<p>随 AspectJ 一起发布的一个最重要的工具是图形结构浏览器，它展示了 Aspect 如何与其它系统组件交互。这个结构浏览器既可以作为流行的 IDE 的插件，也可以作为独立的工具。图 1 显示了先前讨论的日志记录示例的视图。 </p>
		<p>
				<b>图 1.随 AspectJ 一起提供的图形结构浏览器展示了（在其它事物中）AutoLog 建议了哪些方法</b>
				<br />
				<a class="contentlink" onfocus="this.blur()" href="http://www-900.ibm.com/developerWorks/cn/java/j-aspectj/browser.jpg" target="_blank">
						<img alt="按此在新窗口浏览图片" src="http://www-900.ibm.com/developerWorks/cn/java/j-aspectj/browser.jpg" onload="javascript:if(this.width&gt;screen.width-333)this.width=screen.width-333" border="0" />
				</a>
		</p>
		<p>除了结构浏览器和核心编译器之外，您还可以从 AspectJ 网站下载一个 Aspect 支持的调试器、一个 javadoc 工具、一个 Ant 任务以及一个 Emacs 插件。</p>
		<p>让我们返回到语言特性。 </p>
		<p>影响类结构：引入（Introduction）<br />Pointcut 和 Advice 允许影响程序的动态执行；引入
（Introduction）允许修改程序的静态结构。使用引入（Introduction），Aspect 可以向类中添加新的方法和变量、声明一个类
实现一个接口或将检查异常转换为未检查异常（unchecked exception）。 </p>
		<p>引入（Introduction）示例<br />假设您有一个表示持久存储的数据缓存的对象。要测量数据的“更新程度”，您可能决定向该对象添加时间
戳记字段，以便容易地检测对象是否与后备存储器同步。然而，因为对象表示业务数据，就应该将这种机制性细节从对象中隔离。使用 AspectJ，可以用清
单 4 中所显示的语法来向现有的类添加时间戳记： </p>
		<p>
				<b>清单 4. 向现有的类中添加变量和方法</b> <br />public aspect Timestamp {</p>
		<p>  private long <i>value</i>Object.timestamp;</p>
		<p>  public long <i>value</i>Object.getTimestamp(){<br />      return timestamp;<br />  }</p>
		<p>  public void <i>value</i>Object.timestamp(){<br />      //"this" refers to <i>value</i>Object class not Timestamp aspect<br />      this.timestamp = System.currentTimeMillis();<br />  }<br />}<br /> </p>
		<p>除了必须限定在哪个类上声明引入的方法和成员变量以外（因此是 <i>value</i>Object.timestamp），声明引入的方法和成员变量几乎与声明常规类成员相同。 </p>
		<p>混合样式继承<br />AspectJ 允许向接口和类添加成员，允许按 C++ 方式中混合样式继承。如果您希望使清单 4 中的 Aspect 
通用化（generalize）以便能够对各种对象重用时间戳记代码，可以定义一个称为 TimestampedObject 的接口，并使用引入
（Introduction）来将相同成员和变量添加到接口而不是添加到具体类中，如清单 5 所示。 </p>
		<p>
				<b>清单 5. 将行为添加到接口</b> <br />public interface TimestampedObject {<br />    long getTimestamp();<br /> <br />    void timestamp();<br />}<br />//and<br />public aspect Timestamp {</p>
		<p>    private long TimestampedObject.timestamp;</p>
		<p>    public long TimestampedObject.getTimestamp(){<br />        return timestamp;<br />    }<br /> <br />    public void TimestampedObject.timestamp(){<br />        this.timestamp = System.currentTimeMillis();<br />    }<br />}</p>
		<p> </p>
		<p>现在可以使用 declare parents 语法来促使 <i>value</i>Object 实现您的新接口了。declare parents 和其它 AspectJ 类型表达一样，可以同时应用于多个类型：</p>
		<p>
				<br />declare parents: <i>value</i>Object || Big<i>value</i>Object implements TimestampedObject;</p>
		<p> </p>
		<p>既然已经定义了 TimestampedObject 支持的操作，当出现适当环境时，您可以使用 Pointcut 和 Advice 来自动更新时间戳记。我们将在下一节中涉及它，因为它说明了如何在 Advice 中访问上下文。 </p>
		<p>其它 AspectJ 特性<br />使用 Pointcut，您可以方便地定义环境，加上时间戳记的对象将在其中更新戳记。清单 6 中显示了 Timestamp 的补充，在对写方法的任何调用之后给对象加时间戳记： </p>
		<p>
				<b>清单 6. 在 Advice 中访问上下文</b> <br />pointcut objectChanged(TimestampedObject object) : <br />             execution(public void TimestampedObject+.set*(..)) &amp;&amp; <br />             this(object);<br />/*TimestampedObject+ means any subclass of TimestampedObject*/</p>
		<p>after(TimestampedObject object) :  objectChanged(object){<br />        object.timestamp();<br />}</p>
		<p> </p>
		<p>请注意，Pointcut 定义了 after() Advice 使用的参数 — 在本例中，是 TimestampedObject — 在其
上有一个写方法调用。this() Pointcut 标识了所有 join point，其中所有当前执行的对象都属于括号中定义的类型。其它几种类型
的值可以捆绑到 Advice 的参数中，包括方法参数、方法抛出的异常以及方法调用的目标。 </p>
		<p>定制编译错误<br />我发现定制编译错误是 AspectJ 最酷的特性之一。假如您希望隔离一个子系统，以使客户机代码必须通过中间媒介来访问工
作程序对象（这种情况在 Facade 设计模式中出现）。使用 declare error 或 declare warning 语法，您可以定制
 ajc 编译器对潜在 join point 的响应，如清单 7 所示。 </p>
		<p>
				<b>清单 7. 定义定制错误</b> <br />public aspect FacadeEnforcement {</p>
		<p>  pointcut notThruFacade() : within(Client) &amp;&amp; call(public * Worker.*(..));<br />    <br />  declare error : notThruFacade(): <br />    "Clients may not use Worker objects directly.";<br />}<br /> </p>
		<p>除了 ajc 在编译时彻底检测 within Pointcut 以外（大多数 Pointcut 可以根据运行时信息区别开来），within Pointcut 类似于 this()。 </p>
		<p>错误处理<br />我承认 Java 语言中检查异常（checked exception）的价值。然而，我经常希望有一个变通方法，类似于“将该
异常转换为运行时异常”这样简单的命令。有很多次，我正在编写的方法不对异常作出有意义的响应 — 并且有时该方法的潜在使用程序也不响应。我不希望废弃
异常，但是我也不希望为了找到它而一直跟踪到它的所有调用者。有一些巧妙的方法使用 try/catch 块来完成这个任务，但是没有一种象
 AspectJ 中的 declare soft 这样棒。清单 8 中所显示的类试图完成一些 SQL 任务。 </p>
		<p>
				<b>清单 8. 一个具有检查异常的类</b> <br />public class SqlAccess {<br />    <br />    private Connection conn;<br />    private Statement stmt;<br />    </p>
		<p>    public void doUpdate(){<br />        conn = DriverManager.getConnection("url for testing purposes");<br />        stmt = conn.createStatement();<br />        stmt.execute("UPDATE ACCOUNTS SET BALANCE = 0");<br />    }<br />    <br />    public static void main(String[] args)throws Exception{<br />        new SqlAccess().doUpdate();<br />    }<br />}</p>
		<p> </p>
		<p>如果我不使用 AspectJ 或在每个方法说明中声明异常，那么我将不得不插入 try/catch 块来处理已检出的
 SQLException（几乎从 JDBC API 中的每个方法中抛出这个异常）。使用 AspectJ，我可以使用下列内部 Aspect 来将
它作为 org.aspectj.lang.SoftException 自动重新抛出： </p>
		<p>
				<b>清单 9. soft 化异常</b> <br />private static aspect exceptionHandling{<br />  declare soft : SQLException : within(SqlAccess);<br />  <br />  pointcut methodCall(SqlAccess accessor) : this(accessor) <br />    &amp;&amp; call(* * SqlAccess.*(..));<br />    <br />  after(SqlAccess accessor) : methodCall  (accessor){<br />    System.out.println("Closing connections.");<br />    if(accessor.stmt != null){<br />        accessor.stmt.close();<br />    }<br />    if(accessor.conn != null){<br />        accessor.conn.close();<br />    }<br />  }<br />}</p>
		<p> </p>
		<p>无论 SQLAccess 类中的每个方法是抛出异常还是正常返回，Pointcut 和 Advice 都关闭其后的连接和语句。为每个方法都使
用一个错误处理 Aspect 也许有点矫枉过正，但是如果将要添加使用该连接和语句的任何其它方法，错误处理策略也将应用于它们。这种对新代码自动应用
 Aspect 的特性是 AOP 关键的主要优势之一：新代码的作者不必为加入横切行为而了解它们。 </p>
		<p>结束语<br />AspectJ 是否值得使用？Grady Booch 将面向 Aspect 的编程看作是标志软件设计和编写方法基础性转变的三大运动之一。（请在<a class="contentlink" href="http://www-900.ibm.com/developerWorks/cn/java/j-aspectj/#resources" target="_blank"><font color="#4455aa">参考资料</font></a>节
中参阅他的“Through the Looking Glass”。）我赞同他的观点。AOP 解决了面向对象和其它过程性语言未能处理的一块问题空
间。在最近几周我对 AspectJ 的介绍中，我发现它为那些我原以为是编程的基本极限的问题提供了一流的、可重用的解决方案。可以说 AOP 是从我
开始使用对象以来的功能最强大的抽象。 </p>
		<p>当然，AspectJ 确实有一条学习曲线。和所有语言或语言扩展一样，在能够充分利用它的所有强大功能之前，您必需领会它的一些微妙之处。但是，
学习曲线并不太陡峭 — 在通读开发人员指南以及完成一些示例以后，我发现自己已经能够编写有用的 Aspect。AspectJ 给人的感觉是很自然，
就好象它填补了您的编程知识缺陷而不是在一个新方向上的扩展。某些 AspectJ 工具还有些粗糙，但是我还没有遇到任何严重问题。 </p>
		<p>因为 AspectJ 具有对不可模块化的程序进行模块化的强大功能，我认为它值得立即使用。如果您的项目或公司还没有准备好在生产中使用
 AspectJ，可以方便地将 AspectJ 应用于诸如调试和合同履行之类的开发事项。请注意一下这种语言扩展，这将对您有所帮助。 </p>
		<p>参考资料 </p>
		<p>请单击本文顶部或底部的<b>讨论</b>参与本文的论坛。</p>
		<p>
				<br />可以从 <a class="contentlink" href="http://www.aspectj.org/" target="_blank&lt;a" contentlink=""><font color="#4455aa">www.aspectj.org</font></a> 下载 AspectJ 及其相关的工具。 该网站还有 FAQ、邮件列表、精选文章以及到其它 AOP 资源的链接。这是个开始深入研究的好地方。</p>
		<p>
				<br />Grady Booch 的“<a class="contentlink" href="http://www.sdmagazine.com/documents/s=843/sdm0107i/0107i.htm" target="_blank"><font color="#4455aa">Through the Looking Glass</font></a>”（Software Development，2001 年 7 月）讨论了软件工程的未来并预言了多面软件的出现，这种软件同时用多种方法迅速写成。文章将 AOP 引用为编程领域内首批多面运动之一。</p>
		<p>
				<br />另一种多面方法是来自于 IBM Research 团队的 <a class="contentlink" href="http://www-900.ibm.com/developerWorks/cn/cgi-bin/click.cgi?url=http://www.research.ibm.com/hyperspace/&amp;origin=j" target="_blank"><font color="#4455aa">Hyperspaces</font></a>。Hyperspaces 超越了对横切关系的封装，并尝试管理关系的多维分离。<a class="contentlink" href="http://www-900.ibm.com/developerWorks/cn/cgi-bin/click.cgi?url=http://www.research.ibm.com/hyperspace/HyperJ/HyperJ.htm&amp;origin=j" target="_blank"><font color="#4455aa">Hyper/J</font></a>— Hyperspaces 的 Java 支持 — 提供了系统的按需重新模块化。这真是激动人心的功能。</p>
		<p>
				<br />IBM Research 还致力于<a class="contentlink" href="http://www-900.ibm.com/developerWorks/cn/cgi-bin/click.cgi?url=http://www.research.ibm.com/sop/&amp;origin=j" target="_blank"><font color="#4455aa">面向主题（subject）的编程</font></a>，它提供主题 — 具有唯一系统“视图”的类或类片段的集合。主题按组合规则组成应用程序。</p>
		<p>
				<br />
				<a class="contentlink" href="http://aosd.net/" target="_blank">
						<font color="#4455aa">asod.net</font>
				</a> 通常担当 AOP 信息的中央源。该网站提供到其它 AOP 倡导者的链接、用其它语言的 Aspect 实现、类 Aspect 源代码修改以及关于 Aspect 理论的文章。</p>
		<p>
				<br />AOP 的创始文章之一，“<a class="contentlink" href="http://aspectj.org/documentation/papersAndSlides/ECOOP1997-AOP.pdf" target="_blank"><font color="#4455aa">Aspect Oriented Programming</font></a>”（PDF），提供了这一新编程方法的早期观点。本文开始部分引用的示例就是从这本书上抽取出来的，在这个关于性能优化的示例中，不用 Aspect 需要 35,000 行代码而用它只要 1,000 行。</p>
		<p>
				<br />JavaWorld 提供介绍 AOP 的系列短文，“<a class="contentlink" href="http://www.javaworld.com/javaworld/jw-01-2002/jw-0118-aspect.html" target="_blank"><font color="#4455aa">I want my AOP</font></a>”。</p>
		<p>
				<br />Eric Allen 的 <a class="contentlink" href="http://www-106.ibm.com/developerWorks/library/j-djccol" target="_blank"><font color="#4455aa">Diagnosing Java Code 专栏</font></a>讲述了许多由对横切关系的不一致处理而导致的“错误模式”。Allen 讨论了用 OO 技术使这些错误最小化的方法。“<a class="contentlink" href="http://www-106.ibm.com/developerWorks/library/j-diag1.html" target="_blank"><font color="#4455aa">Bug patterns：An introduction</font></a>”讲述了由重复代码引起的常见类型错误 — 在 OOP 中经常无法避免。他在与异常有关的“<a class="contentlink" href="http://www-106.ibm.com/developerWorks/library/j-diag3.html" target="_blank"><font color="#4455aa">The Null Flag bug pattern</font></a>”中特别提到了 AspectJ。</p>
		<p>
				<br />本文中的日志记录示例是从 Jakarta 的 <a class="contentlink" href="http://jakarta.apache.org/cactus" target="_blank"><font color="#4455aa">Cactus</font></a> 项目中抽取出来的。</p>
		<p>
				<br />请到 <a class="contentlink" href="http://www-106.ibm.com/developerWorks/java/?article=jr" target="_blank"><font color="#4455aa">developerWorks Java 技术专区</font></a>查找其它 Java 参考资料。</p>
		<p>关于作者<br />Nicholas Lesiecki 在 .com 的繁荣时期进入了 Java 编程世界，并且随着 <a class="contentlink" href="http://www.amazon.com/exec/obidos/ASIN/047120708X/" target="_blank"><font color="#4455aa">Java Tools for Extreme Programming </font></a>（一份关于如何在诸如 XP 之类灵活过程中利用开放源码构建和测试工具的手册）的出版，他在 XP 和 Java 社区中的地位逐渐变得重要。他目前领导着 eBlox，Inc. 的旗舰在线目录系统 <a class="contentlink" href="http://eblox.com/storeblox.php" target="_blank"><font color="#4455aa">storeBlox</font></a> 的开发。除了经常在 <a class="contentlink" href="http://groups.yahoo.com/group/tucson-jug/" target="_blank"><font color="#4455aa">Tucson JUG</font></a> 演讲之外，他还积极参与 Jakarta 的 <a class="contentlink" href="http://jakarta.apache.org/cactus" target="_blank"><font color="#4455aa">Cactus</font></a> 项目（一个服务器端单元测试框架）。请通过 <a class="contentlink" href="mailto:ndlesiecki@apache.org" target="_blank"><font color="#4455aa">ndlesiecki@apache.org</font></a> 与 Nick 联系。 <br /></p>
<img src ="http://www.blogjava.net/Vencent/aggbug/35962.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-03-18 19:01 <a href="http://www.blogjava.net/Vencent/articles/35962.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多线程(7): JT第5章笔记</title><link>http://www.blogjava.net/Vencent/articles/34882.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Sat, 11 Mar 2006 15:25:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/34882.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/34882.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/34882.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/34882.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/34882.html</trackback:ping><description><![CDATA[<div class="postText">
		<p>《Java Threads》的第5章"Minimal Synchronization
Techniques"，是这本书中到现在我认为最差的一章了，当然主要是我不喜欢JDK 1.5新推出的Atomic
Class，而这一章却花了不少篇章来介绍，且牵强地改造打字程序，又语焉不详地指出这种改造的困难之处和可能带来的副作用，但却又不能从代码的实际运行
中看到这种副作用，很有误导初学者的嫌疑。不过，我想，没有哪个初学者会冒风险为了用Atomic
Class而将原本简单明了的算法改造得如此晦涩难懂，并且还有潜在的出错风险。所以，对于Atomic
Class，我建议跳过不读，绝对没有什么损失。不过对于其中"5.1.3 Double-Checked Locking"和"5.3 Thread
Local Variables"这两节倒要着重读一读，尤其是Thread Local，应该说是Java中一个比较重要的多线程工具。</p>
<p>读到这里，我突然发觉，作为偏参考书的技术书籍，实在不适宜从头到尾采用一个例子，然后结合章节的推广来不断改进这个例子。因为，各章节相对独立，
而读者可能挑任何章节来阅读，那么就会被例子搞到不知所云。所以，如果是我，则会为每个概念或类编写一些小的有针对性的例子，来清除明白地演示其作用。</p>
<p>好了，废话少说。既然看了，还是留下些笔记吧。</p>
<p><span style="font-size: 1.2em;"><strong style="font-size: 1.5em;">Chapter 5. Minimal Synchronization Techniques</strong></span></p>
<p>由于同步以及锁的获取、释放和等待都是比较费时的操作，因此这一章将介绍JDK 1.5新引进的Atomic Classes来避免显示的同步。在这一章的开头简单介绍了Java的内存模型，可以帮助开发者更好地体会Java线程同步的机制。</p>
<p><strong style="font-size: 1.2em;">5.1 Can You Avoid Synchrnoziation?<br></strong> 1. 多线程开发人员常患有同步狂想症。有太多的关于过度或者错误的同步导致程序运行低下的悲惨故事。由于获取锁需要更多额外的操作，以及必须等待当前拥有锁的线程释放锁，导致同步变成了一个十分昂贵的操作。<br>2. 是否能够避免使用同步呢？在极少数情况下，可以通过使用volatile变量来避免显示同步的使用；但大多数多线程环境中显然无法避免。<br>3. 计算机一般通过尽量将数据保存在寄存器以及调整语句的执行顺序来优化程序。</p>
<p><strong>5.1.1 The Effect of Registers<br></strong> 当虚拟机进入一个同步方法或同步块时，它会重新装载缓冲在本地寄存器中的数据；当离开时，则将寄存器中的内容重新写入主存中。</p>
<p><strong>5.1.2 The Effect of Reordering Statements</strong><br>同步块同样会组织语句的重新排列。虚拟机不能将语句从同步块的内部移到同步块的外面。</p>
<p><strong>5.1.3 Double-Checked Locking</strong><br>当需要在多线程环境下使用单件模式(Singleton Patter)时，为了避免多个对象的创建，就需要使用同步，但如果每次获取对象都同步则会相当影响性能，因此，就推出了Double-Checked Locking模式。但在早期的JVM中可能会导致错误，在<a href="http://www.cs.umd.edu/%7Epugh/java/memeoryModel">http://www.cs.umd.edu/~pugh/java/memeoryModel</a> 有详细的说明，值得一读。倒不是去验证可能的错误，那篇文章毕竟是98年写的，在现在的JVM中基本上不可能重现这个错误，而是可以很好地了解一下这个设计模式的来历和作用。</p>
<p><span style="font-size: 1.2em;"><strong>5.2 Atomic Variables</strong></span><br>(略)</p>
<p><span style="font-size: 1.2em;"><strong>5.3 Thread Local Variables</strong></span><br>1. 通过Thread Local可以自动为每个线程保留一份私有拷贝，并且这个过程对调用者来说是透明的。<br>2. JDK 1.5将ThreadLocal转化成了泛类（Generic Class），可以加强类型检测，并在每次获取时不再需要类型转换。<br>3. 常见的使用方法：<br></p>
<div class="mycode">private static ThreadLocal&lt;HashMap&gt; results = new ThreadLocal&lt;HashMap&gt;() {<br>protected HashMap initialValue() {<br>return new HashMap();<br>}<br>}</div>
4. ThreadLocal的一个应用就是实现数据库的事务控制，可以参考Spring的代码，当然不一定要那么复杂。
<p>&nbsp;</p>
<p><strong>5.3.1 Inheritable Thread Local Variables</strong><br><br>IBM DW上的这篇文章<a href="http://www-128.ibm.com/developerworks/cn/java/j-threads/index3.html" target="_blank">轻松使用线程: 不共享有时是最好的</a>不错，如果要学习ThreadLocal，一定要看看这篇文章:)。</p>
	</div><img src ="http://www.blogjava.net/Vencent/aggbug/34882.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-03-11 23:25 <a href="http://www.blogjava.net/Vencent/articles/34882.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Jakarta Commons笔记] Commons Collections - Iterator组</title><link>http://www.blogjava.net/Vencent/articles/34751.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Fri, 10 Mar 2006 15:16:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/34751.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/34751.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/34751.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/34751.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/34751.html</trackback:ping><description><![CDATA[<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">来看最后一组</span><span style="font-family: 'Trebuchet MS';"> <span lang="EN-US">– Iterator</span></span><span style="font-family: 宋体;">。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">LoopingIterator<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">ArrayListIterator<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">FilterIterator<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">UniqueFilterIterator<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">IteratorUtils<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US">java.util.Iterator</span><span style="font-family: 宋体;">接口定义了标准的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Collection</span><span style="font-family: 宋体;">遍历方法，但是如果不做改变的使用它，我们得到的是从头到尾一次性的遍历。假如我们需要循环遍历，假如我们需要遍历某一段，假如我们需要遍历满足某些条件的元素，等等等等，我们就不能完全依赖于这个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Iterator</span><span style="font-family: 宋体;">的标准实现了。除非我们宁可在此基础上在调用的代码中多加一些判断，不过这样的话代码就会显得混乱，时间长了就容易变得难以维护。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Commons Collections</span><span style="font-family: 宋体;">的这一组</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Iterator</span><span style="font-family: 宋体;">为我们带来了便利。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">这些</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Iterator</span><span style="font-family: 宋体;">使用都很一目了然，直接看例子吧：</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">package</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> sean.study.commons.collections;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> java.util.Arrays;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> java.util.Iterator;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> java.util.List;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.collections.Predicate;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.collections.iterators.ArrayListIterator;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.collections.iterators.FilterIterator;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.collections.iterators.LoopingIterator;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.lang.StringUtils;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">public</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> <b style=""><span style="color: navy;">class</span></b> IteratorUsage {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">public</span></b> <b style=""><span style="color: navy;">static</span></b> <b style=""><span style="color: navy;">void</span></b> main(String[] args) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>demoIteratorUsage();<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">public</span></b> <b style=""><span style="color: navy;">static</span></b> void demoIteratorUsage() {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(StringUtils.center(<span style="color: blue;">" demoClosureUsage "</span>, 40, <span style="color: blue;">"="</span>));<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span><span style="">&nbsp;&nbsp;&nbsp; </span><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; color: green; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// data setup<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>String[] weekDays = {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue;">"Monday"</span>, <span style="color: blue;">"Tuesday"</span>, <span style="color: blue;">"Wednesday"</span>,<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue;">"Thursday"</span>, <span style="color: blue;">"Friday"</span>, <span style="color: blue;">"Saturday"</span>, <span style="color: blue;">"Sunday"</span><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>};<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>List weekDayList = Arrays.asList(weekDays);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; color: green; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// workdays<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Iterator iter1 = <b style=""><span style="color: navy;">new</span></b> ArrayListIterator(weekDays, 0, 5);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>printColl(<span style="color: blue;">"Partial:"</span>, iter1, 5);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; color: green; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// loop<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Iterator iter2 = <b style=""><span style="color: navy;">new</span></b> LoopingIterator(weekDayList);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>printColl(<span style="color: blue;">"<st1:place w:st="on">Loop</st1:place>:"</span>, iter2, 10);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; color: green; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// looping workdays<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Predicate notWeekendPredicate = <b style=""><span style="color: navy;">new</span></b> Predicate() {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">public</span></b> <b style=""><span style="color: navy;">boolean</span></b> evaluate(Object obj) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>String str = (String) obj;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">if</span></b> (<span style="color: blue;">"Saturday"</span>.equalsIgnoreCase(str)) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">return</span></b> false;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">if</span></b> (<span style="color: blue;">"Sunday"</span>.equalsIgnoreCase(str)) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">return</span></b> false;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">return</span></b> true;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>};<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Iterator iter3 = <b style=""><span style="color: navy;">new</span></b> FilterIterator(<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">new</span></b> LoopingIterator(weekDayList),<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>notWeekendPredicate<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>printColl(<span style="color: blue;">"No Weekends loop:"</span>, iter3, 12);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(StringUtils.repeat(<span style="color: blue;">"="</span>, 40));<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">public</span></b> <b style=""><span style="color: navy;">static</span></b> <b style=""><span style="color: navy;">void</span></b> printColl(String label, Iterator iter, <b style=""><span style="color: navy;">int</span></b> maxCount) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">if</span></b> (StringUtils.isNotBlank(label)) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(label);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">int</span></b> i = 0;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">while</span></b> (iter.hasNext() &amp;&amp; i &lt; maxCount) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(<span style="color: blue;">"# "</span> + iter.next() + <span style="color: blue;">" #"</span>);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>i++;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US">}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">运行结果如下：</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">=========== demoClosureUsage ===========</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">Partial:</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Monday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Tuesday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Wednesday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Thursday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Friday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><st1:place w:st="on"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">Loop</span></st1:place><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">:</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Monday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Tuesday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Wednesday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Thursday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Friday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Saturday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Sunday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Monday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Tuesday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Wednesday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">No Weekends loop:</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Monday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Tuesday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Wednesday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Thursday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Friday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Monday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Tuesday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Wednesday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Thursday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Friday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Monday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"># Tuesday #</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">========================================</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">有了这些实用的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Iterator</span><span style="font-family: 宋体;">类，我们就可以轻松的实现可配置的遍历行为了。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p><img src ="http://www.blogjava.net/Vencent/aggbug/34751.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-03-10 23:16 <a href="http://www.blogjava.net/Vencent/articles/34751.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Jakarta Commons笔记] 结语</title><link>http://www.blogjava.net/Vencent/articles/34752.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Fri, 10 Mar 2006 15:16:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/34752.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/34752.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/34752.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/34752.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/34752.html</trackback:ping><description><![CDATA[<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">在前面的随笔中，我们一起过了一遍</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Jakarta Commons</span><span style="font-family: 宋体;">这个类库中非常重要的三个子项目：</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Commons Lang</span><span style="font-family: 宋体;">、</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Commons BeanUtils</span><span style="font-family: 宋体;">和</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Commons Collections</span><span style="font-family: 宋体;">，这些工具包在无数开源或商业框架中都可以找到，可以说应用范围非常广。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">当然，</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Jakarta Commons</span><span style="font-family: 宋体;">提供的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">API</span><span style="font-family: 宋体;">远不止我们提到的这些，除了上述三个核心项目之外，还有读取和映射</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">XML</span><span style="font-family: 宋体;">文档的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Digester/Betwixt</span><span style="font-family: 宋体;">、处理命令行参数的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">CLI</span><span style="font-family: 宋体;">、提供常用编码算法的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Codec</span><span style="font-family: 宋体;">、用于读取多种格式的配置文件的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Configuration</span><span style="font-family: 宋体;">、发送电子邮件的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Email</span><span style="font-family: 宋体;">、上传文件的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">FileUpload</span><span style="font-family: 宋体;">、模拟</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">HTTP</span><span style="font-family: 宋体;">客户端的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">HttpClient</span><span style="font-family: 宋体;">、处理日志的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Logging</span><span style="font-family: 宋体;">等等等等，实在是相当的丰富。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US">Jakarta Commons</span><span style="font-family: 宋体;">官网上可以找到完整的组件列表：</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><a href="http://jakarta.apache.org/commons/">http://jakarta.apache.org/commons/</a><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">今后如果发现特别有价值需要跟大家分享的，我还会贴出来，只是不会像这样有条理和规律了。希望我的这一组笔记对大家了解和认识</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Jakarta Commons</span><span style="font-family: 宋体;">有所帮助，也希望这些优秀的类库及其源码能够给大家带来工作效率和编程功底上的提升。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">我整理了一份清单，列出了所有这一系列随笔的链接，方便大家查找和阅读：</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><a href="../../sean/articles/Jakarta_Commons_Notes.html">http://www.blogjava.net/sean/articles/Jakarta_Commons_Notes.html</a><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p><img src ="http://www.blogjava.net/Vencent/aggbug/34752.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-03-10 23:16 <a href="http://www.blogjava.net/Vencent/articles/34752.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Jakarta Commons笔记] Commons Collections - Transformer组</title><link>http://www.blogjava.net/Vencent/articles/34749.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Fri, 10 Mar 2006 15:15:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/34749.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/34749.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/34749.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/34749.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/34749.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 接下来看Transformer组。&nbsp;TransformerChainedTransformerSwitchTransformerTransformerUtils&nbsp;我们有时候需要将某个对象转换成另一个对象供另一组方法调用，而这两类对象的类型有可能并不是出于同一个继承体系的，或者说出了很基本的Object之外没有共同的父类，或者我们根本不关心他们是不是有...&nbsp;&nbsp;<a href='http://www.blogjava.net/Vencent/articles/34749.html'>阅读全文</a><img src ="http://www.blogjava.net/Vencent/aggbug/34749.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-03-10 23:15 <a href="http://www.blogjava.net/Vencent/articles/34749.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Jakarta Commons笔记] Commons Collections - Closure组</title><link>http://www.blogjava.net/Vencent/articles/34750.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Fri, 10 Mar 2006 15:15:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/34750.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/34750.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/34750.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/34750.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/34750.html</trackback:ping><description><![CDATA[<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">接下来看</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Closure</span><span style="font-family: 宋体;">组。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">Closure<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">ChainedClosure<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">IfClosure<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">WhileClosure<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">ClosureUtils<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US">Closure</span><span style="font-family: 宋体;">这一组接口和类提供一个操作对象的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">execute</span><span style="font-family: 宋体;">方法，为我们在处理一系列对象时可以将处理逻辑分离出来。理论上讲，使用</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Transformer</span><span style="font-family: 宋体;">也可以达到类似的效果，只要输出对象和输入对象是同一个对象就好，但是</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Closure</span><span style="font-family: 宋体;">接口定义的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">execute</span><span style="font-family: 宋体;">方法返回</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">void</span><span style="font-family: 宋体;">，并且从效果和功能区分上，</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Closure</span><span style="font-family: 宋体;">可以更好的诠释对象处理或执行的意思。而事实上，</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">ClosureUtils</span><span style="font-family: 宋体;">中也提供了一个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">asClosure</span><span style="font-family: 宋体;">方法包装一个现成的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Transformer</span><span style="font-family: 宋体;">。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">沿用前面的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Emploee</span><span style="font-family: 宋体;">类，我们来给一组员工涨工资：</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">package</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> sean.study.commons.collections;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> java.util.Arrays;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> java.util.Collection;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> java.util.Date;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> java.util.Iterator;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.collections.Closure;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.collections.CollectionUtils;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.lang.StringUtils;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">public</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> <b style=""><span style="color: navy;">class</span></b> ClosureUsage {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">public</span></b> <b style=""><span style="color: navy;">static</span></b> <b style=""><span style="color: navy;">void</span></b> main(String[] args) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>demoClosureUsage();<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">public</span></b> <b style=""><span style="color: navy;">static</span></b> <b style=""><span style="color: navy;">void</span></b> demoClosureUsage() {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(StringUtils.center(<span style="color: blue;">" demoClosureUsage "</span>, 40,<span style="color: blue;"> "="</span>));<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; color: green; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// data setup<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Employee[] employees = <b style=""><span style="color: navy;">new</span></b> Employee[] {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">new</span></b> Employee(<span style="color: blue;">"Tony"</span>, 26, new Date(), <span style="color: blue;">"E4"</span>, 2000),<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">new</span></b> Employee(<span style="color: blue;">"Michelle"</span>, 24, new Date(), <span style="color: blue;">"E4"</span>, 2000),<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">new</span></b> Employee(<span style="color: blue;">"Jack"</span>, 28, new Date(), <span style="color: blue;">"E5"</span>, 3000)<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>};<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Collection empColl = Arrays.asList(employees);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>printColl(<span style="color: blue;">"Before salary increase:"</span>, empColl);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; color: green; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// closure setup<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Closure salaryIncreaseClosure = <b style=""><span style="color: navy;">new</span></b> Closure() {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">public</span></b> <b style=""><span style="color: navy;">void</span></b> execute(Object obj) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Employee emp = (Employee) obj;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>emp.setSalary(emp.getSalary() * 1.20);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>};<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; color: green; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// salary increase<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>CollectionUtils.forAllDo(empColl, salaryIncreaseClosure);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>printColl(<span style="color: blue;">"After salary increase:"</span>, empColl);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(StringUtils.repeat(<span style="color: blue;">"="</span>, 40));<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">public</span></b> <b style=""><span style="color: navy;">static</span></b> <b style=""><span style="color: navy;">void</span></b> printColl(String label, Collection c) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>if (StringUtils.isNotBlank(label)) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(label);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Iterator iter = c.iterator();<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">while</span></b> (iter.hasNext()) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(iter.next());<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US">}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">以下是运行结果：</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">=========== demoClosureUsage ===========</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">Before salary increase:</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">Employee[name=Tony,age=26,dateJoined=<st1:chsdate w:st="on" isrocdate="False" islunardate="False" day="5" month="8" year="2005">2005-08-05</st1:chsdate>,grade=E4,salary=2000.0]</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">Employee[name=Michelle,age=24,dateJoined=<st1:chsdate w:st="on" isrocdate="False" islunardate="False" day="5" month="8" year="2005">2005-08-05</st1:chsdate>,grade=E4,salary=2000.0]</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">Employee[name=Jack,age=28,dateJoined=<st1:chsdate w:st="on" isrocdate="False" islunardate="False" day="5" month="8" year="2005">2005-08-05</st1:chsdate>,grade=E5,salary=3000.0]</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">After salary increase:</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">Employee[name=Tony,age=26,dateJoined=<st1:chsdate w:st="on" isrocdate="False" islunardate="False" day="5" month="8" year="2005">2005-08-05</st1:chsdate>,grade=E4,salary=2400.0]</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">Employee[name=Michelle,age=24,dateJoined=<st1:chsdate w:st="on" isrocdate="False" islunardate="False" day="5" month="8" year="2005">2005-08-05</st1:chsdate>,grade=E4,salary=2400.0]</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">Employee[name=Jack,age=28,dateJoined=<st1:chsdate w:st="on" isrocdate="False" islunardate="False" day="5" month="8" year="2005">2005-08-05</st1:chsdate>,grade=E5,salary=3600.0]</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">========================================</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">我这里举的是一个相对简单的例子，在</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Closure</span><span style="font-family: 宋体;">这一组还有一些很方便的类，如</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">ChainedClosure</span><span style="font-family: 宋体;">可以包装一组</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Closure</span><span style="font-family: 宋体;">作为整体执行；</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">IfClosure</span><span style="font-family: 宋体;">在创建时需要提供给它一个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Predicate</span><span style="font-family: 宋体;">和两个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Closure</span><span style="font-family: 宋体;">，执行时先做</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Predicate</span><span style="font-family: 宋体;">判定再决定执行哪一个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Closure</span><span style="font-family: 宋体;">；</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">SwitchClosure</span><span style="font-family: 宋体;">跟</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">SwitchTransformer</span><span style="font-family: 宋体;">类似，根据创建时传入的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Predicate</span><span style="font-family: 宋体;">组和</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Closure</span><span style="font-family: 宋体;">组对应执行；</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">WhileClosure</span><span style="font-family: 宋体;">则根据创建时传入的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Predicate</span><span style="font-family: 宋体;">做判断，如果为</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">true</span><span style="font-family: 宋体;">则执行</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Closure</span><span style="font-family: 宋体;">，直到</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Predicate</span><span style="font-family: 宋体;">返回</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">false</span><span style="font-family: 宋体;">；等等。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<span style="font-family: 宋体;">具体用法请参考</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Javadoc</span><span style="font-family: 宋体;">。</span><img src ="http://www.blogjava.net/Vencent/aggbug/34750.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-03-10 23:15 <a href="http://www.blogjava.net/Vencent/articles/34750.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Jakarta Commons笔记] Commons Collections - Comparator组</title><link>http://www.blogjava.net/Vencent/articles/34747.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Fri, 10 Mar 2006 15:14:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/34747.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/34747.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/34747.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/34747.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/34747.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 接下来我们会讲到辅助类，首先看Comparator组。&nbsp;ReverseComparatorComparatorChainNullComparatorFixedOrderComparatorComparatorUtils&nbsp;其实Comparator这个概念并不是Commons Collections引入的，在标准的Java Collections A...&nbsp;&nbsp;<a href='http://www.blogjava.net/Vencent/articles/34747.html'>阅读全文</a><img src ="http://www.blogjava.net/Vencent/aggbug/34747.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-03-10 23:14 <a href="http://www.blogjava.net/Vencent/articles/34747.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Jakarta Commons笔记] Commons Collections - Predicate组</title><link>http://www.blogjava.net/Vencent/articles/34748.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Fri, 10 Mar 2006 15:14:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/34748.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/34748.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/34748.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/34748.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/34748.html</trackback:ping><description><![CDATA[<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">接下来看</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Predicate</span><span style="font-family: 宋体;">组</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">Predicate<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">AndPredicate<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">OrPredicate<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">AllPredicate<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">OnePredicate<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">NonePredicate<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">PredicateUtils<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US">Predicate</span><span style="font-family: 宋体;">是</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Commons Collections</span><span style="font-family: 宋体;">中定义的一个接口，可以在</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">org.apache.commons.collections</span><span style="font-family: 宋体;">包中找到。其中定义的方法签名如下：</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">public</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> <b style=""><span style="color: navy;">boolean</span></b> evaluate(Object object)<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">它以一个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Object</span><span style="font-family: 宋体;">对象为参数，处理后返回一个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">boolean</span><span style="font-family: 宋体;">值，检验某个对象是否满足某个条件。其实这个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Predicate</span><span style="font-family: 宋体;">以及上一篇笔记提到的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Comparator</span><span style="font-family: 宋体;">还有我们即将看到的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Transformer</span><span style="font-family: 宋体;">和</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Closure</span><span style="font-family: 宋体;">等都有些类似</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">C/C++</span><span style="font-family: 宋体;">中的函数指针，它们都只是提供简单而明确定义的函数功能而已。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">跟其他组类似，</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Commons Collections</span><span style="font-family: 宋体;">也提供了一组定义好的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Predicate</span><span style="font-family: 宋体;">类供我们使用，这些类都放在</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">org.apache.commons.collections.functors</span><span style="font-family: 宋体;">包中。当然，我们也可以自定义</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Predicate</span><span style="font-family: 宋体;">，只要实现这个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Predicate</span><span style="font-family: 宋体;">接口即可。在</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Commons Collections</span><span style="font-family: 宋体;">中我们也可以很方便使用的一组预定义复合</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Predicate</span><span style="font-family: 宋体;">，我们提供</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">2</span><span style="font-family: 宋体;">个或不定数量个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Predicate</span><span style="font-family: 宋体;">，然后交给它，它可以帮我们处理额外的逻辑，如</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">AndPredicate</span><span style="font-family: 宋体;">处理两个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Predicate</span><span style="font-family: 宋体;">，只有当两者都返回</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">true</span><span style="font-family: 宋体;">它才返回</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">true</span><span style="font-family: 宋体;">；</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">AnyPredicate</span><span style="font-family: 宋体;">处理多个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Predicate</span><span style="font-family: 宋体;">，当其中一个满足就返回</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">true</span><span style="font-family: 宋体;">，等等。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">看看具体的代码中如何使用这些</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Predicate</span><span style="font-family: 宋体;">吧：</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">package</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> sean.study.commons.collections;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.collections.Predicate;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.collections.PredicateUtils;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.collections.functors.InstanceofPredicate;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.collections.functors.NotNullPredicate;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.lang.BooleanUtils;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.lang.StringUtils;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">public</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> <b style=""><span style="color: navy;">class</span></b> PredicateUsage {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">public</span></b> <b style=""><span style="color: navy;">static</span></b> <b style=""><span style="color: navy;">void</span></b> main(String[] args) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>demoPredicates();<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">public</span></b> <b style=""><span style="color: navy;">static</span></b> <b style=""><span style="color: navy;">void</span></b> demoPredicates() {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(StringUtils.center(<span style="color: blue;">" demoPredicates "</span>, 40, <span style="color: blue;">"="</span>));<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Predicate p1 = <b style=""><span style="color: navy;">new</span></b> InstanceofPredicate(String.class);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Predicate p2 = NotNullPredicate.getInstance();<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Predicate p3 = <b style=""><span style="color: navy;">new</span></b> Predicate() {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">public</span></b> <b style=""><span style="color: navy;">boolean</span></b> evaluate(Object obj) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>String str = (String) obj;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">return</span></b> StringUtils.isAlphanumeric(str) <o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&amp;&amp; str.length() &gt;= 6 <o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&amp;&amp; str.length() &lt;= 10;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>};<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span><span style="">&nbsp;&nbsp;&nbsp; </span>Predicate p4 = PredicateUtils.allPredicate(<b style=""><span style="color: navy;">new</span></b> Predicate[]{p1, p2, p3});<span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>String input = <span style="color: blue;">"ABCD1234"</span>;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Object[] raw = <b style=""><span style="color: navy;">new</span></b> Object[] {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue;">"Is '"</span>,<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>input,<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue;">"' a valid input? "</span>,<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>BooleanUtils.toStringYesNo(p4.evaluate(input)),<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue;">"."<o:p></o:p></span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>};<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(StringUtils.join(raw));<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(StringUtils.repeat(<span style="color: blue;">"="</span>, 40));<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US">}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">输出结果如下：</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">============ demoPredicates ============</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">Is 'ABCD1234' a valid input? yes.</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">========================================</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<span style="font-family: 宋体;">这里面我首先定义了</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">3</span><span style="font-family: 宋体;">个简单的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Predicate</span><span style="font-family: 宋体;">，</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">p1</span><span style="font-family: 宋体;">判断对象是否为</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">String</span><span style="font-family: 宋体;">的实例，</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">p2</span><span style="font-family: 宋体;">判断是否对象为</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">null</span><span style="font-family: 宋体;">，</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">p3</span><span style="font-family: 宋体;">是自定义的，判断是否为数字字母的组合，并且长度在</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">6~10</span><span style="font-family: 宋体;">字符。然后我用</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">AllPredicate</span><span style="font-family: 宋体;">将它们组合到一起，成为</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">p4</span><span style="font-family: 宋体;">，当</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">p1</span><span style="font-family: 宋体;">、</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">p2</span><span style="font-family: 宋体;">、</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">p3</span><span style="font-family: 宋体;">都满足时，</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">p4</span><span style="font-family: 宋体;">的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">evaluate</span><span style="font-family: 宋体;">方法才返回</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">true</span><span style="font-family: 宋体;">。利用</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Predicate</span><span style="font-family: 宋体;">我们可以把判断</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">true</span><span style="font-family: 宋体;">或</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">false</span><span style="font-family: 宋体;">的逻辑从特定的业务代码分离出来，以后我们重用也好，重新组装也好，都是很方便的。</span><img src ="http://www.blogjava.net/Vencent/aggbug/34748.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-03-10 23:14 <a href="http://www.blogjava.net/Vencent/articles/34748.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Jakarta Commons笔记] Commons Collections - Collection组</title><link>http://www.blogjava.net/Vencent/articles/34746.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Fri, 10 Mar 2006 15:13:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/34746.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/34746.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/34746.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/34746.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/34746.html</trackback:ping><description><![CDATA[<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">接下来看看</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Collection</span><span style="font-family: 宋体;">组。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">TypedCollection<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">CollectionUtils<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">首先就是这个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">TypedCollection</span><span style="font-family: 宋体;">，它实际上的作用就是提供一个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">decorate</span><span style="font-family: 宋体;">方法，我们传进去一个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Collection</span><span style="font-family: 宋体;">和需要的类型甄别信息</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">java.lang.Class</span><span style="font-family: 宋体;">，它给我们创建一个全新的强类型的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Collection</span><span style="font-family: 宋体;">。我们其实在</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">bag</span><span style="font-family: 宋体;">、</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">buffer</span><span style="font-family: 宋体;">、</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">list</span><span style="font-family: 宋体;">、</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">map</span><span style="font-family: 宋体;">、</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">set</span><span style="font-family: 宋体;">这些子包中都可以找到分别对应</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Bag</span><span style="font-family: 宋体;">、</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Buffer</span><span style="font-family: 宋体;">、</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">List</span><span style="font-family: 宋体;">、</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Map</span><span style="font-family: 宋体;">、</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Set</span><span style="font-family: 宋体;">接口的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">TypedXxxx</span><span style="font-family: 宋体;">版本。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">方法签名：</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">public</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> <b style=""><span style="color: navy;">static</span></b> Collection decorate(Collection coll, Class type)<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">当它执行时，它会判断</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">coll</span><span style="font-family: 宋体;">是否为</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">null</span><span style="font-family: 宋体;">，同时如果</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">coll</span><span style="font-family: 宋体;">包含数据，它会对数据进行验证，看是否满足指定的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">type</span><span style="font-family: 宋体;">条件。最后它返回一个强类型的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Collection</span><span style="font-family: 宋体;">，当我们对这个强类型的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Collection</span><span style="font-family: 宋体;">进行</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">add</span><span style="font-family: 宋体;">操作时，它会帮我们确保添加的是正确的类型。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">而这个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">CollectionUtils</span><span style="font-family: 宋体;">可能大家都已经想到了，就是提供一组针对</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Collection</span><span style="font-family: 宋体;">操作的工具</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">/</span><span style="font-family: 宋体;">静态方法。比较有意思的是对</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Collection</span><span style="font-family: 宋体;">的转型、合并、减等操作。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">由于这两个类的功能和作用都比较清晰，我就不举例说明了，需要进一步了解的请看</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Javadoc</span><span style="font-family: 宋体;">。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p><img src ="http://www.blogjava.net/Vencent/aggbug/34746.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-03-10 23:13 <a href="http://www.blogjava.net/Vencent/articles/34746.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Jakarta Commons笔记] Commons Collections - Buffer组</title><link>http://www.blogjava.net/Vencent/articles/34744.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Fri, 10 Mar 2006 15:12:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/34744.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/34744.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/34744.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/34744.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/34744.html</trackback:ping><description><![CDATA[<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">来看</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Buffer</span><span style="font-family: 宋体;">组。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">Buffer<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">BlockingBuffer<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">BoundedFifoBuffer<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">PriorityBuffer<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">UnboundedFifoBuffer<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">BufferUtils<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US">Buffer</span><span style="font-family: 宋体;">是定义在</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">org.apache.commons.collections</span><span style="font-family: 宋体;">包下面的接口，用于表示按一定顺序除去成员对象的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">collection</span><span style="font-family: 宋体;">如队列等。具体的实现类在</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">org.apache.commons.collections.buffer</span><span style="font-family: 宋体;">包下可以找到。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US">BufferUtils</span><span style="font-family: 宋体;">提供很多静态</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">/</span><span style="font-family: 宋体;">工具方法装饰现有的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Buffer</span><span style="font-family: 宋体;">实例，如将其装饰成</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">BlockingBuffer</span><span style="font-family: 宋体;">、执行类型检查的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">TypedBuffer</span><span style="font-family: 宋体;">、或者不可改变的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">UnmodifiableBuffer</span><span style="font-family: 宋体;">等等。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">最简单直接的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Buffer</span><span style="font-family: 宋体;">实现类是</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">UnboundedFifoBuffer</span><span style="font-family: 宋体;">，提供先进先出的大小可变的队列。而</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">BoundedFifoBuffer</span><span style="font-family: 宋体;">则是对其大小进行了限制，是固定大小的先进先出队列。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">BlockingBuffer</span><span style="font-family: 宋体;">要在多线程的环境中才能体现出它的价值，尤其是当我们需要实现某种流水线时这个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">BlockingBuffer</span><span style="font-family: 宋体;">很有用：每个流水线上的组件从上游的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">BlockingBuffer</span><span style="font-family: 宋体;">获取数据，处理后放到下一个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">BlockingBuffer</span><span style="font-family: 宋体;">中依次传递。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">BlockingBuffer</span><span style="font-family: 宋体;">的核心特色通俗点说就是如果你向它要东西，而它暂时还没有的话，你可以一直等待直至拿到为止。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">PriorityBuffer</span><span style="font-family: 宋体;">则提供比一般的先进先出</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Buffer</span><span style="font-family: 宋体;">更强的控制力：我们可以自定义</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Comparator</span><span style="font-family: 宋体;">给它，告诉它怎么判定它的成员的先后顺序，优先级最高的最先走。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">为了方便和清晰的需要，我在这里只举一个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">BoundedFifoBuffer</span><span style="font-family: 宋体;">，包装成</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">TypedBuffer</span><span style="font-family: 宋体;">，看看在具体的代码中通常如何使用</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Buffer</span><span style="font-family: 宋体;">：（还是沿用上次的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Book</span><span style="font-family: 宋体;">类）</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">package</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> sean.study.commons.collections;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> java.util.Iterator;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.collections.Buffer;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.collections.BufferUtils;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.collections.buffer.BoundedFifoBuffer;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.lang.StringUtils;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">public</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> <b style=""><span style="color: navy;">class</span></b> BufferUsage {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">public</span></b> <b style=""><span style="color: navy;">static</span></b> <b style=""><span style="color: navy;">void</span></b> main(String[] args) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>demoBufferUsage();<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">public</span></b> <b style=""><span style="color: navy;">static</span></b> <b style=""><span style="color: navy;">void</span></b> demoBufferUsage() {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(StringUtils.center(<span style="color: blue;">" demoBagUsage "</span>, 40, <span style="color: blue;">"="</span>));<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; color: green; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// data setup<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Book book1 = <b style=""><span style="color: navy;">new</span></b> Book(<span style="color: blue;">"Refactoring Workbook"</span>, <span style="color: blue;">"7-5083-2208-8"</span>, 29.8);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Book book2 = <b style=""><span style="color: navy;">new</span></b> Book(<span style="color: blue;">"J2EE Design Patterns"</span>, <span style="color: blue;">"7-5083-3099-4"</span>, 45);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Book book3 = <b style=""><span style="color: navy;">new</span></b> Book(<span style="color: blue;">"Agile Software Development"</span>, <span style="color: blue;">"7-5083-1503-0"</span>, 59);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Book book4 = <b style=""><span style="color: navy;">new</span></b> Book(<span style="color: blue;">"Professional JSP"</span>, <span style="color: blue;">"7-5053-8005-2"</span>, 100);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; color: green; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// create a Buffer<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Buffer buffer = <o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>BufferUtils.typedBuffer(<b style=""><span style="color: navy;">new</span></b> BoundedFifoBuffer(3), Book.<b style=""><span style="color: navy;">class</span></b>);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>buffer.add(book1);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>buffer.add(book2);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>buffer.add(book3);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Book removed = (Book) buffer.remove();<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(<span style="color: blue;">"Removed:"</span>);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(removed);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>buffer.add(book4);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; color: green; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// get items in buffer<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">for</span></b> (<b style=""><span style="color: navy;">int</span></b> i = 0; i &lt; 3; i++) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(buffer.get());<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>buffer.remove();<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(StringUtils.repeat(<span style="color: blue;">"="</span>, 40));<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US">}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">以下是运行结果：</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">============= demoBagUsage =============</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">Removed:</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">sean.study.commons.collections.Book@e09713[</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp; </span>name=Refactoring Workbook</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp; </span>ISBN=7-5083-2208-8</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp; </span>retailPrice=29.8</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">]</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">Remaining:</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">sean.study.commons.collections.Book@e09713[</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp; </span>name=J2EE Design Patterns</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp; </span>ISBN=7-5083-3099-4</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp; </span>retailPrice=45.0</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">]</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">sean.study.commons.collections.Book@47b480[</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp; </span>name=Agile Software Development</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp; </span>ISBN=7-5083-1503-0</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp; </span>retailPrice=59.0</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">]</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">sean.study.commons.collections.Book@19b49e6[</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp; </span>name=Professional JSP</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp; </span>ISBN=7-5053-8005-2</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp; </span>retailPrice=100.0</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">]</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">========================================</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">我们可以看到，</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Buffer</span><span style="font-family: 宋体;">的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">add</span><span style="font-family: 宋体;">和</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">remove</span><span style="font-family: 宋体;">方法分别添加新成员和删除最先加入的成员。由于我们的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Buffer</span><span style="font-family: 宋体;">定义为只能装</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">3</span><span style="font-family: 宋体;">个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Book</span><span style="font-family: 宋体;">类的实例，所以不论我们试图加入其他类型的对象，或者加入超过</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">3</span><span style="font-family: 宋体;">个，操作都将失败。如果我们在遍历时使用</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">get()</span><span style="font-family: 宋体;">而不调用</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">remove()</span><span style="font-family: 宋体;">，那么我们将得到</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">3</span><span style="font-family: 宋体;">个相同的拷贝，而这正是我们期望的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">FIFO</span><span style="font-family: 宋体;">队列的行为。假如你需要遍历并保留数据，可以使用标准的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Iterator</span><span style="font-family: 宋体;">机制。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p><img src ="http://www.blogjava.net/Vencent/aggbug/34744.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-03-10 23:12 <a href="http://www.blogjava.net/Vencent/articles/34744.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Jakarta Commons笔记] Commons Collections - Map组</title><link>http://www.blogjava.net/Vencent/articles/34745.html</link><dc:creator>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</dc:creator><author>&lt;font color='GREEN'&gt;Vincent Chen&lt;/font&gt;</author><pubDate>Fri, 10 Mar 2006 15:12:00 GMT</pubDate><guid>http://www.blogjava.net/Vencent/articles/34745.html</guid><wfw:comment>http://www.blogjava.net/Vencent/comments/34745.html</wfw:comment><comments>http://www.blogjava.net/Vencent/articles/34745.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vencent/comments/commentRss/34745.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vencent/services/trackbacks/34745.html</trackback:ping><description><![CDATA[<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">接下来看</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Map</span><span style="font-family: 宋体;">组。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">BidiMap<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">MultiMap<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">LazyMap<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="color: navy; font-family: 'Trebuchet MS';" lang="EN-US">MapUtils<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US">Commons Collections</span><span style="font-family: 宋体;">在</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">java.util.Map</span><span style="font-family: 宋体;">的基础上扩展了很多接口和类，比较有代表性的是</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">BidiMap</span><span style="font-family: 宋体;">、</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">MultiMap</span><span style="font-family: 宋体;">和</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">LazyMap</span><span style="font-family: 宋体;">。跟</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Bag</span><span style="font-family: 宋体;">和</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Buffer</span><span style="font-family: 宋体;">类似，</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Commons Collections</span><span style="font-family: 宋体;">也提供了一个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">MapUtils</span><span style="font-family: 宋体;">。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">所谓</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">BidiMap</span><span style="font-family: 宋体;">，直译就是双向</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Map</span><span style="font-family: 宋体;">，可以通过</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">key</span><span style="font-family: 宋体;">找到</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">value</span><span style="font-family: 宋体;">，也可以通过</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">value</span><span style="font-family: 宋体;">找到</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">key</span><span style="font-family: 宋体;">，这在我们日常的代码</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">-</span><span style="font-family: 宋体;">名称匹配的时候很方便：因为我们除了需要通过代码找到名称之外，往往也需要处理用户输入的名称，然后获取其代码。需要注意的是</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">BidiMap</span><span style="font-family: 宋体;">当中不光</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">key</span><span style="font-family: 宋体;">不能重复，</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">value</span><span style="font-family: 宋体;">也不可以。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">所谓</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">MultiMap</span><span style="font-family: 宋体;">，就是说一个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">key</span><span style="font-family: 宋体;">不在是简单的指向一个对象，而是一组对象，</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">add()</span><span style="font-family: 宋体;">和</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">remove()</span><span style="font-family: 宋体;">的时候跟普通的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Map</span><span style="font-family: 宋体;">无异，只是在</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">get()</span><span style="font-family: 宋体;">时返回一个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Collection</span><span style="font-family: 宋体;">，利用</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">MultiMap</span><span style="font-family: 宋体;">，我们就可以很方便的往一个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">key</span><span style="font-family: 宋体;">上放数量不定的对象，也就实现了一对多。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">所谓</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">LazyMap</span><span style="font-family: 宋体;">，意思就是这个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Map</span><span style="font-family: 宋体;">中的键</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">/</span><span style="font-family: 宋体;">值对一开始并不存在，当被调用到时才创建，这样的解释初听上去是不是有点不可思议？这样的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">LazyMap</span><span style="font-family: 宋体;">有用吗？我们这样来理解：我们需要一个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Map</span><span style="font-family: 宋体;">，但是由于创建成员的方法很“重”（比如数据库访问），或者我们只有在调用</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">get()</span><span style="font-family: 宋体;">时才知道如何创建，或者</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Map</span><span style="font-family: 宋体;">中出现的可能性很多很多，我们无法在</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">get()</span><span style="font-family: 宋体;">之前添加所有可能出现的键</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">/</span><span style="font-family: 宋体;">值对，或者任何其它解释得通的原因，我们觉得没有必要去初始化一个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Map</span><span style="font-family: 宋体;">而又希望它可以在必要时自动处理数据生成的话，</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">LazyMap</span><span style="font-family: 宋体;">就变得很有用了。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">我们还是通过一个具体的例子来说明：</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">package</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> sean.study.commons.collections;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> java.util.Date;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> java.util.HashMap;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> java.util.Map;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.collections.BidiMap;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.collections.Factory;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.collections.MultiHashMap;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.collections.MultiMap;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.collections.bidimap.DualHashBidiMap;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.collections.map.LazyMap;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">import</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> org.apache.commons.lang.StringUtils;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><b style=""><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US">public</span></b><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"> <b style=""><span style="color: navy;">class</span></b> MapUsage {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">public</span></b> <b style=""><span style="color: navy;">static</span></b> <b style=""><span style="color: navy;">void</span></b> main(String[] args) {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>demoBidiMap();<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>demoMultiMap();<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>demoLazyMap();<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">public</span></b> <b style=""><span style="color: navy;">static</span></b> <b style=""><span style="color: navy;">void</span></b> demoBidiMap() {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(StringUtils.center(<span style="color: blue;">" demoBidiMap "</span>, 40, <span style="color: blue;">"="</span>));<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>BidiMap bidiMap = <b style=""><span style="color: navy;">new</span></b> DualHashBidiMap();<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>bidiMap.put(<span style="color: blue;">"BJ"</span>, <span style="color: blue;">"<st1:city w:st="on"><st1:place w:st="on">Beijing</st1:place></st1:city>"</span>);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>bidiMap.put(<span style="color: blue;">"SH"</span>, <span style="color: blue;">"<st1:city w:st="on"><st1:place w:st="on">Shanghai</st1:place></st1:city>"</span>);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>bidiMap.put(<span style="color: blue;">"GZ"</span>, <span style="color: blue;">"<st1:city w:st="on"><st1:place w:st="on">Guangzhou</st1:place></st1:city>"</span>);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>bidiMap.put(<span style="color: blue;">"CD"</span>, <span style="color: blue;">"<st1:city w:st="on"><st1:place w:st="on">Chengdu</st1:place></st1:city>"</span>);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(<span style="color: blue;">"Key-Value: BJ = "</span> + bidiMap.get(<span style="color: blue;">"BJ"</span>));<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(<span style="color: blue;">"Value-Key: <st1:city w:st="on">Chengdu</st1:city> = "</span> + bidiMap.getKey(<span style="color: blue;">"<st1:city w:st="on"><st1:place w:st="on">Chengdu</st1:place></st1:city>"</span>));<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(StringUtils.repeat(<span style="color: blue;">"="</span>, 40));<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">public</span></b> <b style=""><span style="color: navy;">static</span></b> <b style=""><span style="color: navy;">void</span></b> demoMultiMap() {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(StringUtils.center(<span style="color: blue;">" demoMultiMap "</span>, 40, <span style="color: blue;">"="</span>));<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>MultiMap multiMap = <b style=""><span style="color: navy;">new</span></b> MultiHashMap();<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>multiMap.put(<span style="color: blue;">"Sean"</span>, <span style="color: blue;">"C/C++"</span>);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>multiMap.put(<span style="color: blue;">"Sean"</span>, <span style="color: blue;">"OO"</span>);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>multiMap.put(<span style="color: blue;">"Sean"</span>, <span style="color: blue;">"Java"</span>);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>multiMap.put(<span style="color: blue;">"Sean"</span>, <span style="color: blue;">".NET"</span>);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>multiMap.remove(<span style="color: blue;">"Sean"</span>, <span style="color: blue;">"C/C++"</span>);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(<span style="color: blue;">"Sean's skill set: "</span> + multiMap.get(<span style="color: blue;">"Sean"</span>));<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(StringUtils.repeat(<span style="color: blue;">"="</span>, 40));<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">public</span></b> <b style=""><span style="color: navy;">static</span></b> <b style=""><span style="color: navy;">void</span></b> demoLazyMap() {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(StringUtils.center(<span style="color: blue;">" demoLazyMap "</span>, 40, <span style="color: blue;">"="</span>));<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; color: green; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// borrowed from Commons Collection's Javadoc<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Factory factory = <b style=""><span style="color: navy;">new</span></b> Factory() {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">public</span></b> Object create() {<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><b style=""><span style="color: navy;">return</span></b> <b style=""><span style="color: navy;">new</span></b> Date();<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>};<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Map lazy = LazyMap.decorate(<b style=""><span style="color: navy;">new</span></b> HashMap(), factory);<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(lazy.get(<span style="color: blue;">"NOW"</span>));<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println(StringUtils.repeat(<span style="color: blue;">"="</span>, 40));<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; font-family: 'Courier New';" lang="EN-US">}<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">以下是运行结果：</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">============= demoBidiMap ==============</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">Key-Value: BJ = <st1:city w:st="on"><st1:place w:st="on">Beijing</st1:place></st1:city></span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">Value-Key: <st1:city w:st="on"><st1:place w:st="on">Chengdu</st1:place></st1:city> = CD</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">========================================</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">============= demoMultiMap =============</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">Sean's skill set: [OO, Java, .NET]</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">========================================</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">============= demoLazyMap ==============</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">Wed Aug 03 12:44:56 CST 2005</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left;" align="left"><span style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: navy; font-family: 'Courier New';" lang="EN-US">========================================</span><span style="font-size: 9pt; color: navy; font-family: 'Courier New';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 宋体;">简单说一下这个</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Factory</span><span style="font-family: 宋体;">，它是定义在</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">org.apache.commons.collections</span><span style="font-family: 宋体;">包下面的一个接口，用于自定义对象的创建过程。这个有点像是后面我们要讲的</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Transformer</span><span style="font-family: 宋体;">的简化版本，但是也更直接也很好用，至少</span><span style="font-family: 'Trebuchet MS';" lang="EN-US">Commons Collections</span><span style="font-family: 宋体;">通过它向开发人员开放了一个可以方便控制对象创建细节的接口。</span><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-family: 'Trebuchet MS';" lang="EN-US"><o:p>&nbsp;</o:p></span></p><img src ="http://www.blogjava.net/Vencent/aggbug/34745.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vencent/" target="_blank"><font color='GREEN'>Vincent Chen</font></a> 2006-03-10 23:12 <a href="http://www.blogjava.net/Vencent/articles/34745.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>