﻿<?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-WOLF--执着-文章分类-经典文章</title><link>http://www.blogjava.net/sutao/category/24294.html</link><description>用文字记录学习的体验！</description><language>zh-cn</language><lastBuildDate>Thu, 22 Nov 2007 09:21:24 GMT</lastBuildDate><pubDate>Thu, 22 Nov 2007 09:21:24 GMT</pubDate><ttl>60</ttl><item><title>Struts常见错误汇总</title><link>http://www.blogjava.net/sutao/articles/161876.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Tue, 20 Nov 2007 07:52:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/161876.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/161876.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/161876.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/161876.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/161876.html</trackback:ping><description><![CDATA[<h1 id="pageName">Struts常见错误汇总</h1>
<div class="feature">
<p>来源：&nbsp;作者：佚名&nbsp;2007-11-02&nbsp;出处：<a href="http://www.pcdog.com/" target="_blank">pcdog.com</a></p>
</div>
<div class="keyword_list"><br />
&nbsp;&nbsp;&nbsp; 以下所说的struts-config.xml和ApplicationResources.properties等文件名是缺省时使用的，如果你使用了多模块，或指定了不同的<nobr oncontextmenu="return false;" onmousemove="kwM(3);" id="key3" onmouseover="kwE(event,3, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">资源</nobr>文件名称，这些名字要做相应的修改。&nbsp;<br />
<br />
</div>
<div class="story">
<div class="ad0">&nbsp;&nbsp;&nbsp; <strong>1、&#8220;No bean found under attribute key XXX&#8221;</strong> <br />
　在struts-config.xml里定义了一个ActionForm，但type属性指定的类不存在，type属性的值应该是Form类的全名。或者是，在Action的定义中，name或attribute属性指定的ActionForm不存在。&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;<strong> 2、&#8220;Cannot find bean XXX in any scope&#8221;</strong> <br />
　在Action里一般会request.setAttribute()一些对象，然后在转向的<a href="http://www.pcdog.com/special/1199/index.html" target="_blank">jsp</a>文件里（用tag或request.getAttribute()方法）得到这些对象并显示出来。这个异常是说jsp要得到一个对象，但前面的Action里并没有将对象设置到request（也可以是session、servletContext）里。&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp; 可能是名字错了，请检查jsp里的tag的一般是name属性，或getAttribute()方法的参数值；或者是Action<nobr oncontextmenu="return false;" onmousemove="kwM(2);" id="key2" onmouseover="kwE(event,2, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">逻辑</nobr>有问题没有执行setAttribute()方法就先转向了。&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp; 还有另外一个可能，纯粹是jsp文件的问题，例如&lt;logic:iterate&gt;会指定一个id值，然后在循环里&lt;bean: write&gt;使用这个值作为name的值，如果这两个值不同，也会出现此异常。（都是一个道理，request里没有对应的对象。）&nbsp;<br />
<br />
&nbsp;<strong>&nbsp;&nbsp; 3、&#8220;Missing message for key "XXX"&#8221; <br />
</strong>　缺少所需的资源，检查ApplicationResources.properties文件里是否有jsp文件里需要的资源，例如： <br />
　&lt;bean:message key="msg.name.prompt"/&gt; <br />
　这行代码会找msg.name.prompt资源，如果AppliationResources.properties里没有这个资源就会出现本异常。在使用多模块时，要注意在模块的struts-config-xxx.xml里指定要使用的资源文件名称，否则当然什么资源也找不到，这也是一个很容易犯的错误。&nbsp;<br />
<br />
&nbsp;&nbsp;<strong>&nbsp; 4、&#8220;No getter method for property XXX of bean teacher&#8221; <br />
</strong>　这条异常<nobr oncontextmenu="return false;" onmousemove="kwM(1);" id="key1" onmouseover="kwE(event,1, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">信息</nobr>说得很明白，jsp里要取一个bean的属性出来，但这个bean并没有这个属性。你应该检查jsp中某个标签的property属性的值。例如下面代码中的cade应该改为code才对： <br />
　&lt;bean:write name="teacher" property="cade" filter="true"/&gt;&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;<strong> 5、&#8220;Cannot find ActionMappings or ActionFormBeans collection&#8221; <br />
</strong>　待<nobr oncontextmenu="return false;" onmousemove="kwM(4);" id="key4" onmouseover="kwE(event,4, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">解决</nobr>。&nbsp;<br />
<br />
&nbsp;&nbsp;<strong>&nbsp; 6、&#8220;Cannot retrieve mapping for action XXX&#8221;</strong> <br />
　在.jsp的&lt;form&gt;标签里指定action='/XXX'，但这个Action并未在struts-config.xml里设置过。&nbsp;<br />
<br />
&nbsp;<strong>&nbsp;&nbsp; 7、<a href="http://www.pcdog.com/net/2145/index.html" target="_blank">HTTP</a> Status 404 - /xxx/xxx.jsp</strong> <br />
　Forward的path属性指向的jsp页面不存在，请检查路径和模块，对于同一模块中的Action转向，path中不应包含模块名；模块间转向，记住使用contextRelative="true"。&nbsp;<br />
<br />
<strong>&nbsp;&nbsp;&nbsp; 8、没有任何异常信息，显示空白页面 <br />
</strong>　可能是Action里使用的forward与struts-config.xml里定义的forward名称不匹配。&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp; <strong>9、&#8220;The element type "XXX" must be terminated by the matching end-tag "XXX".&#8221;</strong> <br />
　这个是struts-config.xml文件的格式错误，仔细检查它是否是良构的xml文件，关于xml文件的格式这里就不赘述了。&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;<strong>10、&#8220;Servlet.init() for servlet action threw exception&#8221;</strong> <br />
　一般出现这种异常在后面会显示一个关于ActionServlet的异常堆栈信息，其中指出了异常具体出现在代码的哪一行。我曾经遇到的一次提示如下：&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp; <nobr oncontextmenu="return false;" onmousemove="kwM(0);" id="key0" onmouseover="kwE(event,0, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">java</nobr>.lang.NullPointerException <br />
　at org.apache.struts.action.ActionServlet.parseModuleConfigFile(ActionServlet.java:1003) <br />
　at org.apache.struts.action.ActionServlet.initModuleConfig(ActionServlet.java:955)&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp; 为解决问题，先下载struts的源码包，然后在ActionServlet.java的第1003行插入断点，并对各变量进行监视。很丢人，我竟然把struts-config.xml文件弄丢了，因此出现了上面的异常，应该是和CVS同步时不小心删除的。&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp; <strong>11、&#8220;Resources not defined for Validator&#8221;</strong> <br />
　这个是利用Validator插件做验证时可能出现的异常，这时你要检查validation.<nobr oncontextmenu="return false;" onmousemove="kwM(5);" id="key5" onmouseover="kwE(event,5, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">xml</nobr>文件，看里面使用的资源是否确实有定义，form的名称是否正确，等等。</div>
</div>
<img src ="http://www.blogjava.net/sutao/aggbug/161876.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-11-20 15:52 <a href="http://www.blogjava.net/sutao/articles/161876.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java性能-Java performance  </title><link>http://www.blogjava.net/sutao/articles/138864.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Thu, 23 Aug 2007 07:53:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/138864.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/138864.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/138864.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/138864.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/138864.html</trackback:ping><description><![CDATA[<a style="color: #1826ff;" href="http://www.searchfull.net/blog/2007/06/17/1182051084987.html" name="a1182051084987" title="http://www.searchfull.net:80/blog/2007/06/17/1182051084987.html">Java性能-Java performance</a><span style="color: #1826ff;">
</span><br style="color: #1826ff;">
<h4 id="subjcns!3F8031D02C84F0C1!427" class="TextColor1" style="margin-bottom: 0px; color: #1826ff;">How can you improve Java I/O performance?</h4>
<span style="color: #1826ff;">
I/O efficiency should be a high priority for developers looking to optimally increase performance.</span><br style="color: #1826ff;">
<br style="color: #1826ff;"><span style="color: #1826ff;">
The basic rules for speeding up I/O performance are：</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&#8226; Minimise accessing the hard disk.</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&#8226; Minimise accessing the underlying operating system.</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&#8226; Minimise processing bytes and characters individually.</span><br style="color: #1826ff;">
<br style="color: #1826ff;"><span style="color: #1826ff;">
Some of the techniques to improve I/O performance:</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&#8226; Use buffering to minimise disk access and underlying operating system.</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&#8226; It is recommended to use logging frameworks like Log4J or apache commons logging</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&#8226; Use the NIO package, if you are using JDK 1.4 or later</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&#8226; I/O performance can be improved by inimising the calls to the underlying operating systems.</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&#8226; Where applicable caching can be used to improve performance by
reading in all the lines of a file into a Java collection class like an
ArrayList or a HashMap and subsequently access the data from an
in-memory collection instead of the disk.</span><br style="color: #1826ff;">
<br style="color: #1826ff;">
<h4 id="subjcns!3F8031D02C84F0C1!430" class="TextColor1" style="margin-bottom: 0px; color: #1826ff;">How would you improve performance of a Java application?</h4>
<span style="color: #1826ff;">
The Basic Rules are:</span><br style="color: #1826ff;">
<br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;&nbsp;&nbsp; * Pool valuable system resources like threads, database connections, socket connections etc.</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;&nbsp;&nbsp; * Optimize your I/O operations.</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;&nbsp;&nbsp; * Minimize network overheads</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;&nbsp;&nbsp; * Establish whether you have a potential memory problem and manage
your objects efficiently. Use lazy initialization when you want to
distribute the load of creating large amounts of objects.</span><br style="color: #1826ff;">
<br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;</span><br style="color: #1826ff;">
<br style="color: #1826ff;"><span style="color: #1826ff;">
Where applicable apply the following performance tips in your code:</span><br style="color: #1826ff;">
<br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;</span><br style="color: #1826ff;">
<br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;&nbsp;&nbsp; * Use ArrayLists, HashMap etc as opposed to Vector, Hashtable etc where possible.</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;&nbsp;&nbsp; * Set the initial capacity of a collection and StringBuffer/StringBuilder appropriately.</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;&nbsp;&nbsp; * Minimise the use of casting or runtime type checking like instanceof in frequently executed methods or in loops.</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;&nbsp;&nbsp; * Do not compute constants inside a large loop. (loop optimization)</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;&nbsp;&nbsp; * Exception creation can be expensive because it has to create the
full stack trace. The stack trace is obviously useful if you are
planning to log or display the exception to the user. But if you are
using your exception to just control the flow, which is not
recommended, then throw an exception, which is precreated. An efficient
way to do this is to declare a public static final Exception in your
exception class itself.</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;&nbsp;&nbsp; * Avoid using System.out.println and use logging frameworks like Log4J etc</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;&nbsp;&nbsp; * Minimise calls to Date, Calendar, etc related classes.</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;&nbsp;&nbsp; * Minimise JNI calls in your code</span><br style="color: #1826ff;">
<br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;</span><br style="color: #1826ff;">
<br style="color: #1826ff;">
<strong style="color: #1826ff;"> How would you detect and minimise memory leaks in Java?</strong><span style="color: #1826ff;"> </span><br style="color: #1826ff;">
<br style="color: #1826ff;"><span style="color: #1826ff;">
In Java memory leaks are caused by poor program design where object
references are long lived and the garbage collector is unable to
reclaim those objects.</span><br style="color: #1826ff;">
<br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;</span><br style="color: #1826ff;">
<br style="color: #1826ff;"><span style="color: #1826ff;">
Detecting memory leaks:</span><br style="color: #1826ff;">
<br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;&nbsp;&nbsp; * Use tools like JProbe, OptimizeIt etc to detect memory leaks.</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;&nbsp;&nbsp; * Use operating system process monitors like task manager on NT systems, ps, vmstat, iostat, netstat etc on UNIX systems.</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;&nbsp;&nbsp; * Write your own utility class with the help of totalMemory() and
freeMemory() methods in the Java Runtime class. Place these calls in
your code strategically for pre and post memory recording where you
suspect to be causing memory leaks.</span><br style="color: #1826ff;">
<br style="color: #1826ff;"><span style="color: #1826ff;">
Runtime.getRuntime().totalMemory()&#8230;</span><br style="color: #1826ff;">
<br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;</span><br style="color: #1826ff;">
<br style="color: #1826ff;">
<strong style="color: #1826ff;"> Minimising memory leaks</strong><span style="color: #1826ff;"> </span><br style="color: #1826ff;">
<br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;</span><br style="color: #1826ff;">
<br style="color: #1826ff;"><span style="color: #1826ff;">
In Java, typically memory leak occurs when an object of a longer
lifecycle has a reference to objects of a short life cycle. This
prevents the objects with short life cycle being garbage collected. The
developer must remember to remove the references to the short-lived
objects from the long-lived objects. Objects with the same life cycle
do not cause any issues because the garbage collector is smart enough
to deal with the circular references</span><br style="color: #1826ff;">
<br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;&nbsp;&nbsp; * Design applications with an object&#8217;s life cycle in mind, instead of relying on the clever features of the JVM.</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;&nbsp;&nbsp; * Unreachable collection objects can magnify a memory leak problem.
The WeakHashMap is a combination of HashMap and WeakReference. This
class can be used for programming problems where you need to have a
HashMap of information, but you would like that information to be
garbage collected if you are the only one referencing it.</span><br style="color: #1826ff;"><span style="color: #1826ff;">
&nbsp;&nbsp;&nbsp; * Free native system resources like AWT frame, files, JNI etc when finished with them.(call dispose)
</span><br><img src ="http://www.blogjava.net/sutao/aggbug/138864.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-08-23 15:53 <a href="http://www.blogjava.net/sutao/articles/138864.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>说说大型高并发高负载网站的系统架构  </title><link>http://www.blogjava.net/sutao/articles/138856.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Thu, 23 Aug 2007 07:39:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/138856.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/138856.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/138856.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/138856.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/138856.html</trackback:ping><description><![CDATA[<a style="color: #202eff;" href="http://www.searchfull.net/blog/2007/08/04/1186195759355.html" name="a1186195759355" title="http://www.searchfull.net:80/blog/2007/08/04/1186195759355.html">说说大型高并发高负载网站的系统架构</a><span style="color: #202eff;">
</span><br style="color: #202eff;">
<div style="color: #202eff;" class="post-author">By Michael</div>
<div style="color: #202eff;" class="post-content">
<p>转载请保留出处：俊麟 Michael&#8217;s blog (http://www.toplee.com/blog/?p=71)<br>
Trackback Url : <a href="http://www.toplee.com/blog/wp-trackback.php?p=71">http://www.toplee.com/blog/wp-trackback.php?p=71</a></p>
<p>　　我在CERNET做过拨号接入平台的搭建，而后在Yahoo&amp;3721从事过搜索引擎前端开发，又在MOP处理过大型社区猫扑大杂烩的
架构升级等工作，同时自己接触和开发过不少大中型网站的模块，因此在大型网站应对高负载和并发的解决方案上有一些积累和经验，可以和大家一起探讨一下。</p>
<p><br>
一个小型的网站，比如个人网站，可以使用最简单的html静态页面就实现了，配合一些图片达到美化效果，所有的页面均存放在一个目录下，这样的网站对
系统架构、性能的要求都很简单，随着互联网业务的不断丰富，网站相关的技术经过这些年的发展，已经细分到很细的方方面面，尤其对于大型网站来说，所采用的
技术更是涉及面非常广，从硬件到软件、编程语言、数据库、WebServer、防火墙等各个领域都有了很高的要求，已经不是原来简单的html静态网站所
能比拟的。</p>
<p>　　大型网站，比如门户网站。在面对大量用户访问、高并发请求方面，基本的解决方案集中在这样几个环节：使用高性能的服务器、高性能的数据库、高效率的编程语言、还有高性能的Web容器。但是除了这几个方面，还没法根本解决大型网站面临的高负载和高并发问题。</p>
<p>　　上面提供的几个解决思路在一定程度上也意味着更大的投入，并且这样的解决思路具备瓶颈，没有很好的扩展性，下面我从低成本、高性能和高扩张性的角度来说说我的一些经验。</p>
<p><strong> 1、HTML静态化</strong> <br>
其实大家都知道，效率最高、消耗最小的就是纯静态化的html页面，所以我们尽可能使我们的网站上的页面采用静态页面来实现，这个最简单的方法其实也
是最有效的方法。但是对于大量内容并且频繁更新的网站，我们无法全部手动去挨个实现，于是出现了我们常见的信息发布系统CMS，像我们常访问的各个门户站
点的新闻频道，甚至他们的其他频道，都是通过信息发布系统来管理和实现的，信息发布系统可以实现最简单的信息录入自动生成静态页面，还能具备频道管理、权
限管理、自动抓取等功能，对于一个大型网站来说，拥有一套高效、可管理的CMS是必不可少的。</p>
<p>　　除了门户和信息发布类型的网站，对于交互性要求很高的社区类型网站来说，尽可能的静态化也是提高性能的必要手段，将社区内的帖子、文章进行实时
的静态化，有更新的时候再重新静态化也是大量使用的策略，像Mop的大杂烩就是使用了这样的策略，网易社区等也是如此。目前很多博客也都实现了静态化，我
使用的这个Blog程序WordPress还没有静态化，所以如果面对高负载访问，www.toplee.com一定不能承受 <img class="wp-smiley" alt=":)" src="http://www.toplee.com/blog/wp-includes/images/smilies/icon_smile.gif"> </p>
<p>　　同时，html静态化也是某些缓存策略使用的手段，对于系统中频繁使用数据库查询但是内容更新很小的应用，可以考虑使用html静态化来实现，
比如论坛中论坛的公用设置信息，这些信息目前的主流论坛都可以进行后台管理并且存储再数据库中，这些信息其实大量被前台程序调用，但是更新频率很小，可以
考虑将这部分内容进行后台更新的时候进行静态化，这样避免了大量的数据库访问请求。</p>
<p>　　在进行html静态化的时候可以使用一种折中的方法，就是前端使用动态实现，在一定的策略下进行定时静态化和定时判断调用，这个能实现很多灵活性的操作，我开发的台球网站故人居(<a href="http://www.8zone.cn/">www.8zone.cn</a>)就是使用了这样的方法，我通过设定一些html静态化的时间间隔来对动态网站内容进行缓存，达到分担大部分的压力到静态页面上，可以应用于中小型网站的架构上。故人居网站的地址：<a href="http://www.8zone.cn/">http://www.8zone.cn</a>，顺便提一下，有喜欢台球的朋友多多支持我这个免费网站:)</p>
<p><strong> 2、图片服务器分离</strong> <br>
大家知道，对于Web服务器来说，不管是Apache、IIS还是其他容器，图片是最消耗资源的，于是我们有必要将图片与页面进行分离，这是基本上大
型网站都会采用的策略，他们都有独立的图片服务器，甚至很多台图片服务器。这样的架构可以降低提供页面访问请求的服务器系统压力，并且可以保证系统不会因
为图片问题而崩溃。</p>
<p>　　在应用服务器和图片服务器上，可以进行不同的配置优化，比如Apache在配置ContentType的时候可以尽量少支持，尽可能少的LoadModule，保证更高的系统消耗和执行效率。</p>
<p>　　我的台球网站故人居<a href="http://www.8zone.cn/">8zone.cn</a>也使用了图片服务器架构上的分离，目前是仅仅是架构上分离，物理上没有分离，由于没有钱买更多的服务器:)，大家可以看到故人居上的图片连接都是类似img.9tmd.com或者img1.9tmd.com的URL。</p>
<p>　　另外，在处理静态页面或者图片、js等访问方面，可以考虑使用<a href="http://www.lighttpd.net/">lighttpd</a>代替Apache，它提供了更轻量级和更高效的处理能力。</p>
<p><strong> 3、数据库集群和库表散列</strong> <br>
大型网站都有复杂的应用，这些应用必须使用数据库，那么在面对大量访问的时候，数据库的瓶颈很快就能显现出来，这时一台数据库将很快无法满足应用，于是我们需要使用数据库集群或者库表散列。</p>
<p>　　在数据库集群方面，很多数据库都有自己的解决方案，Oracle、Sybase等都有很好的方案，常用的MySQL提供的Master/Slave也是类似的方案，您使用了什么样的DB，就参考相应的解决方案来实施即可。</p>
<p>　　上面提到的数据库集群由于在架构、成本、扩张性方面都会受到所采用DB类型的限制，于是我们需要从应用程序的角度来考虑改善系统架构，库表散列
是常用并且最有效的解决方案。我们在应用程序中安装业务和应用或者功能模块将数据库进行分离，不同的模块对应不同的数据库或者表，再按照一定的策略对某个
页面或者功能进行更小的数据库散列，比如用户表，按照用户ID进行表散列，这样就能够低成本的提升系统的性能并且有很好的扩展性。sohu的论坛就是采用
了这样的架构，将论坛的用户、设置、帖子等信息进行数据库分离，然后对帖子、用户按照板块和ID进行散列数据库和表，最终可以在配置文件中进行简单的配置
便能让系统随时增加一台低成本的数据库进来补充系统性能。</p>
<p><strong> 4、缓存</strong> <br>
缓存一词搞技术的都接触过，很多地方用到缓存。网站架构和网站开发中的缓存也是非常重要。这里先讲述最基本的两种缓存。高级和分布式的缓存在后面讲述。</p>
<p>　　架构方面的缓存，对Apache比较熟悉的人都能知道Apache提供了自己的mod_proxy缓存模块，也可以使用外加的Squid进行缓存，这两种方式均可以有效的提高Apache的访问响应能力。</p>
<p>　　网站程序开发方面的缓存，Linux上提供的<a href="http://www.danga.com/memcached/">Memcached</a>是常用的缓存方案，不少web编程语言都提供memcache访问接口，<a href="http://cn.php.net/memcached">php</a>、perl、c和java都有，可以在web开发中使用，可以实时或者Cron的把数据、对象等内容进行缓存，策略非常灵活。一些大型社区使用了这样的架构。</p>
<p>　　另外，在使用web语言开发的时候，各种语言基本都有自己的缓存模块和方法，PHP有<a href="http://pear.php.net/">Pear</a>的Cache模块和<a href="http://www.toplee.com/blog/?p=100">eAccelerator</a>加速和Cache模块，还要知名的Apc、XCache（国人开发的，支持！）php缓存模块，Java就更多了，.net不是很熟悉，相信也肯定有。</p>
<p><strong> 5、镜像</strong> <br>
镜像是大型网站常采用的提高性能和数据安全性的方式，镜像的技术可以解决不同网络接入商和地域带来的用户访问速度差异，比如ChinaNet和
EduNet之间的差异就促使了很多网站在教育网内搭建镜像站点，数据进行定时更新或者实时更新。在镜像的细节技术方面，这里不阐述太深，有很多专业的现
成的解决架构和产品可选。也有廉价的通过软件实现的思路，比如Linux上的rsync等工具。</p>
<p><strong> 6、负载均衡</strong> <br>
负载均衡将是大型网站解决高负荷访问和大量并发请求采用的终极解决办法。</p>
<p>　　负载均衡技术发展了多年，有很多专业的服务提供商和产品可以选择，我个人接触过一些解决方法，其中有两个架构可以给大家做参考。另外有关初级的负载均衡DNS轮循和较专业的CDN架构就不多说了。</p>
<p><strong> 6.1 硬件四层交换</strong> <br>
第四层交换使用第三层和第四层信息包的报头信息，根据应用区间识别业务流，将整个区间段的业务流分配到合适的应用服务器进行处理。　第四层交换功能就
象是虚IP，指向物理服务器。它传输的业务服从的协议多种多样，有HTTP、FTP、NFS、Telnet或其他协议。这些业务在物理服务器基础上，需要
复杂的载量平衡算法。在IP世界，业务类型由终端TCP或UDP端口地址来决定，在第四层交换中的应用区间则由源端和终端IP地址、TCP和UDP端口共
同决定。</p>
<p>　　在硬件四层交换产品领域，有一些知名的产品可以选择，比如Alteon、F5等，这些产品很昂贵，但是物有所值，能够提供非常优秀的性能和很灵活的管理能力。Yahoo中国当初接近2000台服务器使用了三四台Alteon就搞定了。</p>
<p><strong> 6.2 软件四层交换</strong> <br>
大家知道了硬件四层交换机的原理后，基于OSI模型来实现的软件四层交换也就应运而生，这样的解决方案实现的原理一致，不过性能稍差。但是满足一定量的压力还是游刃有余的，有人说软件实现方式其实更灵活，处理能力完全看你配置的熟悉能力。</p>
<p>　　软件四层交换我们可以使用Linux上常用的LVS来解决，LVS就是Linux Virtual
Server，他提供了基于心跳线heartbeat的实时灾难应对解决方案，提高系统的鲁棒性，同时可供了灵活的虚拟VIP配置和管理功能，可以同时满
足多种应用需求，这对于分布式的系统来说必不可少。</p>
<p>　　一个典型的使用负载均衡的策略就是，在软件或者硬件四层交换的基础上搭建squid集群，这种思路在很多大型网站包括搜索引擎上被采用，这样的架构低成本、高性能还有很强的扩张性，随时往架构里面增减节点都非常容易。这样的架构我准备空了专门详细整理一下和大家探讨。</p>
<p>总结：<br>
对于大型网站来说，前面提到的每个方法可能都会被同时使用到，Michael这里介绍得比较浅显，具体实现过程中很多细节还需要大家慢慢熟悉和体会，
有时一个很小的squid参数或者apache参数设置，对于系统性能的影响就会很大，希望大家一起讨论，达到抛砖引玉之效。</p>
</div>
<br><img src ="http://www.blogjava.net/sutao/aggbug/138856.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-08-23 15:39 <a href="http://www.blogjava.net/sutao/articles/138856.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>apache+tomcat+mysql负载均衡和集群.txt 测试经典</title><link>http://www.blogjava.net/sutao/articles/135999.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Sat, 11 Aug 2007 03:54:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/135999.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/135999.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/135999.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/135999.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/135999.html</trackback:ping><description><![CDATA[<h2 style="color: #1826ff;" class="diaryTitle">apache+tomcat+mysql负载均衡和集群.txt</h2>
<span style="color: #1826ff;">				 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>
<p style="color: #1826ff;">扬子江 发表于 2006-4-11 15:12:38 <br>&nbsp;<br>前言：<br>公司开发了一个网站，估计最高在线人数是3万，并发人数最多100人。开发的网站是否能否承受这个压力，如何确保网站的负荷没有问题，经过研究决定如下：<br>（1） 采用负载平衡和集群技术，初步机构采用Apache+Tomcat的机群技术。<br>（2） 采用压力测试工具，测试压力。工具是Loadrunner。<br>硬件环境搭建：<br>为了能够进行压力测试，需要搭建一个环境。刚开始时，测试在公司局域网内进行，但很快发现了一个问题，即一个脚本的压力测试结果每次都不一样，并且差别很大。原来是受公司网络的影响，于是决定搭建一个完全隔离的局域网测试。搭建后的局域网配置如下：<br>（1） 网络速度：100M<br>（2） 三台服务器：<br>负载服务器 ：操作系统windows2003，<br>Tomcat服务器：操作系统windows2000 Professional<br>数据库服务器：操作系统windows2000 Professional<br>三台机器的cpu 2.4 G, 内存 1G。<br>软件环境搭建：<br>软件的版本如下：<br>Apache 版本：2.054，<br>Tomcat5.0.30,<br>mysql ：4.1.14.<br>JDK1.5<br>压力测试工具：Loadrunner7.8。 </p>
<p style="color: #1826ff;">负载平衡方案如下：<br>一台机器（操作系统2003）安装apache，作为负载服务器，并安装tomcat作为一个worker；一个单独安装tomcat，作为第二个worker；剩下的一台单独作为数据库服务器。<br>Apache和tomcat的负载平衡采用JK1.2.14（没有采用2.0，主要是2.0不再维护了）。<br>集群方案：<br>采用Tomcat本身的集群方案。在server.xml配置。<br>压力测试问题：<br>压力测试后，发现了一些问题，现一一列出来：<br>（1）
采用Tocmat集群后，速度变得很慢。因为集群后，要进行session复制，导致速度较慢。Tomcatd的复制，目前不支持application
复制。复制的作用，主要用来容错的，即一台机器有故障后，apache可以把请求自动转发到另外一个机器。在容错和速度的考虑上，我们最终选择速度，去掉
了Tomcat集群。<br>（2） 操作系统最大并发用户的限制：<br>为了采用网站的压力，我们开始的时候，仅测试Tomcat的最大负载数。
Tomcat服务器安装的操作系统是windows2000
Professional。当我们用压力测试工具，并发测试时，发现只要超过15个并发用户，会经常出现无法连接服务器的情况。经过研究，发现是操作系统
的问题：windows2000 Professional
支持的并发访问用户有限，默认的好像是15个。于是我们把操作系统全部采用windows2003 server版本。<br>（3） 数据库连接池的问题：<br>测
试数据库连接性能时，发现数据库连接速度很慢。每增加一些用户，连接性能就差了很多。我们采用的数据库连接池是DBCP，默认的初始化为50个，应该不会
很慢吧。查询数据库的连接数，发现初始化，只初始化一个连接。并发增加一个用户时，程序就会重新创建一个连接，导致连接很慢。原因就在这里了。如何解决
呢？偶尔在JDK1.4下的Tomcat5.0.30下执行数据库连接压力测试，发现速度很快，程序创建数据库连接的速度也是很快的。看来JDK1.5的
JDBC驱动程序有问题。于是我们修改 JDK的版本为1.4.</p>
<p style="color: #1826ff;">（4） C3P0和DBCP<br>C3P0是Hibernate3.0默认的自带数据库连接池，DBCP是Apache开发的数据库连接池。我们对这两种连接池进行压力测试对比，发现在并发300个用户以下时，DBCP比C3P0平均时间快1秒左右。但在并发400个用户时，两者差不多。</p>
<p style="color: #1826ff;">速度上虽然DBCP比C3P0快些，但是有BUG：当DBCP建立的数据库连接，因为某种原因断掉后，DBCP将不会再重新创建新的连接，导致必须重新启动Tomcat才能解决问题。DBCP的BUG使我们决定采用C3P0作为数据库连接池。<br>调整后的方案：<br>操作系统Windows2003 server版本<br>JDK1.4<br>Tomcat 5.0.30<br>数据库连接池C3P0<br>仅采用负载平衡，不采用集群。<br>软件的配置：<br>Apache配置：主要配置httpd.conf和新增加的文件workers.properties<br>Httpd.conf：<br>#一个连接的最大请求数量<br>MaxKeepAliveRequests 10000 <br>#NT环境，只能配置这个参数来提供性能<br>&lt;IfModule mpm_winnt.c&gt; <br>#每个进程的线程数，最大1920。NT只启动父子两个进程，不能设置启动多个进程<br>ThreadsPerChild 1900 <br>每个子进程能够处理的最大请求数<br>MaxRequestsPerChild 10000<br>&lt;/IfModule&gt;</p>
<p style="color: #1826ff;"># 加载mod_jk<br>#<br>LoadModule jk_module modules/mod_jk.so<br>#<br># 配置mod_jk<br>#<br>JkWorkersFile conf/workers.properties<br>JkLogFile logs/mod_jk.log<br>JkLogLevel info<br>#请求分发，对jsp文件，.do等动态请求交由tomcat处理<br>DocumentRoot "C:/Apache/htdocs"<br>JkMount /*.jsp loadbalancer<br>JkMount /*.do loadbalancer<br>JkMount /servlet/* loadbalancer<br>#关掉主机Lookup，如果为on，很影响性能，可以有10多秒钟的延迟。<br>HostnameLookups Off<br>#缓存配置<br>LoadModule cache_module modules/mod_cache.so<br>LoadModule disk_cache_module modules/mod_disk_cache.so<br>LoadModule mem_cache_module modules/mod_mem_cache.so</p>
<p style="color: #1826ff;">&lt;IfModule mod_cache.c&gt;<br>CacheForceCompletion 100<br>CacheDefaultExpire 3600<br>CacheMaxExpire 86400<br>CacheLastModifiedFactor 0.1</p>
<p style="color: #1826ff;">&lt;IfModule mod_disk_cache.c&gt;<br>CacheEnable disk /<br>CacheRoot c:/cacheroot<br>CacheSize 327680<br>CacheDirLength 4<br>CacheDirLevels 5<br>CacheGcInterval 4<br>&lt;/IfModule&gt;<br>&lt;IfModule mod_mem_cache.c&gt;<br>CacheEnable mem /<br>MCacheSize 8192<br>MCacheMaxObjectCount 10000<br>MCacheMinObjectSize 1<br>MCacheMaxObjectSize 51200<br>&lt;/IfModule&gt;<br>&lt;/IfModule&gt;<br>worker. Properties文件<br>#<br># workers.properties ，可以参考<br><a href="http://jakarta.apache.org/tomcat/connectors-doc/config/workers.html">http://jakarta.apache.org/tomcat/connectors-doc/config/workers.html</a> <br># In Unix, we use forward slashes:<br>ps=</p>
<p style="color: #1826ff;"># list the workers by name</p>
<p style="color: #1826ff;">worker.list=tomcat1, tomcat2, loadbalancer</p>
<p style="color: #1826ff;"># ------------------------<br># First tomcat server<br># ------------------------<br>worker.tomcat1.port=8009<br>worker.tomcat1.host=localhost<br>worker.tomcat1.type=ajp13</p>
<p style="color: #1826ff;"># Specify the size of the open connection cache.<br>#worker.tomcat1.cachesize</p>
<p style="color: #1826ff;">#<br># Specifies the load balance factor when used with<br># a load balancing worker.<br># Note:<br># ----&gt; lbfactor must be &gt; 0<br># ----&gt; Low lbfactor means less work done by the worker.<br>worker.tomcat1.lbfactor=900</p>
<p style="color: #1826ff;"># ------------------------<br># Second tomcat server<br># ------------------------<br>worker.tomcat1.port=8009<br>worker.tomcat1.host=202.88.8.101<br>worker.tomcat1.type=ajp13</p>
<p style="color: #1826ff;"># Specify the size of the open connection cache.<br>#worker.tomcat1.cachesize</p>
<p style="color: #1826ff;">#<br># Specifies the load balance factor when used with<br># a load balancing worker.<br># Note:<br># ----&gt; lbfactor must be &gt; 0<br># ----&gt; Low lbfactor means less work done by the worker.<br>worker.tomcat1.lbfactor=2000</p>
<p style="color: #1826ff;"># ------------------------<br># Load Balancer worker<br># ------------------------</p>
<p style="color: #1826ff;">#<br># The loadbalancer (type lb) worker performs weighted round-robin<br># load balancing with sticky sessions.<br># Note:<br># ----&gt; If a worker dies, the load balancer will check its state<br># once in a while. Until then all work is redirected to peer<br># worker.<br>worker.loadbalancer.type=lb<br>worker.loadbalancer.balanced_workers=tomcat1,tomcat2</p>
<p style="color: #1826ff;">#<br># END workers.properties<br>#</p>
<p style="color: #1826ff;">Tomcat1配置:<br>&lt;!--配置server.xml<br>去掉8080端口，即注释掉如下代码：--&gt;<br>&lt;Connector <br>port="8080" maxThreads="150" minSpareThreads="25" maxSpareThreads="75"<br>enableLookups="false" redirectPort="8443" acceptCount="100"<br>debug="0" connectionTimeout="20000" <br>disableUploadTimeout="true" /&gt;</p>
<p style="color: #1826ff;">&lt;!--配置8009端口如下：--&gt;<br>&lt;Connector port="8009" <br>maxThreads="500" minSpareThreads="400" maxSpareThreads="450"<br>enableLookups="false" redirectPort="8443" debug="0"<br>protocol="AJP/1.3" /&gt;<br>&lt;!--配置引擎--&gt; <br>&lt;Engine name="Catalina" defaultHost="localhost" debug="0" jvmRoute="tomcat1"&gt;</p>
<p style="color: #1826ff;">启动内存配置,开发configure tomcat程序即可配置：<br>Initial memory pool: 200 M<br>Maxinum memory pool:300M<br>Tomcat2配置：<br>配置和tomcat1差不多，需要改动的地方如下：<br>&lt;!--配置引擎--&gt; <br>&lt;Engine name="Catalina" defaultHost="localhost" debug="0" jvmRoute="tomcat2"&gt;</p>
<p style="color: #1826ff;">启动内存配置,开发configure tomcat程序即可配置：<br>Initial memory pool: 512 M<br>Maxinum memory pool:768M<br>Mysql配置：<br>Server类型：Dedicated MySQL Server Machine <br>Database usage:Transational Database Only<br>并发连接数量：Online Transaction Processing(OLTP)<br>字符集：UTF8<br>数据库连接池的配置：<br>我们采用的是spring 框架，配置如下：<br>&lt;property name="hibernateProperties"&gt;<br>&lt;props&gt;<br>&lt;prop key="hibernate.dialect"&gt;org.hibernate.dialect.MySQLDialect&lt;/prop&gt;<br>&lt;prop key="hibernate.connection.driver_class"&gt;com.mysql.jdbc.Driver&lt;/prop&gt;<br>&lt;prop key="hibernate.connection.url"&gt;jdbc:mysql://202.88.1.103/db&lt;/prop&gt; <br>&lt;prop key="hibernate.connection.username"&gt;sa&lt;/prop&gt;<br>&lt;prop key="hibernate.connection.password"&gt;&lt;/prop&gt;</p>
<p style="color: #1826ff;">&lt;prop key="hibernate.show_sql"&gt;false&lt;/prop&gt;<br>&lt;prop key="hibernate.use_sql_comments"&gt;false&lt;/prop&gt;</p>
<p style="color: #1826ff;">&lt;prop key="hibernate.cglib.use_reflection_optimizer"&gt;true&lt;/prop&gt;<br>&lt;prop key="hibernate.max_fetch_depth"&gt;2&lt;/prop&gt;</p>
<p style="color: #1826ff;">&lt;prop key="hibernate.c3p0.max_size"&gt;200&lt;/prop&gt;<br>&lt;prop key="hibernate.c3p0.min_size"&gt;5&lt;/prop&gt;<br>&lt;prop key="hibernate.c3p0.timeout"&gt;12000&lt;/prop&gt;<br>&lt;prop key="hibernate.c3p0.max_statements"&gt;50&lt;/prop&gt;<br>&lt;prop key="hibernate.c3p0.acquire_increment"&gt;1&lt;/prop&gt; <br>&lt;/props&gt;<br>&lt;/property&gt;<br>其他的没有额外配置。<br>LoadRunner 常见问题：<br>（1）sofeware caused connction：这种情况，一般是脚本有问题，或者loadrunner有问题。解决方法：重新启动机器，或者重新录制脚本，估计是loadrunner的bug。<br>（2）cannot connect to server:无法连接到服务器。这种情况是服务器的配置有问题，服务器无法承受过多的并发连接了。需要优化服务器的配置，<br>如操作系统采用windows 2003 server，<br>优化tomcat配置：maxThreads="500" minSpareThreads="400" maxSpareThreads="450"。但是tomcat 最多支持500个并发访问<br>优化apache配置：<br>ThreadsPerChild 1900 <br>MaxRequestsPerChild 10000<br>其他的错误如：<br>Action.c(10): Error -27791: Server has shut down the connection prematurely<br>HTTP Status-Code=503 (Service Temporarily Unavailable)<br>一般都是由于服务器配置不够好引起的，按照问题（2）处理，如果仍旧不行，需要优化硬件和调整程序了。<br>Apache问题：<br>（1） File does not exist: C:/Apache/htdocs/favicon.ico：<br>这个问题是apache，htdocs目录没有favicon.ico文件引起的，该文件是网站的图标，仅在firefox,myIE等浏览器出现。<br>（2） 图片无法显示：<br>配置apache后，却无法显示图片。<br>解决方法：把程序的图片，按照程序结构copy到apache的htdocs目录下。<br>（3） 无法处理请求：<br>当我们输入 ***.do 命令后，apache确返回错误信息，而连接tomcat却没有问题。原因是没有把.do命令转发给tomcat处理。解决方法如下：<br>在apache配置文件中配置如下内容：<br>DocumentRoot "C:/Apache/htdocs"<br>JkMount /*.jsp loadbalancer<br>JkMount /*.do loadbalancer</p>
<p style="color: #1826ff;"><br>总结：<br>网站的压力测试，涉及的知识面挺广的，不仅要熟悉压力测试工具，还要知道如何配置和优化应用服务器和数据库，并且需要知道如何优化网络、操作系统、硬件系统。<br>测
试中不仅要善于发现问题，要知道如何解决。最重要的一点，要有良好的测试方法。刚开始测试时，可以从最简单的测试脚本入手，不需要太复杂的脚本，这样便于
发现问题。如我们刚开始时，就从一个简单的下载登陆界面的脚本入手，测试一个tomcat的压力负载。一个简单的获取登陆的脚本，帮助我们优化了
tomcat的配置；后来再测试数据库连接，也是一个简单的数据库连接脚本，帮助我们优化了数据库连接池；然后利用这些简单的脚本，测试apache的负
载平衡，优化了apache配置。最后运行复杂的脚本，模拟多种角色的用户在不同时间下的处理，以测试网站压力负载。<br>&nbsp;</p>
<p style="color: #1826ff;"><br>DBCP
使用apache的对象池ObjectPool作为连接池的实现，在构造GenericObjectPool时，会生成一个内嵌类Evictor，实现自
Runnable接口。如果_timeBetweenEvictionRunsMillis大于0，每过
_timeBetweenEvictionRunsMillis毫秒Evictor会调用evict()方法，检查对象的闲置时间是否大于
_minEvictableIdleTimeMillis毫秒（_minEvictableIdleTimeMillis小于等于0时则忽略，默认为30
分钟），是则销毁此对象，否则就激活并校验对象，然后调用ensureMinIdle方法检查确保池中对象个数不小于_minIdle。在调用
returnObject方法把对象放回对象池，首先检查该对象是否有效，然后调用PoolableObjectFactory
的passivateObject方法使对象处于非活动状态。再检查对象池中对象个数是否小于_maxIdle，是则可以把此对象放回对象池，否则销毁此
对象</p>
<span style="color: #1826ff;">还有几个很重要的属性，_testOnBorrow、_testOnReturn、_testWhileIdle，这些属性的意义是取
得、返回对象和空闲时是否进行验证，检查对象是否有效，默认都为false即不验证。所以当使用DBCP时，数据库连接因为某种原因断掉后，再从连接池中
取得连接又不进行验证，这时取得的连接实际已经时无效的数据库连接了。网上很多说DBCP的bug应该都是如此吧，只有把这些属性设为true，再提供
_validationQuery语句就可以保证数据库连接始终有效了，oracle数据库可以使用SELECT COUNT(*) FROM
DUAL，不过DBCP要求_validationQuery语句查询的记录集必须不为空，可能这也可以算一个小小的BUG，其实只要
_validationQuery语句执行通过就可以了。
</span><br><img src ="http://www.blogjava.net/sutao/aggbug/135999.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-08-11 11:54 <a href="http://www.blogjava.net/sutao/articles/135999.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>领域模型驱动设计(Evans DDD)之模型提炼</title><link>http://www.blogjava.net/sutao/articles/135323.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Wed, 08 Aug 2007 11:14:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/135323.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/135323.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/135323.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/135323.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/135323.html</trackback:ping><description><![CDATA[<h3 style="color: #2835ff;" align="center">领域模型驱动设计(Evans DDD)之模型提炼</h3>
<p style="color: #2835ff;" align="center"><a href="http://www.jdon.com/aboutme.htm">板桥里人</a> http://www.jdon.com
2006/8/21</p>
<br style="color: #2835ff;">
<p style="color: #2835ff;">　　当Java世界提供的可选择性框架平台越来越多时，我们可能被平台架构所深深困扰，而无暇顾及软件的真正核心：业务建模，其实，业务领域建模同样是一个比平台架构更复杂，更需要学习的新的领域。</p>
<p style="color: #2835ff;">
相反，在实践中，我们技术人员在经过冗长的平台架构学习和实践后，就匆忙开始项目开发，这时是什么指导他们进行软件业务实现呢？大部分可能是依赖数据库
建模，甚至是复杂冗长的数据库存储过程设计，这些已经开始走向面向对象分析设计的反方向，走上了一条错误的软件开发方向，最终开发出缓慢的、经常当机的
Java企业系统。</p>
<p style="color: #2835ff;">　　如果你没有恰当的OO设计思想，Java就会用性能惩罚你，这可能是Java世界的一个潜规则。</p>
<p style="color: #2835ff;">　　那么，一个正确的OOA/OOD/OOP步骤是什么呢？目前围绕模型驱动设计(MDD)的设计思想成为主流思想，MDA更是在MDD基础上提升和升华。下面让我们首先了解，如何使用领域驱动设计思想来分析设计一个软件系统。</p>
<p style="color: #2835ff;">　　当我们不再对一个新系统进行数据库提炼时，取而代之的时面向对象的模型提炼。我们必须大刀阔斧地对业务领域进行细分，将一个复杂的业务领域划分为多个小的子领域，同时还必须分清重点和次要部分，抓住核心领域概念，实现重点突破。</p>
<p style="color: #2835ff;"><strong> 核心领域模型</strong> </p>
<p style="color: #2835ff;">　　精简模型，找出核心领域，将业务需求中最有价值的概念体现出来，让核心变精要，这实际就是一个使复杂问题变简单的过程，也是对我们软件设计人员真正能力的考验。</p>
<p style="color: #2835ff;">　　核心领域模型不是轻易能够发现，特别是他处于一个纷乱复杂的众多领域模型结构中时，核心模型通常是我们某个子领域关注的重点，例如订单模型是订单管理领域的核心；消息模型是论坛或消息领域系统的核心。</p>
<p style="color: #2835ff;">
目前，分析领域有很多模式来帮助我们来提炼核心模型，例如四色原型、Martin Fowler
的分析模式等，例如MF的"分析模式"(Analysis
Patterns)中的记帐模型就是不仅仅用来记录账目数值，而且可以记录和控制账目的每一次修改。而四色原型则是一种高于分析模式的一种原型基本模式，
下面是本人根据四色原型提炼的核心领域模型概念。</p>
<p style="color: #2835ff;">　　一般情况下，在企业应用中，核心模型总是在其周围围绕一些所谓的&#8220;卫星&#8221;，这实际上也是来自<a href="http://www.jdon.com/mda/archetypes.html" target="_blank">四色原型</a>的一个推论，核心模型和其&#8220;卫星&#8221;的类图如下：</p>
<p style="color: #2835ff;" align="center"><img src="http://www.jdon.com/mda/images/model_core.jpg" alt="core model" height="242" width="275"></p>
<p style="color: #2835ff;">
根据Eric
Evans在其&#8220;领域驱动设计&#8221;一书中定义，领域模型划分为实体和值对象两种，实体模型是指业务领域中具有独立属性的对象；而值对象则可能是一种
Description或状态或规则。只要有实体对象，就可能存在实体的状态，状态跟踪有时成为一个业务领域使用计算机软件的首要跟踪，但是，数据库不是
对象状态的唯一表达方式，只是一种存储方式(见<a href="http://www.jdon.com/artichect/state.htm" target="_blank"><strong> 状态对象：数据库的替代者</strong> </a>)。</p>
<p style="color: #2835ff;">　　图中，实体核心对象大部分可能有一种类型，例如核心模型是产品，那么存在产品目录；核心模型是消息；就存在消息类型；核心模型是信息；总存在信息类别，我们总是使用分类方式来管理业务领域的信息，有时，类别甚至复杂到<a href="http://www.jdon.com/jive/thread.jsp?forum=91&amp;thread=23857" target="_blank">树形结构</a>。</p>
<p style="color: #2835ff;">　　核心实体模型有时会有一个1:N关联的子实体，一般可能表达实体的细节，例如：核心模型是订单，那么存在订单条目这样一个细节，一个订单中可能有多个订单条目；如果核心模型是信息，那么存在该信息的多个回复或评论；这样的关联一般存在多个业务领域中。</p>
<p style="color: #2835ff;"><strong> 模型界面实现</strong> </p>
<p style="color: #2835ff;">　　原来，我们以为分析设计阶段无需了解实现细节，分析人员只要闷头做分析UML图，而无需顾及如何具体实现，其实这是一个误区。</p>
<p style="color: #2835ff;">
Eric Evans在其&#8220;领域驱动设计&#8221;一书中认为：分析人员负责从领域中收集基本概念；
设计则必须指明一组适应编程工具构造的组件，以及这些组件必须能够在目标环境中有效执行。模型驱动设计(Model-Driven
Design)抛弃了分裂分析模型与设计的做法，使用单一的模型来满足这两方面的要求。因此，对于核心模型必须掌握了解其实现细节。</p>
<p style="color: #2835ff;">
从另外一个方面来说，中国的客户总是从界面设计来表达他们的意图（如果中国客户能够使用Use
Case等UML图来表达他们概念真是不可想象），例如客户会说，我希望有一个界面让我将订单数据输入，然后能够查询符合查询条件的订单。因此，我们的核
心模型至少能够顺利地映射到界面实现，相反，这个客户有这样订单界面要求，但是你没有提供一个与之适应的核心实体模型，界面实现将变得复杂，甚至走很多弯
路，诞生不少DTO垃圾对象。</p>
<p style="color: #2835ff;">　　以JdonFramework框架实现为例子，框架提供了围绕
核心模型的新增删除修改查询(CRUD)功能以及批量功能的快速实现，尤其CRUD功能实现前提是必须提炼出核心模型，从而其界面设计流程就能通过配置立
即实现，这样一步到位实现领域模型到界面的过渡，可以将我们设计核心模型和客户要求的界面需求能够做到完整的统一。</p>
<p style="color: #2835ff;">　　开源JdonFramework<a href="http://www.jdon.com/jdonframework/download.html?group_id=5298" target="_blank">下载包中message</a>案
例实际就是上述核心模型图的一种实现项目，更复杂的项目可以认为是核心模型的重叠和反复使用（从原理上讲，核心模型是四色原型的体现，而四色原型被认为是
大部分企业系统的基本组成元素，见[book][UML][Peter Coad]Java Modeling in Color with UML）。</p>
<p style="color: #2835ff;"><strong> 核心模型的选择</strong> </p>
<p style="color: #2835ff;">　　实际项目中，会存在多个核心模型的重叠和覆盖使用，主要取决于你的领域关注重点。</p>
<p style="color: #2835ff;">
例如当客户和我们说要做一个旅游网站时，我们必须充分了解需求，它的软件系统重点是哪些功能。如果当他首先说：我需要一个酒店设备的查询系统，因为他的
客户对酒店设备非常关注，那么我们可能认为酒店设备是这个领域模型的核心；酒店设备。如果他又进行描述：我需要一个界面，客户在输入酒店资料时，选择多个
酒店设备，那么在这样一个关注领域，核心模型实际是酒店，而酒店设备可能成为酒店的一个特征实体属性，甚至是值对象了。</p>
<p style="color: #2835ff;">
以进销存系统为例子，在采购系统中，采购单是一个核心实体模型，而原材料是一种辅助实体模型；在库存系统中，入出库单是一个核心实体模型，原材料或成
品代表的是一个库存物品概念模型，当需要库存报表查询输出，可以立即计算出来，或将结果缓存起来，缓存起来的结果其实是库存物品对象的状态，可以使用值对
象来实现。</p>
<p style="color: #2835ff;"><strong> 核心模型的精练</strong> </p>
<p style="color: #2835ff;">
当核心模型被定位和确定后，相当于我们抓住领域本质，这时我们可以使用面向对象的概念对模型进行精练细化，实际就是明确对象的属性，确定模型对象的边
界，通过反复重构，结合GoF等设计模式，使得我们得模型准确反映本质，从而实现模型的灵活性设计。所有这些，都是数据表驱动设计所不能实现的。那你还抱
着数据库建模干什么呢？</p>
<p style="color: #2835ff;">　　见下章：<a href="http://www.jdon.com/mda/dddcase1.html" target="_blank"><strong> 模型驱动设计(MDD)之灵活设计(续)</strong> </a></p>
<br><img src ="http://www.blogjava.net/sutao/aggbug/135323.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-08-08 19:14 <a href="http://www.blogjava.net/sutao/articles/135323.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>快速适应需求变化的软件复用</title><link>http://www.blogjava.net/sutao/articles/135321.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Wed, 08 Aug 2007 11:13:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/135321.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/135321.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/135321.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/135321.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/135321.html</trackback:ping><description><![CDATA[<h3 style="color: #1826ff;" align="center">快速适应需求变化的软件复用</h3>
<p style="color: #1826ff;" align="center"><a href="http://www.jdon.com/aboutme.htm">板桥里人</a> http://www.jdon.com
2006/06/06</p>
<!-- advert -->
<p style="color: #1826ff;">
软件复用本质是为了快速适应不断变化的需求（adapt to changing needs
），两者目标是一致的，但是当我们过于注重软件复用（如组件复用component
reuse又译构件复用）时，千万需要牢记：快速适应不断变化的需求是根本目的，它的重要性要重于组件复用技术本身。本文试图阐述两者概念比较以及时下流
行的组件复用技术概要。</p>
<p style="color: #1826ff;"><strong> 适应需求变化</strong> </p>
<p style="color: #1826ff;">　　现如今是一个计划赶不上变化的时代，企业竞争力逐渐表现在企业适应变化能力的竞争，谁能更快适应市场的变化，谁就能够在竞争中胜出，这种快速适应能力如果靠&#8220;人民战争&#8221;无疑是不现实的，软件可以帮助我们来适应这种快速变化。</p>
<p style="color: #1826ff;">
谈到这里，稍微再说明一下国人软件教育的误区，不错，软件曾经是科学计算的工具，因此，我们非常注重软件的算法和数据结构，甚至将之作为数学的衍生物，
但是，现如今已经成为一种帮助我们快速响应变化的有力工具，如果我们的教育背景中只有算法和数据结构，能够编制出应付快速变化的软件吗？很显然，他们是风
马牛不相及，由此可见国人软件概念和软件教育的落后性，在这样的软件认识背景下，固然设计模式的崇高位置得不到确立，软件设计被抛弃在脑后，编制出的大多
数企业软件系统根本不具备应付变化的能力，程序员拒绝频繁更改程序，甚至借助技术原因阻扰软件的频繁更改，这种软件程序员和软件用户之间的矛盾可以称为
miscommunication， miscommunication是导致软件系统的失败一个重要原因。</p>
<p style="color: #1826ff;">
国内早就有著名言论：&#8220;不上ERP等死；上了ERP找死&#8221;，如果你的企业不上ERP，那么你的企业就不能借助软件应付快速的市场等环境变化，那么必然会
被淘汰；但是，如果上了一个不注重&#8220;适应需求变化&#8221;的ERP软件系统，那就是企业被僵化的ERP软件框死，丧失了使用ERP的根本目的。</p>
<p style="color: #1826ff;">　　适应需求变化则成为现代软件系统一个孜孜不倦的追求目标，那么如何实现呢？</p>
<p style="color: #1826ff;">　　<strong> 原则</strong> ：给予人们可以裁剪他们系统的能力应适应需求变化，建立一个适应需求变化的系统，允许系统在一系列小的、可控制的步骤上进行改变。　　</p>
<p style="color: #1826ff;"><strong> 组件诞生</strong> </p>
<p style="color: #1826ff;">　　将不变的通用的东西抽象出来，以达到在不同项目中重用复用，将我们有限的精力集中在项目具体变化和特点上。当然这些抽象复用的东西之间彼此必须是松耦合，这样才能根据需求挑选组合。</p>
<p style="color: #1826ff;">　　让我们先回顾一下软件的发展史，软件开发的发展史实际是一部我们思维不断抽象拔高的发展过程，这种抽象概念非常类似于建模的思考方式：概要贴切地描述事物，忽视次要的细节。抽象体现在软件开发上就是每个具体项目需要完成的代码行数量越来越少。</p>
<p style="color: #1826ff;">　　从1970到1980这段时间，软件开发从机器语言到汇编语言。进而发展到高级语言，甚至一些CASE工具，面向功能编程发展到面向对象编程，功能模块重用细化到类的重用，类的重用是最初是通过设计模式实现的。</p>
<p style="color: #1826ff;">
进入90年代中期，诞生了基于组件的开发模式（CBD：component based
development），CBD将抽象概念带往了一个新的方向，与减少代码数量相反，CBD将功能各个方面细化分离到不同的、相互隔离层中，如表现层、
业务逻辑层、持久层、安全层以及核心层等，并且可以管理这些组件之间的依赖关系，通过这种分离，我们可以提纯细化组件功能，进而产生可以重用的框架，如
Struts框架可以重用在大部分应用系统的表现层中，，Struts+JdonFramework+Hibernate是一个框架组合，代表一种架构设
计，这种架构设计其实可以重用在大部分应用系统，这种重用我称之为架构级别重用。</p>
<p style="color: #1826ff;"><strong> 组件复用</strong> </p>
<p style="color: #1826ff;">
软件组件(Software
components)是软件提供业务或技术功能的基本单元或元素，这些单元可以独立地被部署、他们可以自我管理并且被虚拟部署到网络的任何地方，业务组
件（(Business components)执行业务逻辑、遵循一定的业务规则并且管理相应的数据（数据库操作称为manage
corporate data）；而技术组件(Technical
components)则提供相应的平台以便业务组件可以依赖其上运行，例如权限、组件管理等。</p>
<p style="color: #1826ff;">
JdonFramework/Spring都属于一种技术组件框架，而我们具体项目的业务层代码如果能够提炼可以复用，则是业务组件；
JdonFramework/Spring则都提供了业务组件赖于运行的一些核心底层机制，特别是组件的管理，如组件的创建、组件的获得、组件的资源管
理、组件的消亡等生命周期支持，所以，我们可以在JdonFramework/Spring中加入自己的业务组件，当然，JdonFramework还提
供了Session等状态管理的支持功能，为业务组件提供了更广阔的生命周期支持。</p>
<p style="color: #1826ff;">　　组件复用
技术以前是停留在编译前期，也就是说：我们在编程时，导入所需要的其他组件Jar包，然后混同我们的项目编译部署，但是这需要通过专业技术人员实现，很显
然是不能适应原则中第一句：给予人们可以裁剪他们系统的能力应适应需求变化，这里的&#8220;人们&#8221;应该是指软件最终用户，应该给予用户自己改变系统的能力，也就
是说：需要提供软件系统运行时能够动态改变自身的能力。</p>
<p style="color: #1826ff;">　　组件复用技术以前停留在软件编译阶段，现在则更靠前，必须在软件运行阶段，当然对技术要求相当高，需要语言支持RTTI（简单又神秘的Class.forName发挥作用了），这在"<a href="http://www.laputan.org/metamorphosis/metamorphosis.html" target="_blank">Evolution, Architecture, and Metamorphosis</a>"一文中被认为是Metamorphosis，现在由于AOP技术出现，AOP有一种动态Weaving技术，实际就是在软件运行时实现动态拦截，这样给予终端用户更大的改变系统能力，他们基本可以以动态插拔的概念实现多个组件的组合运行。在"<a href="http://www.jdon.com/AOPdesign/decorator.htm" target="_blank">AOP vs Decorator</a>"一文中，我把编译阶段的组件组合方式（我更愿意称为静态组合）和运行时组合等两种处理方式，合并称为过滤器模式，如果你希望采取组件可插拔式的复用，就可以使用过滤器模式。</p>
<p style="color: #1826ff;"><strong> 组件可插拔更换</strong> </p>
<p style="color: #1826ff;">　　为什么说组件的可插拔非常重要？</p>
<p style="color: #1826ff;">
组件重用目的是为了更好地适应需求变化，但是有了组件重用不代表就快速适应需求变化，因为组件本身也会产生设计错误（提炼得不够抽象或者组件很难以替
代），这就必然导致软件系统得维护成本提高，那么快速适应需求变化的目标也就成为一纸空文。实践证明：组件设计问题已经成为导致软件开发失败的一个主要因
素。</p>
<p style="color: #1826ff;">　　组件设计有两个主要风险：组件提纯的纯度和组件的替代方式。提炼的纯度也就是抽象的高度，组件的抽象程度越高，当然可重用范围越广，但是往往我们只有经历多个项目后，才发现自己的组件提炼还欠火候，这实际是组件的提炼过程成本。</p>
<p style="color: #1826ff;">
组件提练虽然取决于人为设计因素，但是在实现手段上也依赖于组件的替换方式，通过经常反复频繁的微调和更换，才能将组件不断提炼向理想状态靠拢，所以，
必须有一种方便的组件替换方式提供频繁更换支持，我们总不希望更换组件象以前更换汽车发动机火花塞一样，需要拆开汽车，打开发动机那样麻烦吧？</p>
<p style="color: #1826ff;">
参考PC电脑硬件设计：更新CPU或内存条，只要直接插拔就可以，这些部件和母版都是一种松散的、可插拔的关系，如果软件组件替换是动态的可插拔更加方
便终端用户在软件系统交付后，根据需求改变他们的系统。组件可插拔本质上是这些组件必须是最大化的松耦合，彼此依赖影响非常小，换句话说：如果实现了可插
拔更换，说明你的组件已经实现松耦合了。</p>
<p style="color: #1826ff;">　　那就有可能设计一种软件框架：它能够为每个部件提供非常棒的服务访问，软件组件是 松耦合'loosely coupled'，这些组件的大部分通过几行代码就可以实现替换。目前这种方便的实现方式是使用XML进行组件的配置。</p>
<p style="color: #1826ff;">
JdonFramework/Spring都是这样的一种框架，JdonFramework更进步的是：JF框架本身的组件也是可以替换的，例如你希望
在JF中使用Spring的配置文件，那么你只要做一个Spring配置文件的解析组件，然后替换JF框架原来的XML解析器就可以了。无论
EJB2/EJB3等在这方面要稍逊于Ioc/AOP框架，对于支持EJB3的JBoss 4
这样架构，需要动态更换AOP拦截器还不是很方便，因为JBoss 4本身组件没有象JF那样做到可插拔配置，不过，JBoss
5已经开始走上这条路，使用一个微核心来管理所有的可插拔组件，我曾经在"<a href="http://www.jdon.com/artichect/embeddable.htm" target="_blank">JBoss 5迎来中间件彻底的可配置时代</a>"一文中提出组件是否方便替换是衡量一个组件框架的重要指标。</p>
<p style="color: #1826ff;">　　在最近的TheServerSide文章<a href="http://www.theserverside.com/news/thread.tss?thread_id=40772" target="_blank">'Service Access' to the software components</a>中，主要是谈论了表现层组件的替换访问方式，GIF这样图片组件不可以随意控制调整，基本不能复用，但是通过SVG或XUI等支持XML组件动态替换技术的使用，则可以实现显示图形组件的复用。</p>
<p style="color: #1826ff;"><strong> SOA</strong> </p>
<p style="color: #1826ff;">　　在软件运行时，给予用户动态插拔式更换组件，达到复用的组件更加适合变化的需求，<br>
这是软件业追求的目标，而SOA(Service Oriented Architecture)则是从另外一种方向<br>
也是在运行时提供用户一种改变系统的能力。</p>
<p style="color: #1826ff;">　　SCBA(Services and Components Based Architecture),
SCBA是通过减少需求变化带来的传递损耗和时间来实现的，当需求变化时，SOA的服务将支持跟进变化和替换。</p>
<p style="color: #1826ff;">
SCBA更强调的是一种业务过程重用，而且是跨组织跨多个专业域范围的，例如我以前说的四色图实际是对跨域范围的业务总结，特别是ERP域范围，大多数
企业系统都是由MI等四种原始模型组成的，例如JiveJdon3看上去只是一个论坛系统，实际不只是，它的Message模型可以重用在网站内容系统、
新闻发布系统、电子商务系统、仓库管理系统、资源管理系统等跨域范围中（部分已经实现）。</p>
<p style="color: #1826ff;">　　既
然业务过程和IT系统可以跨组织跨域重用，那么类似软件系统的维护和开发就不必再重新开发，JiveJdon3的Message模型重用在新闻发布系统
中，我需要把JiveJdon3的项目拷贝到新闻发布系统中，然后再针对新闻发布系统特点做些裁剪修改，这这种复制业会带来工作量和维护量，而SCBA则
可以解决这个问题，通过运行时single-copy reuse分享各种服务功能。</p>
<p style="color: #1826ff;">　　更多SOA重用可参考&#8220;<a onmousedown="return clk(0,'','','res','3','')" href="http://colab.cim3.net/file/work/SOACoP/Finals%20SCBA_Whitepaper_Chapter_1_Version%203.5%20OMB%20SUBMISSION.doc" target="_blank">Service Component White Paper</a>&#8221;一文。</p>
<p style="color: #1826ff;"><strong> 总结</strong> </p>
<p style="color: #1826ff;">　　本文总结了软件复用的不同层次：设计复用、组件架构复用以及业务模型复用，复用技术
的不断发展正是由于适应变化需求的要求不断提高导致，本人从2002年开始从事复用技术研究，最初从复用层次底层设计模式开始，在国内媒体第一次全面分析了<a href="http://www.jdon.com/designpatterns/index.htm" target="_blank">GoF设计模式</a>（其中个别模式当时被天极网转载），
经过这几年发展，亲身体会复用技术已经进入了一个新的阶段。特写此文作为小结。</p>
<br><img src ="http://www.blogjava.net/sutao/aggbug/135321.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-08-08 19:13 <a href="http://www.blogjava.net/sutao/articles/135321.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实战DDD(Domain-Driven Design领域驱动设计:Evans DDD)</title><link>http://www.blogjava.net/sutao/articles/135320.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Wed, 08 Aug 2007 11:10:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/135320.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/135320.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/135320.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/135320.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/135320.html</trackback:ping><description><![CDATA[<h3 style="color: #202eff;" align="center">实战DDD(Domain-Driven Design领域驱动设计:Evans DDD)</h3>
<p style="color: #202eff;" align="center"><a href="http://www.jdon.com/aboutme.htm">板桥里人</a> http://www.jdon.com
2006/7/10（转载请保留）</p>
<br style="color: #202eff;">
<p style="color: #202eff;">
2004年著名建模专家Eric Evans发表了他最具影响力的著名书籍：Domain-Driven Design &#8211;Tackling
Complexity in the Heart of Software（中文译名：领域驱动设计　2006年3月清华出版社译本，或称
Domain Driven-Design architecture [Evans DDD]）。</p>
<p style="color: #202eff;">
Martin Fowler作序说；&#8220;希望本书是一本非常有影响力的书籍,.......
Eric最值得我尊敬的一个方面是他敢于讨论还未取得成功的事情&#8221;，其实，时值今年2006年，DDD开发框架已经层出不穷（如RoR、RIFE、
JdonFramework等），我们项目软件包结构都变成了这样：xxx.model;xxx.service，DDD思想已经遍地开花，不能再说不成
功了。</p>
<p style="color: #202eff;">　　DDD是告诉我们如何做好业务层！并以领域驱动设计思想来选择和合适的框架，本文以基于JdonFramework开发的<a href="http://www.jdon.com/jdonframework/jivejdon3/index.html" target="_blank">JiveJdon3.0</a>说明DDD方法的实战应用。</p>
<p style="color: #202eff;">　　首先必须认识到：领域建模是一种艺术的技术，不是数学的技术，它是用来解决复杂软件快速应付变化的解决之道（<a href="http://www.jdon.com/artichect/reuse.html" target="_blank">快速适应需求变化的软件复用</a>）。</p>
<p style="color: #202eff;">　　我们知道软件的产生过程是：分析、设计、编程、测试、部署。过去，分析领域和软件设计是分裂的，分析人员从领域中收集基本概念；而设计必须指明一组能北项目中适应编程工具构造的组件，这些组件必须能够在目标环境中有效执行，并能够正确解决应用程序出现的问题。
模型驱动设计(Model-Driven Design)抛弃了分裂分析模型与设计的做法，使用单一的模型来满足这两方面的要求。这就是领域模型。</p>
<p style="color: #202eff;">　　单一的领域模型同时满足分析原型和软件设计，如果一个模型实现时不实用，重新寻找新模型。如果模型没有忠实表达领域关键概念时，也必须重新寻找新的模型。
建模和设计成为单个迭代循环。将领域模型和设计紧密联系。因此，建模专家必须懂设计，会编程。</p>
<p style="color: #202eff;"><strong> 分层架构</strong> </p>
<p style="color: #202eff;">　　最初层次只分为三层：表现层、业务层和持久层；DDD其实告诉我们如何让实现业务层！</p>
<p style="color: #202eff;">　　一位道友曾经<a href="http://www.jdon.com/jive/article.jsp?forum=16&amp;thread=27452" target="_blank">请教层次的职责，对服务Service提出疑问</a>。根据Eric的理论，业务层将细分为两个层次：应用层和领域层。它们的定义是：应用层：定义软件可以完成的工作，并且指挥具有丰富含义的领域对象来解决问题，保持精练；不包括业务规则或知识，无业务情况的状态；
领域层：负责表示业务概念、业务状态的信息和业务规则，是业务软件核心。</p>
<p style="color: #202eff;">　　层次之间必须清晰分离，每个层都是内聚的，并且只依赖它的下层，为了实现各层的最大解耦，Ioc模式和Ioc容器是目前最好的选择，JdonFramework使用基于PicoContainer的Ioc容器实现了各层的松耦合；</p>
<p style="color: #202eff;">
Eric特别指出：那种将业务逻辑交由业务界面处理的快速UI方式是旁门左道。希望象C/S结构那样可视化拖拖图形就完成的软件开发是一种错误的方向，
开发时快速，难于维护和扩展，虽然使用J2EE技术，其实是一种伪多层技术。可惜，有很多国人在疯狂开发这类工具，大有不撞南墙不低头之势，并且疯狂误导
很多非专业人士，可悲可叹！如果对这段言论持不同意见，建议你购买"领域驱动设计"这本译书，见P53页。</p>
<p style="color: #202eff;"><strong> 领域模型种类</strong> </p>
<p style="color: #202eff;">　　传统模型分为两种：实体（Entity）和值对象（Value Object），现在服务（Service）成为第三种模型元素。</p>
<p style="color: #202eff;">　　实体（Entity）定义：通过一系列连续性（continuity）和标识（identity　ID）来定义；个人认为它和分析领域的<a href="http://www.jdon.com/mda/archetypes.html" target="_blank">四色原型</a>中的PPT原型非常类似，可以看成是PPT原型延续。</p>
<p style="color: #202eff;">　　实体必须拥有自己的唯一ID，主键，如果没有一个ID标识，为每个实例加上一个具有唯一性ID，可能是内部使用。
如JiveJdon3.0中jdonframework.xml中模型增删改查CRUD配置定义：</p>
<table style="color: #202eff;" bgcolor="#cccccc" border="0" cellpadding="2" cellspacing="2" width="100%">
    <tbody>
        <tr>
            <td height="145">&lt;model key="forumId"
            class="com.jdon.jivejdon.model.Forum"&gt;<br>
            .....
            <br>
            &lt;/model&gt;</td>
        </tr>
    </tbody>
</table>
<p style="color: #202eff;">　　其中，forumId是模型com.jdon.jivejdon.model.Forum的主键，唯一ID，每个模型必须有一个专家。<br>
<br>
值对象（Value
Object）：如果一个对象代表了领域的某种描述性特征，且没有概念性的标识。个人认为它是四色原型中Description原型延续。如果我们只关心
模型中一个元素的属性，那么把这个元素划为值对象。值对象是不可变的，不要给它任何标识，避免实体的维护性，降低设计复杂性。我们不关心值对象是哪个实
例。</p>
<p style="color: #202eff;">　　在JiveJdon3.0中，ForumState是一个值对象，它表示论坛当前最新帖子、论坛的主题数量和帖子数量，它的根对象是Forum，是被内聚嵌入到Forum这个实体模型中的，代码如下：</p>
<table style="color: #202eff;" bgcolor="#cccccc" border="0" cellpadding="2" cellspacing="2" width="100%">
    <tbody>
        <tr>
            <td height="145">
            <p>package com.jdon.jivejdon.model;<br>
            </p>
            <p>&nbsp;</p>
            <p>/**<br>
            * Forum State ValueObject<br>
            * this is a embeded class in Forum. <br>
            * @author &lt;a href="mailto:banqiao@jdon.com"&gt;banq&lt;/a&gt;<br>
            *<br>
            */<br>
            public class ForumState { <br>
            <br>
            private int threadCount = 0; //主题数量 <br>
            <br>
            <br>
            private int messageCount = 0;//帖子数量<br>
            <br>
            <br>
            private ForumMessage lastPost; //最新帖子 </p>
            <p>&nbsp; </p>
            <p>　　public int getMessageCount() {<br>
            return messageCount;<br>
            }　　</p>
            <p>　　......<br>
            }  <br>
            </p>
            </td>
        </tr>
    </tbody>
