﻿<?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-Change Dir-随笔分类-Java技术</title><link>http://blogjava.net/changedi/category/43771.html</link><description>先知cd——热爱生活是一切艺术的开始</description><language>zh-cn</language><lastBuildDate>Sat, 28 Feb 2015 03:27:23 GMT</lastBuildDate><pubDate>Sat, 28 Feb 2015 03:27:23 GMT</pubDate><ttl>60</ttl><item><title>该如何良好的实践Java中的Exception机制</title><link>http://www.blogjava.net/changedi/archive/2015/02/26/423050.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Thu, 26 Feb 2015 07:19:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2015/02/26/423050.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/423050.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2015/02/26/423050.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/423050.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/423050.html</trackback:ping><description><![CDATA[<p style="margin:0in;font-family:SimSun;font-size:10.5pt">首先，我先声明一点，我讨论的仅限于互联网数据产品，当然可能会涉及到一些其他的抽象，但是所有的结论不代表能复用到所有场景。</p>  <p style="margin:0in;font-family:SimSun;font-size:10.5pt">&nbsp;</p>  <p style="margin:0in;font-size:10.5pt"><span style="font-family:Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family:SimSun">几乎每个</span><span style="font-family:Calibri">Java</span><span style="font-family:SimSun">程序员都清楚知道</span><span style="font-family:Calibri">Java</span><span style="font-family: SimSun">的异常和错误机制，无论是在面试过程中，还是在学习中，你看到</span><span style="font-family: Calibri">Exception</span><span style="font-family:SimSun">，无非就是了解一下继承关系、子类、和</span><span style="font-family:Calibri">Error</span><span style="font-family:SimSun">的关系等等。当然这些知识点是基础，那么在实践中，用到了吗？你确定你使用</span><span style="font-family:Calibri">Exception</span><span style="font-family: SimSun">时没有偷懒？我的经验告诉我，良好的使用</span><span style="font-family:Calibri">Exception</span><span style="font-family:SimSun">能让你的程序</span><span style="font-family:Calibri">bug</span><span style="font-family:SimSun">更少，或者至少能保证你的程序更容易被理解和跟踪。</span></p>  <p style="margin:0in;font-family:SimSun;font-size:10.5pt">&nbsp;</p>  <p style="margin:0in;font-size:10.5pt"><span style="font-family:Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family:SimSun">先回到老的知识点吧&#8212;&#8212;</span><span style="font-family: Calibri">Java</span><span style="font-family:SimSun">的异常机制，我们知道</span><span style="font-family:Calibri">Java</span><span style="font-family: SimSun">里的异常是完全继承</span><span style="font-family:Calibri">Throwable</span><span style="font-family:SimSun">的，正如</span><span style="font-family:Calibri">java doc</span><span style="font-family: SimSun">里注释的，无论你</span><span style="font-family:Calibri">throw</span><span style="font-family:SimSun">的还是</span><span style="font-family:Calibri">JVM throw</span><span style="font-family:SimSun">的，抑或是你想</span><span style="font-family:Calibri">catch</span><span style="font-family: SimSun">的，都必须继承</span><span style="font-family:Calibri">Throwable</span><span style="font-family:SimSun">。我这里帮助大家纠正的第一个点就是：</span><span style="font-family:Calibri">java.lang.Throwable</span><span style="font-family:SimSun">是一个</span><span style="font-family:Calibri">class</span><span style="font-family:SimSun">，不是一个</span><span style="font-family:Calibri">interface</span><span style="font-family: SimSun">，千万别被名字欺骗。优秀的程序员有好的命名习惯，当</span><span style="font-family: Calibri">Java</span><span style="font-family:SimSun">程序员默认认为带有</span><span style="font-family:Calibri">-able</span><span style="font-family: SimSun">后缀的都该是接口时，</span><span style="font-family:Calibri"> Josh Bloch</span><span style="font-family:SimSun">给大家上了一课&#8212;&#8212;</span><span style="font-family:Calibri">Throwable</span><span style="font-family: SimSun">就是类。回到正题，</span><span style="font-family:Calibri">Throwable</span><span style="font-family:SimSun">有两大子类，一个是</span><span style="font-family:Calibri">java.lang.Error</span><span style="font-family:SimSun">，一个是</span><span style="font-family:Calibri">java.lang.Excpetion</span><span style="font-family:SimSun">，</span><span style="font-family:Calibri">Error</span><span style="font-family:SimSun">是错误，一般多用于系统异常和底层错误，</span><span style="font-family:Calibri">Error</span><span style="font-family: SimSun">抛出就会导致程序终止；而</span><span style="font-family:Calibri">Exception</span><span style="font-family:SimSun">是异常，有程序引起，又分为受检的</span><span style="font-family:Calibri">checked</span><span style="font-family: SimSun">和非受检的</span><span style="font-family:Calibri">unchecked</span><span style="font-family:SimSun">（不知道哪本书这么翻译的来着），受检的异常是普通异常，就是你需要</span><span style="font-family:Calibri">catch</span><span style="font-family: SimSun">的来打日志或者补救的（这种做法叫吞掉异常），非受检的多数是</span><span style="font-family: Calibri">RuntimeException</span><span style="font-family:SimSun">，就是运行时异常，这类异常不建议</span><span style="font-family:Calibri">catch</span><span style="font-family:SimSun">，因为这个是程序</span><span style="font-family: Calibri">bug</span><span style="font-family:SimSun">，需要被人发现，所以建议抛出引起程序终止。</span><span style="font-family:Calibri">Blah~blah~ </span><span style="font-family:SimSun">这些都是老生常谈的话题，需要深入的点是有几个：</span></p>  <p style="margin:0in;font-family:SimSun;font-size:10.5pt">&nbsp;</p>  <p style="margin:0in;font-size:10.5pt"><span style="font-family:Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family:SimSun">第一，</span><span style="font-family:Calibri">Error</span><span style="font-family:SimSun">是建议到系统级别的错误的，包括虚拟机的，我们常见的就是</span><span style="font-family:Calibri">java.lang.VirtualMachineError</span><span style="font-family:SimSun">，这是一个</span><span style="font-family: Calibri">JVM</span><span style="font-family:SimSun">级别的抽象</span><span style="font-family:Calibri">Error</span><span style="font-family: SimSun">，如果你觉得没见过？那么不用奇怪，它的两个儿子你肯定见过：</span><span style="font-family: Calibri">OutOfMemoryError</span><span style="font-family:SimSun">和</span><span style="font-family:Calibri">StackOverflowError</span><span style="font-family:SimSun">。</span><span style="font-family:Calibri">Error</span><span style="font-family:SimSun">其实真没好说的，一般情况不建议捕获，程序员也用的较少，但是你看很多基础框架或者系统软件，都是有自定义</span><span style="font-family:Calibri">Error</span><span style="font-family: SimSun">的，所以当你的工作层次或者范围你能确定比较底层时，其实是可以自定义一些</span><span style="font-family:Calibri">Error</span><span style="font-family: SimSun">来控制程序的错误的。我这样说可能也不是很好理解，换个简单的话：你的架构设计中需要考虑到异常的处理，那么首先要对异常定级别，如果有可能有偏底层的异常时，或者是本不该出现且不建议用户（多数是依赖你的库进行开发的其他程序员）捕获时，定义为</span><span style="font-family:Calibri">Error</span><span style="font-family: SimSun">是个不错的选择。当然也不是说做上层开发的程序员就不能使用</span><span style="font-family: Calibri">Error</span><span style="font-family:SimSun">，只要你设计合理，你可以在必要时抛出</span><span style="font-family:Calibri">Error</span><span style="font-family: SimSun">来终止程序&#8212;&#8212;比如提醒你的老板再不加薪就</span><span style="font-family:Calibri">Error</span><span style="font-family:SimSun">到死：）</span></p>  <p style="margin:0in;font-family:SimSun;font-size:10.5pt">&nbsp;</p>  <p style="margin:0in;font-size:10.5pt"><span style="font-family:Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family:SimSun">第二，</span><span style="font-family:Calibri">Exception</span><span style="font-family:SimSun">分两类这事几乎人人皆知，受检的异常往往是</span><span style="font-family:Calibri">web</span><span style="font-family:SimSun">后端开发或者服务开发自定义的业务异常比如</span><span style="font-family:Calibri">BizServiceException</span><span style="font-family:SimSun">或者常见的</span><span style="font-family:Calibri">DAOException</span><span style="font-family:SimSun">，这些异常在开发定义时总是直接</span><span style="font-family:Calibri">extends Exception</span><span style="font-family:SimSun">，而忽视了究竟这些异常我们对它们的期望是什么，这里我想强调一点，我们在业务系统架构中考虑到异常机制，自定义的异常不是为了有异常而定义异常，一定对它本身是有期望的。我们对异常的一个基本期望是异常究竟该被谁捕获，如果被你的服务下游捕获，那么这必须是一个受检的异常，如果是系统自身需要，那么这个我个人认为是分阶段设计的，在初期，也就是未发布状态，这些</span><span style="font-family:Calibri">Exception</span><span style="font-family: SimSun">应该总是被抛出的，因为这样可以快速的让测试和质量控制人员发现系统崩溃的点。在发布阶段，异常可能需要被内部消化，这时受检异常就要提供给业务系统，让业务开发自行捕获异常。当然，好的系统架构可能会把</span><span style="font-family:Calibri">Exception</span><span style="font-family: SimSun">作为一个内部可见外部不可见的内容，而基于此完全封装一套</span><span style="font-family: Calibri">error code</span><span style="font-family:SimSun">对外，这应该算是比较友好的做法了，也是很多</span><span style="font-family:Calibri">API</span><span style="font-family:SimSun">设计时的标准规范。毕竟对外部透明，不要让用户看到你的</span><span style="font-family:Calibri">Exception</span><span style="font-family: SimSun">，这是非常友好的做法。</span></p>  <p style="margin:0in;font-family:SimSun;font-size:10.5pt">&nbsp;</p>  <p style="margin:0in;font-size:10.5pt"><span style="font-family:Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family:SimSun">第三，关于</span><span style="font-family: Calibri">catch</span><span style="font-family:SimSun">，就针对上面的第二点讲，吞异常这事不是没人干过，我们往往担心系统错误而一个</span><span style="font-family:Calibri">try catch </span><span style="font-family: SimSun">捕获所有</span><span style="font-family:Calibri">Exception</span><span style="font-family:SimSun">，有的甚至不够，还升一级，捕获</span><span style="font-family:Calibri">Throwable</span><span style="font-family: SimSun">，这应该是最糟糕的代码设计（但不幸的是在我现在开发的系统和曾经开发过的业务系统中，这类代码非常普遍）。开发人员不应该因为时间紧、赶进度等接口而忽视</span><span style="font-family:Calibri">Exception</span><span style="font-family: SimSun">，就拿最上层的业务开发举例，开发可能会调用各类服务、访问数据库、访问缓存和文件系统等等，而这些服务必然包含了各种异常，而</span><span style="font-family:Calibri">catch</span><span style="font-family: SimSun">一个</span><span style="font-family:Calibri">Exception</span><span style="font-family:SimSun">，试图通过吞噬异常保护系统或者页面正常访问，而打日志到后台，通过分析日志来偷偷的解决</span><span style="font-family:Calibri">bug</span><span style="font-family:SimSun">&#8230;&#8230;说起来真是汗毛倒竖。我的观点：如果有错误，那么让它尽早暴露出来，我们应该通过尽量多的测试和优化来避免错误，而不是偷偷的隐藏。事实也证明，日志里大量的</span><span style="font-family:Calibri">NPE</span><span style="font-family:SimSun">或者其他</span><span style="font-family:Calibri">RuntimeException</span><span style="font-family:SimSun">存在，但是无人问津，&#8220;系统不是好好的吗？&#8221;，&#8220;页面不是没问题吗&#8221;这样的说辞可以让开发看起来毫无责任，但是这为系统长期的维护和后续的扩展都带来了无尽的烦恼和坑。</span></p>  <p style="margin:0in;font-family:SimSun;font-size:10.5pt">&nbsp;</p>  <p style="margin:0in;font-size:10.5pt"><span style="font-family:Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family:SimSun">综上，我个人的经验告诉我几点对待</span><span style="font-family:Calibri">Exception</span><span style="font-family: SimSun">的方法：</span></p>  <p style="margin:0in;font-size:10.5pt"><span style="font-family:Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1</span><span style="font-family:SimSun">，花时间了解涉及到的每个服务和方法所可能抛出的异常。事实往往是理解异常的关系和机制其实不花时间，了解后再开发，你会比别人知道更多的异常点，这能保证你程序的健壮性；</span></p>  <p style="margin:0in;font-size:10.5pt"><span style="font-family:Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2</span><span style="font-family:SimSun">，无论你在服务开发还是服务使用层级，都要尝试或者想到封装异常，提供友好错误设计的方案，最简单的是自定义一个业务</span><span style="font-family:Calibri">Exception</span><span style="font-family: SimSun">来封装。</span></p>  <p style="margin:0in;font-size:10.5pt"><span style="font-family:Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3</span><span style="font-family:SimSun">，不要在你的方法开始</span><span style="font-family: Calibri">try</span><span style="font-family:SimSun">，结束时</span><span style="font-family:Calibri">catch</span><span style="font-family: SimSun">，这防御性太强了，很美品位。</span></p>  <p style="margin:0in;font-size:10.5pt"><span style="font-family:Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4</span><span style="font-family:SimSun">，前三点可能都是错的，因为我自己也没有完全实践：）</span></p> <div id="haloword-lookup" class="ui-widget-content ui-draggable"><div id="haloword-title"><span id="haloword-word"></span><a herf="#" id="haloword-pron" class="haloword-button" title="发音"></a><audio id="haloword-audio"></audio><div id="haloword-control-container"><a herf="#" id="haloword-add" class="haloword-button" title="加入单词表"></a><a herf="#" id="haloword-remove" class="haloword-button" title="移出单词表"></a><a href="#" id="haloword-open" class="haloword-button" title="查看单词详细释义" target="_blank"></a><a herf="#" id="haloword-close" class="haloword-button" title="关闭查询窗"></a></div></div><div id="haloword-content"></div></div><img src ="http://www.blogjava.net/changedi/aggbug/423050.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2015-02-26 15:19 <a href="http://www.blogjava.net/changedi/archive/2015/02/26/423050.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何高效的实现一个计数器map</title><link>http://www.blogjava.net/changedi/archive/2013/01/20/394460.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Sun, 20 Jan 2013 04:40:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2013/01/20/394460.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/394460.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2013/01/20/394460.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/394460.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/394460.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 这本是多年前一个stackoverflow上的一个讨论，回答中涉及到了多种计数方法。对于一个key-value结构的map，我们在编程时会经常涉及到key是对象，而value是一个integer或long来负责计数，从而统计多个key的频率。 面对这样一个基本需求，可能有很多种实现。比如最基本的使用jdk的map直接实现&#8212;&#8212;value是一个integer或者long。其基本...&nbsp;&nbsp;<a href='http://www.blogjava.net/changedi/archive/2013/01/20/394460.html'>阅读全文</a><img src ="http://www.blogjava.net/changedi/aggbug/394460.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2013-01-20 12:40 <a href="http://www.blogjava.net/changedi/archive/2013/01/20/394460.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HBase的一些应用设计tip</title><link>http://www.blogjava.net/changedi/archive/2013/01/02/393697.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Wed, 02 Jan 2013 11:00:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2013/01/02/393697.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/393697.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2013/01/02/393697.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/393697.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/393697.html</trackback:ping><description><![CDATA[<p>1，对于HBase的存储设计，要考虑它的存储结构是：rowkey+columnFamily:columnQualifier+timestamp(version)+value = KeyValue in HBase，一个KeyValue依次按照rowkey，columnkey和timestamp有序。一个rowkey加一个column信息定位了hbase表的一个逻辑的行结构。</p> <p><a href="http://www.blogjava.net/images/blogjava_net/changedi/Windows-Live-Writer/HBasetip_10C32/0XJJ%7B2%25~G~%5BG%5DJBPMW%7DYE~A_2.jpg"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="0XJJ{2%~G~[G]JBPMW}YE~A" border="0" alt="0XJJ{2%~G~[G]JBPMW}YE~A" src="http://www.blogjava.net/images/blogjava_net/changedi/Windows-Live-Writer/HBasetip_10C32/0XJJ%7B2%25~G~%5BG%5DJBPMW%7DYE~A_thumb.jpg" width="244" height="135"></a>  <p>2，从逻辑存储结构到实际的物理存储结构要经历一个fold过程，所有的columnFamily下的内容被有序的合并，因为HBase把一个ColumnFamily存储为一个StoreFile。  <p>3，把HBase的查询等价为一个逐层过滤的行为，那么在设计存储时就应该明白，使设计越趋向单一的keyvalue性能会越好；如果是因为复杂的业务逻辑导致查询需要确定rowkey、column、timestamp，甚至更夸张的是用到了HBase的Filter在server端做value的处理，那么整个性能会非常低。  <p>4，因此在表结构设计时，HBase里有tall narrow和flat wide两种设计模式，前者行多列少，整个表结构高且窄；后者行少列多，表结构平且宽；但是由于HBase只能在行的边界做split，因此如果选择flat wide的结构，那么在特殊行变的超级大（超过file或region的上限）时，那么这种行为会导致compaction，而这样做是要把row读内存的~~因此，强烈推荐使用tall narrow模式设计表结构，这样结构更趋近于keyvalue，性能更好。  <p>5，一种优雅的行设计叫做partial row scan，我们一般rowkey会设计为&lt;key1&gt;-&lt;key2&gt;-&lt;key3&gt;...，每个key都是查询条件，中间用某种分隔符分开，对于只想查key1的所有这样的情况，在不使用filter的情况下（更高性能），我们可以为每个key设定一个起始和结束的值，比如key1作为开始，key1+1作为结束，这样scan的时候可以通过设定start row和stop row就能查到所有的key1的value，同理迭代，每个子key都可以这样被设计到rowkey中。  <p>6，对于分页查询，推荐的设计方式也不是利用filter，而是在scan中通过offset和limit的设定来模拟类似RDBMS的分页。具体过程就是首先定位start row，接着跳过offset行，读取limit行，最后关闭scan，整个流程结束。  <p>7，对于带有时间范围的查询，一种设计是把时间放到一个key的位置，这样设计有个弊端就是查询时一定要先知道查询哪个维度的时间范围值，而不能直接通过时间查询所有维度的值；另一种设计是把timestamp放到前面，同时利用hashcode或者MD5这样的形式将其打散，这样对于实时的时序数据，因为将其打散导致自动分到其他region可以提供更好的并发写优势。  <p>8，对于读写的平衡，下面这张图更好的说明了key的设计：salting等价于hash，promoted等价于在key中加入其他维度，而random就是MD这样的形式了。  <p><a href="http://www.blogjava.net/images/blogjava_net/changedi/Windows-Live-Writer/HBasetip_10C32/VN%7BYX%60@%5B2P9AQ%5B@(2U8N9%7B0_2.jpg"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="VN{YX`@[2P9AQ[@(2U8N9{0" border="0" alt="VN{YX`@[2P9AQ[@(2U8N9{0" src="http://www.blogjava.net/images/blogjava_net/changedi/Windows-Live-Writer/HBasetip_10C32/VN%7BYX%60@%5B2P9AQ%5B@(2U8N9%7B0_thumb.jpg" width="244" height="152"></a>  <p>9，还有一种高级的设计方式是利用column来当做RDBMS类似二级索引的应用设计，rowkey的存储达到一定程度后，利用column的有序，完成类似索引的设计，比如，一个CF叫做data存放数据本身，ColumnQualifier是一个MD5形式的index，而value是实际的数据；再建一个CF叫做index存储刚才的MD5，这个index的CF的ColumnQualifier是真正的索引字段（比如名字或者任意的表字段，这样可以允许多个），而value是这个索引字段的MD5。每次查询时就可以先在index里找到这个索引（查询条件不同，选择的索引字段不同），然后利用这个索引到data里找到数据，两次查询实现真正的复杂条件业务查询。</p> <p>10，实现二级索引还有其他途径，比如：1，客户端控制，即一次读取将所有数据取回，在客户端做各种过滤操作，优点自然是控制力比较强，但是缺点在性能和一致性的保证上；2，Indexed-Transactional HBase，这是个开源项目，扩展了HBase，在客户端和服务端加入了扩展实现了事务和二级索引；3，Indexed-HBase；4，Coprocessor。</p> <p>11，HBase集成搜索的方式有多种：1，客户端控制，同上；2，Lucene；3，HBasene，4，Coprocessor。</p> <p>12，HBase集成事务的方式：1，ITHBase；2，ZooKeeper，通过分布式锁。</p> <p>13，timestamp虽然叫这个名字，但是完全可以存放任何内容来形成用户自定义的版本信息。</p><img src ="http://www.blogjava.net/changedi/aggbug/393697.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2013-01-02 19:00 <a href="http://www.blogjava.net/changedi/archive/2013/01/02/393697.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HBase一些tip</title><link>http://www.blogjava.net/changedi/archive/2012/12/28/393577.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Fri, 28 Dec 2012 05:59:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2012/12/28/393577.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/393577.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2012/12/28/393577.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/393577.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/393577.html</trackback:ping><description><![CDATA[<p>1，row是有序的，可以看做RDBMS的一级索引</p> <p>2，一个列簇CF的所有列存储在一个HFile里</p> <p>3，CF要在建表时定义，少变化，更不要建太多</p> <p>4，version和timestamp是对应的，每个cell有不同的版本，就说明是在不同的timestamp存储的，如果重复的timestamp，那么就说明是一个版本</p> <p>5，定位一个数据，需要rowkey，column和timestamp，即SortedMap&lt;RowKey,List&lt;SortedMap&lt;Column,List&lt;Value,Timestamp&gt;&gt;&gt;&gt;</p> <p>6，初始一个region，之后自动sharding，一台server大概10-1000个region，每个region大小为1-2GB</p> <p>7，每一个HFile有一个block index，可以只用一次disk seek完成查询</p> <p>8，数据更新时要写commit log即常说的WAL——write-ahead-log，每次操作都会记录在内存memstore，当memstore满了以后自动flush到HFile的disk，在做flush时，reader和writer不被阻塞，可以继续服务（这是因为，flush做的是一个滚动操作，老的满的数据flush到磁盘，而完成后的新的空的memstore继续服务，因为memstore已经是按key的顺序排好的，所以不需要额外操作，只要写和flush就行）</p> <p>9，删除操作是逻辑的，因为存储文件不可变，所以会放置一个删除标记到每个键值对</p> <p>10，通过compaction将小的hfile合并为大的，compaction有两种类型：minor和major，前者通过多路归并完成多个小文件到少量大文件的合并；后者重写整个CF到一个新的文件，在做compaction的时候可以把之前标记过delete的kv pair放弃，即不写到新的文件</p> <p>11，HBase由客户端库，一台master server和多台region server组成，master负责regions的负载均衡，master不存储数据，只做调度</p> <p>12，扫表scan是线性时间的，查询是对数时间的，而极端情况的查询是常数时间的（使用bloom filter）</p> <p>13，在put时，要注意flush的时间，没有flush的数据是不会被get到的，从源码可以了解到，flush有两种情况，一是显示调用flushCommits()；另外就是到了client端的writebuffer上限触发，hbase默认client的writebuffer size是2M，可以通过配置去修改</p> <p>14，HBase的client里，caching针对行模式（返回多少行），而batching针对列模式（返回多少列），都是在scan时提高效率（减少RPC）的方法</p> <p>15，用HBase的接口时，通过Filter的使用可以减少网络传输的数据量，从而减轻在客户端使用的时间成本，get或scan你想要的东西，不要的东西直接在server通过filter过滤到</p> <p>16，在重用Configuration时，要记得每次都会增加一个引用数，因此在使用完后最好调用close方法将connection释放掉</p> <p>17，HBase的block size和hdfs的block size是不一样的，前者是指处理block操作时的数据大小，默认是64KB，而后者是用来分布式存储文件，默认大小是64MB</p> <p>18，RDBMS和Hbase的区别：存储结构b树或b+树，Hbase采用类似LSM树的做法（Log-Structured Merge Trees)，LSMT的简单过程描述是，数据首先被顺序存储到一个log file里，在写满后将这些数据更新到in memory store，然后flush有序key value pair到磁盘，生成一个文件。磁盘文件的组织形式类似B树，但是对于磁盘顺序访问做了优化，其中每个文件都被完全填充为单页或多页的block，而这些文件的update本身是rolling merge策略，即系统在直到block写满的时候才将in memory的数据打包。因为flush是经常进行的，导致系统中会有很多的文件，一个后台进程在不断的合并小文件到大文件从而将磁盘seek缩减到少量的文件范围。于此同时，磁盘的树也可以进行分裂操作，将大文件分割为若干文件以便扩展更新。而所有的存储都是key有序的。</p> <p>19，Hbase查询时，先到in memory里查，再到on disk里查，这样的行为可以保证了一致性；删除时是逻辑删除，先将delete标志打上，后期在异步重写的时候，标记了delete的key会被最终物理删除。</p> <p>20，HBase有两类文件，一类用于WAL的log，另一类用于数据存储。</p> <p>21，一般HBase的访问流程是：先到zookeeper quorum取row key，通过从zk中查询-ROOT-里的服务器名字实现；接着拿着取到的服务器名字去region server查询持有.META. 表region并且包含了rowkey的server名字；最后查询.META.服务器，获取到包含对应rowkey region的server name。一旦获取这些信息，客户端将其缓存起来，以后就知道如何到哪里去查找并且直接和region server联系了。</p> <p>22，在源码级别，HMaster负责分配HRegionServer，HRegionServer维护一个HRegion，当HRegion建立时，为每张表的每个HColumnFamily建立一个Store，每个Store包含一个或者多个StoreFile（轻量级的HFile包装），一个Store同时也有一个MemStore，还有一个HRegionServer共享的HLog。</p> <p>23，在做put操作时，region server先检查本次put是否需要写WAL，一旦数据写入WAL，那么它就进入MemStore，同时检查MemStore是否满，如果是，做一次flush，写到一个HFile里存到HDFS，同时维护一个最后一次写入的序列号，以便系统知道到目前为止的持久数据信息。</p> <p>24，在HFile被持久化后，log文件就不再有用了，这时自动从.log目录移动到.oldlog目录（当然也有配置可以配置滚动周期），默认10分钟后由HBase自动删除。</p> <p>25，每个table有一个目录，在这个目录里，每个列族有一个自己的目录。</p> <p>26，region split发生在当一个region的存储文件大小达到配置的hbase.hregion.max.filesize时进行。具体过程就是：系统为新的region创建两个原region的索引文件，每个各持有原来一半的数据，region server在父region创建一个splits目录，接着关闭region拒绝新请求，然后再splits目录里构建必要的新的region目录文件结构存放刚才的两个half 大小的文件。成功后，系统将两个新的region目录添加到表目录，更新.META.表以表明父region做了split，同时表明新的两个region是什么。</p> <p>27，HFile基于Hadoop的TFile类型，模仿了BigTable的SSTable格式；文件是变长的，其中定长的部分是file info 和trailer，而数据以keyvalue存入data块，默认大小64KB，而HDFS默认块大小是64MB，两者没有关系。结构类似：</p> <p><a href="http://www.blogjava.net/images/blogjava_net/changedi/Windows-Live-Writer/HBase_AB30/YYYY~H0S6~ALGP4DPBEO6DS_2.jpg"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="YYYY~H0S6~ALGP4DPBEO6DS" border="0" alt="YYYY~H0S6~ALGP4DPBEO6DS" src="http://www.blogjava.net/images/blogjava_net/changedi/Windows-Live-Writer/HBase_AB30/YYYY~H0S6~ALGP4DPBEO6DS_thumb.jpg" width="244" height="86"></a>  <p>28，KeyValue在HFile中就是一个简单的字节序列，结构类似</p> <p><a href="http://www.blogjava.net/images/blogjava_net/changedi/Windows-Live-Writer/HBase_AB30/A%5BBN%7D2%604~5B%5DF7@$83%25Z@3S_2.jpg"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="A[BN}2`4~5B]F7@$83%Z@3S" border="0" alt="A[BN}2`4~5B]F7@$83%Z@3S" src="http://www.blogjava.net/images/blogjava_net/changedi/Windows-Live-Writer/HBase_AB30/A%5BBN%7D2%604~5B%5DF7@$83%25Z@3S_thumb.jpg" width="244" height="54"></a>  <p>29，WAL是容灾的重要武器，类似mysql的binlog，记录了所有的变化，这就可以保证在数据进入memstore后而没有持久这段时间因为突发原因导致数据丢失时候的容灾。流程如下：  <p><a href="http://www.blogjava.net/images/blogjava_net/changedi/Windows-Live-Writer/HBase_AB30/8D%60N7YP%5D%25WQ%7DY9LO3H0%7D$CL_2.jpg"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="8D`N7YP]%WQ}Y9LO3H0}$CL" border="0" alt="8D`N7YP]%WQ}Y9LO3H0}$CL" src="http://www.blogjava.net/images/blogjava_net/changedi/Windows-Live-Writer/HBase_AB30/8D%60N7YP%5D%25WQ%7DY9LO3H0%7D$CL_thumb.jpg" width="244" height="132"></a>  <p>30，在上面这图中，有LogSyncer和LogRoller，前者是默认关闭的，如果开启后，那么每次写入都会触发一次sync，将update同步到其他的server，而且还是pipeline形式的顺序写，不是多路复写；后者负责滚动记录log，可以设置时间间隔每隔一定时间来滚动日志，也可以根据大小来滚动，这个都可以配置。  <p>31，容灾恢复数据的一项重要措施是replay日志，也就是重放WAL；日志回放有两种触发条件：一是集群启动时，二是服务器fail时；当master启动时，检查.log目录里是否有log文件，有的话则做log splitting——读入log然后根据记录的region将其分配到新文件。  <p>32，get和scan在近几个版本中实现等价，因为对于特定行和列没有索引的概念，而最小的访问单元是block，因此如果要请求数据，那么一定会加载一个RegionServer的实例的block然后扫描它，Get其实就是一个确定了row的scan。  <p>33，在查询时，一个周期是这样的：因为客户端缓存region的，所以，会先到自己的cache中查找对应region，找到的话则直接访问（1次网络请求即可），如果找不到，则到region server的.META.中去取（3次），如果再找不到，则到-ROOT-找.META.信息（5次），再找不到，只好去zk中取（7次）（这是第21条tip的逆过程） 。 <p>34，region有9种状态（offline,pending open,opening,open,pending close,closing,closed,splitting,split），状态转移可以再master做，也可以在持有region的region server上做。集群通过zk来跟踪状态变化。 <p>35，Hbase的复制策略为容灾提供了高可用，基本模式是：master-push，因为WAL的存在，跟踪复制变得很容易；一个master cluster可以复制到任意数量的slave clusters，region server负责自己的复制。 <p><a href="http://www.blogjava.net/images/blogjava_net/changedi/Windows-Live-Writer/HBase_AB30/F9%7BB6EB%60L4ASJ%5BW5(9D1WZP_2.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="F9{B6EB`L4ASJ[W5(9D1WZP" border="0" alt="F9{B6EB`L4ASJ[W5(9D1WZP" src="http://www.blogjava.net/images/blogjava_net/changedi/Windows-Live-Writer/HBase_AB30/F9%7BB6EB%60L4ASJ%5BW5(9D1WZP_thumb.jpg" width="244" height="173"></a><img src ="http://www.blogjava.net/changedi/aggbug/393577.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2012-12-28 13:59 <a href="http://www.blogjava.net/changedi/archive/2012/12/28/393577.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JVM学习笔记（3）&amp;mdash;&amp;mdash;连接模型（上）</title><link>http://www.blogjava.net/changedi/archive/2012/09/21/388255.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Fri, 21 Sep 2012 06:17:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2012/09/21/388255.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/388255.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2012/09/21/388255.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/388255.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/388255.html</trackback:ping><description><![CDATA[<p>很重要的内容，可能分几天记录</p> <ol> <li>jvm为每个装载的类和接口保存一份独立的常量池。  <li>动态加载最常用的是Class.forName()，这个方法有两个重载版本：Class.forName(String name)和Class.forName(String name, boolean init, ClassLoader loader)。它们均内部调用了forName0(String name, boolean initialize,ClassLoader loader)，这是个native方法。前者调用传递的参数是name、true和启动类加载器。name是要加载类的全限定名，init表明是否要初始化，如果这个类已经被初始化过，这样的加载即使init是true也不会被再初始化，loader是要加载的类加载器，null的话使用默认的启动类加载器。  <li>另一种方式动态加载类就是ClassLoader.loadClass()方法，这个方法也是两个重载版本：ClassLoader.loadClass(String name)和ClassLoader.loadClass(String name, boolean resolve)，其中前者调用了后者，resolve传递false，resolve表示是否在装载时执行该类的连接。  <li>loadClass不初始化类，而forName初始化类，因此如果是需要动态加载类，该类马上被用到那么应该初始化，loadClass只加载，有可能出问题，但是会有安全考虑。  <li>常量池解析：上一篇日志也记录到了，在完成验证和准备后，要进入解析阶段，而解析主要做的就是解析常量池，把符号引用转为直接引用。  <li>对常量池CONSTANT_Class_info的解析，主要解析类和接口的符号引用，有两种入口：1）数组类，指向数组类的符号引用最后解析为一个Class的实例，如果数组的元素类型是引用类型，虚拟机用当前类加载器解析类型，如果数组是基本类型，虚拟机会立即创建关于那个元素类型的新数组类，确定维数，然后创建Class实例表示这个类，由启动类加载器定义。2）非数组类，第一步，装载类型或者任何超类型，先确定引用类型已经被当前类装载器装载过，虚拟机保证每一个类装载器都只装载一个给定名字的类型，这个步骤只是确定类型是否被装载，期间可能抛出的异常有：NoClassDefFoundError，ClassNotFoundError，ClassFormatError，UnsupportedClassVersionError，LinkageError，ClassCircularityError，IncompatibleClassChangeError；第二步，检查访问权限，如果发起引用的类型没有访问被引用类型的权限，jvm抛出IllegalAccessError；第三步，校验类型，出错则抛出VerifyError；第四步，准备类型，前面讲过，就是为不同类型分配内存；第五步，可选的解析类型，第六步，初始化。  <li>对常量池CONSTANT_Fieldref_info的解析，完成对Class_info的解析后，JVM按照一定顺序搜索字段：在被引用的类型中查找具有指定名字和类型的字段，找不到，则检查类型直接实现或扩展的接口，递归检查其超接口，如果还找不到，检查类型直接的超类，并递归检查其所有超类，如果找不到，则失败，抛出NoSuchFieldError异常。找到字段，但是没有访问权限，抛出IllegalAccessError异常。解析完后标记该常量池入口为已解析，并在数据中放入指向这个字段的直接引用。  <li>对常量池CONSTANT_Methodref_info的解析，完成对Class_info的解析后，JVM按照一定顺序搜索方法：如果被解析类型是一个接口，虚拟机抛出IncompatibleClassChangeError异常，如果是个类，JVM检查被引用的类是否有一个方法符合指定的名字以及描述符，如果不符合，找该类的超类，并递归找所有超类，还是找不到，虚拟机检查该类是否直接实现了任何接口，并递归检查接口的超接口，还找不到，则抛出NoSuchMethodError异常，如果找到但是没有访问权限，抛出IllegalAccessError异常。解析完后标记常量池入口为已解析，并在数据中放入指向这个方法的直接引用。  <li>对常量池CONSTANT_InterfaceMethodref_info的解析，完成对Class_info的解析后，JVM按照一定顺序在接口和它的超类型中搜索方法：如果被解析的类型不是接口是类，抛出IncompatibleClassChangeError异常，否则检查接口是否有符合指定名字和限定符的方法，如果没有，JVM检查接口的直接超接口并递归检查所有超接口以及java.lang.Object类来找，如果还没有，抛出NoSuchMethodError异常。解析完后标记常量池入口为已解析，并在数据中放入指向这个方法的直接引用。</li></ol><img src ="http://www.blogjava.net/changedi/aggbug/388255.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2012-09-21 14:17 <a href="http://www.blogjava.net/changedi/archive/2012/09/21/388255.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JVM学习笔记（2）&amp;mdash;&amp;mdash;类型生命周期</title><link>http://www.blogjava.net/changedi/archive/2012/09/19/388086.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Wed, 19 Sep 2012 10:13:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2012/09/19/388086.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/388086.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2012/09/19/388086.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/388086.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/388086.html</trackback:ping><description><![CDATA[<p>直奔主题吧</p> <ol> <li>一个java类经过装载、连接和初始化三步达到程序可用状态，其中连接又包含验证、准备和可选的解析过程，验证是检查数据格式、准备是分配内存、解析负责把常量池的符号引用转换为直接引用。  <li>jvm必须在每个类或接口首次主动使用时初始化，有六种主动使用场景：1）创建某个类的新实例，2）调用某个类的静态方法，3）使用某个类或接口的静态字段，用final修饰的静态字段除外，它被初始化为一个编译时的常量表达式，4）调用Java api中的某些反射方法，5）初始化某个类的子类，6）虚拟机启动时某个被标明为启动类的类（含有main方法的类）。  <li>某个类要初始化，其所有的祖先类必须之前被初始化；接口则不同，只有在某个接口声明的非常量字段被使用时，该接口才初始化。  <li>类装载的三个基本动作：通过完全限定名找到二进制数据流，解析为方法区内的数据结构，创建一个该类型的java.lang.Class的实例。  <li>类装载有可能存在预先装载，在预先装载时出问题，会抛出一个LinkageError的异常。  <li>在准备阶段，内存分配是初始化为默认值的，而不是实际的初始值。默认值列表如下：  <table border="0" cellspacing="0" cellpadding="2" width="400"> <tbody> <tr> <td valign="top" width="200">类型</td> <td valign="top" width="200">默认初始值</td></tr> <tr> <td valign="top" width="200">int</td> <td valign="top" width="200">0</td></tr> <tr> <td valign="top" width="200">long</td> <td valign="top" width="200">0L</td></tr> <tr> <td valign="top" width="200">short</td> <td valign="top" width="200">(short)0</td></tr> <tr> <td valign="top" width="200">char</td> <td valign="top" width="200">'\u0000'</td></tr> <tr> <td valign="top" width="200">byte</td> <td valign="top" width="200">(byte)0</td></tr> <tr> <td valign="top" width="200">boolean</td> <td valign="top" width="200">false</td></tr> <tr> <td valign="top" width="200">reference</td> <td valign="top" width="200">null</td></tr> <tr> <td valign="top" width="200">float</td> <td valign="top" width="200">0.0f</td></tr> <tr> <td valign="top" width="200">double</td> <td valign="top" width="200">0.0d</td></tr></tbody></table> <li>在准备和解析完后，才进入初始化阶段，为变量赋予真正的初始值。  <li>初始化类的步骤：1）如果类存在直接超类，且直接超类还没有被初始化，就先初始化直接超类。2）如果类存在一个类初始化方法，就执行此方法。  <li>第一个被初始化的类永远都是Object。  <li>所有的类变量初始化语句和类型的静态初始化器都被java编译器收集在一起，放到一个特殊的方法中——&lt;clinit&gt;。  <li>如果接口包含任何不能在编译时被解析成为一个常量的字段初始化语句，接口就会拥有一个&lt;clinit&gt;方法。  <li>类变量如果直接赋常量值，那么类是不会初始化的。  <li>类实例化的四种途径：1）new操作符。2）调用Class或Constructor的newInstance()方法。3）调用任何现有对象的clone()方法。4）通过ObjectInputStream的readObject()方法反序列化。  <li>JVM为它编译的每一个类都至少生成一个实例初始化方法&lt;init&gt;。  <li>使用启动类装载器装载的类，永远都不会被垃圾收集。</li></ol><img src ="http://www.blogjava.net/changedi/aggbug/388086.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2012-09-19 18:13 <a href="http://www.blogjava.net/changedi/archive/2012/09/19/388086.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JVM学习笔记（1）&amp;mdash;&amp;mdash;java class</title><link>http://www.blogjava.net/changedi/archive/2012/09/17/387915.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Mon, 17 Sep 2012 08:38:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2012/09/17/387915.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/387915.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2012/09/17/387915.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/387915.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/387915.html</trackback:ping><description><![CDATA[<p>例子主要是《深入jvm》中的例子，class文件是其中的act.class，java源文件是：</p> <p>class Act { </p> <p>&nbsp;&nbsp;&nbsp; public static void doMathForever() { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i = 0; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (;;) { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i += 1; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i *= 2; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br>&nbsp;&nbsp;&nbsp; } <br>} </p> <p>class文件hex形式： </p> <p>CA FE BA BE 00 03 00 2D&nbsp; 00 11 07 00 07 07 00 10 <br>0A 00 02 00 04 0C 00 06&nbsp; 00 05 01 00 03 28 29 56 <br>01 00 06 3C 69 6E 69 74&nbsp; 3E 01 00 03 41 63 74 01 <br>00 08 41 63 74 2E 6A 61&nbsp; 76 61 01 00 04 43 6F 64 <br>65 01 00 0D 43 6F 6E 73&nbsp; 74 61 6E 74 56 61 6C 75 <br>65 01 00 0A 45 78 63 65&nbsp; 70 74 69 6F 6E 73 01 00 <br>0F 4C 69 6E 65 4E 75 6D&nbsp; 62 65 72 54 61 62 6C 65 <br>01 00 0E 4C 6F 63 61 6C&nbsp; 56 61 72 69 61 62 6C 65 <br>73 01 00 0A 53 6F 75 72&nbsp; 63 65 46 69 6C 65 01 00 <br>0D 64 6F 4D 61 74 68 46&nbsp; 6F 72 65 76 65 72 01 00 <br>10 6A 61 76 61 2F 6C 61&nbsp; 6E 67 2F 4F 62 6A 65 63 <br>74 00 20 00 01 00 02 00&nbsp; 00 00 00 00 02 00 09 00 <br>0F 00 05 00 01 00 09 00&nbsp; 00 00 30 00 02 00 01 00 <br>00 00 0C 03 3B 84 00 01&nbsp; 1A 05 68 3B A7 FF F9 00 <br>00 00 01 00 0C 00 00 00&nbsp; 12 00 04 00 00 00 05 00 <br>02 00 07 00 05 00 08 00&nbsp; 09 00 06 00 00 00 06 00 <br>05 00 01 00 09 00 00 00&nbsp; 1D 00 01 00 01 00 00 00 <br>05 2A B7 00 03 B1 00 00&nbsp; 00 01 00 0C 00 00 00 06 <br>00 01 00 00 00 02 00 01&nbsp; 00 0E 00 00 00 02 00 08 </p> <ol> <li>java的class文件是8位二进制流，数据项按顺序存放，无间隔，占多字节的数据项以高位在前的顺序分几个字节存放；  <li>java class基本类型：u1,u2,u4,u8，分别对应：1,2,4,8字节的无符号类型；  <li>java class file表格展示：（太大了，来个url自己看吧，<a href="http://en.wikipedia.org/wiki/Java_class_file">wikipedia</a>）  <li>表项详解：1）magic（魔数）：说白了就是cafebabe，本来java就是咖啡嘛，这4个字节用来区分是否是java的class文件，有则是；2）minor_version&amp;major_version：两个字节的minor和两个字节的major，以上为例就是minor：3，major：2D（JDK 1.1）；3）再之后就是常量池了，2个字节表示constant_pool_count，本例是17，表示class文件中常量池中的项数（比实际的大1），接着就是常量池，连续的constant_pool_count-1个字节存储常量池各个入口，常量池入口项解释见本文第5条笔记；4）在之后的是access_flags：2个字节表示访问类型，是类还是接口，是public还是private，abstract或者final等等，标志位具体定义见本文第6条笔记，本例是00 20，表示老版本ACC_SUPER；5)之后是this_class，这是2字节的一个对常量池的索引，本例是00 01，即本例的自身类叫做Act；6）之后就是super_class，也是一个2字节常量池索引，指向父类的名字， 本例是00 02，即java.lang.Object；7）interface_count和interfaces：interface_count指出本文件有多少直接实现或者由接口扩展的父接口的数量，本例没有，故为00 00，之后是interfaces的具体内容，实际的项数就是之前的interface_count数，因为interface_count=0，所以本例的interfaces就没有值；8）接下来是fields_count和fields：对本类所声明的字段的描述，首先是个2字节的count，本例是00 00，所以后续也没有fields的项；9）再之后就是methods_count和methods了，count是一个2字节数据，本例的method_count是00 02，这个count只表示在类或接口中显式定义的方法，继承的方法不计数，count后是method_info的表，包含方法的一些信息如方法名、描述符等，本例中00 09表明方法是public（01）&amp;static（08），00 0F是方法名的常量池入口，即常量池的第15项doMathForever，再下来00 05是方法描述符常量池入口，即常量池第5项：()V，然后00 01是属性表的count数，表示1项属性，接下来是00 09表示属性表的常量池入口即常量池第9项Code，接下来的4个字节00 00 00 30表示code属性长度：48字节，接着00 02是操作数最大数，然后00 01是局部变量存储长度，这里方法里只有一个变量i，所以是1，然后00 00 00 0c是code字节码长度12，然后的12个字节就是字节码code了，再后的00 00是异常数，之后异常栈数是0，跳过，就是00 01的属性数，然后00 0C指向常量池的第12项即LineNumberTable，这是一个code属性，之后的00 00 00 12是属性长度，再后的00 04是line_number_info表的项数，接下来的4项（每项4字节）表示line_number_info，00 00 表示代码偏移量，00 05表示代码行号，后面的类似；10）最后是attributes_count和attributes，表明了类的属性，属性比较特殊，jvm定义了两种属性：SourceCode和InnerClass。  <li>常量池各个标志解读（来源wikipedia）<a href="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/JVM1javaclass_A81F/image_2.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/JVM1javaclass_A81F/image_thumb.png" width="541" height="203"></a> ，这里详解一下本例中的常量池，常量池是 <pre>cp_info
       {
           tag;
           info[];
       }</pre><pre>类似这样的结构，先有一个无符号byte作为tag标志，对应表格中的数据，额外的info字节数组存储对应的数据index.<br>我以表格的形式列出常量池的所有数据，应该算一目了然了吧：</pre>
<li>
<table border="0" cellspacing="0" cellpadding="2" width="567">
<tbody>
<tr>
<td valign="top" width="73">常量index</td>
<td valign="top" width="43">标志</td>
<td valign="top" width="107">标志内容</td>
<td valign="top" width="46">字节</td>
<td valign="top" width="150">具体数据</td>
<td valign="top" width="146">实际含义</td></tr>
<tr>
<td valign="top" width="73">1</td>
<td valign="top" width="43">07</td>
<td valign="top" width="107">00 07</td>
<td valign="top" width="46">2</td>
<td valign="top" width="150">class reference</td>
<td valign="top" width="146">常量池第7项是该class的内容</td></tr>
<tr>
<td valign="top" width="73">2</td>
<td valign="top" width="43">07</td>
<td valign="top" width="107">00 10</td>
<td valign="top" width="46">2</td>
<td valign="top" width="150">class reference</td>
<td valign="top" width="146">常量池第16项是该class的内容</td></tr>
<tr>
<td valign="top" width="73">3</td>
<td valign="top" width="43">0A</td>
<td valign="top" width="107">00 02 00 04</td>
<td valign="top" width="46">4</td>
<td valign="top" width="150">method ref</td>
<td valign="top" width="146">两个index，前两个字节表示池内的class索引位置，后两个字节是名字和类型描述</td></tr>
<tr>
<td valign="top" width="73">4</td>
<td valign="top" width="43">0C</td>
<td valign="top" width="107">00 06 00 05</td>
<td valign="top" width="46">4</td>
<td valign="top" width="150">name &amp; type</td>
<td valign="top" width="146">就是第3项方法指向的名字和类型的index</td></tr>
<tr>
<td valign="top" width="73">5</td>
<td valign="top" width="43">01</td>
<td valign="top" width="107">00 03</td>
<td valign="top" width="46">2+x</td>
<td valign="top" width="150">x个utf-8字符，此处x=3</td>
<td valign="top" width="146">实际值：()V，表示type（第三项方法的类型，具体含义参见描述符定义）</td></tr>
<tr>
<td valign="top" width="73">6</td>
<td valign="top" width="43">01</td>
<td valign="top" width="107">00 06</td>
<td valign="top" width="46">2+x</td>
<td valign="top" width="150">x=6</td>
<td valign="top" width="146">实际值：&lt;init&gt;，表示name（第三项方法的名字）</td></tr>
<tr>
<td valign="top" width="73">7</td>
<td valign="top" width="43">01</td>
<td valign="top" width="107">00 03</td>
<td valign="top" width="46">2+x</td>
<td valign="top" width="150">x=3</td>
<td valign="top" width="146">实际值：Act，第一项指向的具体字符内容</td></tr>
<tr>
<td valign="top" width="73">8</td>
<td valign="top" width="43">01</td>
<td valign="top" width="107">00 08</td>
<td valign="top" width="46">2+x</td>
<td valign="top" width="150">x=8</td>
<td valign="top" width="146">实际值：Act.java，</td></tr>
<tr>
<td valign="top" width="73">9</td>
<td valign="top" width="43">01</td>
<td valign="top" width="107">00 04</td>
<td valign="top" width="46">2+x</td>
<td valign="top" width="150">x=4</td>
<td valign="top" width="146">实际值：Code</td></tr>
<tr>
<td valign="top" width="73">10</td>
<td valign="top" width="43">01</td>
<td valign="top" width="107">00 0D</td>
<td valign="top" width="46">2+x</td>
<td valign="top" width="150">x=0D=13</td>
<td valign="top" width="146">实际值：ConstantValue</td></tr>
<tr>
<td valign="top" width="73">11</td>
<td valign="top" width="43">01</td>
<td valign="top" width="107">00 0A</td>
<td valign="top" width="46">2+x</td>
<td valign="top" width="150">x=0A=10</td>
<td valign="top" width="146">实际值：Exceptions</td></tr>
<tr>
<td valign="top" width="73">12</td>
<td valign="top" width="43">01</td>
<td valign="top" width="107">00 0F</td>
<td valign="top" width="46">2+x</td>
<td valign="top" width="150">x=0F=15</td>
<td valign="top" width="146">实际值：LineNumberTable</td></tr>
<tr>
<td valign="top" width="73">13</td>
<td valign="top" width="43">01</td>
<td valign="top" width="107">00 0E</td>
<td valign="top" width="46">2+x</td>
<td valign="top" width="150">x=0E=14</td>
<td valign="top" width="146">实际值：LocalVariable</td></tr>
<tr>
<td valign="top" width="73">14</td>
<td valign="top" width="43">01</td>
<td valign="top" width="107">00 0A</td>
<td valign="top" width="46">2+x</td>
<td valign="top" width="150">x=0A=10</td>
<td valign="top" width="146">实际值：SourceFile</td></tr>
<tr>
<td valign="top" width="73">15</td>
<td valign="top" width="43">01</td>
<td valign="top" width="107">00 0D</td>
<td valign="top" width="46">2+x</td>
<td valign="top" width="150">x=0D=13</td>
<td valign="top" width="146">实际值：doMathForever</td></tr>
<tr>
<td valign="top" width="73">16</td>
<td valign="top" width="43">01</td>
<td valign="top" width="107">00 10</td>
<td valign="top" width="46">2+x</td>
<td valign="top" width="150">x=10=16</td>
<td valign="top" width="146">实际值：java/lang/Object</td></tr></tbody></table>
<li>访问标志，待完善，<a href="http://hi.baidu.com/game_engine/item/03482a35c4d0af9ab90c0311">这里</a>有详细的spec 
<li>描述符的完整定义：非终结符是正常体，终结符是粗体，*号表示之前符号出现0或多次 
<table border="0" cellspacing="0" cellpadding="2" width="593">
<tbody>
<tr>
<td valign="top" width="284">FieldDescriptor</td>
<td valign="top" width="307">FieldType</td></tr>
<tr>
<td valign="top" width="284">ComponentType</td>
<td valign="top" width="307">FieldType</td></tr>
<tr>
<td valign="top" width="284">FieldType</td>
<td valign="top" width="307">BaseType,ObjectType,ArrayType</td></tr>
<tr>
<td valign="top" width="284">BaseType</td>
<td valign="top" width="307"><strong>B,C,D,F,I,J,S,Z</strong></td></tr>
<tr>
<td valign="top" width="284">ObjectType</td>
<td valign="top" width="307"><strong>L&lt;classname&gt;;</strong></td></tr>
<tr>
<td valign="top" width="284">ArrayType</td>
<td valign="top" width="307"><strong>[</strong>ComponentType</td></tr>
<tr>
<td valign="top" width="284">MethodDescriptor</td>
<td valign="top" width="307"><strong>(</strong>ParameterDescriptor*<strong>)</strong>ReturnDescriptor</td></tr>
<tr>
<td valign="top" width="284">ParameterDescriptor</td>
<td valign="top" width="307">FieldType</td></tr>
<tr>
<td valign="top" width="284">ReturnDescriptor</td>
<td valign="top" width="307">FieldType,<strong>V</strong></td></tr></tbody></table>
<li>基本类型终结符：V代表void 
<table border="0" cellspacing="0" cellpadding="2" width="400">
<tbody>
<tr>
<td valign="top" width="200">终结符</td>
<td valign="top" width="200">类型</td></tr>
<tr>
<td valign="top" width="200">B</td>
<td valign="top" width="200">byte</td></tr>
<tr>
<td valign="top" width="200">C</td>
<td valign="top" width="200">char</td></tr>
<tr>
<td valign="top" width="200">D</td>
<td valign="top" width="200">double</td></tr>
<tr>
<td valign="top" width="200">F</td>
<td valign="top" width="200">float</td></tr>
<tr>
<td valign="top" width="200">I</td>
<td valign="top" width="200">int</td></tr>
<tr>
<td valign="top" width="200">J</td>
<td valign="top" width="200">long</td></tr>
<tr>
<td valign="top" width="200">S</td>
<td valign="top" width="200">short</td></tr>
<tr>
<td valign="top" width="200">Z</td>
<td valign="top" width="200">boolean</td></tr></tbody></table>
<li>一些描述符的例子： 
<table border="0" cellspacing="0" cellpadding="2" width="535">
<tbody>
<tr>
<td valign="top" width="200">描述符</td>
<td valign="top" width="333">字段或方法声明</td></tr>
<tr>
<td valign="top" width="200">I</td>
<td valign="top" width="333">int a;</td></tr>
<tr>
<td valign="top" width="200">[[J</td>
<td valign="top" width="333">long[][] b;</td></tr>
<tr>
<td valign="top" width="200">[Ljava/lang/Object;</td>
<td valign="top" width="333">java.lang.Object[] c;</td></tr>
<tr>
<td valign="top" width="200">Ljava/util/HashMap;</td>
<td valign="top" width="333">java.util.HashMap map;</td></tr>
<tr>
<td valign="top" width="200">[[[Z</td>
<td valign="top" width="333">boolean[][][] ok;</td></tr>
<tr>
<td valign="top" width="200">()I</td>
<td valign="top" width="333">int m1();</td></tr>
<tr>
<td valign="top" width="200">()Ljava/lang/String;</td>
<td valign="top" width="333">String m2();</td></tr>
<tr>
<td valign="top" width="200">([Ljava/lang/String;)V</td>
<td valign="top" width="333">void main(String[] args);</td></tr>
<tr>
<td valign="top" width="200">()V</td>
<td valign="top" width="333">void m3();</td></tr>
<tr>
<td valign="top" width="200">(JI)V</td>
<td valign="top" width="333">void m4(long a,int b);</td></tr>
<tr>
<td valign="top" width="200">(Z[Ljava/lang/String;II)Z</td>
<td valign="top" width="333">boolean m5(boolean a,String[] b,int c, int d);</td></tr>
<tr>
<td valign="top" width="200">([BII)I</td>
<td valign="top" width="333">int m6(byte[] a,int b,int c);</td></tr></tbody></table>
<li>声明字段时的字段表field_info： 
<table border="0" cellspacing="0" cellpadding="2" width="582">
<tbody>
<tr>
<td valign="top" width="110">类型</td>
<td valign="top" width="115">名称</td>
<td valign="top" width="88">数量</td>
<td valign="top" width="267">含义</td></tr>
<tr>
<td valign="top" width="110">u2</td>
<td valign="top" width="115">access_flags</td>
<td valign="top" width="88">1</td>
<td valign="top" width="267">访问标志</td></tr>
<tr>
<td valign="top" width="110">u2</td>
<td valign="top" width="115">name_index</td>
<td valign="top" width="88">1</td>
<td valign="top" width="267">字段简单名称的常量池utf8_info入口索引</td></tr>
<tr>
<td valign="top" width="110">u2</td>
<td valign="top" width="115">descriptor_index</td>
<td valign="top" width="88">1</td>
<td valign="top" width="267">字段描述符的常量池utf8_info入口索引</td></tr>
<tr>
<td valign="top" width="110">u2</td>
<td valign="top" width="115">attributes_count</td>
<td valign="top" width="88">1</td>
<td valign="top" width="267">attribute_info表的项数</td></tr>
<tr>
<td valign="top" width="110">attribute_info</td>
<td valign="top" width="115">attributes</td>
<td valign="top" width="88">attributes_count</td>
<td valign="top" width="267">字段属性：ConstantValue, Deprecated, Synthetic（JVM规范）</td></tr></tbody></table>
<li>field_info中的access_flags标志含义： 
<table border="0" cellspacing="0" cellpadding="2" width="400">
<tbody>
<tr>
<td valign="top" width="100">标志名</td>
<td valign="top" width="100">值</td>
<td valign="top" width="100">含义</td>
<td valign="top" width="100">使用范围</td></tr>
<tr>
<td valign="top" width="100">ACC_PUBLIC</td>
<td valign="top" width="100">0x0001</td>
<td valign="top" width="100">public</td>
<td valign="top" width="100">类和接口</td></tr>
<tr>
<td valign="top" width="100">ACC_PRIVATE</td>
<td valign="top" width="100">0x0002</td>
<td valign="top" width="100">private</td>
<td valign="top" width="100">类</td></tr>
<tr>
<td valign="top" width="100">ACC_PROTECTED</td>
<td valign="top" width="100">0x0004</td>
<td valign="top" width="100">protected</td>
<td valign="top" width="100">类</td></tr>
<tr>
<td valign="top" width="100">ACC_STATIC</td>
<td valign="top" width="100">0x0008</td>
<td valign="top" width="100">static</td>
<td valign="top" width="100">类和接口</td></tr>
<tr>
<td valign="top" width="100">ACC_FINAL</td>
<td valign="top" width="100">0x0010</td>
<td valign="top" width="100">final</td>
<td valign="top" width="100">类和接口</td></tr>
<tr>
<td valign="top" width="100">ACC_VOLATILE</td>
<td valign="top" width="100">0x0040</td>
<td valign="top" width="100">volatile</td>
<td valign="top" width="100">类</td></tr>
<tr>
<td valign="top" width="100">ACC_TRANSIENT</td>
<td valign="top" width="100">0x0080</td>
<td valign="top" width="100">transient</td>
<td valign="top" width="100">类</td></tr></tbody></table>
<li>声明方法时的方法表method_info： 
<table border="0" cellspacing="0" cellpadding="2" width="577">
<tbody>
<tr>
<td valign="top" width="101">类型</td>
<td valign="top" width="101">名称</td>
<td valign="top" width="101">数量</td>
<td valign="top" width="272">含义</td></tr>
<tr>
<td valign="top" width="101">u2</td>
<td valign="top" width="101">access_flags</td>
<td valign="top" width="101">1</td>
<td valign="top" width="272">访问修饰符</td></tr>
<tr>
<td valign="top" width="101">u2</td>
<td valign="top" width="101">name_index</td>
<td valign="top" width="101">1</td>
<td valign="top" width="272">方法简单名称的常量池入口</td></tr>
<tr>
<td valign="top" width="101">u2</td>
<td valign="top" width="101">descriptor_index</td>
<td valign="top" width="101">1</td>
<td valign="top" width="272">方法描述符的常量池入口</td></tr>
<tr>
<td valign="top" width="101">u2</td>
<td valign="top" width="101">attributes_count</td>
<td valign="top" width="101">1</td>
<td valign="top" width="272">属性表的项数</td></tr>
<tr>
<td valign="top" width="101">attribute_info</td>
<td valign="top" width="107">attributes</td>
<td valign="top" width="112">attributes_count</td>
<td valign="top" width="272">方法属性：Code,Deprecated, Exceptions和Synthetic（JVM规范）</td></tr></tbody></table>
<li>method_info表中的访问标志对应含义：值得说明的是接口的方法一定是public和abstract的，接口初始化方法可以用strictFP 
<table border="0" cellspacing="0" cellpadding="2" width="576">
<tbody>
<tr>
<td valign="top" width="100">标志名</td>
<td valign="top" width="100">值</td>
<td valign="top" width="100">含义</td>
<td valign="top" width="274">使用范围</td></tr>
<tr>
<td valign="top" width="100">ACC_PUBLIC</td>
<td valign="top" width="100">0x0001</td>
<td valign="top" width="100">public</td>
<td valign="top" width="274">类和接口</td></tr>
<tr>
<td valign="top" width="100">ACC_PRIVATE</td>
<td valign="top" width="100">0x0002</td>
<td valign="top" width="100">private</td>
<td valign="top" width="274">类</td></tr>
<tr>
<td valign="top" width="100">ACC_PROTECTED</td>
<td valign="top" width="100">0x0004</td>
<td valign="top" width="100">protected</td>
<td valign="top" width="274">类</td></tr>
<tr>
<td valign="top" width="100">ACC_STATIC</td>
<td valign="top" width="100">0x0008</td>
<td valign="top" width="100">static</td>
<td valign="top" width="274">类</td></tr>
<tr>
<td valign="top" width="100">ACC_FINAL</td>
<td valign="top" width="100">0x0010</td>
<td valign="top" width="100">final</td>
<td valign="top" width="274">类</td></tr>
<tr>
<td valign="top" width="100">ACC_SYNCHRONIZED</td>
<td valign="top" width="100">0x0020</td>
<td valign="top" width="100">synchronized</td>
<td valign="top" width="274">类</td></tr>
<tr>
<td valign="top" width="100">ACC_NATIVE</td>
<td valign="top" width="100">0x0100</td>
<td valign="top" width="100">native</td>
<td valign="top" width="274">类</td></tr>
<tr>
<td valign="top" width="100">ACC_ABSTRACT</td>
<td valign="top" width="100">0x0400</td>
<td valign="top" width="100">abstract</td>
<td valign="top" width="274">类和接口</td></tr>
<tr>
<td valign="top" width="100">ACC_STRICT</td>
<td valign="top" width="100">0x0800</td>
<td valign="top" width="100">strictFP</td>
<td valign="top" width="274">类和接口的&lt;clinit&gt;方法</td></tr></tbody></table>
<li>类和接口的初始化方法(&lt;clinit&gt;)只有JVM可以直接调用，永远不会被java字节码直接调用。 
<li>JVM规范定义的所有属性： 
<table border="0" cellspacing="0" cellpadding="2" width="558">
<tbody>
<tr>
<td valign="top" width="133">属性名</td>
<td valign="top" width="133">使用者</td>
<td valign="top" width="290">描述</td></tr>
<tr>
<td valign="top" width="133">Code</td>
<td valign="top" width="133">method_info</td>
<td valign="top" width="290">方法的字节码和其他数据</td></tr>
<tr>
<td valign="top" width="133">ConstantValue</td>
<td valign="top" width="133">field_info</td>
<td valign="top" width="290">final变量的值</td></tr>
<tr>
<td valign="top" width="133">Deprecated</td>
<td valign="top" width="133">field_info,method_info</td>
<td valign="top" width="290">字段或方法被禁用的指示符</td></tr>
<tr>
<td valign="top" width="133">Exceptions</td>
<td valign="top" width="133">method_info</td>
<td valign="top" width="290">方法可能抛出的可被检测的异常</td></tr>
<tr>
<td valign="top" width="133">InnerClasses</td>
<td valign="top" width="133">ClassFile</td>
<td valign="top" width="290">内部、外部类的列表</td></tr>
<tr>
<td valign="top" width="133">LineNumberTable</td>
<td valign="top" width="133">Code_attribute</td>
<td valign="top" width="290">方法的行号与字节码的映射</td></tr>
<tr>
<td valign="top" width="133">LocalVariableTable</td>
<td valign="top" width="133">Code_attribute</td>
<td valign="top" width="290">方法的局部变量的描述</td></tr>
<tr>
<td valign="top" width="133">SourceFile</td>
<td valign="top" width="133">ClassFile</td>
<td valign="top" width="290">源文件名</td></tr>
<tr>
<td valign="top" width="133">Synthetic</td>
<td valign="top" width="133">field_info,method_info</td>
<td valign="top" width="290">编译器产生的字段或者方法的指示符</td></tr></tbody></table>
<li>code属性的表code_attribute： 
<table border="0" cellspacing="0" cellpadding="2" width="569">
<tbody>
<tr>
<td valign="top" width="101">类型</td>
<td valign="top" width="101">名称</td>
<td valign="top" width="101">数量</td>
<td valign="top" width="264">含义</td></tr>
<tr>
<td valign="top" width="101">u2</td>
<td valign="top" width="101">attribute_name_index</td>
<td valign="top" width="101">1</td>
<td valign="top" width="264">包含“Code”的常量池入口</td></tr>
<tr>
<td valign="top" width="101">u4</td>
<td valign="top" width="101">attribute_length</td>
<td valign="top" width="101">1</td>
<td valign="top" width="264">去除起始6个字节后的code属性长度</td></tr>
<tr>
<td valign="top" width="101">u2</td>
<td valign="top" width="101">max_stack</td>
<td valign="top" width="101">1</td>
<td valign="top" width="264">方法执行任意时刻，该方法操作数栈的最大长度（以字为单位）</td></tr>
<tr>
<td valign="top" width="101">u2</td>
<td valign="top" width="101">max_locals</td>
<td valign="top" width="101">1</td>
<td valign="top" width="264">方法局部变量需要的存储空间长度（以字为单位）</td></tr>
<tr>
<td valign="top" width="101">u4</td>
<td valign="top" width="101">code_length</td>
<td valign="top" width="101">1</td>
<td valign="top" width="264">该方法字节码流的长度</td></tr>
<tr>
<td valign="top" width="101">u1</td>
<td valign="top" width="101">code</td>
<td valign="top" width="101">code_length</td>
<td valign="top" width="264">&nbsp;</td></tr>
<tr>
<td valign="top" width="101">u2</td>
<td valign="top" width="101">exception_table_length</td>
<td valign="top" width="101">1</td>
<td valign="top" width="264">异常表项数</td></tr>
<tr>
<td valign="top" width="101">exception_info</td>
<td valign="top" width="101">exception_table</td>
<td valign="top" width="101">exception_table_length</td>
<td valign="top" width="264">异常表</td></tr>
<tr>
<td valign="top" width="101">u2</td>
<td valign="top" width="101">attributes_count</td>
<td valign="top" width="101">1</td>
<td valign="top" width="264">属性数</td></tr>
<tr>
<td valign="top" width="101">attribute_info</td>
<td valign="top" width="107">attributes</td>
<td valign="top" width="112">attributes_count</td>
<td valign="top" width="264">code属性：LineNumberTable和LocalVariableTable（JVM规范）</td></tr></tbody></table>
<li>异常表excption_info： 
<table border="0" cellspacing="0" cellpadding="2" width="588">
<tbody>
<tr>
<td valign="top" width="100">类型</td>
<td valign="top" width="100">名称</td>
<td valign="top" width="100">数量</td>
<td valign="top" width="286">含义</td></tr>
<tr>
<td valign="top" width="100">u2</td>
<td valign="top" width="100">start_pc</td>
<td valign="top" width="100">1</td>
<td valign="top" width="286">代码数组起始处到异常处理器起始处的代码偏移量</td></tr>
<tr>
<td valign="top" width="100">u2</td>
<td valign="top" width="100">end_pc</td>
<td valign="top" width="100">1</td>
<td valign="top" width="286">代码数组起始处到异常处理器结束后的一个字节的偏移量</td></tr>
<tr>
<td valign="top" width="100">u2</td>
<td valign="top" width="100">handler_pc</td>
<td valign="top" width="100">1</td>
<td valign="top" width="286">代码数组起始处跳转到异常处理器的第一条指令的偏移量</td></tr>
<tr>
<td valign="top" width="100">u2</td>
<td valign="top" width="100">catch_type</td>
<td valign="top" width="100">1</td>
<td valign="top" width="286">异常处理器捕获的异常类型的Class_info常量池入口，如果为0则表示处理finally子句，即处理所有异常</td></tr></tbody></table>
<li>constantValue属性：各种基础类型加字符串类型的常量池入口查找，结构很简单，这里就不列出了。 
<li>LineNumberTable属性建立了方法字节码流便宜量和源代码行号之间的映射关系： 
<table border="0" cellspacing="0" cellpadding="2" width="484">
<tbody>
<tr>
<td valign="top" width="65">类型</td>
<td valign="top" width="56">名称</td>
<td valign="top" width="105">数量</td>
<td valign="top" width="256">含义</td></tr>
<tr>
<td valign="top" width="65">u2</td>
<td valign="top" width="56">attribute_name_index</td>
<td valign="top" width="105">1</td>
<td valign="top" width="256">包含“LineNumberTable”的常量池入口</td></tr>
<tr>
<td valign="top" width="65">u4</td>
<td valign="top" width="56">attribute_length</td>
<td valign="top" width="105">1</td>
<td valign="top" width="256">去除起始6字节后的属性长度</td></tr>
<tr>
<td valign="top" width="65">u2</td>
<td valign="top" width="56">line_number_table_length</td>
<td valign="top" width="105">1</td>
<td valign="top" width="256">line_number_info表长度</td></tr>
<tr>
<td valign="top" width="65">line_number_info</td>
<td valign="top" width="56">line_number_table</td>
<td valign="top" width="105">line_number_<br>table_length</td>
<td valign="top" width="256">属性表</td></tr></tbody></table>
<li>line_number_info表很简单，就两个项：u2的start_pc给出新行开始时代码数组的偏移量，u2的line_number给出了从start_pc开始的行号。 </li></ol>
<p>&nbsp;</p>
<p>这次就到这里。to be continued...</p><img src ="http://www.blogjava.net/changedi/aggbug/387915.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2012-09-17 16:38 <a href="http://www.blogjava.net/changedi/archive/2012/09/17/387915.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JVM学习笔记（0）&amp;mdash;&amp;mdash;JVM一把抓</title><link>http://www.blogjava.net/changedi/archive/2012/09/07/387252.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Fri, 07 Sep 2012 06:57:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2012/09/07/387252.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/387252.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2012/09/07/387252.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/387252.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/387252.html</trackback:ping><description><![CDATA[<p>从毕业的时候断断续续读这本书，发现已经很久了，一直只是到概念层次，没有深入细节。今天重读这本书，希望能从中获取更多。</p> <p>今天先开个头。笔记是无结构的流式记录，类似tips的list吧~</p> <ol> <li>每个java程序运行于自己的JVM实例中，java程序的启动入口必须是public static void main(String[] args)；  <li>每个java程序，开始于main，结束于所有非守护线程的终止；  <li>jvm的体系结构包含：类装载器子系统（装载class）、运行时数据区（存放数据）、执行引擎（执行被装载类的指令）；  <li>运行时数据区包含：堆、方法区、java栈、本地方法栈、PC寄存器。其中堆和方法区是所有线程共享的，而其他三者是线程独享的；  <li>jvm数据类型分两种：基本类型{数值类型{浮点数{float,double}，整数{byte,short,int,long,char}}，boolean，returnAddress}和引用类型{引用{类，接口，数组}}，基本类型存数据本身，引用类型存数据引用；  <li>boolean是个特别的类型，jvm处理按int来操作，0为false，非0为true，boolean数组是按byte数组来访问的；  <li>引用类型中，类和接口都是对类或者实现了接口的类的实例的引用，数组是对数组对象的引用，一个特殊引用是null，表示没有引用任何对象；  <li>数据类型取值范围：{byte：1字节有符号，short：2字节有符号，int：4字节有符号，long：8字节有符号，char：2字节无符号，float：4字节IEEE754单精度，double：8字节IEEE754双精度，returnAddress：统一方法中某操作码的地址，reference：堆中对象的引用或null}  <li>JVM数据单元是字，字长的设计最短要32bit即4个字节，保证能容纳byte，short，int，char，float，returnAddress和reference类型的值；  <li>JVM有两种类加载器：启动类装载器和用户自定义类装载器，前者是jvm实现的一部分，后者是java程序的一部分，不同类装载器装载的类被放在虚拟机内部不同的命名空间；  <li>方法区存储：{类加载时，读入class文件后，解析得到的类型信息：全限定名，直接父类的全限定名，是类类型还是接口类型，访问修饰符，直接实现接口的全限定名有序列表}，{常量池：直接常量（string，int等）和对其他类型、字段和方法的符号引用}，{字段信息：字段名，字段类型，字段修饰符}，{方法信息：方法名，方法返回类型，方法参数的数量和类型，方法的修饰符}，{类变量：static}，{编译时常量：final}，{指向ClassLoader的引用：如果是自定义装载的}，{指向Class类的引用：Class.forName()或者object.getClass()}，{方法表：虚拟机为每个非抽象类生成一个方法表}；  <li>堆存储：所有运行时创建的类实例或数组都放到同一个堆中；  <li>程序计数器：大小1个字长，内容总是下一条将被执行指令的地址；  <li>java栈：只有push和pop操作，单位是一个栈帧，保存线程的运行状态，每个帧中存储当前的参数、局部变量、中间运算结果等。当方法以return或者异常抛出结束时，当前帧pop，当调用一个java方法时，push一个帧成为当前帧。因为java栈数据是每线程私有的，可以不考虑同步问题。java栈的每个栈帧又包含三部分：局部变量区、操作数栈和帧数据区。局部变量和方法参数存入局部变量区，操作数栈是jvm的工作区，指令都要经过栈弹出数据进行运算，一般的iload,istore等指令就是push和pop；帧数据区主要是支持常量池解析、正常方法返回以及异常派发机制；  <li>本地方法栈：线程调用一个本地方法时，本地方法接口使用本地方法栈；  <li>执行引擎：执行指令，通用技术有解释、即时编译、自适应优化和芯片级执行，Sun的hotspot使用自适应优化：刚开始对所有代码解释运行，监视代码运行情况，把经常执行的代码编译为本地代码，优化，然后继续执行。</li></ol><img src ="http://www.blogjava.net/changedi/aggbug/387252.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2012-09-07 14:57 <a href="http://www.blogjava.net/changedi/archive/2012/09/07/387252.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>服务器端的推</title><link>http://www.blogjava.net/changedi/archive/2012/08/12/385309.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Sun, 12 Aug 2012 02:51:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2012/08/12/385309.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/385309.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2012/08/12/385309.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/385309.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/385309.html</trackback:ping><description><![CDATA[<p>服务器端推的技术，对于普通的互联网站式应用是很少涉及到的，大家已经习惯了请求响应式的”拉“，但是对于现在ajax的快速发展，以及html5的诞生，服务器端的推送技术被越来越多的提到。这里总结几个push技术。如何push，给谁push，这就引出了推技术的核心——发布订阅模型。我们常见的推主要有email系统、RSS、IM、消息系统等。</p> <p>假设一个场景，一个网站，想对登陆用户进行消息提醒，那么如何选择技术实现呢？现在大多数的实现是轮询——也就是间隔拉技术，定时的用ajax请求访问server，将返回的数据更新到页面上，通过间隔拉取来模拟出push的效果。但这毕竟还不是推，而且存在的核心问题就是请求浪费，资源浪费，本可避免的服务器端压力，总之一句话：低效率。</p> <p>单纯的服务器端推：</p> <p>1，http服务一般是做长连接的，连接不断开，那么当有事件发生时，服务器端可以定向的向持有连接的客户端push数据。</p> <p>2，http响应header里的content-type设置为multipart/mixed这样的MIME，这种技术可以通过boundary来在header的content-type里设置一个边界值，客户端通过解析边界值来区分不同的显示部分。换句话说，服务器端告诉客户端这个响应是有多个部分的，客户端应该通过boundary来区分这些部分并分别处理。这种技术有个明显的劣势是IE不支持，多数是被用到webcam这样的应用中。</p> <p>3，websocket，html5才支持的最新技术，优点嘛自然是高效，但是缺点就是客户端浏览器的支持度了。</p> <p>另外的几种技术：</p> <p>1，pushlet：与刚才1中提到一样的持久连接，服务端定期的返回js片段给到客户端，客户端持续显示loading状态，在收到js后执行，将结果更新到页面上。缺点的话是服务器端对客户端超时的控制没有掌握，在超时后，只有客户端主动刷新才能解决。详细优缺点参看<a href="http://blog.csdn.net/adminadmin/article/details/669226">这篇文章</a></p> <p>2，长轮询：与传统定时轮询不同，长轮询会在服务器端阻塞请求，直到有数据的时候再做响应，而服务器端在接到响应后马上重新请求，如此往复。具体可以参看<a href="http://www.ibm.com/developerworks/cn/web/wa-lo-comet/">这篇文章</a></p> <p>3，Flash XML Socket relays：通过加入一个relay服务器，这个服务器接收到客户端的一个请求，且这个请求基于tcp的连接，然后relay会返回一个id给到客户端，然后客户端会带着这个id请求web服务器，web服务器会把响应消息给到relay，relay再通过flash socket分发出去。当然tcp并发连接就是个瓶颈，但是这种做法的效率很高，对于小规模实现有益。</p> <p>众所周知的服务器端推就是comet技术了，长轮询其实也是一种comet技术。comet技术本身是个泛化了的概念，具体实现可以有多种，但是通用且多数的实现时基于XHR（XMLHttpRequest）的ajax长轮询。</p> <p>对于具体的业务场景，我们可能选择不同的服务器端推策略，对于现有的web应用比如聊天和消息可能TCP或者长连接就能解决问题，但是对于大并发下的大型网站，拉取是更合适的选择，长轮询可能用的会多一些。当然我们最期望的是websocket的表现~</p> <p>参考文章：</p> <p><a title="http://en.wikipedia.org/wiki/Push_technology" href="http://en.wikipedia.org/wiki/Push_technology">http://en.wikipedia.org/wiki/Push_technology</a></p> <p><a title="http://en.wikipedia.org/wiki/Extensible_Messaging_and_Presence_Protocol" href="http://en.wikipedia.org/wiki/Extensible_Messaging_and_Presence_Protocol">http://en.wikipedia.org/wiki/Extensible_Messaging_and_Presence_Protocol</a></p> <p><a title="http://en.wikipedia.org/wiki/Internet_Relay_Chat" href="http://en.wikipedia.org/wiki/Internet_Relay_Chat">http://en.wikipedia.org/wiki/Internet_Relay_Chat</a></p> <p><a title="http://en.wikipedia.org/wiki/Comet_(programming)" href="http://en.wikipedia.org/wiki/Comet_(programming)">http://en.wikipedia.org/wiki/Comet_(programming)</a></p> <p><a title="http://en.wikipedia.org/wiki/MIME#Mixed-Replace_.28experimental.29" href="http://en.wikipedia.org/wiki/MIME#Mixed-Replace_.28experimental.29">http://en.wikipedia.org/wiki/MIME#Mixed-Replace_.28experimental.29</a></p><img src ="http://www.blogjava.net/changedi/aggbug/385309.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2012-08-12 10:51 <a href="http://www.blogjava.net/changedi/archive/2012/08/12/385309.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>分享一个LRUMap的实现&amp;mdash;&amp;mdash;来自apache common-collections框架</title><link>http://www.blogjava.net/changedi/archive/2012/05/31/379658.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Thu, 31 May 2012 05:16:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2012/05/31/379658.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/379658.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2012/05/31/379658.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/379658.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/379658.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 今天主要分享一个LRUmap的实现。我们经常会用到需要使用map来保存数据的时候，由于map本身的映射高效，最适合做随机读取的存储结构。当然LRU算法是在有限大小的存储集合下的一种调度算法，即最近最少使用。对于一个给定大小限制的容器，如何分配资源就涉及到调度，而LRU就是一种经典的调度了，在容器中定义一个最后使用时间，当容器满时，再来新的元素，那么淘汰最近最少使用的元素，把新的元素替换之，这是最直...&nbsp;&nbsp;<a href='http://www.blogjava.net/changedi/archive/2012/05/31/379658.html'>阅读全文</a><img src ="http://www.blogjava.net/changedi/aggbug/379658.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2012-05-31 13:16 <a href="http://www.blogjava.net/changedi/archive/2012/05/31/379658.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Turbine框架</title><link>http://www.blogjava.net/changedi/archive/2012/05/17/378394.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Thu, 17 May 2012 05:54:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2012/05/17/378394.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/378394.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2012/05/17/378394.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/378394.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/378394.html</trackback:ping><description><![CDATA[<p>首先，必须承认，turbine作为一个开发框架，已经快绝迹了，阿里巴巴的webx框架是基于turbine做的，所以这里简单介绍一下，如果是阿里系新入职的同学，可以参考一下，当然任何开发人员如果感兴趣turbine的设计，都欢迎。</p> <p>turbine是什么？</p> <p>turbine是一个应用开发框架，是一个开发web应用的工具箱，100%纯java，且基于jdk1.3及以上。j2ee兼容且基于servlet，面向MVC构建。</p> <p>turbine的框架架构overview如下：</p> <p><a href="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/Turbine_C394/image_2.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" alt="image" src="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/Turbine_C394/image_thumb.png" height="256" width="627" border="0" /></a> </p> <p>turbine的代码结构包含了services、modules和util几个大类，在上图中可见，在servlet基础之上，以MVC为基础结构，modules包含了view部分及action，view主要是pages，其中有三种具体的module&#8212;&#8212;screen、layout和navigation，action作为controller存在，toolbox提供了很多通用的tool，service则是整个框架的插件。一个完整的请求处理流程如下：</p> <p><a href="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/Turbine_C394/image_4.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" alt="image" src="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/Turbine_C394/image_thumb_1.png" height="376" width="628" border="0" /></a> </p> <p>请求到来，turbine的controller处理，view部分渲染页面，然后响应输出。</p> <p>就顺着这个流程，分析一下turbine的架构，对于view部分，我们最直观想到的就是pages，page模块值包含了几个概念，是jsp的？还是velocity的？仅此而已。那么，以一个velocity页面为例，如何组织呢？turbine讲究的是&#8220;约定胜于配置&#8221;，记住这句真言，也就可以理解turbine了。在开发应用中，要建立三个页面目录，分别是screen、layout和navigation，screen是页面的主体内容，layout是页面的布局，而navigation则是一些页面修饰元素，比如下面这个页面结构：</p> <p><a href="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/Turbine_C394/image_6.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" alt="image" src="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/Turbine_C394/image_thumb_2.png" height="345" width="629" border="0" /></a> </p> <p>这三个部分的调用顺序如下：</p> <p><a href="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/Turbine_C394/image_8.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" alt="image" src="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/Turbine_C394/image_thumb_3.png" height="343" width="629" border="0" /></a> </p> <p>因为约定的代码结构是在三个目录下写对应名字的java代码，因此名字如果不一致，那么就会出错。当然，页面模板目录有默认的结构，如果在对应的目录下找不到文件，就会读取default.vm文件。</p> <p><a href="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/Turbine_C394/image_10.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" alt="image" src="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/Turbine_C394/image_thumb_4.png" height="335" width="240" border="0" /></a> </p> <p>类似servlet，写一个java文件对应处理screen页面，那么代码可能是这样的：</p> <p><a href="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/Turbine_C394/image_12.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" alt="image" src="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/Turbine_C394/image_thumb_5.png" height="264" width="480" border="0" /></a> </p> <p>可以看到，这种处理代码很像servlet，方法就像是servlet标准中的doGet和doPost，只不过参数进行了封装。其实，turbine就是一个servlet，看看turbine的源码，Turbine类继承了HttpServlet，实现了doGet和doPost方法，除了一开始初始化一系列配置相关的变量外，在接到一个http请求（get）后，turbine会执行doGet方法，turbine封装了request和response，构建了一个叫做RunData的对象，Rundata是个接口，具体实现是DefaultTurbineRunData，其内部提供了获取http各种数据的方法接口。在每个请求周期，turbine都会利用TurbineRunDataService新建一个RunData，将所有基于servlet的请求相关的东西塞到这个data中。然后，利用从request中得到的请求地址，再调用PageLoader找到对应的Page，执行其中的build方法，其中DefaultPage里会通过LayoutLoader和ScreenLoader来定位到对应的layout和screen，然后执行其中的build相关方法。这样，一整套请求执行就完成了。值得说明的就是如果是表单提交，那么多数情况会多出一个action的执行，也是在page里进行的。如下图</p> <p><a href="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/Turbine_C394/image_14.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" alt="image" src="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/Turbine_C394/image_thumb_6.png" height="192" width="451" border="0" /></a> </p> <p>至于turbine中的tool，这类工具是通过配置，以&#8220;拉&#8221;模式被应用的。当应用启动后，在vm页面中以$开始调用某个tool的时候，就会初始化这个tool。当然，这里就用到了TurbinePullService。</p> <p>在初步了解了turbine后，如果使用过webx，那么就会知道并一定程度理解了webx的设计；没使用过的，结合自己用过的mvc框架，也可以了解一些框架设计的思路。</p> <p>参考资料：</p> <p><a href="http://wiki.apache.org/turbine/Turbine2/Tutorial">Turbine Tutorial</a></p> <p><a href="http://turbine.apache.org/index.html">Apache Turbine</a></p> <p>本文全部图片都截取自Turbine Tutorial，使用请注明</p><img src ="http://www.blogjava.net/changedi/aggbug/378394.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2012-05-17 13:54 <a href="http://www.blogjava.net/changedi/archive/2012/05/17/378394.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实际应用delegate做好api简洁设计&amp;mdash;&amp;mdash;从commons-io排序器想开</title><link>http://www.blogjava.net/changedi/archive/2012/04/28/376947.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Sat, 28 Apr 2012 03:47:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2012/04/28/376947.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/376947.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2012/04/28/376947.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/376947.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/376947.html</trackback:ping><description><![CDATA[<p>我们已经知道，在完成一个通用功能的设计时，必然会抽象并且隔离功能级别，把最一般的功能抽象出来，放到接口里去，具体实现接口的类完成具体功能。因为所有的具体实现都有共同的接口，虽然功能实际不同，但是抽象含义相似，因此在抽象级别，其他类调用时就可以把最抽象的接口作为代理（委托）来调用，思路简单清晰。</p>
<p>在commons-io这个开源框架中，封装了对io的基本操作，其中org.apache.commons.io.comparator包就是经典的设计典范，comparator顾名思义就是为了提供一系列的文件排序器，辅助排序。这里我把结构图画一下：</p>
<p><a href="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/delegateapicommonsio_A603/image_4.png"><img style="border-bottom: 0px; border-left: 0px; width: 438px; display: inline; height: 228px; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/delegateapicommonsio_A603/image_thumb_1.png" width="438" height="228" /></a> </p>
<p>一个AbstractFileComparator抽象类完成了一层包内抽象，直接实现接口Comparator&lt;File&gt;，并且提供了sort方法完成了通过比较的排序功能：</p>
<p>public File[] sort(File... files) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (files != null) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Arrays.sort(files, this);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return files;<br />&nbsp;&nbsp;&nbsp; } 
<p>public List&lt;File&gt; sort(List&lt;File&gt; files) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (files != null) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Collections.sort(files, this);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return files;<br />&nbsp;&nbsp;&nbsp; } 
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>所有的具体排序器实现都继承了这个AbstractFileComparator抽象类，实现compare方法，完成各自的比较，比如有根据文件大小比较的SizeFileComparator，有根据修改时间比较的LastModifiedFileComparator等等。值得一提的就是用到了委托的ReverseComparator和CompositeFileComparator，Reverse顾名思义就是反转排序，默认的排序器都是升序的，谁小把谁排在前面，ReverseComparator通过代理一个Comparator</p>
<p>private final Comparator&lt;File&gt; delegate;</p>
<p>构造时作为参数把delegate实例化，public ReverseComparator(Comparator&lt;File&gt; delegate)，最后实现compare方法：</p>
<p>public int compare(File file1, File file2) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return delegate.compare(file2, file1); // parameters switched round<br />&nbsp;&nbsp; } 
<p>完成整个反转排序的功能，看出端倪了吧。一个代理的引入，减少了一半的工作量，把排序功能实现的非常全面。</p>
<p>同理，组合排序器的实现正好利用了多维的代理</p>
<p>private final Comparator&lt;File&gt;[] delegates;</p>
<p>构造时传入的参数是一个可变长度数组，public CompositeFileComparator(Comparator&lt;File&gt;... delegates)，或者一个可迭代对象，public CompositeFileComparator(Iterable&lt;Comparator&lt;File&gt;&gt; delegates)，实现的compare方法如下：</p>
<p>public int compare(File file1, File file2) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int result = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (Comparator&lt;File&gt; delegate : delegates) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = delegate.compare(file1, file2);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (result != 0) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return result;<br />&nbsp;&nbsp;&nbsp; } 
<p>组合排序就是提供一系列排序器，顺序比较，直到出现不相等情况。考虑到实际应用，我们经常是否只是实现了Comparable接口，在compareTo方法中写if else呢？引入代理的排序器api设计，给了我们不错的启示。</p><img src ="http://www.blogjava.net/changedi/aggbug/376947.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2012-04-28 11:47 <a href="http://www.blogjava.net/changedi/archive/2012/04/28/376947.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>分享代码系列——vlist</title><link>http://www.blogjava.net/changedi/archive/2012/04/15/374226.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Sun, 15 Apr 2012 04:29:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2012/04/15/374226.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/374226.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2012/04/15/374226.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/374226.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/374226.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: vlist是一种列表的实现。结构如下图：&nbsp;（图来源wikipedia）类似链接表的结构，但是，不是线性的。它的结构基于一种2的幂次扩展，第一个链接节点包含了列表的前一半数据，第二个包含了剩下一半的一半，依次递归。节点的基本结构不像LinkedList的节点是双端队列，每个VListCell包含了下个节点的指针mNext和前一个节点的指针mPrev，同时内置一个数组mElems用来...&nbsp;&nbsp;<a href='http://www.blogjava.net/changedi/archive/2012/04/15/374226.html'>阅读全文</a><img src ="http://www.blogjava.net/changedi/aggbug/374226.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2012-04-15 12:29 <a href="http://www.blogjava.net/changedi/archive/2012/04/15/374226.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>logback那些事</title><link>http://www.blogjava.net/changedi/archive/2012/03/31/373139.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Sat, 31 Mar 2012 09:14:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2012/03/31/373139.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/373139.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2012/03/31/373139.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/373139.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/373139.html</trackback:ping><description><![CDATA[<p>logback：</p> <p>logback可以认为是log4j的升级版，依然出自Ceki G&#252;lc&#252;，使用简单，只需要在你的classpath里包含slf4j-api.jar、logback-core.jar以及logback-classic.jar即可。</p> <p>简单代码示例如下：</p> <p>import org.slf4j.Logger;<br />import org.slf4j.LoggerFactory;</p> <p>import ch.qos.logback.classic.LoggerContext;<br />import ch.qos.logback.core.util.StatusPrinter;<br />public class LogTest {</p> <p><br />&nbsp;&nbsp;&nbsp; public static void main(String[] args) {<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Logger logger = LoggerFactory<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .getLogger(LogTest .class.getName());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logger.debug("Hello world.");</p> <p>}</p> <p>其中的logger对象和LoggerFactory都来自slf4j项目，slf4j是一个很好的facade，包装了接口，就像之前写的一篇文章中的提到的commons-logging框架。</p> <p>同样也可以认为logback+slf4j是log4j+commons-logging的升级版吧。</p> <p>logback的架构：</p> <p>logback包含3个子工程&#8212;&#8212;classic、core和access。core是其他两个的基础，也是logback的核心；classic扩展了core，内置了slf4j，但也支持各种其他log门面。同log4j一样，logback的主要构成也是Logger、Appender和Layout。Logger是核心控制器及调用入口，Appender主管配置和写日志实际process，Layout控制日志样式，是Appender的重要配置。值得注意的是，3个基本核心居然不都在core模块中，Logger是在classic里的。</p> <p>对于Logger来讲，和Log4j一样，Logger是一个层次结构，每个logger都有一个name属性在LoggerFactory中被一个map管理着。对于Logback来说，这个factory就是classic下的LoggerContext。这里插一段自我理解，在做facade模式的时候，代码结构可能会引入一个占位性质的类，就像slf4j中的StaticLoggerBinder，这个类在org.slf4j.impl包下，是一个单例，但是私有构造函数却抛出了一个异常，这个在不熟悉这种写法时会产生困惑。其实这是很合理的，logback的classic中也有org.slf4j.impl这个包，其中也有StaticLoggerBinder这个类，但是内容完整了许多。这就完成了slf4j的任务，同时解除了耦合。我认为这种解耦合方式非常好，plugin的感觉。</p> <p>再回来说LoggerContext，这个对应了log4j的LogManager和Hierarchy，用一个hashtable来维护logger的cache。代码真的是简洁了很多，再回头看看log4j中LogManager的getLogger方法，就知道logback的简洁了，一个while遍历省去了一个hierarchy。当然这里得补充一句，log4j包括logback的整个日志框架对于logger对象，是一个层次结构，这也是为什么log4j中有个Hierarchy的东西的原因。是一个层次的话，对于通过包名来管理日志记录等级的管理方式来说，就存在着level的控制，也就是说，你某个包名的类被设定了日志级别是什么，那么对应级别以下的日志才会被打印出来。有这样一个规则，logger的日志记录有效level由hierarchy中离它最近且方向向上（upwards）的一个logger的级别决定。如官网上的例子：</p> <p><a href="http://www.blogjava.net/images/blogjava_net/changedi/Windows-Live-Writer/logback_C9C9/image_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.blogjava.net/images/blogjava_net/changedi/Windows-Live-Writer/logback_C9C9/image_thumb.png" width="244" height="106" /></a></p> <p>这里有4个logger，但是只有root被设定了level是DEBUG，其他几个logger由于没有被设定，依照规则，就都是root的level了。</p> <p><a href="http://www.blogjava.net/images/blogjava_net/changedi/Windows-Live-Writer/logback_C9C9/image_4.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.blogjava.net/images/blogjava_net/changedi/Windows-Live-Writer/logback_C9C9/image_thumb_1.png" width="244" height="103" /></a></p> <p>第二个例子中，每个logger都自己设定了level，那么依据规则，离它最近的被使用，当然自己离自己最近了。</p> <p><a href="http://www.blogjava.net/images/blogjava_net/changedi/Windows-Live-Writer/logback_C9C9/image_6.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.blogjava.net/images/blogjava_net/changedi/Windows-Live-Writer/logback_C9C9/image_thumb_2.png" width="244" height="104" /></a></p> <p>第三个例子里，X.Y没有设定level，那么离它最近且upwards的一个是X，那么X.Y的level就和X的一样。</p> <p>level控制是日志框架的基础，什么样的日志在什么环境下被打印出来，这种设定可以配置才是一个合理的日志系统。一贯的level控制规则如下显示：</p> <p><a href="http://www.blogjava.net/images/blogjava_net/changedi/Windows-Live-Writer/logback_C9C9/image_8.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.blogjava.net/images/blogjava_net/changedi/Windows-Live-Writer/logback_C9C9/image_thumb_3.png" width="240" height="69" /></a></p> <p>appender这个东西，和log4j是一样的，支持一个logger有多个appender，在AppenderAttachableImpl里会维护一个CopyOnWriteArrayList来存放一个logger的appender。每次log的时候都会遍历这个list里的appender然后调用对应的doAppend方法。我们在配置的时候每个logger的配置上有个additivity属性，默认为true。appender这个东西同logger一样有继承性。additivity属性就是控制这种继承的，true代表开启，false代表关闭，一般使用都会设置false，因为如果是true，那么如果appender比较多的话可能日志打的就有点太离谱了。</p> <p>Layout和log4j一样，我没有细研究过，但是我认为这是控制输出的一大法宝，下次研究layout的时候做一个详细的分享，一般大家都使用patternLayout，写个表达式足以。</p> <p>在之前的那篇写log的文章中，提到过一个优化写法，就是不要直接写出这样的代码：</p><pre>logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));</pre>
<p>构造string参数是复杂且耗时的。要用if判断一下。而slf4j提供了比较合适的解决方法：</p><pre>Object entry = new SomeObject(); <br />logger.debug("The entry is {}.", entry);</pre>
<p>这样的代码就更符合程序设计人员的编写习惯，而且可读性我认为要远远高于用+号连接。但是遗憾的是，这种编码风格作者并没有持续贯彻下去，没有用变长参数，而是用的object[]终止了参数的个数。也就是说，你对于多个变量的log的话，只能这么写：</p><pre>Object[] paramArray = {newVal, below, above};<br />logger.debug("Value {} was inserted between {} and {}.", paramArray);</pre>
<p>在执行log的时候，会有一个判断流程，依据官网上的介绍，我简要翻译一下：</p>
<p>1，Get the filter chain decision：如果存在，尝试调用<code>TurboFilter</code> ，<code>TurboFilter</code> 会设置一个整个上下文范围的阈值或者过滤掉每个log请求的相关参数。如果这个filter返回的参数是<code>FilterReply.DENY</code> ，那么log结束；如果<code>FilterReply.NEUTRAL</code>返回，则进入第2步，如果FilterReply.ACCEPT ，直接第3步。</p>
<p>2， Apply the <a href="http://logback.qos.ch/manual/architecture.html#basic_selection">basic selection rule</a>，如果log请求的阈值和高于配置的阈值，那么放弃处理该log。</p>
<p>3， Create a <code>LoggingEvent</code> object，logback会构建一个LoggingEvent对象，包含了所有的请求参数。其中有些参数可能是延迟加载的。</p>
<p>4， Invoking appenders，logback调用doAppend方法。</p>
<p>5， Formatting the output，layout会把LoggingEvent对象按固定格式格式化并返回字符串形式，像SocketAppender这样的方法不会返回字符串，相似的只会把它序列化。</p>
<p>6，&nbsp; Sending out the <code><font face="微软雅黑">LoggingEvent，把最终形式打印到对应的目的地址。</font></code></p>
<p><code><font face="微软雅黑">流程图见这里<a href="http://logback.qos.ch/manual/underTheHood.html">http://logback.qos.ch/manual/underTheHood.html</a></font></code></p>
<p><code><font face="微软雅黑">最后还是通过性能讨论结束这篇短文，性能的东西，我们不去看代码的话，是无法估计复杂度的变化的。那么就官网上给出的3条提示，第一点针对参数构建，第二点针对level的定位，这个在看过代码后，发现确实精简了，尤其是那种复杂的hierarchy结构没有了，线性的链条运行起来明显会快，算是去除冗余做了优化吧。第3条针对说format和write会快，尤其是format被大力投入改进，这个在看过代码后，可以做个比较。</font></code></p>
<p>本文算是一篇半自主半翻译的文章吧，重在学习。</p>
<p>参考文献：</p>
<p><a href="http://logback.qos.ch/manual/introduction.html">http://logback.qos.ch/manual/introduction.html</a></p><img src ="http://www.blogjava.net/changedi/aggbug/373139.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2012-03-31 17:14 <a href="http://www.blogjava.net/changedi/archive/2012/03/31/373139.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>微博sdk的设计</title><link>http://www.blogjava.net/changedi/archive/2012/02/12/369810.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Sun, 12 Feb 2012 03:23:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2012/02/12/369810.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/369810.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2012/02/12/369810.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/369810.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/369810.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 框架介绍：<br>主要分为几个部分，核心httpClient部分，认证相关的token部分和api调用部分。 <br><br>Weibo这个类是一个主体核心，调用的入口。 <br><br>当用户完成上面介绍的授权后，通过weibo这个类来调用api实现功能。<br>&nbsp;&nbsp;<a href='http://www.blogjava.net/changedi/archive/2012/02/12/369810.html'>阅读全文</a><img src ="http://www.blogjava.net/changedi/aggbug/369810.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2012-02-12 11:23 <a href="http://www.blogjava.net/changedi/archive/2012/02/12/369810.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MySql性能相关的一些概念(性能tip0）</title><link>http://www.blogjava.net/changedi/archive/2012/01/17/368624.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Tue, 17 Jan 2012 00:58:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2012/01/17/368624.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/368624.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2012/01/17/368624.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/368624.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/368624.html</trackback:ping><description><![CDATA[<p>题首：这是最近读《高性能MySqL 第二版》记录下来的东西~</p> <p>#读锁（共享锁）、写锁（排他锁）：读锁是共享的，互不阻塞，读取同一资源互不影响；写锁排他，一个写锁会阻塞其他的读写操作。</p> <p>#锁定对象的粒度：表锁和行锁。</p> <p>表锁：整个表加锁，当写操作时，加写锁，资源访问排他。当没有写时，加读锁，读锁互不冲突。写锁比读锁有高优先级。开销较小。</p> <p>行级锁：对一行加锁，开销大，支持最大并发处理。</p> <p>#事务：ACID</p> <p>A原子性：一个事务是一个原子不可分的工作单元，内部的工作不会被部分执行，要么全部执行，要么根本不执行</p> <p>C一致性：数据库从一种一致状态转到另一种一致状态，事务执行过程中的数据改变不会影响数据库数据。</p> <p>I 隔离性：某个事务的结果只有在事务完成后才对其他事务可见。</p> <p>D持久性：一个事务提交后的结果改变将是持久的，不会马上消失。</p> <p>#MVCC：多版本并发控制</p> <p>#几个存储引擎：</p> <p>MyISAM：加表锁，在select查询时可以在同一张表完成插入（并发插入），可以基于BLOB和TEXT的前500字符进行相关索引。</p> <p>InnoDB：事务引擎，适合处理大量短期事务，基于聚簇索引，不压缩索引</p> <p>Memory：基于堆的，内存存储，支持哈希索引</p> <p>Archive：只支持insert和select，不支持索引，缓冲了数据写操作，插入时使用zlib算法压缩，比MyISAM磁盘IO消耗少，所有 的select查询执行全表扫描，适合logging，支持行级锁。</p> <table border="0" cellspacing="0" cellpadding="2" width="597"> <tbody> <tr> <td valign="top" width="101"><strong>存储引擎</strong></td> <td valign="top" width="101"><strong>MySqL版本</strong></td> <td valign="top" width="99"><strong>事务</strong></td> <td valign="top" width="98"><strong>锁粒度</strong></td> <td valign="top" width="98"><strong>主要应用</strong></td> <td valign="top" width="98"><strong>忌用</strong></td></tr> <tr> <td valign="top" width="101">MyISAM</td> <td valign="top" width="103">全部</td> <td valign="top" width="99">不支持</td> <td valign="top" width="98">支持并发插入的表锁</td> <td valign="top" width="98">select，insert，高负载</td> <td valign="top" width="98">读写并重的场合</td></tr> <tr> <td valign="top" width="101">MyISAM Merge</td> <td valign="top" width="105">全部</td> <td valign="top" width="99">不支持</td> <td valign="top" width="98">支持并发插入的表锁</td> <td valign="top" width="98">分段归档，数据仓库</td> <td valign="top" width="97">许多全局查找</td></tr> <tr> <td valign="top" width="100">Memory(Heap)</td> <td valign="top" width="107">全部</td> <td valign="top" width="98">不支持</td> <td valign="top" width="97">表锁</td> <td valign="top" width="97">中间计算，静态数据查找</td> <td valign="top" width="97">大型数据集，持久性存储</td></tr> <tr> <td valign="top" width="100">InnoDB</td> <td valign="top" width="108">全部</td> <td valign="top" width="98">支持</td> <td valign="top" width="97">支持MVCC的行级锁</td> <td valign="top" width="97">事务处理</td> <td valign="top" width="97">无</td></tr> <tr> <td valign="top" width="100">Falcon</td> <td valign="top" width="109">6.0</td> <td valign="top" width="98">支持</td> <td valign="top" width="97">支持MVCC的行级锁</td> <td valign="top" width="97">事务处理</td> <td valign="top" width="97">无</td></tr> <tr> <td valign="top" width="100">Archive</td> <td valign="top" width="110">4.1</td> <td valign="top" width="98">支持</td> <td valign="top" width="97">支持MVCC的行级锁</td> <td valign="top" width="97">日志记录，聚合分析</td> <td valign="top" width="96">需要随机读取、更新、删除</td></tr> <tr> <td valign="top" width="99">CSV</td> <td valign="top" width="111">4.1</td> <td valign="top" width="98">不支持</td> <td valign="top" width="97">表锁</td> <td valign="top" width="97">日志记录，大规模加载外部数据</td> <td valign="top" width="96">需要随机读取、索引</td></tr> <tr> <td valign="top" width="99">Blackhole</td> <td valign="top" width="112">4.1</td> <td valign="top" width="98">支持</td> <td valign="top" width="96">支持MVCC的行级锁</td> <td valign="top" width="96">日志记录或同步归档</td> <td valign="top" width="96">除非有特别目的，否则不适合任何场合</td></tr> <tr> <td valign="top" width="99">Federated</td> <td valign="top" width="112">5.0</td> <td valign="top" width="98">N/A</td> <td valign="top" width="96">N/A</td> <td valign="top" width="96">分布式数据源</td> <td valign="top" width="96">除非有特别目的，否则不适合任何场合</td></tr> <tr> <td valign="top" width="99">NDB Cluster</td> <td valign="top" width="112">5.0</td> <td valign="top" width="98">支持</td> <td valign="top" width="96">行级锁</td> <td valign="top" width="96">高可靠性</td> <td valign="top" width="96">大部分典型应用</td></tr> <tr> <td valign="top" width="99">PBXT</td> <td valign="top" width="112">5.0</td> <td valign="top" width="98">支持</td> <td valign="top" width="96">支持MVCC的行级锁</td> <td valign="top" width="96">事务处理，日志记录</td> <td valign="top" width="96">需要聚集索引</td></tr> <tr> <td valign="top" width="99">SolidDB</td> <td valign="top" width="112">5.0</td> <td valign="top" width="98">支持</td> <td valign="top" width="96">支持MVCC的行级锁</td> <td valign="top" width="96">事务处理</td> <td valign="top" width="96">无</td></tr> <tr> <td valign="top" width="99">Maria</td> <td valign="top" width="112">6.x</td> <td valign="top" width="98">支持</td> <td valign="top" width="96">支持MVCC的行级锁</td> <td valign="top" width="97">替代MyISAM</td> <td valign="top" width="96">无</td></tr></tbody></table><img src ="http://www.blogjava.net/changedi/aggbug/368624.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2012-01-17 08:58 <a href="http://www.blogjava.net/changedi/archive/2012/01/17/368624.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>mysql性能tip(1)</title><link>http://www.blogjava.net/changedi/archive/2011/12/12/366123.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Mon, 12 Dec 2011 02:24:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2011/12/12/366123.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/366123.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2011/12/12/366123.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/366123.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/366123.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 数据类型选择方面的几个原则：<br><br>1，更小通常更好，选择能正确表示数据的最小类型。<br><br>2，简单就好，用简单类型优于用复杂类型。<br><br>3，避免NULL，尽量定义字段为not null。性能提升很小。<br><br>&nbsp;&nbsp;<a href='http://www.blogjava.net/changedi/archive/2011/12/12/366123.html'>阅读全文</a><img src ="http://www.blogjava.net/changedi/aggbug/366123.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2011-12-12 10:24 <a href="http://www.blogjava.net/changedi/archive/2011/12/12/366123.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>工具包系列(2)：imageSpider工具&amp;mdash;&amp;mdash;可定制的图像抓取</title><link>http://www.blogjava.net/changedi/archive/2011/11/02/362540.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Wed, 02 Nov 2011 07:43:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2011/11/02/362540.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/362540.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2011/11/02/362540.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/362540.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/362540.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 这个工具是一个可定制的图像抓取工具<br> <br>我希望这个小工具的功能点有以下几项：1.给定页面抓取页面的图片；2.给定页面和过滤规则，抓取页面的图片并存到本地磁盘或内存；<br> <br>主要的技术点不多：1.图片链接的获取（htmlparser搞定）；2.图片的读写（imageIo搞定）；3.规则的制定（来源于需求）<br> <br>介于方法的多样，第一个版本的spider只是很简单的功能实现，未来希望加入的就是可扩展的规则对象<br> <br>少废话，上代码：<br>&nbsp;&nbsp;<a href='http://www.blogjava.net/changedi/archive/2011/11/02/362540.html'>阅读全文</a><img src ="http://www.blogjava.net/changedi/aggbug/362540.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2011-11-02 15:43 <a href="http://www.blogjava.net/changedi/archive/2011/11/02/362540.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>工具包系列(1)：htmlStat工具&amp;mdash;&amp;mdash;统计页面信息</title><link>http://www.blogjava.net/changedi/archive/2011/10/31/362365.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Mon, 31 Oct 2011 05:28:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2011/10/31/362365.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/362365.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2011/10/31/362365.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/362365.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/362365.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: htmlStat主要想做什么，就是统计页面的信息，我一直认为页面的结构设计是设计人员按照思维套路来进行的。数字往往反映了一个设计的一个很重要的方面，比如它使用的各个tag的比例，文字的数量，图片的数量和大小等等。而想学习理解出这一套思路，先统计页面信息是最重要的。<br> <br>当然先说下开发环境：jdk1.6.11，maven2，git<br> <br>主要的依赖目前只在pom中更新了一部分，有加入的会慢慢加入，具体可以看github上的项目信息<br> <br>有愿意一起玩代码的，可以留言我，<br>&nbsp;&nbsp;<a href='http://www.blogjava.net/changedi/archive/2011/10/31/362365.html'>阅读全文</a><img src ="http://www.blogjava.net/changedi/aggbug/362365.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2011-10-31 13:28 <a href="http://www.blogjava.net/changedi/archive/2011/10/31/362365.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>tomcat流程总结</title><link>http://www.blogjava.net/changedi/archive/2011/09/27/359612.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Tue, 27 Sep 2011 06:54:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2011/09/27/359612.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/359612.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2011/09/27/359612.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/359612.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/359612.html</trackback:ping><description><![CDATA[<p>首先声明，这个可能已经算是老掉牙的东西了~~~Long Long ago  <p>断断续续两周时间来看了看tomcat4的源码。虽然有点古旧，但是配合着《How tomcat works》一书看看源码，还是很惬意的事情。中途数次想拿起纸笔抑或打开word书写下笔记，但是书中简洁的文风让我觉得没有什么可以记下的。直到最后读完这书，过完源码。才觉得应该记下一些要点来。简单称之为总结吧。  <p><a href="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/tomcat_D196/clip_image002_2.gif"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image002" border="0" alt="clip_image002" src="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/tomcat_D196/clip_image002_thumb.gif" width="244" height="113"></a>  <p>其实搞懂tomcat或者是类似的servlet的工作原理，只要配合理解这张图就可以了。这就是tomcat的整个工作流程。  <p>一个HTTP请求到来，其实本质上只是一个输入流，在这个流中蕴含了那些字节代表了这个请求的语义。而图中的1.message就抽象了这个流，把它表示为一条信息。在到达容器的第一时刻，容器是交给connector来处理的。首先这里得考虑一个容器的启动过程，启动时做的一个重要事情就是初始化connector，而connector初始化时干什么呢？显然，创建socket。一切初始化好了，才有第一步消息到来这件事情咯。  <p>信息到了，connector干的事情就是如图中的2和3步——创建http请求对象和响应对象。当然这个行为也不是connector自己干的，它只是雇佣了一个叫做HttpProcessor的兄弟来干活。真正的creation都是这个兄弟干的。HttpProcessor里面设计了一些简单的并发多线程trick，基本上就是让socket等待着请求信息的到来，来一个，就处理一个。HttpProcessor的一句话总结就是利用多线程技术parse整个请求的stream。几个parse步骤分别是：解析connection；解析request；解析headers。补充一句，request和response对象都是在HttpProcessor初始化的时候初始化的，但是它们内容的填充是在parse的时候完成的。  <p>接着，connector的任务就结束了。然后一个invoke其实就是工作的交接，该context重磅登场了。Context以其名字就决定了其霸气的侧漏无疑，基本上所有的东西都包含在内。我们把3的invoke当做一些context的自我设置（初始化），那么4的invoke就是context的表演开始了。首先在图里没有给出的是loader和logger的处理，context会在这两个依赖对象不为空的情况下运行它们。Loader是设置java class loader的，tomcat自己定义了一个classloader来加载特定的类。而logger无非就是把日志给启动起来。当然在启动pipeline之前做了启动subcontainer的操作。这是可以理解的，用计算机本质的递归来理解，有点像是先序遍历树的感觉。而pipeline被启动后，后续还有一个manager的启动，这个manager是主要用来管理session的。而所有这些都是可以配置的。  <p>照着上图主要说说pipeline，pipeline就是流水线了，上面有很多的阀门valve，阀门可以自己加，pipeline的的工作就是步骤5，顺序invoke每个阀门。其实也不是pipeline启动，pipeline其实只是启动了内置的pipelineContext对象，而这个对象会不断的调用invokenext()方法来实现流水线的执行。而这些个valve会调用wrapper，他们的invoke方法会启动wrapper，在检测完mapping后，wrapper会allocate一个servlet实例，接着servlet启动、干活、开始自己的生命周期&#8230;&#8230;这个世界就开始活跃了。  <p>That is it  <p>最后奉上一张稍微详细点的图帮助理解。  <p><a href="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/tomcat_D196/clip_image004_2.gif"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image004" border="0" alt="clip_image004" src="http://www.blogjava.net/images/blogjava_net/changedi/WindowsLiveWriter/tomcat_D196/clip_image004_thumb.gif" width="240" height="110"></a>  <p>当然，美妙的设计这里没有讲，不是因为时间不够或者是空间不足，而是我自己还没有完全的消化，tomcat我认为从设计上讲，结构是beautiful的。光是lifecycle的设计以及各个类模块区分（connector，loader，context，wrapper以及manager等等）之间的初始化调用等细节每个拿出来都够写本书了。So~~~read the fucking source code by yourself。  <p>参考资料：</p> <p>《How tomcat works》</p> <p>Tomcat 系统架构与设计模式，第 1 部分: 工作原理<a title="http://www.ibm.com/developerworks/cn/java/j-lo-tomcat1/" href="http://www.ibm.com/developerworks/cn/java/j-lo-tomcat1/">http://www.ibm.com/developerworks/cn/java/j-lo-tomcat1/</a></p>  <img src ="http://www.blogjava.net/changedi/aggbug/359612.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2011-09-27 14:54 <a href="http://www.blogjava.net/changedi/archive/2011/09/27/359612.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>commons-pool学习笔记</title><link>http://www.blogjava.net/changedi/archive/2011/05/06/349665.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Fri, 06 May 2011 02:53:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2011/05/06/349665.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/349665.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2011/05/06/349665.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/349665.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/349665.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Object pool就是一个管理对象的池子。新版本利用jdk 1.5以后的特性，结合泛型，而不是利用Object来实现了。&nbsp;&nbsp;<a href='http://www.blogjava.net/changedi/archive/2011/05/06/349665.html'>阅读全文</a><img src ="http://www.blogjava.net/changedi/aggbug/349665.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2011-05-06 10:53 <a href="http://www.blogjava.net/changedi/archive/2011/05/06/349665.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>调试技巧（随时总结）</title><link>http://www.blogjava.net/changedi/archive/2011/04/25/348978.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Mon, 25 Apr 2011 07:45:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2011/04/25/348978.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/348978.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2011/04/25/348978.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/348978.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/348978.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 调试技巧（随时总结）：<br><br>F5单步进入（在需要进入某步方法时）<br><br>F6单步调试（一般用于单步执行）<br><br>F7单步跳出（跳出该调试区段方法）<br><br>F8调试恢复<br><br>&nbsp;&nbsp;<a href='http://www.blogjava.net/changedi/archive/2011/04/25/348978.html'>阅读全文</a><img src ="http://www.blogjava.net/changedi/aggbug/348978.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2011-04-25 15:45 <a href="http://www.blogjava.net/changedi/archive/2011/04/25/348978.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JTidy的一些小tips</title><link>http://www.blogjava.net/changedi/archive/2011/04/19/348595.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Tue, 19 Apr 2011 13:33:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2011/04/19/348595.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/348595.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2011/04/19/348595.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/348595.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/348595.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 今天看了一下JTidy的使用，目的就是为了格式化一个不标准的html到标准的xhtml。<br>JTidy是一个用java写的HTML语法检查器，用JTidy可以检查并修正语法不正确的html，同时还可以对html的DOM进行分析。Xhtml和html有很多不同，其中几个主要的区别是<br>&nbsp;&nbsp;<a href='http://www.blogjava.net/changedi/archive/2011/04/19/348595.html'>阅读全文</a><img src ="http://www.blogjava.net/changedi/aggbug/348595.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2011-04-19 21:33 <a href="http://www.blogjava.net/changedi/archive/2011/04/19/348595.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Velocity学习笔记（下）</title><link>http://www.blogjava.net/changedi/archive/2011/04/07/347794.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Thu, 07 Apr 2011 07:43:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2011/04/07/347794.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/347794.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2011/04/07/347794.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/347794.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/347794.html</trackback:ping><description><![CDATA[&nbsp;
<h1>Velocity<span style="font-family: 宋体">笔记下</span></h1>
<h2>Velocity<span style="font-family: 宋体">与</span>struts<span style="font-family: 宋体">结合应用：</span></h2>
<p><span style="font-family: 宋体">具体通过一个实际的例子来解释，例子选择以传统的注册模块为主（主要是</span>joseph<span style="font-family: 宋体">的书上就这么写的）</span></p>
<p><span style="font-family: 宋体">首先，</span>web.xml<span style="font-family: 宋体">文件配置情况</span>struts<span style="font-family: 宋体">部分就不讲了，</span>velocity<span style="font-family: 宋体">的配置如下所示：</span></p>
<p>&lt;servlet&gt;</p>
<p>&lt;servlet-name&gt;velocity&lt;/servlet-name&gt;</p>
<p>&lt;servlet-class&gt;org.apache.velocity.tools.view.servlet.</p>
<p>VelocityViewServlet&lt;/servlet-class&gt;</p>
<p>&lt;init-param&gt;</p>
<p>&lt;param-name&gt;toolbox&lt;/param-name&gt;</p>
<p>&lt;param-value&gt;/WEB-INF/toolbox.xml&lt;/param-value&gt;</p>
<p>&lt;/init-param&gt;</p>
<p>&lt;load-on-startup&gt;10&lt;/load-on-startup&gt;</p>
<p>&lt;/servlet&gt;</p>
<p>&lt;!-- Action Servlet Mapping --&gt;</p>
<p>&lt;servlet-mapping&gt;</p>
<p>&lt;servlet-name&gt;velocity&lt;/servlet-name&gt;</p>
<p>&lt;url-pattern&gt;*.vm&lt;/url-pattern&gt;</p>
<p>&lt;/servlet-mapping&gt;</p>
<p><span style="font-family: 宋体">其中</span>velocity<span style="font-family: 宋体">的</span>servlet<span style="font-family: 宋体">配置中的初始参数传入了</span>toolbox.xml<span style="font-family: 宋体">，该文件的具体内容如下：</span></p>
<p>&lt;?xml version="1.0"?&gt;</p>
<p>&lt;toolbox&gt;</p>
<p>&lt;tool&gt;</p>
<p>&lt;key&gt;toolLoader&lt;/key&gt;</p>
<p>&lt;class&gt;org.apache.velocity.tools.tools.ToolLoader&lt;/class&gt;</p>
<p>&lt;/tool&gt;</p>
<p>&lt;tool&gt;</p>
<p>&lt;key&gt;link&lt;/key&gt;</p>
<p>&lt;class&gt;org.apache.velocity.tools.struts.LinkTool&lt;/class&gt;</p>
<p>&lt;/tool&gt;</p>
<p>&lt;tool&gt;</p>
<p>&lt;key&gt;msg&lt;/key&gt;</p>
<p>&lt;class&gt;org.apache.velocity.tools.struts.MessageTool&lt;/class&gt;</p>
<p>&lt;/tool&gt;</p>
<p>&lt;tool&gt;</p>
<p>&lt;key&gt;errors&lt;/key&gt;</p>
<p>&lt;class&gt;org.apache.velocity.tools.struts.ErrorsTool&lt;/class&gt;</p>
<p>&lt;/tool&gt;</p>
<p>&lt;tool&gt;</p>
<p>&lt;key&gt;form&lt;/key&gt;</p>
<p>&lt;class&gt;org.apache.velocity.tools.struts.FormTool&lt;/class&gt;</p>
<p>&lt;/tool&gt;</p>
<p>&lt;/toolbox&gt;</p>
<p><span style="font-family: 宋体">这个</span>xml<span style="font-family: 宋体">文件的意义就在于定义了很多类，来串联整个</span>struts<span style="font-family: 宋体">和</span>velocity<span style="font-family: 宋体">还有</span>javabean<span style="font-family: 宋体">等各个元素。</span></p>
<p><span style="font-family: 宋体">接着就开始配置</span>struts<span style="font-family: 宋体">了，首先考虑到这个应用，</span>struts<span style="font-family: 宋体">的第一步就是要写</span>form<span style="font-family: 宋体">了。首先构建一个</span>RegisterForm<span style="font-family: 宋体">。代码如下，这个</span>javabean<span style="font-family: 宋体">用来当做</span>model<span style="font-family: 宋体">定义数据。</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">package</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> app;</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">import</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> org.apache.struts.action.*;</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">public</span></strong><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">class</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> <u>RegisterForm</u> </span><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">extends</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> ActionForm {</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; color: black; font-size: 10pt">&nbsp;</span><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">protected</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> String </span><span style="font-family: 'Courier New'; color: #0000c0; font-size: 10pt">username</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">;</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; color: black; font-size: 10pt">&nbsp;</span><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">protected</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> String </span><span style="font-family: 'Courier New'; color: #0000c0; font-size: 10pt">password</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">;</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; color: black; font-size: 10pt">&nbsp;</span><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">protected</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> String </span><span style="font-family: 'Courier New'; color: #0000c0; font-size: 10pt">password2</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">;</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; color: black; font-size: 10pt">&nbsp;</span><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">public</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> String <span style="background: silver">getUsername</span>() { </span><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">return</span></strong><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">this</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt">.</span><span style="font-family: 'Courier New'; color: #0000c0; font-size: 10pt">username</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">; }</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; color: black; font-size: 10pt">&nbsp;</span><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">public</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> String getPassword() { </span><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">return</span></strong><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">this</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt">.</span><span style="font-family: 'Courier New'; color: #0000c0; font-size: 10pt">password</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">; }</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; color: black; font-size: 10pt">&nbsp;</span><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">public</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> String getPassword2() { </span><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">return</span></strong><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">this</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt">.</span><span style="font-family: 'Courier New'; color: #0000c0; font-size: 10pt">password2</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">; }</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; color: black; font-size: 10pt">&nbsp;</span><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">public</span></strong><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">void</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> setUsername(String username) { </span><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">this</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt">.</span><span style="font-family: 'Courier New'; color: #0000c0; font-size: 10pt">username</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> = username; };</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; color: black; font-size: 10pt">&nbsp;</span><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">public</span></strong><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">void</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> setPassword(String password) { </span><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">this</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt">.</span><span style="font-family: 'Courier New'; color: #0000c0; font-size: 10pt">password</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> = password; };</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; color: black; font-size: 10pt">&nbsp;</span><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">public</span></strong><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">void</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> setPassword2(String password) { </span><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">this</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt">.</span><span style="font-family: 'Courier New'; color: #0000c0; font-size: 10pt">password2</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> = password; };</span></p>
<p><span style="font-family: 'Courier New'; color: black; font-size: 10pt">}</span></p>
<p><span style="font-family: 宋体">该</span>javabean<span style="font-family: 宋体">有</span>3<span style="font-family: 宋体">个</span>field<span style="font-family: 宋体">属性，分别是</span>username<span style="font-family: 宋体">用户名，</span>password<span style="font-family: 宋体">密码和</span>password2<span style="font-family: 宋体">验证密码。</span></p>
<p><span style="font-family: 宋体">接着写控制处理逻辑</span>RegisterAction<span style="font-family: 宋体">。代码如下：</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">package</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> app;</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">import</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> org.apache.struts.action.*;</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">import</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> javax.servlet.http.*;</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">import</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> <u>java.io</u>.*;</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">public</span></strong><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">class</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> RegisterAction </span><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">extends</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> Action {</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; color: black; font-size: 10pt">&nbsp;</span><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">public</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> ActionForward perform(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) {</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; color: black; font-size: 10pt">&nbsp;&nbsp;&nbsp; RegisterForm rf = (RegisterForm) form;</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; color: black; font-size: 10pt">&nbsp;&nbsp;&nbsp; String <u>username</u> = rf.getUsername();</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; color: black; font-size: 10pt">&nbsp;&nbsp;&nbsp; String password = rf.getPassword();</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; color: black; font-size: 10pt">&nbsp;&nbsp;&nbsp; String password2 = rf.getPassword2();</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; color: black; font-size: 10pt">&nbsp;&nbsp;&nbsp; </span><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">if</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> (password.equals(password2)) {</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; color: black; font-size: 10pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">return</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> mapping.findForward(</span><span style="font-family: 'Courier New'; color: #2a00ff; font-size: 10pt">"success"</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">);</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; color: black; font-size: 10pt">&nbsp;&nbsp;&nbsp; }</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; color: black; font-size: 10pt">&nbsp;&nbsp;&nbsp; </span><strong><span style="font-family: 'Courier New'; color: #7f0055; font-size: 10pt">return</span></strong><span style="font-family: 'Courier New'; color: black; font-size: 10pt"> mapping.findForward(</span><span style="font-family: 'Courier New'; color: #2a00ff; font-size: 10pt">"failure"</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">);</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; color: black; font-size: 10pt">&nbsp;}</span></p>
<p><span style="font-family: 'Courier New'; color: black; font-size: 10pt">}</span></p>
<p><span style="font-family: 宋体">通过</span>form<span style="font-family: 宋体">表单读入数据，如果密码和验证密码相同，那么就跳到</span>success<span style="font-family: 宋体">，否则是</span>failure<span style="font-family: 宋体">，这个逻辑非常简单。</span>Struts<span style="font-family: 宋体">中也看不出任何的</span>velocity<span style="font-family: 宋体">相关（那当然，这就叫低耦合，各干各的，分层处理）</span></p>
<p><span style="font-family: 宋体">然后该配置熟悉的</span>struts-config.xml<span style="font-family: 宋体">了。核心代码如下：</span></p>
<p>&lt;struts-config&gt;</p>
<p>&lt;form-beans&gt;</p>
<p>&lt;form-bean name="registerForm" type="RegisterForm"/&gt;</p>
<p>&lt;/form-beans&gt;</p>
<p>&lt;action-mappings&gt;</p>
<p>&lt;action path="/struts"</p>
<p>type="RegisterAction"</p>
<p>name="registerForm"&gt;</p>
<p>&lt;forward name="success" path="/success.vm"/&gt;</p>
<p>&lt;forward name="failure" path="/failure.vm"/&gt;</p>
<p>&lt;/action&gt;</p>
<p>&lt;/action-mappings&gt;</p>
<p>&lt;/struts-config&gt;</p>
<p><span style="font-family: 宋体">配置文件与传统的</span>struts<span style="font-family: 宋体">出奇的一致，唯一变化的就是在</span>forward<span style="font-family: 宋体">里的</span>path<span style="font-family: 宋体">写成了</span>vm<span style="font-family: 宋体">文件，而不是我们传统的</span>jsp<span style="font-family: 宋体">。</span></p>
<p><span style="font-family: 宋体">好了，写到现在，</span>MVC<span style="font-family: 宋体">中的</span>M<span style="font-family: 宋体">和</span>C<span style="font-family: 宋体">都完成了，该是</span>velocity<span style="font-family: 宋体">上场了——</span>View<span style="font-family: 宋体">层。</span></p>
<p><span style="font-family: 宋体">注册页面</span>register.vm<span style="font-family: 宋体">的核心代码：</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; font-size: 10pt">&lt;form action="struts.do" method="post"&gt;</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; font-size: 10pt">&nbsp;username: &lt;input type="text" name="username"/&gt;&lt;BR&gt;</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; font-size: 10pt">&nbsp;password: &lt;input type="text" name="password"/&gt;&lt;BR&gt;</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; font-size: 10pt">&nbsp;again&nbsp;&nbsp; : &lt;input type="text" name="password2"/&gt;&lt;BR&gt;</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; font-size: 10pt">&lt;input type="submit" name="submit" value="Register"/&gt;</span></p>
<p><span style="font-family: 'Courier New'; font-size: 10pt">&lt;/form&gt;</span></p>
<p>Success<span style="font-family: 宋体">跳转页面</span>success.vm<span style="font-family: 宋体">：</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; font-size: 10pt">&lt;HTML&gt;</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; font-size: 10pt">&lt;HEAD&gt;</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; font-size: 10pt">&nbsp;&lt;TITLE&gt;Success&lt;/TITLE&gt;</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; font-size: 10pt">&lt;/HEAD&gt;</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; font-size: 10pt">&lt;BODY&gt;</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; font-size: 10pt">&nbsp;Registration Success!</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; font-size: 10pt">&nbsp;Thanks for logging in $!registerForm.username</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; font-size: 10pt">&nbsp;&lt;P&gt;&lt;A href="register.vm"&gt;Try Another?&lt;/A&gt;&lt;/P&gt;</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Courier New'; font-size: 10pt">&lt;/BODY&gt;</span></p>
<p><span style="font-family: 'Courier New'; font-size: 10pt">&lt;/HTML&gt;</span></p>
<p><span style="font-family: 宋体">其中只用到了一个</span><span style="font-family: 'Courier New'; font-size: 10pt">$!registerForm.username</span><span style="font-family: 宋体; font-size: 10pt">。整个代码完成了，压根没用到什么</span><span style="font-family: 'Courier New'; font-size: 10pt">context</span><span style="font-family: 宋体; font-size: 10pt">之类的东西。<br />
</span><span style="font-family: 宋体"><br />
源代码来自</span><a href="http://www.wiley.com/legacy/compbooks/gradecki/apache/index.html">http://www.wiley.com//legacy/compbooks/gradecki/apache/index.html</a></p>
<span style="font-family: 宋体; font-size: 10.5pt">下载</span><span style="font-family: 'Calibri','sans-serif'; font-size: 10.5pt">ch17.zip</span><span style="font-family: 宋体; font-size: 10.5pt">即可。<br />
另<font face="宋体"><a href="http://www.ibm.com/developerworks/cn/java/j-sr1.html">http://www.ibm.com/developerworks/cn/java/j-sr1.html</a></font>里<a class="dwauthor" title="" href="http://www.ibm.com/developerworks/cn/java/j-sr1.html#author1" rel="#authortip1" hoverintent_t="undefined" hoverintent_s="0" jquery1302160132409="77">George Franciscus</a>讲的也很详细。<br />
</span>
<img src ="http://www.blogjava.net/changedi/aggbug/347794.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2011-04-07 15:43 <a href="http://www.blogjava.net/changedi/archive/2011/04/07/347794.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>velocity学习笔记（上）</title><link>http://www.blogjava.net/changedi/archive/2011/04/07/velocity.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Thu, 07 Apr 2011 03:03:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2011/04/07/velocity.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/347770.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2011/04/07/velocity.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/347770.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/347770.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 杂七杂八的看了一些velocity的资料，把所见所得做个简单不系统的笔记写下来，算是增强记忆。<br><br>&nbsp;&nbsp;<a href='http://www.blogjava.net/changedi/archive/2011/04/07/velocity.html'>阅读全文</a><img src ="http://www.blogjava.net/changedi/aggbug/347770.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2011-04-07 11:03 <a href="http://www.blogjava.net/changedi/archive/2011/04/07/velocity.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Commons-lang记录</title><link>http://www.blogjava.net/changedi/archive/2011/03/24/346976.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Thu, 24 Mar 2011 12:05:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2011/03/24/346976.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/346976.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2011/03/24/346976.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/346976.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/346976.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Commons-lang记录：<br>一个最常用的工具，作为jdk的补充，有必要看一下源码~~<br><br>&nbsp;&nbsp;<a href='http://www.blogjava.net/changedi/archive/2011/03/24/346976.html'>阅读全文</a><img src ="http://www.blogjava.net/changedi/aggbug/346976.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2011-03-24 20:05 <a href="http://www.blogjava.net/changedi/archive/2011/03/24/346976.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>spring复习速记</title><link>http://www.blogjava.net/changedi/archive/2011/03/19/346593.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Sat, 19 Mar 2011 05:12:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2011/03/19/346593.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/346593.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2011/03/19/346593.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/346593.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/346593.html</trackback:ping><description><![CDATA[正统的学习笔记没有记，为什么？提醒自己，spring你是学过的，这次复习，只是把要点记下来就可以了，也是为什么只看spring in action的原因：<br />
<br />
&nbsp;
<h1>Spring<span style="font-family: 宋体">基础学习注记</span> </h1>
<h1>Spring<span style="font-family: 宋体">是轻量级的，</span>AOP<span style="font-family: 宋体">的，</span>DI<span style="font-family: 宋体">的，框架的，容器的</span></h1>
<p><strong><span style="font-family: 宋体">轻量级</span></strong><span style="font-family: 宋体">：体积（</span>2.5M<span style="font-family: 宋体">），开销</span></p>
<p><strong>DI</strong><span style="font-family: 宋体">：通过</span>DI<span style="font-family: 宋体">来松耦。所谓依赖注入，即组件之间的依赖关系由容器在运行期决定，形象的来说，即由容器动态的将某种依赖关系注入到组件之中</span></p>
<p><strong>AOP</strong><span style="font-family: 宋体">：理解为&#8220;切面&#8221;比较合适，</span>AOP<span style="font-family: 宋体">则是针对业务处理过程中的切面进行提取，它所面对的是处理过程中的某个步骤或阶段，以获得逻辑过程中各部分之间低耦合性的隔离效果。</span><span style="font-family: 'Verdana','sans-serif'">OOD/OOP</span><span style="font-family: 宋体">面向名词领域，</span><span style="font-family: 'Verdana','sans-serif'">AOP</span><span style="font-family: 宋体">面向动词领域。</span><span style="font-family: 'Verdana','sans-serif'">AOP</span><span style="font-family: 宋体">还有另外一个重要特点：源码组成无关性。</span></p>
<p><strong><span style="font-family: 宋体">容器的</span></strong><span style="font-family: 宋体">：负责AO的lifecycle和configuration。可以定义AO如何被创建、如何配置和如何相互关联。</span></p>
<p><strong><span style="font-family: 宋体">框架</span></strong><span style="font-family: 宋体">：配置和组合应用，管理AO，通过XML配置，并提供很多基础设施服务，比如事务管理，持久化框架集成。<br />
<img border="0" alt="" src="http://www.blogjava.net/images/blogjava_net/changedi/blog.PNG" /><br />
</span></p>
<p>Spring&#8217;s core container<span style="font-family: 宋体">：提供基本功能，包括</span>BeanFactory<span style="font-family: 宋体">（</span>DI<span style="font-family: 宋体">的基础，</span>spring<span style="font-family: 宋体">框架的基础）。</span></p>
<p><strong><em>Application context module</em></strong><strong><em><span style="font-family: 宋体">：</span></em></strong>core<span style="font-family: 宋体">使</span>spring<span style="font-family: 宋体">像个容器，而</span>context<span style="font-family: 宋体">则使其像一个框架。常用的一个应用就是集成</span>velocity<span style="font-family: 宋体">和</span>freemarker<span style="font-family: 宋体">的一个集成点。</span></p>
<h2>Spring&#8217;s AOP module<span style="font-family: 宋体">：顾名思义。</span></h2>
<p><strong><em>JDBC abstraction and the DAO module</em></strong><strong><em><span style="font-family: 宋体">：</span></em></strong><span style="font-family: 宋体">集成数据库操作。这个模块会利用</span>AOP<span style="font-family: 宋体">模块提供的事务管理功能。</span></p>
<p><strong><em>Object-relational mapping (ORM) integration module</em></strong><strong><em><span style="font-family: 宋体">：</span></em></strong><span style="font-family: 宋体">在</span>DAO<span style="font-family: 宋体">的基础上提供</span>ORM<span style="font-family: 宋体">的</span>solution<span style="font-family: 宋体">。</span>Spring<span style="font-family: 宋体">不实现自己的</span>ORM<span style="font-family: 宋体">，只是提供一个与</span>ORM<span style="font-family: 宋体">框架结合的接口，比如</span>Hibernate<span style="font-family: 宋体">，</span>JPA,JDO,IBATIS<span style="font-family: 宋体">等。同样</span>spring<span style="font-family: 宋体">的事务管理也与这些框架相结合。</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><strong><em>Java Management Extensions (JMX)</em></strong><strong><em><span style="font-family: 宋体">：</span></em></strong><span style="font-family: 'NewBaskerville-Roman','serif'">Exposing the inner workings of a Java application for management is a critical part of making an application production ready. Spring&#8217;s </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">JMX </span><span style="font-family: 'NewBaskerville-Roman','serif'">module makes it easy to expose your application&#8217;s beans as </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">JMX </span><span style="font-family: 'NewBaskerville-Roman','serif'">MBeans. This makes it possible to monitor and reconfigure a running application.</span></p>
<h2>Java EE Connector API (JCA)</h2>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">The enterprise application landscape is littered with a mishmash of applications</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">running on an array of disparate servers and platforms. Integrating these applications</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">can be tricky. The Java </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">EE </span><span style="font-family: 'NewBaskerville-Roman','serif'">Connection </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">API </span><span style="font-family: 'NewBaskerville-Roman','serif'">(better known as </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">JCA</span><span style="font-family: 'NewBaskerville-Roman','serif'">) provides a</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">standard way of integrating Java applications with a variety of enterprise information</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">systems, including mainframes and databases.</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">In many ways, </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">JCA </span><span style="font-family: 'NewBaskerville-Roman','serif'">is much like </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">JDBC</span><span style="font-family: 'NewBaskerville-Roman','serif'">, except where </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">JDBC </span><span style="font-family: 'NewBaskerville-Roman','serif'">is focused on database</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">access, </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">JCA </span><span style="font-family: 'NewBaskerville-Roman','serif'">is a more general-purpose </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">API </span><span style="font-family: 'NewBaskerville-Roman','serif'">connecting to legacy systems. Spring&#8217;s</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">support for </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">JCA </span><span style="font-family: 'NewBaskerville-Roman','serif'">is similar to its </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">JDBC </span><span style="font-family: 'NewBaskerville-Roman','serif'">support, abstracting away </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">JCA</span><span style="font-family: 'NewBaskerville-Roman','serif'">&#8217;s boilerplate</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">code into templates.</span></p>
<h2>The Spring MVC framework</h2>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 宋体">与</span><span style="font-family: 'NewBaskerville-Roman','serif'">ORM</span><span style="font-family: 宋体">不同，</span><span style="font-family: 'NewBaskerville-Roman','serif'">MVC</span><span style="font-family: 宋体">模块既结合已有的像</span><span style="font-family: 'NewBaskerville-Roman','serif'">Struts</span><span style="font-family: 宋体">、</span><span style="font-family: 'NewBaskerville-Roman','serif'">Tapestry</span><span style="font-family: 宋体">、</span><span style="font-family: 'NewBaskerville-Roman','serif'">WebWork</span><span style="font-family: 宋体">这样的框架，也提供了自己的</span><span style="font-family: 'NewBaskerville-Roman','serif'">MVC</span><span style="font-family: 宋体">框架。</span></p>
<h2>Spring Portlet MVC</h2>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">Many web applications are page based—that is, each request to the application</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">results in a completely new page being displayed. Each page typically presents a</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">specific piece of information or prompts the user with a specific form. In contrast,</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">portlet-based applications aggregate several bits of functionality on a single web</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">page. This provides a view into several applications at once.</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">If you&#8217;re building portlet-enabled applications, you&#8217;ll certainly want to look at</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">Spring&#8217;s Portlet </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">MVC </span><span style="font-family: 'NewBaskerville-Roman','serif'">framework. Spring Portlet </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">MVC </span><span style="font-family: 'NewBaskerville-Roman','serif'">builds on Spring </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">MVC </span><span style="font-family: 'NewBaskerville-Roman','serif'">to provide</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">a set of controllers that support Java&#8217;s portlet </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">API</span><span style="font-family: 'NewBaskerville-Roman','serif'">.</span></p>
<h2>Spring&#8217;s web module</h2>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 宋体">提供</span><span style="font-family: 'FranklinGothic-DemiItal','sans-serif'">MVC</span><span style="font-family: 宋体">模块需要的</span><span style="font-family: 'FranklinGothic-DemiItal','sans-serif'">classes</span><span style="font-family: 宋体">。</span></p>
<h2>Remoting</h2>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">Not all applications work alone. Oftentimes, it&#8217;s necessary for an application to</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">leverage the functionality of another application to get its work done. When the</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">other application is accessed over the network, some form of remoting is used</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">for communication.</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">Spring&#8217;s remoting support enables you to expose the functionality of your Java</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">objects as remote objects. Or if you need to access objects remotely, the remoting</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">module also makes simple work of wiring remote objects into your application as</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">if they were local </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">POJO</span><span style="font-family: 'NewBaskerville-Roman','serif'">s. Several remoting options are available, including</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">Remote Method Invocation (</span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">RMI</span><span style="font-family: 'NewBaskerville-Roman','serif'">), Hessian, Burlap, </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">JAX</span><span style="font-family: 'NewBaskerville-Roman','serif'">-</span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">RPC</span><span style="font-family: 'NewBaskerville-Roman','serif'">, and Spring&#8217;s own</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">HTTP </span><span style="font-family: 'NewBaskerville-Roman','serif'">Invoker.</span></p>
<h2>Java Message Service (JMS)</h2>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">The downside to remoting is that it depends on network reliability and that both</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">ends of the communication be available. Message-oriented communication, on</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">the other hand, is more reliable and guarantees delivery of messages, even if the</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">network and endpoints are unreliable.</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">Spring&#8217;s Java Message Service (</span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">JMS</span><span style="font-family: 'NewBaskerville-Roman','serif'">) module helps you send messages to </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">JMS</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">message queues and topics. At the same time, this module also helps you create message-driven </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">POJO</span><span style="font-family: 'NewBaskerville-Roman','serif'">s that are capable of consuming asynchronous messages.</span></p>
<h2><span style="font-family: 宋体">解释一个</span>spring<span style="font-family: 宋体">的</span>xml<span style="font-family: 宋体">：</span></h2>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">&lt;beans&gt;</span><span style="font-family: 宋体">是根元素。</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">&lt;bean&gt;</span><span style="font-family: 宋体">告诉容器如何配置一个</span><span style="font-family: 'NewBaskerville-Roman','serif'">class</span><span style="font-family: 宋体">，</span><span style="font-family: 'NewBaskerville-Roman','serif'">id</span><span style="font-family: 宋体">属性表示这个</span><span style="font-family: 'NewBaskerville-Roman','serif'">bean</span><span style="font-family: 宋体">对象的名字，</span><span style="font-family: 'NewBaskerville-Roman','serif'">class</span><span style="font-family: 宋体">属性表示这个</span><span style="font-family: 'NewBaskerville-Roman','serif'">bean</span><span style="font-family: 宋体">对象的具体</span><span style="font-family: 'NewBaskerville-Roman','serif'">class</span><span style="font-family: 宋体">。</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">&lt;bean&gt;</span><span style="font-family: 宋体">下的</span><span style="font-family: 'NewBaskerville-Roman','serif'">&lt;property&gt;</span><span style="font-family: 宋体">用于设置一个该</span><span style="font-family: 'NewBaskerville-Roman','serif'">bean</span><span style="font-family: 宋体">对象的属性</span><span style="font-family: 'NewBaskerville-Roman','serif'">property</span><span style="font-family: 宋体">，</span><span style="font-family: 'NewBaskerville-Roman','serif'">name</span><span style="font-family: 宋体">属性表示这个</span><span style="font-family: 'NewBaskerville-Roman','serif'">property</span><span style="font-family: 宋体">的名字，</span><span style="font-family: 'NewBaskerville-Roman','serif'">value</span><span style="font-family: 宋体">属性传递给这个</span><span style="font-family: 'NewBaskerville-Roman','serif'">property</span><span style="font-family: 宋体">值。用</span><span style="font-family: 'NewBaskerville-Roman','serif'">property</span><span style="font-family: 宋体">这种方式，等同于利用</span><span style="font-family: 'NewBaskerville-Roman','serif'">bean</span><span style="font-family: 宋体">对象的</span><span style="font-family: 'NewBaskerville-Roman','serif'">set</span><span style="font-family: 宋体">方法。</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">&lt;bean&gt;</span><span style="font-family: 宋体">下的</span><span style="font-family: 'NewBaskerville-Roman','serif'">&lt;constructor-arg&gt;</span><span style="font-family: 宋体">与</span><span style="font-family: 'NewBaskerville-Roman','serif'">&lt;property&gt;</span><span style="font-family: 宋体">类似，只是这个等同于利用</span><span style="font-family: 'NewBaskerville-Roman','serif'">bean</span><span style="font-family: 宋体">对象的赋值构造函数。</span></p>
<h2><span style="font-family: 宋体">粗解</span>DI</h2>
<p><img border="0" alt="" src="http://www.blogjava.net/images/blogjava_net/changedi/blog2.PNG" /></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">The key benefit of </span><span style="font-family: 'NewBaskerville-Roman','serif'; font-size: 9.5pt">DI </span><span style="font-family: 'NewBaskerville-Roman','serif'">is loose coupling.</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">Interface programming</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 宋体">通过配置文件</span><span style="font-family: 'NewBaskerville-Roman','serif'">xml</span><span style="font-family: 宋体">，写</span><span style="font-family: 'NewBaskerville-Roman','serif'">beanfactory</span><span style="font-family: 宋体">等，来实现简单注入，从而松耦。</span></p>
<h2><span style="font-family: 宋体">粗解</span>AOP</h2>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 宋体">解释</span><span style="font-family: 'NewBaskerville-Roman','serif'">aop</span><span style="font-family: 宋体">的</span><span style="font-family: 'NewBaskerville-Roman','serif'">xml</span><span style="font-family: 宋体">配置元素：</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'NewBaskerville-Roman','serif'">&lt;aop:config&gt;</span><span style="font-family: 宋体">解释要做</span><span style="font-family: 'NewBaskerville-Roman','serif'">aop</span><span style="font-family: 宋体">配置，是</span><span style="font-family: 'NewBaskerville-Roman','serif'">spring aop</span><span style="font-family: 宋体">基本必备的元素</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 宋体">——</span><span style="font-family: 'NewBaskerville-Roman','serif'">&lt;aop:aspect&gt;</span><span style="font-family: 宋体">表示声明一个</span><span style="font-family: 'NewBaskerville-Roman','serif'">aspect</span><span style="font-family: 宋体">，这个</span><span style="font-family: 'NewBaskerville-Roman','serif'">aspect</span><span style="font-family: 宋体">的功能被定义在其</span><span style="font-family: 'NewBaskerville-Roman','serif'">ref</span><span style="font-family: 宋体">属性中，</span><span style="font-family: 'NewBaskerville-Roman','serif'">ref</span><span style="font-family: 宋体">一般会联系一个已经定义好的</span><span style="font-family: 'NewBaskerville-Roman','serif'">bean</span><span style="font-family: 宋体">对象。一个</span><span style="font-family: 'NewBaskerville-Roman','serif'">aspect</span><span style="font-family: 宋体">由</span><span style="font-family: 'NewBaskerville-Roman','serif'">pointcuts</span><span style="font-family: 宋体">（功能在哪里实现）和</span><span style="font-family: 'NewBaskerville-Roman','serif'">advice</span><span style="font-family: 宋体">（功能怎样实现）组成。</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 宋体">————</span><span style="font-family: 'NewBaskerville-Roman','serif'">&lt;aop:pointcut&gt;</span><span style="font-family: 宋体">定义一个</span><span style="font-family: 'NewBaskerville-Roman','serif'">pointcut</span><span style="font-family: 宋体">，触发条件是某方法被执行。</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 宋体">————</span><span style="font-family: 'NewBaskerville-Roman','serif'">&lt;aop:before&gt;</span><span style="font-family: 宋体">顾名思义，一个</span><span style="font-family: 'NewBaskerville-Roman','serif'">advice</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 宋体">————</span><span style="font-family: 'NewBaskerville-Roman','serif'">&lt;aop:after&gt;</span><span style="font-family: 宋体">同上。</span></p>
<h1><em><span style="line-height: 240%; font-family: 'NewBaskerville-Italic','serif'; font-size: 30pt">Basic bean wiring</span></em></h1>
<p>The act of creating these associations between application objects is the</p>
<p>essence of dependency injection (DI) and is commonly referred to as <strong><em>wiring</em></strong>.</p>
<h2>Spring container</h2>
<p><img border="0" alt="" src="http://www.blogjava.net/images/blogjava_net/changedi/blog3.PNG" /></p>
<h3><em>BeanFactory</em></h3>
<p><span style="font-family: 宋体">顾名思义，遵循工厂模式的一个类，管理和分发</span>beans<span style="font-family: 宋体">。</span></p>
<p><span style="font-family: 宋体">通用的工厂，可以管理分发各种类型的</span>beans<span style="font-family: 宋体">。</span></p>
<p>Beanfactory<span style="font-family: 宋体">参与了</span>bean<span style="font-family: 宋体">的整个生命周期。</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 宋体">多种实现方式，最常用的是</span>org.springframework.beans.factory.xml.XmlBeanFactory<span style="font-family: 宋体">，通过加载</span>xml<span style="font-family: 宋体">来实现。当然必须要传递一个</span>Resource<span style="font-family: 宋体">给</span>beanfactory<span style="font-family: 宋体">。例：</span><span style="font-family: Courier; font-size: 8pt">BeanFactory factory = new XmlBeanFactory(new FileSystemResource("c:/beans.xml"));</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 宋体; font-size: 8pt">得到一个</span><span style="font-family: Courier; font-size: 8pt">bean</span><span style="font-family: 宋体; font-size: 8pt">的方法就是调用</span><span style="font-family: Courier; font-size: 10pt">getBean()</span><span style="font-family: 宋体; font-size: 10pt">。比如：</span><span style="font-family: Courier; font-size: 8pt">MyBean myBean = (MyBean) factory.getBean("myBean");</span></p>
<h3><em>application context</em></h3>
<p><span style="font-family: 宋体">等同于</span>beanfactory<span style="font-family: 宋体">，但是提供</span>more<span style="font-family: 宋体">：</span></p>
<p style="text-indent: -18pt; margin-left: 18pt" class="MsoListParagraph">1．&nbsp;<span style="font-family: 宋体">支持</span>I18N<span style="font-family: 宋体">的消息</span></p>
<p style="text-indent: -18pt; margin-left: 18pt" class="MsoListParagraph">2．&nbsp;<span style="font-family: 宋体">提供一般基本方法去加载</span>file resources</p>
<p style="text-indent: -18pt; margin-left: 18pt" class="MsoListParagraph">3．&nbsp;<span style="font-family: 宋体">发布</span>events<span style="font-family: 宋体">到已经注册为</span>listener<span style="font-family: 宋体">的</span>beans</p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: Courier; font-size: 10pt">ClassPathXmlApplicationContext</span><span style="font-family: 宋体; font-size: 10pt">和</span><span style="font-family: Courier; font-size: 10pt">FileSystemXmlApplicationContext</span><span style="font-family: 宋体; font-size: 10pt">比较常用。例：</span><span style="font-family: Courier; font-size: 8pt">ApplicationContext context = new FileSystemXmlApplicationContext("c:/foo.xml"); ApplicationContext context = new ClassPathXmlApplicationContext("foo.xml");</span></p>
<h3>bean&#8217;s life</h3>
<p><img border="0" alt="" src="http://www.blogjava.net/images/blogjava_net/changedi/blog4.PNG" /></p>
<h2><img border="0" alt="" src="http://www.blogjava.net/images/blogjava_net/changedi/blog5.PNG" /></h2>
<h2>Creating Beans</h2>
<p><span style="font-family: 宋体">分两步，首先声明一个</span>bean<span style="font-family: 宋体">，即定义一个类。然后注入，即为其注入属性内容。</span></p>
<p><span style="font-family: 宋体">何时选择</span>setter<span style="font-family: 宋体">注入，何时选择</span>constructor<span style="font-family: 宋体">注入，见</span>spring in action<span style="font-family: 宋体">原书第</span>45<span style="font-family: 宋体">页。</span></p>
<h2>Injecting into bean properties</h2>
<p><span style="font-family: 宋体">通过</span>&lt;property&gt;<span style="font-family: 宋体">元素完成注入。其等价于调用</span>bean<span style="font-family: 宋体">对应类的</span>setXXX<span style="font-family: 宋体">方法。</span></p>
<p><span style="font-family: 宋体">例：</span><span style="font-family: Courier; font-size: 8pt">&lt;property name="song" value="Jingle Bells" /&gt;</span></p>
<p><span style="font-family: 宋体">其中</span>value<span style="font-family: 宋体">的值，</span>spring<span style="font-family: 宋体">会根据</span>property<span style="font-family: 宋体">的具体类别来选择不同的数据类型。</span></p>
<p>&lt;property name="instrument" ref="saxophone" /&gt;<span style="font-family: 宋体">这样的声明中，表示该</span>property<span style="font-family: 宋体">是一个类的对象，其类就是已经声明过的某个</span>bean<span style="font-family: 宋体">：</span>saxophone<span style="font-family: 宋体">。</span></p>
<p><span style="font-family: 宋体">在</span>&lt;property&gt;<span style="font-family: 宋体">下直接定义</span>bean<span style="font-family: 宋体">叫做</span>inner bean<span style="font-family: 宋体">。（当然通过</span>constructor<span style="font-family: 宋体">道理相同）</span></p>
<p><span style="font-family: 宋体">对于复杂集合类型：<br />
<img border="0" alt="" src="http://www.blogjava.net/images/blogjava_net/changedi/blog6.PNG" /><br />
</span></p>
<p><span style="font-family: 宋体">其中的</span>map<span style="font-family: 宋体">需要注意一下。</span>Props<span style="font-family: 宋体">的代码实现上与</span>map<span style="font-family: 宋体">也不同。</span></p>
<h2>Autowiring</h2>
<h3>The four types of autowiring</h3>
<p>byName<span style="font-family: 宋体">：找到</span>name<span style="font-family: 宋体">相匹配的，</span>wire</p>
<p>byType<span style="font-family: 宋体">：找到</span>type<span style="font-family: 宋体">匹配的，</span>wire</p>
<p>constructor<span style="font-family: 宋体">：利用</span>constructor<span style="font-family: 宋体">参数匹配，</span>wire</p>
<p>autodetect<span style="font-family: 宋体">：先</span>constructor<span style="font-family: 宋体">，再</span>byType</p>
<h2>Controlling bean creation</h2>
<p><span style="font-family: 宋体">有多少对象实例，就由多少</span>bean</p>
<p><span style="font-family: 宋体">从静态的工厂去构造</span>bean<span style="font-family: 宋体">，而不是</span>constructor</p>
<p><span style="font-family: 宋体">构造好</span>bean<span style="font-family: 宋体">后要及时初始化，在</span>bean<span style="font-family: 宋体">销毁之前要及时</span>clean up</p>
<h3>Bean scoping</h3>
<p><span style="font-family: 宋体">所有的</span>spring beans<span style="font-family: 宋体">都是单例的。</span></p>
<p><span style="font-family: 宋体">通过设置</span>&lt;bean&gt;<span style="font-family: 宋体">的</span>scope=&#8221;prototype&#8221;<span style="font-family: 宋体">，</span>spring<span style="font-family: 宋体">可以在需要的时候产生新的</span>bean<span style="font-family: 宋体">的实例。<br />
<br />
<img border="0" alt="" src="http://www.blogjava.net/images/blogjava_net/changedi/blog7.PNG" /><br />
<br />
</span></p>
<h3>Initializing and destroying beans</h3>
<p>&lt;bean&gt;<span style="font-family: 宋体">中有</span>init-method<span style="font-family: 宋体">和</span>destroy-method<span style="font-family: 宋体">负责设置初始化和销毁时调用的方法。</span></p>
<p><span style="font-family: 宋体">如果很多</span>bean<span style="font-family: 宋体">都有同样的初始化和销毁程序，那么可以在</span>&lt;beans&gt;<span style="font-family: 宋体">中设置</span>defaultinit-</p>
<p>method <span style="font-family: 宋体">和</span> default-destroy-method</p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 宋体">还有种方法就是</span>bean<span style="font-family: 宋体">类的定义时，让类去实现</span><span style="font-family: Courier; font-size: 10pt">InitializingBean </span><span style="font-family: 宋体">和</span><span style="font-family: Courier; font-size: 10pt">DisposableBean</span><span style="font-family: 'NewBaskerville-Roman','serif'">.</span></p>
<h1>Advising beans</h1>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 宋体">重点讲述</span>AOP<span style="font-family: 宋体">。</span></p>
<h2>Introducing AOP</h2>
<p style="text-align: left" class="MsoNormal" align="left">Aspect<span style="font-family: 宋体">帮助我们建模那些</span>cross-cutting concerns<span style="font-family: 宋体">（一个应用中在多个位置起到作用的点，比如</span>security<span style="font-family: 宋体">）。<br />
<br />
<img border="0" alt="" src="http://www.blogjava.net/images/blogjava_net/changedi/blog8.PNG" /><br />
</span></p>
<h3>Defining AOP terminology</h3>
<p style="text-align: left" class="MsoNormal" align="left">AOP<span style="font-family: 宋体">一般用</span>advice<span style="font-family: 宋体">、</span>pointcut<span style="font-family: 宋体">和</span>joinpoint<span style="font-family: 宋体">描述。<br />
<img border="0" alt="" src="http://www.blogjava.net/images/blogjava_net/changedi/blog9.PNG" /><br />
</span></p>
<p style="text-align: left" class="MsoNormal" align="left">Advice<span style="font-family: 宋体">：</span>aspect<span style="font-family: 宋体">必定是在做一个</span>job<span style="font-family: 宋体">，即要做某个功能。其中这个</span>job<span style="font-family: 宋体">就叫做</span>advice<span style="font-family: 宋体">。</span>Advice<span style="font-family: 宋体">定义了</span>aspect<span style="font-family: 宋体">的</span>what<span style="font-family: 宋体">和</span>when<span style="font-family: 宋体">。</span></p>
<p style="text-align: left" class="MsoNormal" align="left">Joinpoint<span style="font-family: 宋体">：在整个</span>application<span style="font-family: 宋体">中有可能用到</span>advice<span style="font-family: 宋体">的连接点。</span></p>
<p style="text-align: left" class="MsoNormal" align="left">Pointcut<span style="font-family: 宋体">：定义了</span>aspect<span style="font-family: 宋体">的</span>where<span style="font-family: 宋体">。</span></p>
<p style="text-align: left" class="MsoNormal" align="left">Aspect<span style="font-family: 宋体">：是</span>advice<span style="font-family: 宋体">和</span>pointcut<span style="font-family: 宋体">的</span>merger<span style="font-family: 宋体">。</span></p>
<h3>Spring&#8217;s AOP support</h3>
<p style="text-align: left" class="MsoNormal" align="left">Spring<span style="font-family: 宋体">支持</span>4<span style="font-family: 宋体">种风格的</span>aop<span style="font-family: 宋体">：</span></p>
<p style="text-align: left" class="MsoNormal" align="left">Spring<span style="font-family: 宋体">的</span>advice<span style="font-family: 宋体">都是</span>java<span style="font-family: 宋体">写的。</span></p>
<p style="text-align: left" class="MsoNormal" align="left">Spring<span style="font-family: 宋体">在运行时</span>advise object<span style="font-family: 宋体">。<br />
<br />
<img border="0" alt="" src="http://www.blogjava.net/images/blogjava_net/changedi/blog10.PNG" /><br />
</span></p>
<p style="text-align: left" class="MsoNormal" align="left">Spring<span style="font-family: 宋体">只支持方法连接点</span>method joinpoint<span style="font-family: 宋体">。</span></p>
<h1>Spring MVC</h1>
<p><img border="0" alt="" src="http://www.blogjava.net/images/blogjava_net/changedi/blog11.PNG" /><br />
<img border="0" alt="" src="http://www.blogjava.net/images/blogjava_net/changedi/blog12.PNG" /><br />
<img border="0" alt="" src="http://www.blogjava.net/images/blogjava_net/changedi/blog13.PNG" /><br />
<img border="0" alt="" src="http://www.blogjava.net/images/blogjava_net/changedi/blog14.PNG" /></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 宋体; font-size: 10pt">其中，一个</span><span style="font-family: Courier; font-size: 10pt">command object </span><span style="font-family: 宋体; font-size: 10pt">就是一个像</span><span style="font-family: Courier; font-size: 10pt">struts</span><span style="font-family: 宋体; font-size: 10pt">中的</span><span style="font-family: Courier; font-size: 10pt">actionform</span><span style="font-family: 宋体; font-size: 10pt">一样的东西。<br />
<img border="0" alt="" src="http://www.blogjava.net/images/blogjava_net/changedi/blog15.PNG" /><br />
</span></p>
<p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: Courier; font-size: 10pt">Wizard</span><span style="font-family: 宋体; font-size: 10pt">是一个可以将多个页面联合起来作为一个</span><span style="font-family: Courier; font-size: 10pt">form</span><span style="font-family: 宋体; font-size: 10pt">的东西。<br />
<img border="0" alt="" src="http://www.blogjava.net/images/blogjava_net/changedi/blog16.PNG" /><br />
<br />
基本搞完了，总的来讲，学习的东西就要经常用，否则慢慢的就会淡忘了，尤其是技术上的一些细节。如果没遇到类似的问题，是很难记忆深刻的~~~</span></p>
<img src ="http://www.blogjava.net/changedi/aggbug/346593.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2011-03-19 13:12 <a href="http://www.blogjava.net/changedi/archive/2011/03/19/346593.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Rope与StringBuilder的简单比较</title><link>http://www.blogjava.net/changedi/archive/2010/01/25/310736.html</link><dc:creator>changedi</dc:creator><author>changedi</author><pubDate>Mon, 25 Jan 2010 07:20:00 GMT</pubDate><guid>http://www.blogjava.net/changedi/archive/2010/01/25/310736.html</guid><wfw:comment>http://www.blogjava.net/changedi/comments/310736.html</wfw:comment><comments>http://www.blogjava.net/changedi/archive/2010/01/25/310736.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/changedi/comments/commentRss/310736.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/changedi/services/trackbacks/310736.html</trackback:ping><description><![CDATA[<p>最近看了这篇文章 <a href="http://www.ibm.com/developerworks/cn/java/j-ropes/?S_TACT=105AGX52&amp;S_CMP=techcsdn">http://www.ibm.com/developerworks/cn/java/j-ropes/?S_TACT=105AGX52&amp;S_CMP=techcsdn</a><br />
<br />
作者比较了String和StringBuffer与Rope结构的常用操作速度。并以实验证明了Rope的性能。我在自己的机器上实验，同样也证明了Rope的高效，但是作者没有用StringBuilder和Rope做比较，所以我们不妨一试。<br />
暂时的实验结果表明，就append和delete操作而言，StringBuilder胜过Rope，那么Rope的真正优势在哪里呢？时间仓促，没有深入研究，特此立一文，以后细看其结构~~~<br />
<br />
我的测试代码如下：<br />
</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><span style="color: #008080">&nbsp;1</span><img id="Codehighlighter1_0_10_Open_Image" onclick="this.style.display='none'; Codehighlighter1_0_10_Open_Text.style.display='none'; Codehighlighter1_0_10_Closed_Image.style.display='inline'; Codehighlighter1_0_10_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif"  alt="" /><img style="display: none" id="Codehighlighter1_0_10_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_0_10_Closed_Text.style.display='none'; Codehighlighter1_0_10_Open_Image.style.display='inline'; Codehighlighter1_0_10_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif"  alt="" /><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_0_10_Closed_Text">/**&nbsp;*/</span><span id="Codehighlighter1_0_10_Open_Text"><span style="color: #008000">/**</span><span style="color: #008000"><br />
</span><span style="color: #008080">&nbsp;2</span><span style="color: #008000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;*&nbsp;<br />
</span><span style="color: #008080">&nbsp;3</span><span style="color: #008000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif"  alt="" />&nbsp;</span><span style="color: #008000">*/</span></span><span style="color: #000000"><br />
</span><span style="color: #008080">&nbsp;4</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.io.</span><span style="color: #000000">*</span><span style="color: #000000">;<br />
</span><span style="color: #008080">&nbsp;5</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.util.</span><span style="color: #000000">*</span><span style="color: #000000">;<br />
</span><span style="color: #008080">&nbsp;6</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /><br />
</span><span style="color: #008080">&nbsp;7</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;org.ahmadsoft.ropes.</span><span style="color: #000000">*</span><span style="color: #000000">;<br />
</span><span style="color: #008080">&nbsp;8</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /><br />
</span><span style="color: #008080">&nbsp;9</span><span style="color: #000000"><img id="Codehighlighter1_82_125_Open_Image" onclick="this.style.display='none'; Codehighlighter1_82_125_Open_Text.style.display='none'; Codehighlighter1_82_125_Closed_Image.style.display='inline'; Codehighlighter1_82_125_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif"  alt="" /><img style="display: none" id="Codehighlighter1_82_125_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_82_125_Closed_Text.style.display='none'; Codehighlighter1_82_125_Open_Image.style.display='inline'; Codehighlighter1_82_125_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif"  alt="" /></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_82_125_Closed_Text">/**&nbsp;*/</span><span id="Codehighlighter1_82_125_Open_Text"><span style="color: #008000">/**</span><span style="color: #008000"><br />
</span><span style="color: #008080">10</span><span style="color: #008000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;*&nbsp;</span><span style="color: #808080">@author</span><span style="color: #008000">&nbsp;Jia&nbsp;Yu<br />
</span><span style="color: #008080">11</span><span style="color: #008000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;*&nbsp;@date&nbsp;2010-1-25<br />
</span><span style="color: #008080">12</span><span style="color: #008000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif"  alt="" />&nbsp;</span><span style="color: #008000">*/</span></span><span style="color: #000000"><br />
</span><span style="color: #008080">13</span><span style="color: #000000"><img id="Codehighlighter1_146_1098_Open_Image" onclick="this.style.display='none'; Codehighlighter1_146_1098_Open_Text.style.display='none'; Codehighlighter1_146_1098_Closed_Image.style.display='inline'; Codehighlighter1_146_1098_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif"  alt="" /><img style="display: none" id="Codehighlighter1_146_1098_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_146_1098_Closed_Text.style.display='none'; Codehighlighter1_146_1098_Open_Image.style.display='inline'; Codehighlighter1_146_1098_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif"  alt="" /></span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Test2&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_146_1098_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_146_1098_Open_Text"><span style="color: #000000">{<br />
</span><span style="color: #008080">14</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" /><br />
</span><span style="color: #008080">15</span><span style="color: #000000"><img id="Codehighlighter1_150_173_Open_Image" onclick="this.style.display='none'; Codehighlighter1_150_173_Open_Text.style.display='none'; Codehighlighter1_150_173_Closed_Image.style.display='inline'; Codehighlighter1_150_173_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"  alt="" /><img style="display: none" id="Codehighlighter1_150_173_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_150_173_Closed_Text.style.display='none'; Codehighlighter1_150_173_Open_Image.style.display='inline'; Codehighlighter1_150_173_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_150_173_Closed_Text">/**&nbsp;*/</span><span id="Codehighlighter1_150_173_Open_Text"><span style="color: #008000">/**</span><span style="color: #008000"><br />
</span><span style="color: #008080">16</span><span style="color: #008000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080">@param</span><span style="color: #008000">&nbsp;args<br />
</span><span style="color: #008080">17</span><span style="color: #008000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">*/</span></span><span style="color: #000000"><br />
</span><span style="color: #008080">18</span><span style="color: #000000"><img id="Codehighlighter1_215_1096_Open_Image" onclick="this.style.display='none'; Codehighlighter1_215_1096_Open_Text.style.display='none'; Codehighlighter1_215_1096_Closed_Image.style.display='inline'; Codehighlighter1_215_1096_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"  alt="" /><img style="display: none" id="Codehighlighter1_215_1096_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_215_1096_Closed_Text.style.display='none'; Codehighlighter1_215_1096_Open_Image.style.display='inline'; Codehighlighter1_215_1096_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;main(String[]&nbsp;args)&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_215_1096_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_215_1096_Open_Text"><span style="color: #000000">{<br />
</span><span style="color: #008080">19</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;TODO&nbsp;Auto-generated&nbsp;method&nbsp;stub</span><span style="color: #008000"><br />
</span><span style="color: #008080">20</span><span style="color: #008000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" /></span><span style="color: #000000"><br />
</span><span style="color: #008080">21</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;max&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">100000</span><span style="color: #000000">;<br />
</span><span style="color: #008080">22</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;eq&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">""</span><span style="color: #000000">;<br />
</span><span style="color: #008080">23</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Rope&nbsp;r&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;Rope.BUILDER.build(</span><span style="color: #000000">""</span><span style="color: #000000">);<br />
</span><span style="color: #008080">24</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringBuffer&nbsp;sb&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;StringBuffer(</span><span style="color: #000000">""</span><span style="color: #000000">);<br />
</span><span style="color: #008080">25</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringBuilder&nbsp;sb2&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;StringBuilder(</span><span style="color: #000000">""</span><span style="color: #000000">);<br />
</span><span style="color: #008080">26</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" /><br />
</span><span style="color: #008080">27</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">double</span><span style="color: #000000">&nbsp;st&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;System.nanoTime();<br />
</span><span style="color: #008080">28</span><span style="color: #000000"><img id="Codehighlighter1_481_499_Open_Image" onclick="this.style.display='none'; Codehighlighter1_481_499_Open_Text.style.display='none'; Codehighlighter1_481_499_Closed_Image.style.display='inline'; Codehighlighter1_481_499_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"  alt="" /><img style="display: none" id="Codehighlighter1_481_499_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_481_499_Closed_Text.style.display='none'; Codehighlighter1_481_499_Open_Image.style.display='inline'; Codehighlighter1_481_499_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;&nbsp;i&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">&nbsp;max;&nbsp;i</span><span style="color: #000000">++</span><span style="color: #000000">)&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_481_499_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_481_499_Open_Text"><span style="color: #000000">{<br />
</span><span style="color: #008080">29</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eq&nbsp;</span><span style="color: #000000">+=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">h</span><span style="color: #000000">"</span><span style="color: #000000">;<br />
</span><span style="color: #008080">30</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
</span><span style="color: #008080">31</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">double</span><span style="color: #000000">&nbsp;ed&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;System.nanoTime();<br />
</span><span style="color: #008080">32</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(ed&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;st);<br />
</span><span style="color: #008080">33</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" /><br />
</span><span style="color: #008080">34</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;st&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;System.nanoTime();<br />
</span><span style="color: #008080">35</span><span style="color: #000000"><img id="Codehighlighter1_624_673_Open_Image" onclick="this.style.display='none'; Codehighlighter1_624_673_Open_Text.style.display='none'; Codehighlighter1_624_673_Closed_Image.style.display='inline'; Codehighlighter1_624_673_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"  alt="" /><img style="display: none" id="Codehighlighter1_624_673_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_624_673_Closed_Text.style.display='none'; Codehighlighter1_624_673_Open_Image.style.display='inline'; Codehighlighter1_624_673_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;&nbsp;i&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">&nbsp;max;&nbsp;i</span><span style="color: #000000">++</span><span style="color: #000000">)&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_624_673_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_624_673_Open_Text"><span style="color: #000000">{<br />
</span><span style="color: #008080">36</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sb.append(</span><span style="color: #000000">"</span><span style="color: #000000">h</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
</span><span style="color: #008080">37</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;sb.deleteCharAt(0);</span><span style="color: #008000"><br />
</span><span style="color: #008080">38</span><span style="color: #008000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
</span><span style="color: #008080">39</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ed&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;System.nanoTime();<br />
</span><span style="color: #008080">40</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println((</span><span style="color: #0000ff">double</span><span style="color: #000000">)&nbsp;ed&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">double</span><span style="color: #000000">)&nbsp;st);<br />
</span><span style="color: #008080">41</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" /><br />
</span><span style="color: #008080">42</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;st&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;System.nanoTime();<br />
</span><span style="color: #008080">43</span><span style="color: #000000"><img id="Codehighlighter1_809_860_Open_Image" onclick="this.style.display='none'; Codehighlighter1_809_860_Open_Text.style.display='none'; Codehighlighter1_809_860_Closed_Image.style.display='inline'; Codehighlighter1_809_860_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"  alt="" /><img style="display: none" id="Codehighlighter1_809_860_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_809_860_Closed_Text.style.display='none'; Codehighlighter1_809_860_Open_Image.style.display='inline'; Codehighlighter1_809_860_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;&nbsp;i&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">&nbsp;max;&nbsp;i</span><span style="color: #000000">++</span><span style="color: #000000">)&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_809_860_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_809_860_Open_Text"><span style="color: #000000">{<br />
</span><span style="color: #008080">44</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sb2.append(</span><span style="color: #000000">"</span><span style="color: #000000">h</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
</span><span style="color: #008080">45</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;sb2.deleteCharAt(0);</span><span style="color: #008000"><br />
</span><span style="color: #008080">46</span><span style="color: #008000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
</span><span style="color: #008080">47</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ed&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;System.nanoTime();<br />
</span><span style="color: #008080">48</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println((</span><span style="color: #0000ff">double</span><span style="color: #000000">)&nbsp;ed&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">double</span><span style="color: #000000">)&nbsp;st);<br />
</span><span style="color: #008080">49</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" /><br />
</span><span style="color: #008080">50</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;st&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;System.nanoTime();<br />
</span><span style="color: #008080">51</span><span style="color: #000000"><img id="Codehighlighter1_996_1018_Open_Image" onclick="this.style.display='none'; Codehighlighter1_996_1018_Open_Text.style.display='none'; Codehighlighter1_996_1018_Closed_Image.style.display='inline'; Codehighlighter1_996_1018_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"  alt="" /><img style="display: none" id="Codehighlighter1_996_1018_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_996_1018_Closed_Text.style.display='none'; Codehighlighter1_996_1018_Open_Image.style.display='inline'; Codehighlighter1_996_1018_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;&nbsp;i&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">&nbsp;max;&nbsp;i</span><span style="color: #000000">++</span><span style="color: #000000">)&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_996_1018_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_996_1018_Open_Text"><span style="color: #000000">{<br />
</span><span style="color: #008080">52</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r.append(</span><span style="color: #000000">"</span><span style="color: #000000">h</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
</span><span style="color: #008080">53</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
</span><span style="color: #008080">54</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ed&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;System.nanoTime();<br />
</span><span style="color: #008080">55</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println((</span><span style="color: #0000ff">double</span><span style="color: #000000">)&nbsp;ed&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">double</span><span style="color: #000000">)&nbsp;st);<br />
</span><span style="color: #008080">56</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
</span><span style="color: #008080">57</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif"  alt="" />}</span></span><span style="color: #000000"><br />
</span><span style="color: #008080">58</span><span style="color: #000000"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span></div>
<p><br />
结果如下：<br />
1.6120785922E10<br />
1.0273193E7<br />
2647639.0<br />
9781992.0<br />
只从数量级比较的话，String的低效就不说了，毕竟基于Char[]实现的，而StringBuffer比StringBuilder慢也可以理解，毕竟加入了同步的考虑，也算是为线程安全付出的代价，但是所谓的树型机制的Rope还是比不过StringBuilder啊~~~<br />
<br />
Rope for Java 下载：<a href="http://ahmadsoft.org/ropes/">点击这里。<br />
</a>这里附加了文章中的测试代码：<a href="http://ahmadsoft.org/source/xref/ropes-1.1.3/src/org/ahmadsoft/ropes/test/PerformanceTest.java">点击这里。<br />
</a></p>
 <img src ="http://www.blogjava.net/changedi/aggbug/310736.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/changedi/" target="_blank">changedi</a> 2010-01-25 15:20 <a href="http://www.blogjava.net/changedi/archive/2010/01/25/310736.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>