</table>
<p style="color: #202eff;">　　同样ForumThreadState是也是一种值对象，根据Eric的值对象设计，ForumThreadState和ForumState是可以合并成一个对象的，值对象中没有ID等唯一标识。</p>
<p style="color: #202eff;"><img src="http://www.jdon.com/mda/images/forum.jpg" alt="forum" height="187" width="314"></p>
<p style="color: #202eff;">&nbsp;</p>
<p style="color: #202eff;">　　Eric认为：服务Service是描述领域概念最自然的方式，是四色原型的MI原型的延续，
优秀服务3个特征：<br>
1.与领域概念相关的操作行为、但不是实体和值对象中固有的部分。<br>
2.接口根据领域模型中其他元素定义<br>
3.操作是无状态的。</p>
<p style="color: #202eff;">
在JiveJdon3中，com.jdon.jivejdon.service.ForumService和Forum实体模型及其值对象
ForumState共同完成领域模型，其中ForumService属于应用服务层；而后两者属于领域层；其他服务
ForumMessageService、AccountService和UploadService等都是此类性质。</p>
<p style="color: #202eff;"><strong> 领域对象的生命周期Scope</strong> </p>
<p style="color: #202eff;">
Spring 1.x刚出来时确实忽悠了大家一把，因为他没有领域对象的生命周期支持，直到Spring 2.0才将如new Bean
scope，当初那些疯狂捧Spring 1.x 臭脚的所谓高手是不是还是基于数据库驱动的思维，根本没有真正OO模式思维，当今天JBoss
Seam、Scopes等框架开始重视对象生命周期支持后，曾经发生在Jdon社区争战硝烟已经过去，成为历史。</p>
<p style="color: #202eff;">　　Eric认为：每个对象独有器生命周期，一个对象在创建以后，可能要经历各种不同的状态，并最终消亡。
对象生命周期由长短：临时对象；常驻内存；有的与其他对象存在复杂的依赖关系；状态变化时必须满足一些不变量的约束条件。
如何管理这些对象提出挑战！处理不好会偏离MDD的方向。</p>
<p style="color: #202eff;">　　在生命周期中维护对象的完整性。避免模型由于管理生命周期的复杂性而陷入困境。有
三个模式来处理：
聚合（Aggregate）：定义清晰的所有权和边界使模型更加紧凑，避免出现盘根错节的对象关系网；工厂（Factory）和组合（Respository）。</p>
<p style="color: #202eff;">　　当一个对象生命周期之始，使用工厂和组合提供了访问和控制模型对象的方法，完善了MDD。
建立聚合的模型，并且把工厂和组合加入设计中来，可以使我们系统地对模型对象进行管理。
聚合圈出一个范伟，在这个范围中，对象无论在哪个生命周期，保持不变性。</p>
<p style="color: #202eff;">
在JiveJdon3.0中，值对象ForumState是被聚合在实体模型Forum中，Forum作为ForumState的一个根，由于它们数据
必须保持一致性，不变量(invariant)是指无论何时发生数据变化必须满足一致性规则，由于根控制了访问，就无法绕过它修改内部元素，例如，如果没
有Forum实体对象这个根，就无法去修改对象状态ForumState，ForumState获得是通过Forum的getter方法获得的。</p>
<p style="color: #202eff;">　　ForumState和Forum的分离有可以使修改论坛状态数据（当发一个新帖时，必须更新当前论坛的最新帖子为该新帖），不会影响到Forum其他元素，特别是使用事务锁定时，不必锁住整个对象，见"领域驱动设计"书籍P92。</p>
<p style="color: #202eff;">　　另外，ForumThread和ForumMessage的关联关系必设定成单向的，而不是双向的，因为领域建模中，关联越简单越好。</p>
<p style="color: #202eff;">
在JiveJdon3.0中，你可能注意到有一个com.jdon.jivejdon.service.factory.ForumBuilder，所
有实体模型对象的获得都是从这个工厂创建出来的，我曾经徘徊过：这个工厂类是否应该属于持久层，因为JiveJdon3.0持久层没有使用
Hibernate这样O/R
Mapping框架，而是直接使用SQL，但是从持久层输出的都是对象，这是必须坚持的一个设计原则（好像是MF的一个什么元数据模式） 。</p>
<p style="color: #202eff;">　　但是，Eric明确告诉我们，领域模型的工厂属于应用层，页就是还是应该处于业务层的，这样好处很多，业务层设计根本无需从Hibernate等持久层框架获得，而是从自己的工厂获得。</p>
<p style="color: #202eff;">
组合（Respository）又被翻译成仓储，我认为组合合适，主要用来返回一批对象，查询组合常用来返回批量查询结果，JdonFramework
两个快速开发支持：批量查询其实应该是Respository的实现，实际也是过去Master-details的一种查询实现。</p>
<p style="color: #202eff;">　　以com.jdon.jivejdon.presentation.action.ThreadListAction为例子，其功能是查询论坛Forum下所有主题ForumThread，并分页显示，实现效果<a href="http://www.jdon.com/jivejdon//forum/threadList.shtml?forumId=102" target="_blank">按这里</a>，我们在customizeListForm方法中将根Model Forum设置进入，在threadList.jsp中，我们使用struts的标签库logic:iterator来遍历组合对象threadListForm中的ForumThread集合。</p>
<p style="color: #202eff;"><strong> 失血模型</strong> </p>
<p style="color: #202eff;"> 　　MF（Martin Fowler）曾经提出有名的贫血模型或失血模型，让我们好生迷惑和彷徨，他认为实体模型对象中只有弱行为setter和getter方法，没有真正行为，好像缺少血液的人，不和谐了，不少高手又被忽悠了，大谈贫血模型。</p>
<p style="color: #202eff;">　　其实，Eric已经认为，在DDD中，领域中一些概念不能作为模型中的对象来处理的，如果将这些功能概念强行加给实体对象和值对象，破坏模型中对象的定义，人为添加没有意义的对象。服务是描述领域概念最自然的方式。</p>
<p style="color: #202eff;">　　为了在这些大师之间取得一个平衡，有人将Model的持久化操作（CRUD行为）整入到领域模型中，这是不是违背当初Dao模式初衷，Dao模式其实是桥模式和适配器模式组合（见SUN的J2EE核心模式）。</p>
<span style="color: #202eff;">
无论如何，我们的DDD项目中都是以失血模型存在着，所以，Eric呼唤：建模专家必须懂得实现，懂得软件技术，MF可能会听进去的。
</span><br> <img src ="http://www.blogjava.net/sutao/aggbug/135320.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-08-08 19:10 <a href="http://www.blogjava.net/sutao/articles/135320.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 当前Java软件开发中几种认识误区</title><link>http://www.blogjava.net/sutao/articles/135315.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Wed, 08 Aug 2007 10:42:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/135315.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/135315.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/135315.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/135315.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/135315.html</trackback:ping><description><![CDATA[<h3 style="color: #1826ff;" align="center">                    当前Java软件开发中几种认识误区</h3>
<p style="color: #1826ff;" align="center"><a href="http://www.jdon.com/aboutme.htm">板桥里人</a> http://www.jdon.com
2006/9/1（转载请保留）</p>
<br style="color: #1826ff;">
<p style="color: #1826ff;">　　越来越多人开始使用Java，但是他们大多数人没有做好足够的思想准备(没有接受OO思想体系<a href="http://www.jdon.com/trainning.htm" target="_blank">相关培训</a>)，以致不能很好驾驭Java项目，甚至
导致开发后的Java系统性能缓慢甚至经常当机。很多人觉得这是Java复杂导致，其实根本原因在于：我们原先掌握的关于软件知识(OO方面)不是太贫乏就是不恰当，存在认识上和方法上的误区。</p>
<p style="color: #1826ff;"><strong> 软件的生命性</strong> </p>
<p style="color: #1826ff;">　　软件是有生命的，这可能是老调重弹了，但是因为它事关分层架构的原由，反复强调都不过分。</p>
<p style="color: #1826ff;">　　一个有生命的软件首先必须有一个灵活可扩展的基础架构，其次才是完整的功能。</p>
<p style="color: #1826ff;">
目前很多人对软件的焦点还是落在后者：完整的功能，觉得一个软件功能越完整越好，其实关键还是架构的灵活性，就是前者，基础架构好，功能添加只是时间和
工作量问题，但是如果架构不好，功能再完整，也不可能包括未来所有功能，软件是有生命的，在未来成长时，更多功能需要加入，但是因为基础架构不灵活不能方
便加入，死路一条。<br>
<br>
正因为普通人对软件存在短视误区，对功能追求高于基础架构，很多吃了亏的老程序员就此离开软件行业，带走宝贵的失败经验，新的盲目的年轻程序员还是使
用老的思维往前冲。其实很多国外免费开源框架如ofbiz
compiere和slide也存在这方面陷阱，貌似非常符合胃口，其实类似国内那些几百元的盗版软件，扩展性以及持续发展性严重不足。</p>
<p style="color: #1826ff;">　　那么选择现在一些流行的框架如Hibernate、Spring/Jdonframework是否就表示基础架构打好了呢？其实还不尽然，关键还是取决于你如何使用这些框架来搭建你的业务系统。</p>
<p style="color: #1826ff;"><strong> 存储过程和复杂SQL语句的陷阱</strong> </p>
<p style="color: #1826ff;">　　首先谈谈存储过程使用的误区，使用存储过程架构的人以为可以解决性能问题，其实它正是导致性能问题的罪魁祸首之一，打个比喻：如果一个人频临死亡，打一针可以让其延长半年，但是打了这针，其他所有医疗方案就全部失效，请问你会使用这种短视方案吗？</p>
<p style="color: #1826ff;">
为什么这样说呢？如果存储过程都封装了业务过程，那么运行负载都集中在数据库端，要中间J2EE应用服务器干什么？要中间服务器的分布式计算和集群能力
做什么？只能回到过去集中式数据库主机时代。现在软件都是面向互联网的，不象过去那样局限在一个小局域网，多用户并发访问量都是无法确定和衡量，依靠一台
数据库主机显然是不能够承受这样恶劣的用户访问环境的。（当然搞数据库集群也只是五十步和百步的区别）。</p>
<p style="color: #1826ff;">
从分层角度来看，现在三层架构：表现层、业务层和持久层，三个层次应该分割明显，职责分明：持久层职责持久化保存业务模型对象，业务层对持久层的调用只是
帮助我们激活曾经委托其保管的对象，所以，不能因为持久层是保管者，我们就以其为核心围绕其编程，除了要求其归还模型对象外，还要求其做其做复杂的业务组
合。打个比喻：你在火车站将水果和盘子两个对象委托保管处保管，过了两天来取时，你还要求保管处将水果去皮切成块，放在盘子里，做成水果盘给你，合理吗？</p>
<p style="color: #1826ff;">　　上面是谈过分依赖持久层的一个现象，还有一个正好相反现象，持久层散发出来，开始挤占业务层，腐蚀业务层，整个业务层到处看见的是数据表的影子（包括数据表的字段），而不是业务对象。这样程序员应该多看看<a href="http://www.martinfowler.com/eaaCatalog/index.html" target="_blank">OO经典PoEAA</a>。<a href="http://www.martinfowler.com/eaaCatalog/index.html" target="_blank">PoEAA</a> 认为除了持久层，不应该在其他地方看到数据表或表字段名。</p>
<p style="color: #1826ff;">　　当然适量使用存储过程，使用数据库优点也是允许的。按照Evans DDD理论，可以将SQL语句和存储过程作为规则Specification一部分。 </p>
<p style="color: #1826ff;"><strong> Hibernate等ORM问题</strong> <br>
现在使用Hibernate人也不少，但是他们发现Hibernate性能缓慢，所以寻求解决方案，其实并不是
Hibernate性能缓慢，而是我们使用方式发生错误：</p>
<p style="color: #1826ff;">　　&#8220;最近本人正搞一个项目，项目中我们用到了struts1.2+hibernate3,
由于关系复杂表和表之间的关系很多，在很多地方把lazy都设置false，所以导致数据一加载很慢，而且查询一条数据更是非常的慢。&#8221;</p>
<p style="color: #1826ff;">
Hibernate是一个基于对象模型持久化的技术，因此，关键是我们需要设计出高质量的对象模型，遵循DDD领域建模原则，减少降低关联，通过分层等
有效办法处理关联。如果采取围绕数据表进行设计编程，加上表之间关系复杂（没有科学方法处理、侦察或减少这些关系），必然导致
系统运行缓慢，其实同样问题也适用于当初对EJB的实体Bean的CMP抱怨上，实体Bean是Domain
Model持久化，如果不首先设计Domain
Model，而是设计数据表，和持久化工具设计目标背道而驰，能不出问题吗？关于这个问题N多年就在Jdon争论过。</p>
<p style="color: #1826ff;">　　这里同样延伸出另外一个问题：数据库设计问题，数据库是否需要在项目开始设计？<br>
如果我们进行数据库设计，那么就产生了一系列问题：当我们使用Hibernate实现持久保存时，必须考虑事先设计好的数据库表结构以及他们的关系如何和
业务对象实现映射，这实际上是非常难实现的，这也是很多人觉得使用ORM框架棘手根本原因所在。</p>
<p style="color: #1826ff;">　　当然，也有脑力相当发达的人可以
实现，但是这种围绕数据库实现映射的结果必然扭曲业务对象，这类似于两个板块（数据表和业务对象）相撞，必然产生地震，地震的结果是两败俱伤，
软的一方吃亏，业务对象是代码，相对于不容易变更的数据表结构，属于软的一方，最后导致业务对象变成数据传输对象DTO, DTO满天飞，性能和维护问题随之而来。</p>
<p style="color: #1826ff;">　　领域建模解决了上述众多不协调问题，特别是ORM痛苦使用问题，关于ORM/Hibernate使用还是那句老话：如果你不掌握领域建模方法，那么就不要用Hibernate，对于这个层次的你：也许No ORM 更是一个简单之道：
No ORM: The simplest solution<br>
<a href="http://www.theserverside.com/blogs/thread.tss?thread_id=41715" target="_blank">http://www.theserverside.com/blogs/thread.tss?thread_id=41715</a></p>
<p style="color: #1826ff;"><strong> Spring分层矛盾问题</strong> <br>
Spring是以挑战EJB面貌出现，其本身拥有的强大组件定制功能是优点，但是存在实战的一些问题，Spring作为业务层框架，不支持业务层Session
功能。</p>
<p style="color: #1826ff;">　　具体举例如下：当我们实现购物车之类业务功能时，需要将购物场合保存到Session中，由于业务层没有方便的Session支持，我们只得将购物车保存到
HttpSession，而HttpSession只有通过HttpRequest才能获得，再因为在Spring业务层容器中是无法访问到HttpRequest这个对象的，所以，
最后我们只能将&#8220;购物车保存到HttpSession&#8221;这个功能放在表现层中实现，而这个功能明显应该属于业务层功能，这就导致我们的Java项目层次混乱，维护性差。
违背了使用Spring和分层架构最初目的。</p>
<p style="color: #1826ff;">　　相关案例：请教一个在完整提交前临时保存的问题:<br>
<a href="http://www.jdon.com/jive/article.jsp?forum=46&amp;thread=28429" target="_blank">http://www.jdon.com/jive/article.jsp?forum=46&amp;thread=28429</a></p>
<p style="color: #1826ff;"><strong> 领域驱动设计DDD</strong> <br>
现在回到我们讨论的重点上来，分层架构是我们使用Java的根本原因之一，域建模专家Eric Evans在他的&#8220;Domain Model
Design&#8221;一书中开篇首先强调的是分层架构，整个DDD理论实际是告诉我们如何使用模型对象oo技术和分层架构来设计实现一个Java项目。</p>
<p style="color: #1826ff;">
我们现在很多人知道Java项目基本有三层：表现层　业务层和持久层，当我们执著于讨论各层框架如何选择之时，实际上我们真正的项目开发工作还没有开
始，
就是我们选定了某种框架的组合（如Struts+Spring+Hibernate或Struts+EJB或Struts+
JdonFramework），我们还没有意识到业务层工作还需要大量工作，DDD提供了在业务层中再划分新的层次思想，如领域层和服务层，甚至再细分为
作业层、能力层、策略层等等。通过层次细化方式达到复杂软件的松耦合。DDD提供了如何细分层次的方式</p>
<p style="color: #1826ff;">　　当我们将精力花费在架构技术层面的讨论和研究上时，我们可能忘记以何种依据选择这些架构技术？选择标准是什么？领域驱动设计DDD
回答了这样的问题，DDD会告诉你如果一个框架不能协助你实现分层架构，那就抛弃它，同时，DDD也指出选择框架的考虑目的，使得你不会
人云亦云，陷入复杂的技术细节迷雾中，迷失了架构选择的根本方向。</p>
<p style="color: #1826ff;">　　现在也有些人误以为DDD是一种新的理论，其实DDD和设计模式一样，不是一种新的理论，而是实战经验的总结，它将前人
使用面向模型设计的方法经验提炼出来，供后来者学习，以便迅速找到驾驭我们软件项目的根本之道。</p>
<p style="color: #1826ff;">　　现在Evans　DDD概念很火，因为它将著名的<a href="http://www.martinfowler.com/eaaCatalog/index.html" target="_blank">PoEAA</a>进行了具化，实现了<a href="http://www.martinfowler.com/eaaCatalog/index.html" target="_blank">PoEAA</a>可操作性，这也是MF大力推崇的原因。最近(8月8日)一位老外博客上用微软的.NET架构和Evans DDD比较的文章：<a href="http://weblogs.asp.net/pgielens/archive/2006/08/08/Organizing-Domain-Logic.aspx">http://weblogs.asp.net/pgielens/archive/2006/08/08/Organizing-Domain-Logic.aspx</a>，这篇文章比较了微软的三层服务应用架构[Microsoft TLSA]和Evans DDD的架构，
使用Microsoft .NET Pet Shop 4为例子，解释两个目标的区别，并且表明<br>
微软是如何在案例中更好地实现支持后者。这篇文章帮助哪些.NET平台上有域设计知识的人实现更好地提高。</p>
<span style="color: #1826ff;">
另外一本关于.NET的DDD书籍也已经出版，这些都说明Evans
DDD这把火已经烧到.NET领域，当然DDD在Java领域生根开花多年，Evans的DDD书籍就是以Java为例子的，笔者板桥里人也率先在
2005年推出DDD框架JdonFramework 1.3版本，这些都说明，Java在整个软件业先进思想的实践上总是领先一步。
</span><br><img src ="http://www.blogjava.net/sutao/aggbug/135315.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-08-08 18:42 <a href="http://www.blogjava.net/sutao/articles/135315.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>面向对象与领域建模</title><link>http://www.blogjava.net/sutao/articles/135314.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Wed, 08 Aug 2007 10:40:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/135314.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/135314.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/135314.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/135314.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/135314.html</trackback:ping><description><![CDATA[<h3 style="color: #101fff;" align="center">面向对象与领域建模</h3>
<p style="color: #101fff;" align="center"><a href="http://www.jdon.com/aboutme.htm">板桥里人</a> http://www.jdon.com
2006/12/6（转载请保留）</p>
<br style="color: #101fff;">
<p style="color: #101fff;"><strong> 多变且复杂的需求</strong> </p>
<p style="color: #101fff;"> 　　如果没有多变的需求，也许就没有今天的面向对象软件，我们曾经试图通过需求管理、需求跟踪等等管理方式约束和减少需求频繁更新带给软件的冲击，可是这样下去的结果只有一个：使得软件更加僵化；或者程序员更加
劳累。</p>
<p style="color: #101fff;"> 　　需求不但多变，而且经常是不可能第一次就能掌握，需求反映了某个领域的专业知识，例如数学、管理、财务或
电子商务等等，每个特定案例需求又有其特别复杂之处，几乎没有人能够第一次接触就可以深入掌握这些专业领域的
需求本质，就是专门的建模专家也不例外。</p>
<p style="color: #101fff;"> 　　既然需求是多变而且复杂的，所以，就不能使用&#8220;堵&#8221;式方法对其进行控制和管理，只能顺势而为，通过灵活多变的
以及迭代反复的方式逐步抓住需求，并且作为需求的实现软件系统必须能够迅速应对需求变化，需求变化有多快，软件
变化就有多快。</p>
<p style="color: #101fff;"> 　　因此，对于多变的需求，我们的解决之道是：引入灵活多变的架构，面向对象OO架构正是应对多变需求而生，强调软件的可维护性
和拓展性，OO可能不是最好方式，但是目前是最合适的；对于复杂的需求，我们的解决之道是：委派专门的建模专家跟踪理解需求，
在需求和需求实现之间搭建桥梁，项目方法上采取多次迭代的敏捷软件开发方式，逐步了解学习掌握需求。</p>
<p style="color: #101fff;"> 　　在这里稍微说明一下，很多人总是将软件和数学、管理、财务混为一谈，其实软件本身就是一门独立的专业，是为
数学、管理。财务等专业领域服务的，不能期望软件人员也是其他领域专业人员，可是在中国现实中，很多人总是
无法分辨，例如某局长将整个机关考核信息化的任务交给电脑中心，这就是将考核管理专业和软件专业混同的例子，
在考核管理和软件之间需要一个领域建模专家，由他来理解或者设计考核管理体系，然后通过模型，表达成
软件人员能够看懂的符号，软件人员通过模型了解领域。</p>
<p style="color: #101fff;"> 　　曾经有需求专家呼吁：最好将需求给所有软件人员都了解，需求专家和一般软件人员一起工作，这些想法的本质是
好的，但是不可能实现的，不可能每个软件人员不但了解软件架构和OO思想；还能够掌握另外一个专业领域的艰深知识，
所以，现在我们提出：将领域专家建立的统一领域模型让所有软件人员都了解，让一般软件人员围绕领域模型工作，这样
的方式才切实可行。</p>
<p style="color: #101fff;"><strong> 需求分析方法演变</strong> </p>
<p style="color: #101fff;"> 　　历史上，对需求分析方法可以说经过三个阶段：<br>
<br>
第一阶段：围绕数据库的驱动的分析设计，新软件项目总是从设计数据库及其字段开始。这个阶段特征就是围绕数据库编程，典型的是
DBase/Foxpro，以及后来的Delphi/VB技术。<br>
<br>
这种围绕数据库分析设计的缺点非常明显：首先，不能迅速有效全面认识反映需求，世界不只是由简单的关系数据组成，而且
使用关系数据来反映现实需求，不符合人类自然思维（OO才是），是一种扭曲的分析方法，特别对于初学者，他们接受数据库分析方法的难度反而可能会大于OO
分析方法，现在很多职业学校和社会培训，基础课程从数据库开始，从某种程度上，是历史倒退， 严重阻碍中国软件发展的进程。<br>
<br>
围绕数据库分析极其容易导致过程化设计编程，围绕数据分析和过程化编程是一对恶魔，数据库结构确立后，就让普通程序员写SQL
语句，SQL语句执行有明显的先后顺序，在这样顺序过程编程思维中，OO思维就难以生存。长此以往，成为习惯后，就很难改变到
OO设计上，所以，传统编程经验越丰富，转变到OO设计就越难。<br>
<br>
在运行性能方面：围绕数据库分析设计容易导致软件运行时负载集中在数据库端，系统性能难于扩展（走上集中式、昂贵的、高风险的大型机模式），
闲置了中间件J2EE服务器分布式集群处理能力，就是使用了集群，也分担不了负载。<br>
<br>
最后，我们必须认识到：对象和关系数据库存在阻抗，本身是矛盾竞争的，他们是两种分析看待需求的流派，可以说是水火不容，
要么你采取数据库分析设计以及过程化编程，要么完全采取OO，现在使用.NET和Java这样OO语言的人很多，但是70%左右都是使用OO语言<br>
编写传统过程化系统，在Java中这样做，会有极差性能；而这种现象在.NET中又极容易得到纵容，.NET是一个系列阵营，正如Windows系列一样，
当你和别人说，你在使用Windows，别人可能觉得你没有落后时代，但是他们哪里知道你在使用Windows 3.1呢？<br>
<br>
第二阶段：面向对象的分析设计方法诞生后，有了专门的分析和设计阶段之分，我们使用UML符号来表达分析设计思想，分析设计进入了一个相对更高的层
次，拥有了自己一套科学且艺术的方法论。但是有一个致命缺点：分析阶段和设计阶段是断裂的，互相不能很好衔接，为什么？<br>
<br>
首先，我们看看分析人员和设计人员在职责重点工作是什么？<br>
分析人员的职责：是负责从需求领域中收集基本概念。而设计人员的职责：必须指明一组能北项目中适应编程工具构造的组件，这些组件必须能够在目标环境中有效执行，并能够正确解决应用程序出现的问题
两个阶段两者目标不一致，分析人员只管需求分析，至于是否适合设计，或者能够导出适宜设计的分析结果，这个尺度很难衡量和把握；<br>
<br>
而设计人员因为照顾代码可运行，因此，经常可能会抱怨分析员给出的结果过于粗糙，不适合设计，这样分析设计两个阶段就导致分裂，项目失败。</p>
<p style="color: #101fff;">　　在这个阶段，虽然有UML帮助，但是UML不是思想，打个比喻：会CAD的绘图员就是建筑师吗？很显然，UML就是CAD图符号，UML不等于分析设计思想。
所以，有人说UML不是银弹，这些就象说中医不是科学一样绕人（中医就不是西医，当然就不是科学）。</p>
<p style="color: #101fff;">
第三阶段：融合了分析阶段和设计阶段的领域驱动设计（Evans: DDD）。2004年Eric Evans 发表Domain-Driven
Design &#8211;Tackling Complexity in the Heart of Software （领域驱动设计 ）简称Evans
DDD， 领域建模是一种艺术的技术，它是用来解决复杂软件快速应付变化的解决之道，所以，从Evans
DDD通篇文章中，你找不到科学象征的定理和公式，当然如果 你试图寻找这样寻找，你也就陷入了&#8220;中医是不是科学&#8221;怪圈了。</p>
<p style="color: #101fff;">　　Evans DDD抛弃了分裂分析模型与设计的做法，使用单一的模型来满足这两方面的要求。这就是领域模型。
单一的领域模型同时满足分析原型和软件设计 ，如果一个模型实现时不实用，重新寻找新模型。如果模型没有忠实表达领域关键概念时，也必须重新寻找新的模型。
建模和设计成为单个迭代循环。将领域模型和设计紧密联系。因此，建模专家必须懂设计。<br>
</p>
<p style="color: #101fff;"><strong> 领域建模的重要性</strong> </p>
<p style="color: #101fff;"> 　　如果你说一个软件开发需要经过需求、分析和设计三个阶段的话，那么可能反映你的思想已经落伍，软件开发现在是
经过需求、建模阶段，混合了分析和设计阶段，可以更激进地说：我们国家的系统分析员和系统设计员考试也许应该合并了，
合并成建模专家的考试，否则，这些都是中国软件落后世界十年的证据，可悲的是：我们自己可能都不知道。<br>
<br>
Evans DDD可以说是近期与SOA相提并论的两大重要技术思想，SOA是着重于软件集成方面；而EvansDDD才是着重我们软件开发上，
在大部分情况下，软件开发重要程度不亚于软件集成，但是因为软件开发方面开源力量冲击，软件集成上工业厂商利润最高，
所以，工业厂商在SOA叫得最响，我们参加得各种会议几乎都是SOA，当心被误导，工业厂商从来不会告诉你事实得争相。</p>
<p style="color: #101fff;">　　 没有面向对象的分析设计，哪里面向对象的构件或组件？过去经验不是证明：我们使用大量的构件组件，却在编制面向过程的体系？<br>
<br>
以EJB2为例子，在EJB2过去大部分系统中，我们常常以数据库为中心，实体Bean因为特殊技术原因，僵硬一块，变成数据库
的代名词，我们围绕实体Bean编制出大量的值对象Vale Obejct，或称为DTO（Data Transfer Object），在这样系统中，从对象
的名称也可以看出，对象是为数据服务的，对象从属于数据库的。<br>
<br>
现在，要彻底改变过来，OO就是以对象为主，数据库是从属对象设计的，如果说EJB2的实体bean技术让你不得不走上传统过程化编程歧路，那么
EJB3已经更正了实体Bean设计缺陷，从EJB发展可以看到一个侧面：工业厂商更多关心的是功能，而不是设计？<br>
<br>
只有谁才真正关心你的软件设计和代码质量？只有你自己。我不是提倡都不要参加工业厂商的会议，而是需要每个人冷静想想：
到底谁是自己代码的主人？</p>
<p style="color: #101fff;">　　领域建模属于与具体.NET或Java技术无关的设计思想，有人总是说：.NET比Java简单，其实这又是一个大误区，如果都达到同样设计水准，无论使用.NET或Java，都需要付出同样的努力；那为什么有人觉得.NET简单，那是因为设计要求降低了，参见这篇<a href="http://weblogs.asp.net/pgielens/archive/2006/08/08/Organizing-Domain-Logic.aspx" target="_blank">.NET的DDD文章</a>。<br>
<br>
<strong> 分层架构</strong> </p>
<p style="color: #101fff;"> 　　分层架构是现代OO软件企业系统的基本架构，只有分层才能达到良好的可拓展性和维护性。基本三层：表现层、业务层和持久层 ;J2EE中表现层和持久层有成熟框架支持，应用重点在业务层。</p>
<p style="color: #101fff;">
业务层根据Evans
DDD，可以再细分为应用层和领域层两种，在业务层设计编码中，大量应用OO设计原则和设计模式。领域层定义：负责表达业务领域概念、业务状态以及业务规
则，是整个业务软件核心和重点。 应用层定义：负责完成功能，并且协调丰富的领域对象来实现功能，不能包括业务规则，无业务状态； </p>
<p style="color: #101fff;">　　每个层都是内聚的，并且只依赖它的下层，为了实现各层的最大解耦，IOC/DI容器是当前Java业务层的最好选择 。</p>
<p style="color: #101fff;">　　 没有分层架构的快速开发基本是旁门左道，不如返回Foxpro和Delphi/VB两层时代。将本属于业务层的逻辑交由表现层来处理的快速UI方式也是一种旁门左道。快速开发必须基于良好的质量，虽然良好的分层架构带来开发效率的降低，但是这些也是可以有方法解决。</p>
<p style="color: #101fff;"><strong> 建模与项目管理</strong> <br>
<br>
在我们大多数从软件项目管理上寻找软件永恒解决之道时，他们可能没有意识到又在范&#8220;缘木求鱼&#8221;老毛病了，
打个比喻很容易明白这个道理：冷兵器时代（也就是火枪没有没有发明之前），各种排兵布阵可能在作战指挥时
很有效；但是到了火器时代，所有的过去作战方式就落伍了；当然到了现在信息化战争时代，更是天壤之别。</p>
<p style="color: #101fff;">　　 Evans DDD领域驱动建模的诞生，对过去传统的项目管理都提出挑战，当我们还在争论RUP好还是敏捷好的时候，
谁会想到我们应该采取围绕统一领域模型的迭代驱动开发呢？</p>
<p style="color: #101fff;">　　 有人可能还在疑惑？我接到一个大项目，那么我的建模和架构设计时间应该是5个月还是5年呢？当然应该回答他：都不行，需求是多变且复杂的，计划赶不上变化，现在就应该开始DDD建模。<br>
<br>
(以上文字源自板桥本人的第四届中国软件技术大会&#8220;领域设计建模&#8221;演讲稿 )</p>
<p style="color: #101fff;">相关文章：</p>
<p style="color: #101fff;"><a href="http://www.jdon.com/mda/nlayes.html" target="_blank"><strong> 当前Java项目开发中几种认识误区</strong> </a></p>
<p style="color: #101fff;"><a href="http://www.jdon.com/mda/dddcase2.html" target="_blank"><strong> 领域建模之建模设计系列</strong> </a></p>
<p style="color: #101fff;"><a href="http://www.jdon.com//mda/ddd.html" target="_blank"><strong> 实战DDD(Domain-Driven   Design领域驱动设计)</strong> </a></p>
<p style="color: #101fff;"><a href="http://www.jdon.com/artichect/javaee.html" target="_blank"><strong> JavaEE/J2EE面向对象编程之道</strong>  </a></p>
<p style="color: #101fff;"><a href="http://www.jdon.com/mda/Feature_Driven_Development.html" target="_blank"><strong> Feature-Driven Development特征驱动开发</strong> </a></p>
<p style="color: #101fff;"><a href="http://www.jdon.com/artichect/reuse.html" target="_blank"><strong> 快速适应需求变化的软件复用 </strong> </a></p>
<p style="color: #101fff;"><a href="http://www.jdon.com/artichect/java_ee_architecture.htm" target="_blank"><strong> Java企业系统架构选择考量</strong> </a></p>
<p style="color: #101fff;"><a href="http://www.jdon.com/artichect/dbover.htm" target="_blank"><strong> 数据库时代的终结</strong> </a></p>
<p style="color: #101fff;"><strong> <a href="http://www.jdon.com/article/29301.html" target="_blank">数学建模对程序设计的影响</a></strong> </p>
<p style="color: #101fff;"><strong> <a href="http://www.jdon.com/article/30036.html" target="_blank">两年的技术经历，在J2EE上疑惑?</a></strong>  </p>
<p style="color: #101fff;"><a href="http://www.jdon.com/article/30840.html" target="_blank"><strong> 致面向对象技术初学者的一封公开信</strong> </a></p>
<p style="color: #101fff;"><a href="http://www.jdon.com/jivejdon/thread/31369.html" target="_blank"><strong> 贫血和充血模型的比较之我见</strong> </a></p>
<p style="color: #101fff;"><a href="http://www.jdon.com/jivejdon/query/searchThreadAction.shtml?query=ddd" target="_blank"><strong> 更多关于DDD讨论</strong> </a></p>
<p style="color: #101fff;"><a href="http://www.jdon.com/jive/thread.jsp?forum=46&amp;thread=30173" target="_blank"><strong> 发表讨论</strong> </a></p>
<p style="color: #101fff;">&nbsp;</p>
<br style="color: #101fff;"><img src ="http://www.blogjava.net/sutao/aggbug/135314.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-08-08 18:40 <a href="http://www.blogjava.net/sutao/articles/135314.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jbosscache-treecache</title><link>http://www.blogjava.net/sutao/articles/134753.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Mon, 06 Aug 2007 10:01:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/134753.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/134753.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/134753.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/134753.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/134753.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 集群配置（一）：Tomcat集群配置&nbsp;&nbsp;&nbsp;&nbsp;相关文档请参见各个工具相应提供的文档，工具的安装此处不再介绍，默认地，将Apache安装在＄APACHE目录，并将mod_jk-apache-2.2.2.so改名为mod_jk.so放在＄APACHE/&nbsp;modules下（注意JK与Apache&nbsp;httpd的版本关系），两个Tomcat...&nbsp;&nbsp;<a href='http://www.blogjava.net/sutao/articles/134753.html'>阅读全文</a><img src ="http://www.blogjava.net/sutao/aggbug/134753.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-08-06 18:01 <a href="http://www.blogjava.net/sutao/articles/134753.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JBossCache-TreeCache体验</title><link>http://www.blogjava.net/sutao/articles/134751.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Mon, 06 Aug 2007 09:44:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/134751.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/134751.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/134751.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/134751.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/134751.html</trackback:ping><description><![CDATA[<br style="color: #1826ff;"><br style="color: #1826ff;"><span style="color: #1826ff;">TreeCache是一种结构化的、基于复制的事务缓存。TreeCache是JBoss应用服务器中集群服务—包括JNDI集群、HTTP和EJB的Sesssion集群、JMS集群—的基础框架。其可以单独</span>
<p style="color: #1826ff;"><nobr id="key0" style="border-bottom: 0px dotted; text-decoration: underline; background-color: transparent;" onclick="return kwc();" target="_blank" oncontextmenu="return false;" onmouseover="kwE(event,0, this);" onmouseout="kwL(event, this);" onmousemove="kwM(0);">使用</nobr>，
可以集成到JBossAS应用，也可以集成到其他的应用服务器上。TreeCache是一种树状结构，每个节点拥有一个名字和多个或者没有子节点，除跟节
点没有子节点其他节点有且只有一个父母节点，可以通过路径名来访问子节点（FQN：Full &nbsp; Qualified &nbsp;
Name），在一个TreeCache中可以存在多棵树，，即可以有多个根节点。当<nobr id="key6" style="border-bottom: 0px dotted; text-decoration: underline; background-color: transparent;" onclick="return kwc();" target="_blank" oncontextmenu="return false;" onmouseover="kwE(event,7, this);" onmouseout="kwL(event, this);" onmousemove="kwM(7);">应用</nobr>于分布式环境时，由于TreeCache是基于复制的，每个子节点的值必须是可序列化的。 &nbsp; <br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
在下面中，将通过例子来了解TreeCache的功能及其配置，使用JBossCache1.4和JDK5.0。首先是一个最基本使用TreeCache
的程序例子并配置一个TreeCache的配置骨架（各种常用的配置可参见jboss-cache-dist-1.4.0.CR1版本的etc目录，如下
各种配置参考也可见该目录下的范例配置，以下不再强调），见下： &nbsp; <br> &nbsp; [code] &nbsp; <br> &nbsp; TreeCache &nbsp; tree &nbsp; = &nbsp; new &nbsp; TreeCache(); &nbsp; <br> &nbsp; tree.setClusterProperties("treecache.xml"); &nbsp;  &nbsp; <br> &nbsp; tree.createService(); &nbsp;  &nbsp; <br> &nbsp; tree.startService(); &nbsp;  &nbsp; <br> &nbsp; tree.put("/a/b/c", &nbsp; "name", &nbsp; "Ben"); &nbsp; <br> &nbsp; tree.put("/a/b/c/d", &nbsp; "uid", &nbsp; new &nbsp; Integer(322649)); &nbsp; <br> &nbsp; Integer &nbsp; tmp &nbsp; = &nbsp; (Integer) &nbsp; tree.get("/a/b/c/d", &nbsp; "uid"); &nbsp; <br> &nbsp; tree.remove("/a/b"); &nbsp; <br> &nbsp; tree.stopService(); &nbsp; <br> &nbsp; tree.destroyService(); &nbsp;  &nbsp; <br> &nbsp; [/code] &nbsp; <br> &nbsp; [code] &nbsp; <br> &nbsp; treecache.xml： &nbsp; <br> &nbsp; &lt;server&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;mbean &nbsp; code="org.jboss.cache.TreeCache" &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; name="jboss.cache:service=TreeCache"&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;depends&gt;jboss:service=Naming&lt;/depends&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;depends&gt;jboss:service=TransactionManager&lt;/depends&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;attribute &nbsp; name="ClusterName"&gt;TreeCache-Cluster&lt;/attribute&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;attribute &nbsp; name="ClusterConfig"&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;config&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;UDP &nbsp; mcast_addr="228.1.2.3" &nbsp; mcast_port="48866" &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; ip_ttl="64" &nbsp; ip_mcast="true" &nbsp;  &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; mcast_send_buf_size="150000" &nbsp; mcast_recv_buf_size="80000" &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; ucast_send_buf_size="150000" &nbsp; ucast_recv_buf_size="80000" &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; loopback="false"/&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;PING &nbsp; timeout="2000" &nbsp; num_initial_members="3" &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; up_thread="false" &nbsp; down_thread="false"/&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;MERGE2 &nbsp; min_interval="10000" &nbsp; max_interval="20000"/&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;FD_SOCK/&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;VERIFY_SUSPECT &nbsp; timeout="1500" &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; up_thread="false" &nbsp; down_thread="false"/&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;pbcast.NAKACK &nbsp; gc_lag="50" &nbsp; retransmit_timeout="600,1200,2400,4800" &nbsp; <br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; max_xmit_size="8192" &nbsp;
up_thread="false" &nbsp; down_thread="false"/&gt; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;UNICAST &nbsp; timeout="600,1200,2400" &nbsp;
window_size="100" &nbsp; min_threshold="10" &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; down_thread="false"/&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;pbcast.STABLE &nbsp; desired_avg_gossip="20000" &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; up_thread="false" &nbsp; down_thread="false"/&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;FRAG &nbsp; frag_size="8192" &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; down_thread="false" &nbsp; up_thread="false"/&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;pbcast.GMS &nbsp; join_timeout="5000" &nbsp; join_retry_timeout="2000" &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; shun="true" &nbsp; print_local_addr="true"/&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;pbcast.STATE_TRANSFER &nbsp; up_thread="true" &nbsp; down_thread="true"/&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;/config&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;/attribute&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;/mbean&gt; &nbsp; <br> &nbsp; &lt;/server&gt; &nbsp; <br> &nbsp; [/code] &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; 其中ClusterConfig配置在前面JavaGroups的介绍详细介绍，其它配置比较简单，需要进一步了解请参见TreeCache文档。</p>
<br style="color: #1826ff;">
<p style="color: #1826ff;"><br></p>
<p style="color: #1826ff;">一、Cache分类 &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
TreeCache按功能分为三类：本地(Local)Cache、复制(Replication)Cache和失效(Invalidation)
Cache。本地Cache只应用于本地环境，后两个Cache可应用于分布式环境，其中，在分布式环境中，复制Cache当一个Cache实例的一个节
点值发生变化时会将变化复制到其它实例中，而失效Cache是当一个Cache实例的一个节点值发生变化时会将其它实例的相应节点的值设为空，让其重新去
获得该值，可通过这种方式缓存大对象以减少在实例中复制对象的代价。分布式Cache（复制和失效Cache）又分为两种，同步（REPL_ASYNC）
和异步（REPL_SYNC），同步Cache是在一个Cache实例做修改时，等待变化应用到其它实例后才返回，而异步Cache是在一个Cache实
例做修改时，即刻返回。其配置见下： &nbsp; <br> &nbsp; [code] &nbsp; <br> &nbsp; &lt;!-- &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp; Valid &nbsp; modes &nbsp; are &nbsp; LOCAL &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; REPL_ASYNC &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; REPL_SYNC &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; INVALIDATION_ASYNC &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; INVALIDATION_SYNC &nbsp; <br> &nbsp; --&gt; &nbsp; <br> &nbsp; &lt;attribute &nbsp; name="CacheMode"&gt;REPL_SYNC&lt;/attribute&gt; &nbsp; <br> &nbsp; [/code] &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; 二、事务和并行(Transaction &nbsp; And &nbsp; Concurrent) &nbsp; <br>&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
TreeCache是一种事务Cache，与JDBC一样，其包括两方面内容：锁和隔离级别。锁分为悲观锁和乐观锁，当使用悲观锁时，分为五个隔离级别，
分别是SERIALIZABLE、REPEATABLE_READ &nbsp;
(default)、READ_COMMITTED、READ_UNCOMMITTED和NONE，隔离级别逐步减弱。乐观锁也叫版本锁，其对</p>
<p style="color: #1826ff;"><nobr id="key5" style="border-bottom: 1px dotted #6600ff; text-decoration: underline; background-color: transparent;" onclick="return kwc();" target="_blank" oncontextmenu="return false;" onmouseover="kwE(event,6, this);" onmouseout="kwL(event, this);" onmousemove="kwM(6);">数据</nobr>进
行操作时，将其复制到临时区，操作之后将版本与原有数据比较，如果一致则将递增版本并写回，如果不一致则回滚，由于乐观锁仅在复制出数据和提交数据时对数
据加锁，所以并行度更高，但如果写操作比较频繁地话则容易出现冲突导致回滚。TreeCache默认使用悲观锁。使用TreeCache时，需要使用容器
提供的事务管理器，一般使JBossTransactionManagerLookup和
GenericTransactionManagerLookup，前者应用于JBOSS<nobr id="key4" style="border-bottom: 0px dotted; text-decoration: underline; background-color: transparent;" onclick="return kwc();" target="_blank" oncontextmenu="return false;" onmouseover="kwE(event,5, this);" onmouseout="kwL(event, this);" onmousemove="kwM(5);">服务器</nobr>，后者应用于其他服务器，也可使用DummyTransactionManagerLookup用于测试。如上介绍的配置如下： &nbsp; <br> &nbsp; [code] &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;attribute &nbsp; name="NodeLockingScheme"&gt;OPTIMISTIC&lt;/attribute&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;attribute &nbsp; name="IsolationLevel"&gt;REPEATABLE_READ&lt;/attribute&gt; &nbsp; <br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;attribute &nbsp;
name="TransactionManagerLookupClass"&gt;org.jboss.cache.DummyTransactionManagerLookup&lt;/attribute&gt;
&nbsp; <br> &nbsp; [/code] &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; 三、逐出策略(Eviction &nbsp; Policy) &nbsp; <br>&nbsp; &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; 由于内存<nobr id="key3" style="border-bottom: 0px dotted; text-decoration: underline; background-color: transparent;" onclick="return kwc();" target="_blank" oncontextmenu="return false;" onmouseover="kwE(event,4, this);" onmouseout="kwL(event, this);" onmousemove="kwM(4);">数量</nobr>的
局限，不可能将所有的Cache数据存放在内存中，但使用内存达到一定极限时，会将部分数据清除出内存，保存到其它持久媒质中，定义的什么时候清除、如何
清除的策略就是逐出策略。自定义一个逐出策略需要实现org.jboss.cache.eviction.EvictionPolicy、
org.jboss.cache.eviction.EvictionAlgorithm、 &nbsp; <br>&nbsp; &nbsp; org.jboss.cache.eviction.EvictionQueue &nbsp; 和org.jboss.cache.eviction.EvictionConfiguration四个接口，<nobr id="key2" style="border-bottom: 1px dotted #6600ff; text-decoration: underline; background-color: transparent;" onclick="return kwc();" target="_blank" oncontextmenu="return false;" onmouseover="kwE(event,3, this);" onmouseout="kwL(event, this);" onmousemove="kwM(3);">系统</nobr>提
供了LRU(Least &nbsp; recently &nbsp; used，最近最少使用)、LFU(Least &nbsp; Frequently &nbsp;
Used最不经常使用)、FIFO(First &nbsp; In &nbsp; First &nbsp; Out先进先出)、MRU(Most &nbsp; Recently &nbsp;
Used最近最经常使用)四种实现，详细参见org.jboss.cache.eviction包的源<nobr id="key1" style="border-bottom: 0px dotted; text-decoration: underline; background-color: transparent;" onclick="return kwc();" target="_blank" oncontextmenu="return false;" onmouseover="kwE(event,1, this);" onmouseout="kwL(event, this);" onmousemove="kwM(1);">代码</nobr>。配置如下： &nbsp; <br> &nbsp; [code] &nbsp; <br> &nbsp; &lt;attribute &nbsp; name="EvictionPolicyConfig"&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;config&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;attribute &nbsp; name="wakeUpIntervalSeconds"&gt;5&lt;/attribute&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;region &nbsp; name="/_default_"&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;attribute &nbsp; name="maxNodes"&gt;5000&lt;/attribute&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;attribute &nbsp; name="timeToLiveSeconds"&gt;1000&lt;/attribute&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;/region&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;region &nbsp; name="/org/jboss/data" &nbsp; <br> &nbsp; policyClass="org.jboss.cache.eviction.FIFOPolicy"&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;attribute &nbsp; name="maxNodes"&gt;5000&lt;/attribute&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;/region&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;region &nbsp; name="/test/" &nbsp; policyClass="org.jboss.cache.eviction.MRUPolicy"&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;attribute &nbsp; name="maxNodes"&gt;10000&lt;/attribute&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;/region&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;region &nbsp; name="/maxAgeTest/"&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;attribute &nbsp; name="maxNodes"&gt;10000&lt;/attribute&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;attribute &nbsp; name="timeToLiveSeconds"&gt;8&lt;/attribute&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;attribute &nbsp; name="maxAgeSeconds"&gt;10&lt;/attribute&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;/region&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;/config&gt; &nbsp; <br> &nbsp; &lt;/attribute&gt; &nbsp; <br> &nbsp; [/code] &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; 也可以多对所有的区域定义同样的逐出策略 &nbsp; <br> &nbsp; [code] &nbsp; <br> &nbsp; &lt;attribute &nbsp; name="EvictionPolicyClass"&gt;org.jboss.cache.eviction.LFUPolicy&lt;/attribute&gt; &nbsp; <br> &nbsp; [/code] &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; 四、Cache加载 &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; 由于逐出策略的存在，那么当我们重新需要获得一个原来在缓存中但确由内存原因被逐出的数据时，就需要定义一种加载策略，使地可以重新找回数据，同时，Cache加载也肩负在将数据逐出时将数据保存到持久媒质的责任。 &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; 根据将数据保存媒质的不同，Cache加载包括FileCacheLoader、JDBCCacheLoader等等，可以同时使用多种加载器来灵活定制加载策略。例见下： &nbsp; <br> &nbsp; [code] &nbsp; <br> &nbsp; &lt;attribute &nbsp; name="CacheLoaderConfiguration"&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;config&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;passivation&gt;false&lt;/passivation&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;preload&gt;/&lt;/preload&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;shared&gt;true&lt;/shared&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;cacheloader&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;class&gt;org.jboss.cache.loader.ClusteredCacheLoader&lt;/class&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;properties&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; timeout=1000 &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;/properties&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;async&gt;true&lt;/async&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;fetchPersistentState&gt;false&lt;/fetchPersistentState&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; ignoreModifications&gt;false&lt;/ignoreModifications&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;purgeOnStartup&gt;false&lt;/purgeOnStartup&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;/cacheloader&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;cacheloader&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;class&gt;org.jboss.cache.loader.JDBCCacheLoader&lt;/class&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;properties&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; cache.jdbc.table.name=jbosscache &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; cache.jdbc.table.create=true &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; cache.jdbc.table.drop=true &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; cache.jdbc.table.primarykey=jbosscache_pk &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; cache.jdbc.fqn.column=fqn &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; cache.jdbc.fqn.type=varchar(255) &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; cache.jdbc.node.column=node &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; cache.jdbc.node.type=longblob &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; cache.jdbc.parent.column=parent &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; cache.jdbc.driver=com.mysql.jdbc.Driver &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; cache.jdbc.url=jdbc:mysql://localhost:3306/jbossdb &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; cache.jdbc.user=root &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; cache.jdbc.password= &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;/properties&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;async&gt;true&lt;/async&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;fetchPersistentState&gt;false&lt;/fetchPersistentState&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;purgeOnStartup&gt;false&lt;/purgeOnStartup&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;/cacheloader&gt; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; &lt;/config&gt; &nbsp; <br> &nbsp; &lt;/attribute&gt; &nbsp; <br> &nbsp; [/code] &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; 我们将通过定制如上的配置信息以更有效地使用JBossCache。详细情况可参考JBoss &nbsp; TreeCache参考文档和范例。</p>
<br style="color: #1826ff;">
<p style="color: #1826ff;"><br></p>
<p style="color: #1826ff;"><br></p><img src ="http://www.blogjava.net/sutao/aggbug/134751.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-08-06 17:44 <a href="http://www.blogjava.net/sutao/articles/134751.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>请教如何提高查询系统的性能？</title><link>http://www.blogjava.net/sutao/articles/134505.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Sun, 05 Aug 2007 06:26:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/134505.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/134505.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/134505.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/134505.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/134505.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 请教如何提高查询系统的性能？                                                                        发表: 2004年07月14日 20:22                                                                        回复     ...&nbsp;&nbsp;<a href='http://www.blogjava.net/sutao/articles/134505.html'>阅读全文</a><img src ="http://www.blogjava.net/sutao/aggbug/134505.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-08-05 14:26 <a href="http://www.blogjava.net/sutao/articles/134505.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Tomcat集群与负载均衡详细</title><link>http://www.blogjava.net/sutao/articles/134193.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Fri, 03 Aug 2007 03:17:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/134193.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/134193.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/134193.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/134193.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/134193.html</trackback:ping><description><![CDATA[<div class="w_t1">
<div class="w_c2">
<div class="l2 f16">
<h1>Tomcat集群与负载均衡</h1>
</div>
<div class="r2 top8">[<a  href="javascript:d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&amp;u='+escape(d.location.href)+'&amp;c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();">收藏此页</a>] [<a  href="javascript:window.print();">打印</a>]</div>
</div>
<div class="top11">
</div>
<div class="w_c2">
<div class="l2">
作者：<strong class="red">Trackback</strong>&nbsp;&nbsp;2007-07-11
</div>
<div class="r2">
<div><strong>内容导航：</strong></div>
<a  href="javascript:;" id="Nav1" class="sel">
第1页 															</a>
<div class="pp">
<div style="visibility: hidden;" id="Nav1Menu" class="p">
<a  href="http://tech.it168.com/j/2007-07-11/200707111635343.shtml" title="" class="hov1">第1页：<span>
第1页 </span></a>
</div>
</div>
</div>
<script>init_Nav();</script>
</div>
</div>
<div id="1">【IT168
技术文档】在单一的服务器上执行WEB应用程序有一些重大的问题，当网站成功建成并开始接受大量请求时，单一服务器终究无法满足需要处理的负荷量，所以就
有点显得有点力不从心了。另外一个常见的问题是会产生单点故障，如果该服务器坏掉，那么网站就立刻无法运作了。不论是因为要有较佳的扩充性还是容错能力，
我们都会想在一台以上的服务器计算机上执行WEB应用程序。所以，这时候我们就需要用到集群这一门技术了。<br><br>在进入集群系统架构探讨之前，先定义一些专门术语：<br>1. 集群(Cluster)：是一组独立的计算机系统构成一个松耦合的多处理器系统，它们之间通过网络实现进程间的通信。应用程序可以通过网络共享内存进行消息传送，实现分布式计算机。 <br>2. 负载均衡(Load Balance)：先得从集群讲起，集群就是一组连在一起的计算机，从外部看它是一个系统，各节点可以是不同的操作系统或不同硬件构成的计算机。如一个提供Web服务的集群，对外界来看是一个大Web服务器。不过集群的节点也可以单独提供服务。<br>3. 特点：在现有网络结构之上，负载均衡提供了一种廉价有效的方法扩展服务器带宽和增加吞吐量，加强网络数据处理能力，提高网络的灵活性和可用性。集群系统(Cluster)主要解决下面几个问题： <br>高可靠性（HA）：利用集群管理软件，当主服务器故障时，备份服务器能够自动接管主服务器的工作，并及时切换过去，以实现对用户的不间断服务。<br>高性能计算（HP）：即充分利用集群中的每一台计算机的资源，实现复杂运算的并行处理，通常用于科学计算领域，比如基因分析，化学分析等。 <br>负载平衡：即把负载压力根据某种算法合理分配到集群中的每一台计算机上，以减轻主服务器的压力，降低对主服务器的硬件和软件要求。<br><br>目前比较常用的负载均衡技术主要有： <br>　　1. 基于DNS的负载均衡 <br>
通过DNS服务中的随机名字解析来实现负载均衡，在DNS服务器中，可以为多个不同的地址配置同一个名字，而最终查询这个名字的客户机将在解析这个名字
时得到其中一个地址。因此，对于同一个名字，不同的客户机会得到不同的地址，他们也就访问不同地址上的Web服务器，从而达到负载均衡的目的。 <br><br>　　2. 反向代理负载均衡 （如Apache+JK2+Tomcat这种组合）<br>
使用代理服务器可以将请求转发给内部的Web服务器，让代理服务器将请求均匀地转发给多台内部Web服务器之一上，从而达到负载均衡的目的。这种代理方
式与普通的代理方式有所不同，标准代理方式是客户使用代理访问多个外部Web服务器，而这种代理方式是多个客户使用它访问内部Web服务器，因此也被称为
反向代理模式。<br><br>　　3. 基于NAT（Network Address Translation）的负载均衡技术 （如Linux Virtual Server，简称LVS）<br>
网络地址转换为在内部地址和外部地址之间进行转换，以便具备内部地址的计算机能访问外部网络，而当外部网络中的计算机访问地址转换网关拥有的某一外部地
址时，地址转换网关能将其转发到一个映射的内部地址上。因此如果地址转换网关能将每个连接均匀转换为不同的内部服务器地址，此后外部网络中的计算机就各自
与自己转换得到的地址上服务器进行通信，从而达到负载分担的目的。<br><br>介绍完上面的集群技术之后，下面就基于Tomcat的集群架构方案进行说明：<br><br>上
面是采用了Apache httpd作为web服务器的，即作为Tomcat的前端处理器，根据具体情况而定，有些情况下是不需要Apache
httpd作为 web 服务器的，如系统展现没有静态页面那就不需要Apache httpd，那时可以直接使用Tomcat作为web
服务器来使用。使用Apache httpd主要是它在处理静态页面方面的能力比Tomcat强多了。<br>1、 用户的网页浏览器做完本地 DNS和企业授权的DNS之的请求/响应后，这时候企业授权的DNS（即21cn BOSS DNS）会给用户本地的DNS服务器提供一个NAT请求分配器（即网关）IP。<br><br><br>2、
NAT分配器，它会根据特定的分配算法，来决定要将连接交给哪一台内部 Apache
httpd来处理请求。大多数的NAT请求分配器提供了容错能力：根据侦测各种WEB服务器的失效状况，停止将请求分配给已经宕掉的服务器。并且有些分配
器还可以监测到WEB服务器机器的负载情况，并将请求分配给负载最轻的服务器等等。Linux Virtual
Server是一个基于Linux操作系统上执行的VS-NAT开源软件套件，而且它有丰富的功能和良好的说明文件。商业硬件解决方案 Foundry
Networks的ServerIron是目前业界公认最佳的请求分配器之一。<br><br><br>3、 Apache httpd +
Mod_JK2在这里是作为负载均衡器，那为什么要做集群呢？如果集群系统要具备容错能力，以便在任何单一的硬件或软件组件失效时还能100%可用，那么
集群系统必须没有单点故障之忧。所以，不能只架设一台有mod_jk2的Apache httpd，因为如果
httpd或mod_jk2失效了，将不会再有请求被会送交到任何一个Tomcat 实例。这种情况下，Apache
httpd就是瓶劲，特别在访问量大的网站。<br><br><br>4、 Mod_JK2负载均衡与故障复原，决定把Apache
httpd当成web服务器，而且使用mod_jk2将请求传送给Tomcat，则可以使用mod_jk2的负载均衡与容错功能。在集群系统中，带有
mod_jk2的Apache httpd可以做的事情包括：<br>A、 将请求分配至一或多个Tomcat实例上<br>你可以在mod_jk2的workers.properties文件中，设定许多Tomcat实例，并赋于每个实例一个lb_factor值，以作为请求分配的加权因子。<br><br><br>B、 侦测Tomcat实例是否失败<br>当Tomcat实例的连接器服务不再响应时，mod_jk2会及时侦测到，并停止将请求送给它。其他的Tomcat实例则会接受失效实例的负载。<br><br><br>C、 侦测Tomcat实例在失效后的何时恢复<br>因连接器服务失效，而停止将请求分配给Tomcat实例之后，mod_jk2会周期性地检查是否已恢复使用性，并自动将其加入现行的Tomcat实例池中。<br><br><br>5、 Tomcat中的集群原理是通过组播的方式进行节点的查找并使用TCP连接进行会话的复制。这里提示一下就是，对每个请求的处理，Tomcat都会进行会话复制，复制后的会话将会慢慢变得庞大。<br><br><br>6、 Mod_jk2同时支持会话亲和和会话复制。在tomcat 5中如何实现会话亲和和会话复制？把server.xml中的<cluster></cluster>标签去掉就实现会话亲和，把<cluster></cluster>标签加上就实现会话复制。<br><br><br>7、
会话亲和：就是表示来自同会话的所有请求都由相同的Tomcat
实例来处理，这种情况下，如果Tomcat实例或所执行的服务器机器失效，也会丧失Servlet的会话数据。即使在集群系统中执行更多的Tomcat实
例，也永远不会复制会话数据。这样是提高集群性能的一种方案，但不具备有容错能力了。<br><br><br>8、 使用会话复制，则当一个Tomcat实例宕掉时，由于至少还有另一个Tomcat实例保有一份会话状态数据，因而数据不会丧失。但性能会有所降低。</div><img src ="http://www.blogjava.net/sutao/aggbug/134193.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-08-03 11:17 <a href="http://www.blogjava.net/sutao/articles/134193.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>