﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-CONAN ZONE-文章分类-J2EE</title><link>http://www.blogjava.net/conans/category/32375.html</link><description>你越挣扎我就越兴奋</description><language>zh-cn</language><lastBuildDate>Fri, 12 Mar 2010 03:01:55 GMT</lastBuildDate><pubDate>Fri, 12 Mar 2010 03:01:55 GMT</pubDate><ttl>60</ttl><item><title>JSP页面缓存技术--浏览器缓存</title><link>http://www.blogjava.net/conans/articles/314962.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Tue, 09 Mar 2010 08:20:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/314962.html</guid><description><![CDATA[<p style="margin: 0cm 0cm 0pt;" class="MsoNormal"><span style="font-family: 宋体;">一、概述</span></p>
<p><span style="font-size: 12pt; font-family: 宋体;">&nbsp;&nbsp;&nbsp; 缓</span><span style="font-family: 宋体;">存的思想可以应用在软件分层的各个层面。它是一种内部机制，对外界而言，是不可感知的。</span></p>
<p><span style="font-family: 宋体;">&nbsp;&nbsp;&nbsp; 数据库本身有缓存，<span style="background: #d9d9d9 none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;">持久层</span>也可以缓存。（比如：</span><font face="Times New Roman">hibernate</font><span style="font-family: 宋体;">，还分</span><font face="Times New Roman">1</font><span style="font-family: 宋体;">级和</span><font face="Times New Roman">2</font><span style="font-family: 宋体;">级缓存）</span></p>
<p><span style="background: #d9d9d9 none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; font-family: 宋体;"><font style="background-color: #ffffff;">&nbsp;&nbsp;&nbsp; </font>业务层</span><span style="font-family: 宋体;">也可以有缓存（但一般来说，这是一个过程域，不会设缓存）。</span></p>
<p><span style="background: #d9d9d9 none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; font-family: 宋体;"><font style="background-color: #ffffff;" color="#ffffff">&nbsp;&nbsp;&nbsp; </font>表现层</span><span style="background: #d9d9d9 none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;"><font face="Times New Roman">/</font></span><span style="background: #d9d9d9 none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; font-family: 宋体;">数据服务层</span><span style="font-family: 宋体;">（传统</span><font face="Times New Roman">web</font><span style="font-family: 宋体;">的表现层）也可以设置缓存（</span><font face="Times New Roman">jsp cache </font><span style="font-family: 宋体;">就是这一层，实现在</span><font face="Times New Roman">app server</font><span style="font-family: 宋体;">上的缓存机制）</span></p>
<p><span style="font-family: 宋体;">&nbsp;&nbsp;&nbsp; 另外</span><span style="background: #d9d9d9 none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;"><font face="Times New Roman">Browser</font></span><span style="font-family: 宋体;">也有缓存（如</span><font face="Times New Roman">IE</font><span style="font-family: 宋体;">）这个大家也都知道（实现在</span><font face="Times New Roman"> web server </font><span style="font-family: 宋体;">上的缓存机制）。越上层的缓存效果越好，越底层的缓存影响越深远。</span></p>
<p><font face="Times New Roman">&nbsp;</font><span style="font-family: 宋体;">二、缓存实现（</span><span style="font-size: 12pt; font-family: 宋体;">浏览器缓存当前访问的JSP动态页面</span><span style="font-family: 宋体;">）</span> </p>
<p style="margin: 0cm 0cm 0pt;" class="MsoNormal"><span style="font-family: 宋体;">（一）、服务端方法：</span></p>
<ol>
    <li style="margin: 0cm 0cm 0pt; text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">&lt;％ &nbsp;&nbsp;</span></li>
    <li style="margin: 0cm 0cm 0pt; text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">response.setHeader("Pragma","No-cache");&nbsp; &nbsp;&nbsp;</span></li>
    <li style="margin: 0cm 0cm 0pt; text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">response.setHeader("Cache-Control","no-cache");&nbsp; &nbsp;&nbsp;</span></li>
    <li style="margin: 0cm 0cm 0pt; text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">response.setDateHeader("Expires",&nbsp;-<span style="color: #c00000;">10</span>); &nbsp;&nbsp;</span></li>
    <li style="margin: 0cm 0cm 0pt; text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">％&gt;&nbsp;&nbsp;</span></li>
</ol>
<p style="margin: 0cm 0cm 0pt;" class="MsoNormal"><span style="font-family: 宋体;">（二）、客户端方法：</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt;" class="MsoNormal"><font face="Times New Roman">meta</font><span style="font-family: 宋体;">是用来在</span><font face="Times New Roman">HTML</font><span style="font-family: 宋体;">文档中模拟</span><font face="Times New Roman">HTTP</font><span style="font-family: 宋体;">协议的响应头报文。</span><font face="Times New Roman">meta </font><span style="font-family: 宋体;">标签用于网页的＜</span><font face="Times New Roman">head</font><span style="font-family: 宋体;">＞与＜</span><font face="Times New Roman">/head</font><span style="font-family: 宋体;">＞中，</span><font face="Times New Roman">meta </font><span style="font-family: 宋体;">标签的用处很多。</span><font face="Times New Roman">meta </font><span style="font-family: 宋体;">的属性有两种：</span><span style="background: #d9d9d9 none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;"><font face="Times New Roman">name</font></span><span style="background: #d9d9d9 none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; font-family: 宋体;">和</span><span style="background: #d9d9d9 none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;"><font face="Times New Roman">http-equiv</font></span><span style="font-family: 宋体;">。</span><font face="Times New Roman">name</font><span style="font-family: 宋体;">属性主要用于<span style="background: #d9d9d9 none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;">描述网页</span>，对应于</span><font face="Times New Roman">content</font><span style="font-family: 宋体;">（网页内容），<span style="background: #d9d9d9 none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;">以便于搜索引擎机器人查找、分类</span>（目前几乎所有的搜索引擎都使用网上机器人自动查找</span><font face="Times New Roman">meta</font><span style="font-family: 宋体;">值来给网页分类）。这其中<span style="color: #33cccc;">最重要的是</span></span><span style="color: #33cccc;"><font face="Times New Roman">description</font></span><span style="color: #33cccc; font-family: 宋体;">（站点在搜索引擎上的描述）和</span><span style="color: #33cccc;"><font face="Times New Roman">keywords</font></span><span style="color: #33cccc; font-family: 宋体;">（分类关键词）</span><span style="font-family: 宋体;">，所以应该给每页加一个</span><font face="Times New Roman">meta</font><span style="font-family: 宋体;">值。比较常用的有以下几个：</span><font face="Times New Roman"> <br />
name </font><span style="font-family: 宋体;">属性</span><font face="Times New Roman"> <br />
1</font><span style="font-family: 宋体;">、＜</span><font face="Times New Roman">meta name="Generator" contect=""</font><span style="font-family: 宋体;">＞用以说明生成工具（如</span><font face="Times New Roman">Microsoft FrontPage 4.0</font><span style="font-family: 宋体;">）等；</span><font face="Times New Roman"> <br />
2</font><span style="font-family: 宋体;">、＜</span><font face="Times New Roman">meta name="KEYWords" contect=""</font><span style="font-family: 宋体;">＞向搜索引擎说明你的网页的关键词；</span><font face="Times New Roman"> <br />
3</font><span style="font-family: 宋体;">、＜</span><font face="Times New Roman">meta name="DEscription" contect=""</font><span style="font-family: 宋体;">＞告诉搜索引擎你的站点的主要内容；</span><br />
<font face="Times New Roman">4</font><span style="font-family: 宋体;">、＜</span><font face="Times New Roman">meta name="Author" contect="</font><span style="font-family: 宋体;">你的姓名</span><font face="Times New Roman">"</font><span style="font-family: 宋体;">＞告诉搜索引擎你的站点的制作的作者；</span><br />
<font face="Times New Roman">5</font><span style="font-family: 宋体;">、＜</span><font face="Times New Roman">meta name="Robots" contect="all|none|index|noindex|follow|nofollow"</font><span style="font-family: 宋体;">＞</span><font face="Times New Roman"> <br />
<br />
</font><span style="font-family: 宋体;">其中的属性说明如下：</span><font face="Times New Roman"> <br />
</font><span style="font-family: 宋体;">设定为</span><font face="Times New Roman">all</font><span style="font-family: 宋体;">：文件将被检索，且页面上的链接可以被查询；</span><font face="Times New Roman"> <br />
</font><span style="font-family: 宋体;">设定为</span><font face="Times New Roman">none</font><span style="font-family: 宋体;">：文件将不被检索，且页面上的链接不可以被查询；</span><br />
<span style="font-family: 宋体;">设定为</span><font face="Times New Roman">index</font><span style="font-family: 宋体;">：文件将被检索；</span><font face="Times New Roman"> <br />
</font><span style="font-family: 宋体;">设定为</span><font face="Times New Roman">follow</font><span style="font-family: 宋体;">：页面上的链接可以被查询；</span><br />
<span style="font-family: 宋体;">设定为</span><font face="Times New Roman">noindex</font><span style="font-family: 宋体;">：文件将不被检索，但页面上的链接可以被查询；</span><font face="Times New Roman"> <br />
</font><span style="font-family: 宋体;">设定为</span><font face="Times New Roman">nofollow</font><span style="font-family: 宋体;">：文件将不被检索，页面上的链接可以被查询。</span><font face="Times New Roman"> <br />
<br />
http-equiv</font><span style="font-family: 宋体;">属性</span><font face="Times New Roman"> <br />
1</font><span style="font-family: 宋体;">、＜</span><font face="Times New Roman">meta http-equiv="Content-Type" contect="text/html";charset=gb_2312-80"</font><span style="font-family: 宋体;">＞</span><font face="Times New Roman"> <br />
</font><span style="font-family: 宋体;">和</span><span style="font-family: 宋体;">＜</span><font face="Times New Roman">meta http-equiv="Content-Language" contect="zh-CN"</font><span style="font-family: 宋体;">＞用以说明主页制作所使用的文字以及语言；又如英文是</span><font face="Times New Roman">ISO-8859-1</font><span style="font-family: 宋体;">字符集，还有</span><font face="Times New Roman">BIG5</font><span style="font-family: 宋体;">、</span><font face="Times New Roman">utf-8</font><span style="font-family: 宋体;">、</span><font face="Times New Roman">shift-Jis</font><span style="font-family: 宋体;">、</span><font face="Times New Roman">Euc</font><span style="font-family: 宋体;">、</span><font face="Times New Roman">Koi8-2</font><span style="font-family: 宋体;">等字符集；</span><font face="Times New Roman"> <br />
2</font><span style="font-family: 宋体;">、＜</span><font face="Times New Roman">meta http-equiv="Refresh" contect="n;url=http://yourlink"</font><span style="font-family: 宋体;">＞定时让网页在指定的时间</span><font face="Times New Roman">n</font><span style="font-family: 宋体;">内，跳转到页面</span><font face="Times New Roman">http;//yourlink</font><span style="font-family: 宋体;">；</span><br />
<font face="Times New Roman">3</font><span style="font-family: 宋体;">、＜</span><font face="Times New Roman">meta http-equiv="Expires" contect="Mon,12 May 2001 00:20:00 GMT"</font><span style="font-family: 宋体;">＞可以用于设定网页的到期时间，一旦过期则必须到服务器上重新调用。需要注意的是必须使用</span><font face="Times New Roman">GMT</font><span style="font-family: 宋体;">时间格式；</span><br />
<font face="Times New Roman">4</font><span style="font-family: 宋体;">、＜</span><font face="Times New Roman">meta http-equiv="Pragma" contect="no-cache"</font><span style="font-family: 宋体;">＞是用于设定禁止浏览器从本地机的缓存中调阅页面内容，设定后一旦离开网页就无法从</span><font face="Times New Roman">Cache</font><span style="font-family: 宋体;">中再调出；</span><font face="Times New Roman"> <br />
5</font><span style="font-family: 宋体;">、＜</span><font face="Times New Roman">meta http-equiv="set-cookie" contect="Mon,12 May 2001 00:20:00 GMT"</font><span style="font-family: 宋体;">＞</span><font face="Times New Roman">cookie</font><span style="font-family: 宋体;">设定，如果网页过期，存盘的</span><font face="Times New Roman">cookie</font><span style="font-family: 宋体;">将被删除。需要注意的也是必须使用</span><font face="Times New Roman">GMT</font><span style="font-family: 宋体;">时间格式；</span><font face="Times New Roman"> <br />
6</font><span style="font-family: 宋体;">、＜</span><font face="Times New Roman">meta http-equiv="Pics-label" contect=""</font><span style="font-family: 宋体;">＞网页等级评定，在</span><font face="Times New Roman">IE</font><span style="font-family: 宋体;">的</span><font face="Times New Roman">internet</font><span style="font-family: 宋体;">选项中有一项内容设置，可以防止浏览一些受限制的网站，而网站的限制级别就是通过</span><font face="Times New Roman">meta</font><span style="font-family: 宋体;">属性来设置的；</span><font face="Times New Roman"> <br />
7</font><span style="font-family: 宋体;">、＜</span><font face="Times New Roman">meta http-equiv="windows-Target" contect="_top"</font><span style="font-family: 宋体;">＞强制页面在当前窗口中以独立页面显示，可以防止自己的网页被别人当作一个</span><font face="Times New Roman">frame</font><span style="font-family: 宋体;">页调用；</span><br />
<font face="Times New Roman">8</font><span style="font-family: 宋体;">、＜</span><font face="Times New Roman">meta http-equiv="Page-Enter" contect="revealTrans(duration=10,transtion= 50)"</font><span style="font-family: 宋体;">＞和＜</span><font face="Times New Roman">meta http-equiv="Page-Exit" contect="revealTrans(duration=20</font><span style="font-family: 宋体;">，</span><font face="Times New Roman">transtion =6)"</font><span style="font-family: 宋体;">＞设定进入和离开页面时的特殊效果，这个功能即</span><font face="Times New Roman">FrontPage</font><span style="font-family: 宋体;">中的</span><font face="Times New Roman">&#8220;</font><span style="font-family: 宋体;">格式</span><font face="Times New Roman">/</font><span style="font-family: 宋体;">网页过渡</span><font face="Times New Roman">&#8221;</font><span style="font-family: 宋体;">，不过所加的页面不能够是一个</span><font face="Times New Roman">frame</font><span style="font-family: 宋体;">页面。</span></p>
<p><font face="Times New Roman">&nbsp;</font><font face="Times New Roman">&nbsp;</font><span style="font-family: 宋体;">三、缓存应用</span></p>
<p><span style="font-family: 宋体;">（一）、防止</span><font face="Times New Roman">JSP</font><span style="font-family: 宋体;">页面缓存</span><span style="font-family: 宋体;">为了防止浏览器缓存当前访问的JSP动态页面，可以采用如下的方式进行设置：<br />
&lt;% <br />
// 将过期日期设置为一个过去时间</span></p>
<p><span style="font-family: 宋体;">response.setHeader("Expires", "</span><span style="font-family: 宋体;">Sat, 6 May 1995</span><span style="font-family: 宋体;">12:00:00 GMT</span><span style="font-family: 宋体;">");</span></p>
<p><span style="font-family: 宋体;">// 设置 HTTP/1.1 no-cache 头<br />
response.setHeader("Cache-Control", "no-store,no-cache,must-revalidate");</span></p>
<p><span style="font-family: 宋体;">// 设置 IE 扩展 HTTP/1.1 no-cache headers， 用户自己添加<br />
response.addHeader("Cache-Control", "post-check=0, pre-check=0");</span></p>
<p><span style="font-family: 宋体;">// 设置标准 HTTP/1.0 no-cache header.<br />
response.setHeader("Pragma", "no-cache");<br />
%&gt;</span></p>
<p><span style="font-family: 宋体;">当然，每一个页面都包含这些代码会很繁琐，可以通过自定义过滤器（Filter）的方法来处理相关的页面</span><font face="Times New Roman">&nbsp;</font><font face="Times New Roman">&nbsp;</font></p>
<p><span style="font-family: 宋体;">（</span><span style="font-family: 宋体;">二）、</span><font face="Times New Roman">jsp,html </font><span style="font-family: 宋体;">清除页面缓存</span></p>
<p><span style="font-family: 宋体;">1.禁止客户端缓存要在&lt;head&gt;中加入类似如下内容： </span></p>
<p><span style="font-family: 宋体;">&lt;META HTTP-EQUIV="pragma" CONTENT="no-cache"&gt; <br />
&lt;META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate"&gt; <br />
&lt;META HTTP-EQUIV="expires" CONTENT="</span><span style="font-family: 宋体;">Wed, 26 Feb 1997</span><span style="font-family: 宋体;">08:21:57 GMT</span><span style="font-family: 宋体;">"&gt; </span></p>
<p><span style="font-family: 宋体;">或</span><span style="color: #333333; font-family: Tahoma;">&nbsp; &nbsp;&lt;meta http-equiv="pragma" content="no-cache"&gt;<br />
&nbsp; &nbsp; &nbsp;&lt;meta http-equiv="cache-control" content="no-cache"&gt;<br />
&nbsp; &nbsp; &nbsp;&lt;meta http-equiv="expires" content="0"&gt;&nbsp;&nbsp;&nbsp;</span></p>
<p><span style="font-family: 宋体;">2.在服务器的动态网页中禁止缓存，要加入类似如下脚本 </span></p>
<p><span style="font-family: 宋体;">response.setHeader("Pragma","No-cache"); <br />
response.setHeader("Cache-Control","no-cache"); <br />
response.setDateHeader("Expires", 0);&nbsp;</span><font face="Times New Roman">&nbsp;</font></p>
<p><span style="font-family: 宋体;">（三）设置有限时间的缓存</span></p>
<p><span style="color: black; font-family: 'Courier New';">&nbsp;&nbsp;&nbsp; </span><strong><span style="color: #7f0055; font-family: 'Courier New';">int</span></strong><span style="color: black; font-family: 'Courier New';"> minutes = 10;</span></p>
<p><span style="color: black; font-family: 'Courier New';">&nbsp;&nbsp;&nbsp; Date d = </span><strong><span style="color: #7f0055; font-family: 'Courier New';">new</span></strong><span style="color: black; font-family: 'Courier New';"> Date();</span></p>
<p><span style="color: black; font-family: 'Courier New';">&nbsp;&nbsp;&nbsp; String modDate = d.toGMTString();</span></p>
<p><span style="color: black; font-family: 'Courier New';">&nbsp;&nbsp;&nbsp; String expDate = </span><strong><span style="color: #7f0055; font-family: 'Courier New';">null</span></strong><span style="color: black; font-family: 'Courier New';">;</span></p>
<p><span style="color: black; font-family: 'Courier New';">&nbsp;&nbsp;&nbsp; expDate = (</span><strong><span style="color: #7f0055; font-family: 'Courier New';">new</span></strong><span style="color: black; font-family: 'Courier New';"> Date(d.getTime() + minutes * 60000)).toGMTString();</span></p>
<p><span style="color: black; font-family: 'Courier New';">&nbsp;&nbsp;&nbsp; response.setHeader(</span><span style="color: #2a00ff; font-family: 'Courier New';">"Last-Modified"</span><span style="color: black; font-family: 'Courier New';">, modDate);</span></p>
<p><span style="color: black; font-family: 'Courier New';">&nbsp;&nbsp;&nbsp; response.setHeader(</span><span style="color: #2a00ff; font-family: 'Courier New';">"Expires"</span><span style="color: black; font-family: 'Courier New';">, expDate);</span></p>
<p><span style="color: black; font-family: 'Courier New';">&nbsp;&nbsp;&nbsp; response.setHeader(</span><span style="color: #2a00ff; font-family: 'Courier New';">"Cache-Control"</span><span style="color: black; font-family: 'Courier New';">, </span><span style="color: #2a00ff; font-family: 'Courier New';">"public"</span><span style="color: black; font-family: 'Courier New';">); </span><span style="color: #3f7f5f; font-family: 'Courier New';">//&nbsp;&nbsp; HTTP/1.1</span></p>
<p><span style="color: black; font-family: 'Courier New';">&nbsp;&nbsp;&nbsp; response.setHeader(</span><span style="color: #2a00ff; font-family: 'Courier New';">"Pragma"</span><span style="color: black; font-family: 'Courier New';">, </span><span style="color: #2a00ff; font-family: 'Courier New';">"Pragma"</span><span style="color: black; font-family: 'Courier New';">); </span><span style="color: #3f7f5f; font-family: 'Courier New';">//&nbsp;&nbsp; HTTP/1.0</span><font face="Times New Roman">&nbsp;</font><font face="Times New Roman">&nbsp;</font></p>
<p><span style="font-family: 宋体;">补充：</span><span style="font-family: 宋体;">关于</span><font face="Times New Roman">.jsp cache</font><span style="font-family: 宋体;">的几条建议</span><font face="Times New Roman">:</font></p>
<p><font face="Times New Roman">1.jsp cache</font><span style="font-family: 宋体;">最好做在过滤器上</span><font face="Times New Roman">,</font><span style="font-family: 宋体;">把需要缓冲的页面集中在同一个目录下</span><font face="Times New Roman">,</font><span style="font-family: 宋体;">每次更改只须更改</span><font face="Times New Roman">web.xml</font><span style="font-family: 宋体;">就可以完成缓冲设置</span><font face="Times New Roman">,</font><span style="font-family: 宋体;">这样比较方便</span><font face="Times New Roman">.</font></p>
<p><font face="Times New Roman">2.Gzip</font><span style="font-family: 宋体;">压缩可以将页面压缩得很小</span><font face="Times New Roman">,</font><span style="font-family: 宋体;">平均压缩比为</span><font face="Times New Roman">1/3,jsp cache</font><span style="font-family: 宋体;">的</span><font face="Times New Roman">HashMap</font><span style="font-family: 宋体;">缓冲压缩后的页面</span><font face="Times New Roman">,</font><span style="font-family: 宋体;">肯定比没压缩前更节约内存消耗</span><font face="Times New Roman">,</font><span style="font-family: 宋体;">并且效率更高</span><font face="Times New Roman">.</font><span style="font-family: 宋体;">关于</span><font face="Times New Roman">Gzip</font><span style="font-family: 宋体;">可以参考这个开源项目</span><font face="Times New Roman">:</font><a href="http://sourceforge.net/projects/pjl-comp-filter" target="_blank"><span style="color: windowtext; text-decoration: none;"><font face="Times New Roman">http://sourceforge.net/projects/pjl-comp-filter</font></span></a><font face="Times New Roman">&nbsp;</font><font face="Times New Roman"> <br />
</font></p>
<img src ="http://www.blogjava.net/conans/aggbug/314962.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2010-03-09 16:20 <a href="http://www.blogjava.net/conans/articles/314962.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Quartz CronTrigger最完整配置说明</title><link>http://www.blogjava.net/conans/articles/302658.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Tue, 17 Nov 2009 03:27:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/302658.html</guid><description><![CDATA[<span class="Apple-style-span" style="border-collapse: separate; color: #000000; font-family: Simsun; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"><span class="Apple-style-span" style="color: #7b7d62; font-family: verdana,Arial,helvetica,sans-seriff; font-size: 12px; line-height: 18px;">转自：</span></span><a href="../../xmatthew/archive/2009/02/15/253864.html">http://www.blogjava.net/xmatthew/archive/2009/02/15/253864.html</a><br />
<span class="Apple-style-span" style="border-collapse: separate; color: #000000; font-family: Simsun; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"><span class="Apple-style-span" style="color: #7b7d62; font-family: verdana,Arial,helvetica,sans-seriff; font-size: 12px; line-height: 18px;">CronTrigger配置格式:<br />
<br />
格式: [秒] [分] [小时] [日] [月] [周] [年]<br />
<br />
<table style="margin: 2px;" border="0" cellpadding="2" cellspacing="2" height="111" width="500">
    <tbody>
        <tr>
            <td style="font-size: 12px;">&nbsp;序号</td>
            <td style="font-size: 12px;">说明<span class="Apple-converted-space">&nbsp;</span><br />
            </td>
            <td style="font-size: 12px;">&nbsp;是否必填</td>
            <td style="font-size: 12px;">&nbsp;允许填写的值</td>
            <td style="font-size: 12px;">允许的通配符<span class="Apple-converted-space">&nbsp;</span><br />
            </td>
        </tr>
        <tr>
            <td style="font-size: 12px;">&nbsp;1</td>
            <td style="font-size: 12px;">&nbsp;秒</td>
            <td style="font-size: 12px;">&nbsp;是</td>
            <td style="font-size: 12px;">&nbsp;0-59&nbsp;</td>
            <td style="font-size: 12px;">&nbsp; , - * /</td>
        </tr>
        <tr>
            <td style="font-size: 12px;">&nbsp;2</td>
            <td style="font-size: 12px;">&nbsp;分</td>
            <td style="font-size: 12px;">&nbsp;是</td>
            <td style="font-size: 12px;">&nbsp;0-59<span class="Apple-converted-space">&nbsp;</span><br />
            </td>
            <td style="font-size: 12px;">&nbsp; , - * /</td>
        </tr>
        <tr align="left" valign="middle">
            <td style="font-size: 12px;">&nbsp;3</td>
            <td style="font-size: 12px;">小时</td>
            <td style="font-size: 12px;">&nbsp;是</td>
            <td style="font-size: 12px;">&nbsp;0-23</td>
            <td style="font-size: 12px;">&nbsp; , - * /</td>
        </tr>
        <tr align="left" valign="middle">
            <td style="font-size: 12px;">&nbsp;4</td>
            <td style="font-size: 12px;">&nbsp;日</td>
            <td style="font-size: 12px;">&nbsp;是</td>
            <td style="font-size: 12px;">&nbsp;1-31</td>
            <td style="font-size: 12px;">&nbsp; , - * ? / L W</td>
        </tr>
        <tr align="left" valign="middle">
            <td style="font-size: 12px;">&nbsp;5</td>
            <td style="font-size: 12px;">&nbsp;月</td>
            <td style="font-size: 12px;">&nbsp;是</td>
            <td style="font-size: 12px;">&nbsp;1-12 or JAN-DEC</td>
            <td style="font-size: 12px;">&nbsp; , - * /</td>
        </tr>
        <tr align="left" valign="middle">
            <td style="font-size: 12px;">&nbsp;6</td>
            <td style="font-size: 12px;">&nbsp;周</td>
            <td style="font-size: 12px;">&nbsp;是</td>
            <td style="font-size: 12px;">&nbsp;1-7 or SUN-SAT</td>
            <td style="font-size: 12px;">&nbsp; , - * ? / L #</td>
        </tr>
        <tr>
            <td style="font-size: 12px;">&nbsp;7</td>
            <td style="font-size: 12px;">&nbsp;年</td>
            <td style="font-size: 12px;">&nbsp;否</td>
            <td style="font-size: 12px;">&nbsp;empty 或 1970-2099</td>
            <td style="font-size: 12px;">&nbsp;, - * /</td>
        </tr>
    </tbody>
</table>
<br />
通配符说明:<br />
<tt><strong><span style="color: red;"><tt><strong><span style="font-size: 12pt;"><tt><strong><span style="font-size: 12pt;">*</span></strong></tt></span></strong></tt><span class="Apple-converted-space">&nbsp;</span></span></strong></tt>表示所有值. 例如:在分的字段上设置 "*",表示每一分钟都会触发。<br />
<tt><strong><span style="color: red;"><tt><strong><span style="font-size: 12pt;">?</span></strong></tt></span></strong></tt><span class="Apple-converted-space">&nbsp;</span>表示不指定值。使用的场景为不需要关心当前设置这个字段的值。例如:要在每月的10号触发一个操作，但不关心是周几，所以需要周位置的那个字段设置为"?" 具体设置为 0 0 0 10<span class="Apple-converted-space">&nbsp;</span><span style="color: red;"><span style="font-size: 12pt;"><span style="color: red;">*</span></span></span><span class="Apple-converted-space">&nbsp;</span>?<br />
<tt><strong><span style="color: red;"><span style="font-size: 12pt;"><tt><strong><span style="color: red;">-</span></strong></tt></span></span></strong></tt><span class="Apple-converted-space">&nbsp;</span>表示区间。例如 在小时上设置 "10-12",表示 10,11,12点都会触发。<br />
<tt><strong><span style="color: red;"><span style="font-size: 12pt;">,</span></span></strong></tt><span class="Apple-converted-space">&nbsp;</span>表示指定多个值，例如在周字段上设置 "MON,WED,FRI" 表示周一，周三和周五触发<br />
<tt><strong><span style="color: red;"><tt><strong><span style="font-size: 12pt;"><tt><strong>/</strong></tt></span></strong></tt><span class="Apple-converted-space">&nbsp;</span></span></strong></tt>用于递增触发。如在秒上面设置"5/15" 表示从5秒开始，每增15秒触发(5,20,35,50)。 在月字段上设置'1/3'所示每月1号开始，每隔三天触发一次。<br />
<tt><strong><span style="color: red;"><span style="font-size: 12pt;">L</span></span></strong></tt><span class="Apple-converted-space">&nbsp;</span>表示最后的意思。在日字段设置上，表示当月的最后一天(依据当前月份，如果是二月还会依据是否是润年[leap]), 在周字段上表示星期六，相当于"7"或"SAT"。如果在"L"前加上数字，则表示该数据的最后一个。例如在周字段上设置"6L"这样的格式,则表示&#8220;本月最后一个星期五"<span class="Apple-converted-space">&nbsp;</span><br />
<tt><strong><span style="color: red;"><tt><strong><span style="font-size: 12pt;">W</span></strong></tt></span></strong></tt><span class="Apple-converted-space">&nbsp;</span>表示离指定日期的最近那个工作日(周一至周五). 例如在日字段上设置"15W"，表示离每月15号最近的那个工作日触发。如果15号正好是周六，则找最近的周五(14号)触发, 如果15号是周未，则找最近的下周一(16号)触发.如果15号正好在工作日(周一至周五)，则就在该天触发。如果指定格式为 "1W",它则表示每月1号往后最近的工作日触发。如果1号正是周六，则将在3号下周一触发。(注，"W"前只能设置具体的数字,不允许区间"-").<br />
<table class="tipMacro" align="center" border="0" cellpadding="5" cellspacing="8" width="85%">
    <colgroup><col width="24"><col></colgroup>
    <tbody>
        <tr>
            <td style="font-size: 12px;" valign="top">小提示<br />
            </td>
            <td style="font-size: 12px;">
            <p>'L'和 'W'可以一组合使用。如果在日字段上设置"LW",则表示在本月的最后一个工作日触发(一般指发工资<img src="/CuteSoft_Client/CuteEditor/images/emteeth.gif" alt="" align="absmiddle" border="0" /><span class="Apple-converted-space">&nbsp;</span>)&nbsp;</p>
            </td>
        </tr>
    </tbody>
</table>
<tt><strong><span style="color: red;"><span style="font-size: 12pt;">#</span></span></strong></tt><span class="Apple-converted-space">&nbsp;</span>序号(表示每月的第几个周几)，例如在周字段上设置"6#3"表示在每月的第三个周六.注意如果指定"#5",正好第五周没有周六，则不会触发该配置(用在母亲节和父亲节再合适不过了)
<table class="infoMacro" align="center" border="0" cellpadding="5" cellspacing="8" width="85%">
    <colgroup><col width="24"><col></colgroup>
    <tbody>
        <tr>
            <td style="font-size: 12px;" valign="top">小提示<br />
            </td>
            <td style="font-size: 12px;">
            <p>周字段的设置，若使用英文字母是不区分大小写的<span class="Apple-converted-space">&nbsp;</span><tt>MON</tt><span class="Apple-converted-space">&nbsp;</span><tt>与mon相同</tt>.</p>
            </td>
        </tr>
    </tbody>
</table>
<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<span class="Apple-converted-space">&nbsp;</span><br />
常用示例:<br />
&nbsp;<span class="Apple-converted-space">&nbsp;</span><br />
<table class="confluenceTable">
    <tbody>
        <tr>
            <td class="confluenceTd" style="font-size: 12px;"><tt>0 0 12 * * ?</tt></td>
            <td class="confluenceTd" style="font-size: 12px;">每天12点触发</td>
        </tr>
        <tr>
            <td class="confluenceTd" style="font-size: 12px;"><tt>0 15 10 ? * *</tt></td>
            <td class="confluenceTd" style="font-size: 12px;">每天10点15分触发</td>
        </tr>
        <tr>
            <td class="confluenceTd" style="font-size: 12px;"><tt>0 15 10 * * ?</tt></td>
            <td class="confluenceTd" style="font-size: 12px;">每天10点15分触发</td>
        </tr>
        <tr>
            <td class="confluenceTd" style="font-size: 12px;"><tt>0 15 10 * * ? *</tt></td>
            <td class="confluenceTd" style="font-size: 12px;">每天10点15分触发</td>
        </tr>
        <tr>
            <td class="confluenceTd" style="font-size: 12px;"><tt>0 15 10 * * ? 2005</tt></td>
            <td class="confluenceTd" style="font-size: 12px;">2005年每天10点15分触发</td>
        </tr>
        <tr>
            <td class="confluenceTd" style="font-size: 12px;"><tt>0 * 14 * * ?</tt></td>
            <td class="confluenceTd" style="font-size: 12px;">每天下午的 2点到2点59分每分触发</td>
        </tr>
        <tr>
            <td class="confluenceTd" style="font-size: 12px;"><tt>0 0/5 14 * * ?</tt></td>
            <td class="confluenceTd" style="font-size: 12px;">每天下午的 2点到2点59分(整点开始，每隔5分触发)</td>
        </tr>
        <tr>
            <td class="confluenceTd" style="font-size: 12px;"><tt>0 0/5 14,18 * * ?</tt></td>
            <td class="confluenceTd" style="font-size: 12px;">每天下午的 2点到2点59分(整点开始，每隔5分触发)<br />
            每天下午的 18点到18点59分(整点开始，每隔5分触发)<br />
            </td>
        </tr>
        <tr>
            <td class="confluenceTd" style="font-size: 12px;"><tt>0 0-5 14 * * ?</tt></td>
            <td class="confluenceTd" style="font-size: 12px;">每天下午的 2点到2点05分每分触发</td>
        </tr>
        <tr>
            <td class="confluenceTd" style="font-size: 12px;"><tt>0 10,44 14 ? 3 WED</tt></td>
            <td class="confluenceTd" style="font-size: 12px;">3月分每周三下午的 2点10分和2点44分触发</td>
        </tr>
        <tr>
            <td class="confluenceTd" style="font-size: 12px;"><tt>0 15 10 ? * MON-FRI</tt></td>
            <td class="confluenceTd" style="font-size: 12px;">从周一到周五每天上午的10点15分触发</td>
        </tr>
        <tr>
            <td class="confluenceTd" style="font-size: 12px;"><tt>0 15 10 15 * ?</tt></td>
            <td class="confluenceTd" style="font-size: 12px;">每月15号上午10点15分触发</td>
        </tr>
        <tr>
            <td class="confluenceTd" style="font-size: 12px;"><tt>0 15 10 L * ?</tt></td>
            <td class="confluenceTd" style="font-size: 12px;">每月最后一天的10点15分触发</td>
        </tr>
        <tr>
            <td class="confluenceTd" style="font-size: 12px;"><tt>0 15 10 ? * 6L</tt></td>
            <td class="confluenceTd" style="font-size: 12px;">每月最后一周的星期五的10点15分触发</td>
        </tr>
        <tr>
            <td class="confluenceTd" style="font-size: 12px;"><tt>0 15 10 ? * 6L 2002-2005</tt></td>
            <td class="confluenceTd" style="font-size: 12px;">从2002年到2005年每月最后一周的星期五的10点15分触发</td>
        </tr>
        <tr>
            <td class="confluenceTd" style="font-size: 12px;"><tt>0 15 10 ? * 6#3</tt></td>
            <td class="confluenceTd" style="font-size: 12px;">每月的第三周的星期五开始触发</td>
        </tr>
        <tr>
            <td class="confluenceTd" style="font-size: 12px;"><tt>0 0 12 1/5 * ?</tt></td>
            <td class="confluenceTd" style="font-size: 12px;">每月的第一个中午开始每隔5天触发一次</td>
        </tr>
        <tr>
            <td class="confluenceTd" style="font-size: 12px;"><tt>0 11 11 11 11 ?</tt></td>
            <td class="confluenceTd" style="font-size: 12px;">每年的11月11号 11点11分触发(光棍节)</td>
        </tr>
    </tbody>
</table>
</span></span>
<img src ="http://www.blogjava.net/conans/aggbug/302658.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2009-11-17 11:27 <a href="http://www.blogjava.net/conans/articles/302658.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>web会话状态维持</title><link>http://www.blogjava.net/conans/articles/299650.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Sun, 25 Oct 2009 02:59:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/299650.html</guid><description><![CDATA[如果你对以下问题感兴趣但是又不能确切的回答，你就应该阅读此文．
<br />
1.Session是什么？
<br />
2.Cookie又是什么？
<br />
3.如果完全禁用了Cookies，Session还起作用吗？
<br />
4.为什么有的网站登录一次以后就不用再登录?
<br />
5.ASP中的Session是否依赖Cookie?
<br />
6.JSP中的Session是否依赖Cookie?
<br />
7.ASP.NET中的Session又是怎么回事?
<br />
<br />
下面将详细的讲述会话状态的维持,看完之后你应该可以回答上面的几个问题了
<br />
1.Session和Cookie的由来
<br />
这里我不区分Cookie和Cookies,只是一个复数形式而已.我们都知道http是无状态的协议,就是说每次请求都是分开的，服务器根本不
知道两次请求是否是同一个人,如果我们的内容是完全公开的,也就是所有内容谁都可以看(比如sina的新闻),这种情况呀根本就没有必要知道两次请求是不
是同一个.但是大部分情况下我们不希望这样,我们希望只有会员登录之后才能访问(所有的论坛几乎都是这样).而其他人不允许他们反问,于是便要知道每次请
求的是不是同一个人,这就是会话,也就是一个Session,而且这个Session是以Cookie为基础的,Cookie最才是网景公司提出的,也叫
小甜饼.
<br />
服务器端对每个请求维持一个会话,并且有一个唯一的SessionID.如果客户端没有禁用Cookie的话,客户第一次请求的时候这个ID会
写到客户端的硬盘上(不相信?看一下文件夹C:\Documents and Settings\UserName\Local
Settings\Temporary Internet Files
下的Cookie文件,都是文本文件).以后你每次请求的时候都会加上这个ID值,服务器端就可以知道是不是同一个请求了.如果还不相信的话,你可以这样
做个试验:
<br />
1.选择一个你要用用户名登录的网站(最好是ASP的,如论坛).
<br />
2.先正常登录一遍,确定可以登录,再把浏览器关了)
<br />
3.选择Internet选项(IE属性页),选择隐藏选项卡,把设置调到最高,确定.
<br />
4.重新开IE,登录你刚才登录过的站点,怎么登都等不上去的.
<br />
<br />
2.Session和Cookie的关系
<br />
当前维持会话状态的途径有且只有两种种
<br />
第一种:Cookie,最常见的,95%以上的会话都是Cookie的功劳.
<br />
第二种:URL重写,把SessionID附加到URL中,JSP实现了但用的不多.
<br />
如果你用过session,你可能很奇怪:我们一般都是用session维持会话,这里怎么没有?
<br />
答案很简单:上面两种都是途径,Session是我们的目的.一句话概括Session和Cookie的关系:Cookie是维持Session最常见的一种途径.
<br />
<br />
3.Cookie的过期和Session的超时
<br />
你可以自己设置Cookie的过期(其实是服务器替你设置的),如果你设置为用不过期,
<br />
以后就都不用再重新登陆了,如果这台机器就你一个人用完全可以这样设置,否则
<br />
最好不要这样设置.如果你很长时间没有反应,就是没有新的请求,Session就有可能
<br />
过期,你可能遇到这样的情况:明明已经登录了,过了一会儿回来却说我没有登录
<br />
提示重新登录.就是因为Session过期了,服务器可以设置过期的时间.
<br />
<br />
4.禁用了Cookie如何实现会话
<br />
如果客户端完全禁用Cookie,将会发生什么现象:
<br />
对于ASP,无法跟踪会话,也就是每个请求都当作新的请求.
<br />
对于JSP,可以通过重写URL实现会话,session.encodeURL(String path)
<br />
session.encodeURL("index.jsp")=index.jsp;jsessionid=431D980051204FC8DC3
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BF75840F7AF71
<br />
可以看到后面的sessionid并没有包括在QueryString中(在?后面)
<br />
对于ASP.NET 同样支持重写URL,学习JSP的,不过JSP并不是所有的WebServer都支持重写URL
<br />
5.QueryString和HiddenForm
<br />
你可能觉得他们也可以维持会话，但是事实上是不可以的，他们只能传递参数。不过在ASP.NET中的服务器事件模型广泛了使用了Hidden来表示控件的viewState(这个也是ASP.NET比ASP,JSP先进的地方,是一种全新的技术)
<br />
为什么他们只能传递参数而不能实现会话呢?大致过程是这样的:
<br />
服务器接收到一个请求,如果没有获得SessionID,就产生一个新的会话.可能你认为这样可以保持会话 url?sessionid=234234234234.
<br />
这是一个误区,因为服务器已经处在一个新的会话中了,只不过可以获得上次会话的ID号而已.
<br />
<br />
6.QueryString和HiddenForm的区别
<br />
QueryString是URL中问号后面的?querystring.一般浏览器都把URL限制在255个字符以内所以没办法传递大量的数据,方法必须为get.HiddenForm是表单数据,方法为可以是get或者post(一般用post)
<br />
<br />
7.误区
<br />
我看到有人在论坛上说在自己的Web服务器上构建一个Session,然后链接到别人的程序这样可以越过验证.Session只在同一个
Application中才有效,所以这个设想是徒劳的,不过如果你们的程序是同一个Application中的(比如一些个人主页空间就有可能)是可以
这样做的.
<br />
<br />
8.题外话
<br />
利用Cookie攻击,因为客户端完全禁用Cookie之后,每次请求服务器都要产生一个会话.如果会话超时时间是15分钟的话,我们通过完全禁用Cookie的方法在15分钟内不停的请求让服务器产生大量的会话,实行DOS攻击(前提是大量的请求和服务器不做过滤)
<img src ="http://www.blogjava.net/conans/aggbug/299650.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2009-10-25 10:59 <a href="http://www.blogjava.net/conans/articles/299650.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jmesa乱码解决方法</title><link>http://www.blogjava.net/conans/articles/290047.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Thu, 06 Aug 2009 02:01:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/290047.html</guid><description><![CDATA[jmesa表格显示在初次显示时是的，当刷性或者查询操作后会变成乱码。解决方法：<br />
方法一 ：原有输出方法<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080;">1</span>&nbsp;<span style="color: #000000;">response.setContentType(</span><span style="color: #000000;">"</span><span style="color: #000000;">text/html;charset=UTF-8</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
</span><span style="color: #008080;">2</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">byte</span><span style="color: #000000;">[]&nbsp;contents&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;html.getBytes();<br />
</span><span style="color: #008080;">3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.getOutputStream().write(contents);</span></div>
修改为：<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080;">1</span>&nbsp;<span style="color: #000000;">response.setContentType(</span><span style="color: #000000;">"</span><span style="color: #000000;">text/plain;charset=UTF-8</span><span style="color: #000000;">"</span><span style="color: #000000;">);&nbsp;&nbsp;<br />
</span><span style="color: #008080;">2</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.getWriter().write(tableData);</span></div>
<br />
方法二：在所部属的服务器的JVM参数中增加下列参数：<br />
-Ddefault.client.encoding=UTF-8 -Dclient.encoding.override=UTF-8 -Dfile.encoding=UTF-8<br />
然后重启服务器即可（本方法在WAS6.1.0.25）上测试通过<br />
<img src ="http://www.blogjava.net/conans/aggbug/290047.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2009-08-06 10:01 <a href="http://www.blogjava.net/conans/articles/290047.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Eclipse 远程调试 WebSphere Application Server (WAS)</title><link>http://www.blogjava.net/conans/articles/270393.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Wed, 13 May 2009 05:41:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/270393.html</guid><description><![CDATA[我们用 Eclipse 开发 Web 项目时，多会用某个插件(如 MyEclipse) 来对 Tomcat 中的应用进行单步调试。而要调试
WAS 下的应用，MyEclipse 也是可以的，但在 MyEclipse 中启动 WAS 比较慢，且需要在本地安装一个
WAS。再有便捷点的方法是用 WSAD (Websphere Studio Application Developer) 或它的升级版 RAD
(Rational Application Developer)，它们内置了对 WAS 很好的支持，不过也需要本机安装了
WAS，WSAD/RAD 肥大的身躯自是不必说。若要让 WSAD/RAD 进行远程调试，似乎还得在Server 上安装个 IBM Agent
Controller。<br />
<br />
实际上 WAS 就支持远程调试的设置，打开它，你只需要用 Eclipse Debug 中的 Remote
Java Application 功能连接到服务器上相应端口即行。设置很简单，这样的办法你甚至可以在闲时偷偷的调试一下生产环境的 WAS
应用以验证测试环境难以/无法重现的问题。具体做法如下(WAS 5.x 和 6.x 下的操作基本相同)：&nbsp;<br />
<br />
<strong>一：配置 WAS，打开调试服务</strong><br />
<br />
进到 WAS(或ND) 的管理控制台，在<strong>服务器</strong>-&gt;<strong>应用程序服务器</strong>中，点击要启用调试服务的应用服务器，然后进入<strong>调试服务</strong>，勾选上<strong>启动</strong>(指定当服务器启动时服务器是否将尝试启动指定的服务。)。<strong>JVM 调试端口</strong>默认为 7777，注意该端口不能有冲突(如有多个应服务器要启用调试服务时，需要指定别的端口)。其他选项默认，或根据实际来设定。<br />
<br />
<strong>确定</strong>、<strong>保存</strong>后重启应用服务器，WAS Base 版需要回到操作系统下重启，如果是在 ND 管理控制台下，可直接在页面中重启应用服务器。<br />
<br />
<strong>二：配置 Eclipse，使用远程调试<br />
</strong><br />
Eclipse 的菜单 <strong>Run</strong> -&gt; <strong>Open Debug Dialog</strong> 窗口中，右击 <strong>Remote Java Application</strong>-&gt;<strong>New</strong>，在右方的 <strong>Conect</strong> 标签页中，选择你要调试的 <strong>Project</strong>(即发布到 WAS 下启用了调试服务的，在你的 Eclipse 中存在的项目)，<strong>Host</strong> 填上 WAS 服务器的 IP，<strong>Port</strong> 就是前面的 JVM 调试端口。其他两个标签页 <strong>Source</strong>/<strong>Common</strong> 可留意下。<br />
<br />
点击 Debug 按钮，这时候 Eclipse 即处理于侦听&nbsp; WAS 服务器的 JVM 调试端口的状态。<br />
<br />
<strong>三：打上断点，调试应用</strong><br />
<br />
在
你的 Eclipse 中的项目(注意，该项目已部署到 WAS 上的) 要调试的代码行中打上断点，然后可以在网页上浏览 WAS
上的该应用。当执行到所在断点的代码行时，Eclipse 就会停在该行上，让你尽情的 F5/F6 的跳，像平时那样
Watch/Inspect/Display表达式或变量。<br />
<br />
<br />
其他缺点就是：<br />
<br />
1）观察不到控制台的输出，还得看 WAS 的 SystemOut.log 文件或日志文件。 <br />
2）JSP 文件无法调试，因为定位不到原码，并且这种方式也不足以聪明。<br />
3）代码更新后，需手工把类文件或 JSP 文件拷到 WAS 的相应目录下。<br />
4）启动了调试服务后，严重影响功能，通过鼠标点击就能感觉到，所以正式系统上完事后赶紧关了该功能。
<img src ="http://www.blogjava.net/conans/aggbug/270393.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2009-05-13 13:41 <a href="http://www.blogjava.net/conans/articles/270393.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Web分页打印：细线表格+分页打印之终极攻略收藏</title><link>http://www.blogjava.net/conans/articles/256543.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Wed, 25 Feb 2009 01:44:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/256543.html</guid><description><![CDATA[<p>最近给客户做打印的时候，客户提出打印时不要打印该页面的头，只是打印表格里面的内容，因为头部有背景和打印按钮，而且要细线表格的那种，我想细线表格不是很简单吗</p>
<p>&nbsp;</p>
<p>如果你还不知道<strong>细线表格怎么做</strong>，请看下面的代码实现效果：）</p>
<p>
<pre>&lt;table cellSpacing=0 cellPadding=0 border=0&gt;
&lt;tr&gt;
&lt;td bgcolor='black'&gt;
&lt;table cellSpacing=1 cellPadding=1 border=0&gt;
&lt;tr align=center bgcolor='#ffffff'&gt;
&lt;td colspan=2&gt;国家级&lt;/td&gt;&lt;td colspan=1&gt;市级&lt;/td&gt;
&lt;/tr&gt;
&lt;tr bgcolor='#ffffff' align=center&gt;
&lt;td&gt;人民日报&lt;/td&gt;
&lt;td&gt;解放日报&lt;/td&gt;
&lt;td&gt;新民晚报&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
</pre>
<p>&nbsp;</p>
<p>然后把IE的设置为<strong>可以打印背景</strong>，本以为可以大功告成了</p>
<p>结果打印一预览，头部一个<strong>大黑块</strong>，为什么呢，因为我头部里面的有一个背景，结果占用页面！</p>
<p>
<pre>.gTitle
{
width:100%;
height:32px;
line-height:32px;
<span style="color: #ff0000">background-image:url(images/gtitle.gif);
</span>	padding-left:130px;
margin-bottom:10px;
}
</pre>
<p>&nbsp;</p>
<p>开始郁闷啦，在网上搜了半天都没有一个完美的解决方案，决定自己搞定。</p>
<p>自己琢磨了半天，终于搞定：）</p>
<p>Css定义如下：</p>
<p>noneprint： 打印时隐藏的样式定义</p>
<p>tabPrint：&nbsp;&nbsp;&nbsp; 要打印的细线表格样式定义</p>
<p>nextPate：&nbsp; 分页的样式定义</p>
<p>linetd：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 呵呵，此处最关键，让你的表格打印时<strong>完美无<span style="color: #ff0000">缺</span></strong></p>
<p>&nbsp;</p>
<p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools"><a onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" href="http://blog.csdn.net/maomaoysq/archive/2009/02/24/3933480.aspx#">view plain</a><a onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" href="http://blog.csdn.net/maomaoysq/archive/2009/02/24/3933480.aspx#">copy to clipboard</a><a onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;" href="http://blog.csdn.net/maomaoysq/archive/2009/02/24/3933480.aspx#">print</a><a onclick="dp.sh.Toolbar.Command('About',this);return false;" href="http://blog.csdn.net/maomaoysq/archive/2009/02/24/3933480.aspx#">?</a></div>
</div>
<ol class="dp-css">
    <li class="alt"><span><span>@media&nbsp;</span><span class="value">print</span><span>&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li class=""><span>.noneprint{</span><span class="keyword">display</span><span>:</span><span class="value">none</span><span>;} &nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>} &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>.tabPrint&nbsp;td &nbsp;&nbsp;</span></li>
    <li class=""><span>{ &nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">border-left</span><span>:</span><span class="value">#000000</span><span>&nbsp;</span><span class="value">solid</span><span>&nbsp;</span><span class="value">1px</span><span>; &nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">border-top</span><span>:</span><span class="value">#000000</span><span>&nbsp;</span><span class="value">solid</span><span>&nbsp;</span><span class="value">1px</span><span>; &nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">height</span><span>:</span><span class="value">21px</span><span>; &nbsp;&nbsp;</span></span></li>
    <li class=""><span>} &nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>table.tabPrint &nbsp;&nbsp;</span></li>
    <li class="alt"><span>{ &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">border-right</span><span>:</span><span class="value">#000000</span><span>&nbsp;</span><span class="value">solid</span><span>&nbsp;</span><span class="value">1px</span><span>; &nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">border-bottom</span><span>:</span><span class="value">#000000</span><span>&nbsp;</span><span class="value">solid</span><span>&nbsp;</span><span class="value">1px</span><span>; &nbsp;&nbsp;</span></span></li>
    <li class=""><span>} &nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>.nextPage &nbsp;&nbsp;</span></li>
    <li class="alt"><span>{ &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">page-break-after</span><span>:</span><span class="value">always</span><span>; &nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>} &nbsp;&nbsp;</span></li>
    <li class=""><span>.linetd &nbsp;&nbsp;</span></li>
    <li class="alt"><span>{ &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">border-bottom</span><span>:</span><span class="value">solid</span><span>&nbsp;</span><span class="value">1px</span><span>&nbsp;</span><span class="value">#000</span><span>; &nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<textarea class="css" style="display: none" name="code" rows="15" cols="50">@media print {
.noneprint{display:none;}
}
.tabPrint td
{
border-left:#000000 solid 1px;
border-top:#000000 solid 1px;
height:21px;
}
table.tabPrint
{
border-right:#000000 solid 1px;
border-bottom:#000000 solid 1px;
}
.nextPage
{
page-break-after:always;
}
.linetd
{
border-bottom:solid 1px #000;
}</textarea>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>页面HTML如下：&nbsp;</p>
<p><span style="color: #ff0000">记得</span>在thead加上style="display:table-header-group;font-weight:bold"，这样每个页面才会有都表头哟</p>
<p>&nbsp;
<pre>&lt;div class="noneprint"&gt;
&lt;div class="gTitle"&gt;&gt;&gt;&lt;A href="../Default.aspx" mce_href="Default.aspx"&gt;首页&lt;/A&gt;&gt;&gt;&lt;A href="Default.aspx" mce_href="Default.aspx"&gt;门户&lt;/A&gt;&gt;&gt;信息管理&lt;/div&gt;
&lt;table cellSpacing="0" cellPadding="2" width="100%" align="center" border="0" ID="Table1"&gt;
&lt;tr&gt;
&lt;td align="right"&gt;标题：&lt;/td&gt;
&lt;td&gt;&lt;input name="txtFName" type="text" id="txtFName" style="width:150px;" /&gt;&lt;/td&gt;
&lt;td align="right"&gt;所属街道：&lt;/td&gt;
&lt;td&gt;&lt;select name="ddlStreet" id="ddlStreet"&gt;
&lt;option selected="selected" value=""&gt;-请选择状态-&lt;/option&gt;
&lt;/select&gt;&lt;/td&gt;
&lt;td align="right"&gt;录入日期：&lt;/td&gt;
&lt;td colSpan="3"&gt;&lt;input name="sDate" type="text" id="sDate" onclick="setday(this)" style="width:80px;" /&gt;--
&lt;input name="eDate" type="text" id="eDate" onclick="setday(this)" style="width:80px;" /&gt;&lt;/td&gt;
&lt;td&gt;&lt;input type="submit" name="btnSearch" value="查询" id="btnSearch" class="Button" /&gt;
&lt;input type="button" onclick="window.print()" value="打印" class="Button" ID="Button1" NAME="Button1"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;table class='tabPrint' align="center" width="95%" cellSpacing="0" cellPadding="0" border="0"
ID="Table2"&gt;
&lt;thead <span style="color: #ff0000">style="display:table-header-group;font-weight:bold"</span> mce_style="display:table-header-group;font-weight:bold"&gt;
&lt;tr align="center"&gt;
&lt;td rowspan="2"&gt;所属街道&lt;/td&gt;
&lt;td rowspan="2"&gt;标题&lt;/td&gt;
&lt;td rowspan="2"&gt;录入日期&lt;/td&gt;
&lt;td colspan="2"&gt;国家级&lt;/td&gt;
&lt;td colspan="1"&gt;市级&lt;/td&gt;
&lt;/tr&gt;
&lt;tr align="center"&gt;
&lt;td&gt;人民日报&lt;/td&gt;
&lt;td&gt;解放日报&lt;/td&gt;
&lt;td&gt;新民晚报&lt;/td&gt;
&lt;/tr&gt;
&lt;/thead&gt;&lt;tbody&gt;
&lt;tr align="center"&gt;
&lt;td&gt;浦东新区浦三街道&lt;/td&gt;
&lt;td&gt;测试&lt;/td&gt;
&lt;td&gt;02-24-2009&lt;/td&gt;
&lt;td&gt;&#8730;&lt;/td&gt;
&lt;td&gt;&#8730;&lt;/td&gt;
&lt;td&gt;&#8730;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr align="center"&gt;
&lt;td&gt;浦东新区浦三街道&lt;/td&gt;
&lt;td&gt;sseref&lt;/td&gt;
&lt;td&gt;02-24-2009&lt;/td&gt;
&lt;td&gt;&nbsp;&lt;/td&gt;
&lt;td&gt;&nbsp;&lt;/td&gt;
&lt;td&gt;&nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr align="center"&gt;
&lt;td&gt;浦东新区浦三街道&lt;/td&gt;
&lt;td&gt;sseref&lt;/td&gt;
&lt;td&gt;02-24-2009&lt;/td&gt;
&lt;td&gt;&nbsp;&lt;/td&gt;
&lt;td&gt;&nbsp;&lt;/td&gt;
&lt;td&gt;&nbsp;&lt;/td&gt;
&lt;/tr&gt;
<span style="color: #ff0000">&lt;tr align="center" class='nextPage'&gt;
&lt;td colspan="6" class='linetd'&gt;第1页&lt;/td&gt;
&lt;/tr&gt;</span>
&lt;tr align="center"&gt;
&lt;td&gt;浦东新区浦三街道&lt;/td&gt;
&lt;td&gt;sdsedjiik&lt;/td&gt;
&lt;td&gt;02-24-2009&lt;/td&gt;
&lt;td&gt;&nbsp;&lt;/td&gt;
&lt;td&gt;&nbsp;&lt;/td&gt;
&lt;td&gt;&nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr align="center"&gt;
&lt;td&gt;浦东新区浦三街道&lt;/td&gt;
&lt;td&gt;sdsedjiik&lt;/td&gt;
&lt;td&gt;02-24-2009&lt;/td&gt;
&lt;td&gt;&nbsp;&lt;/td&gt;
&lt;td&gt;&nbsp;&lt;/td&gt;
&lt;td&gt;&nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr align="center"&gt;
&lt;td&gt;浦东新区浦三街道&lt;/td&gt;
&lt;td&gt;sdsedjiik&lt;/td&gt;
&lt;td&gt;02-24-2009&lt;/td&gt;
&lt;td&gt;&nbsp;&lt;/td&gt;
&lt;td&gt;&nbsp;&lt;/td&gt;
&lt;td&gt;&nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr align="center"&gt;
&lt;td&gt;浦东新区浦三街道&lt;/td&gt;
&lt;td&gt;sdsedjiik&lt;/td&gt;
&lt;td&gt;02-24-2009&lt;/td&gt;
&lt;td&gt;&nbsp;&lt;/td&gt;
&lt;td&gt;&nbsp;&lt;/td&gt;
&lt;td&gt;&nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr align="center"&gt;
&lt;td&gt;浦东新区浦三街道&lt;/td&gt;
&lt;td&gt;sdsedjiik&lt;/td&gt;
&lt;td&gt;02-24-2009&lt;/td&gt;
&lt;td&gt;&nbsp;&lt;/td&gt;
&lt;td&gt;&nbsp;&lt;/td&gt;
&lt;td&gt;&nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>呵呵，标记为红色的地方你可要看仔细哟，完不完美全靠它！<br />
<br />
转自：http://blog.csdn.net/maomaoysq/archive/2009/02/24/3933480.aspx</p>
<img src ="http://www.blogjava.net/conans/aggbug/256543.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2009-02-25 09:44 <a href="http://www.blogjava.net/conans/articles/256543.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java、PHPRPC、Hessian、Burlap 序列化的效率对比</title><link>http://www.blogjava.net/conans/articles/255094.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Tue, 17 Feb 2009 06:58:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/255094.html</guid><description><![CDATA[<div id="related_topics" style="position: relative" _eventid="4" _madepositioned="true">相关文章: <span class="close"><a title="关闭" onclick="$('related_topics').hide();return false;" href="http://www.javaeye.com/topic/333720#">&nbsp;</a></span>
<ul>
    <li><a title=".NET 中对 PHP、Binary、SOAP、XML、JSON、Hessian 等序列化的效率对比" href="http://www.javaeye.com/topic/301613" target="_blank">.NET 中对 PHP、Binary、SOAP、XML、JSON、Hessian 等序列化的效率对比</a>
    <li><a title="取代 DWR 的好东西—— PHPRPC for Java" href="http://www.javaeye.com/topic/21790" target="_blank">取代 DWR 的好东西—— PHPRPC for Java</a>
    <li><a title="试试一个面向服务的开源AJAX库Objot" href="http://www.javaeye.com/topic/84735" target="_blank">试试一个面向服务的开源AJAX库Objot</a>
    <li><a title="Hessian开始支持RIA了（JavaFX和Flex）" href="http://www.javaeye.com/topic/125573" target="_blank">Hessian开始支持RIA了（JavaFX和Flex）</a> </li>
</ul>
<br />
<span>推荐圈子: <a href="http://flex2.group.javaeye.com/" target="_blank">flex</a></span> <br />
<a href="http://www.javaeye.com/wiki/topic/333720" target="_blank">更多相关推荐</a> </div>
<script type="text/javascript">
            new Draggable("related_topics");
          </script>下面是对在 Java 6 下对 Java（就是 RMI 使用的数据表示方式）、PHPRPC、Hessian（2个协议版本都有）、Burlap 序列化/反序列化的效率对比，其中 PHPRPC 序列化来自最新版本的 <a href="http://www.phprpc.org/zh_CN/download/" target="_blank">PHPRPC</a> 3.0.2 for Java，Hessian 和 Burlap 序列化来自<a href="http://hessian.caucho.com/#Java" target="_blank">Hessian</a> 的最新版 3.2.1，Java 序列化是采用 JDK 6 中内置的功能。 <br />
<br />
测试程序可从此处下载：<a href="http://www.javaeye.com/topics/download/8fb86b16-4bbd-3f97-bb48-e6cd42b368a8" target="_blank">PHPRPC___Hessian_Test.zip</a> <br />
<br />
下面是测试程序的运行结果图： <br />
<br />
<br />
<img src="http://www.javaeye.com/upload/attachment/75902/a0d4e7fc-0a32-34f2-a74b-c257b7195044.jpg" _counted="undefined"  alt="" /> <br />
<br />
<img src="http://www.javaeye.com/upload/attachment/75905/191b88ad-8729-3837-8df7-4735c5769297.jpg" _counted="undefined"  alt="" /> <br />
<br />
<img src="http://www.javaeye.com/upload/attachment/75904/e28188d3-4c25-3e6c-8785-961cbcc96a39.jpg" _counted="undefined"  alt="" /> <br />
<br />
<img src="http://www.javaeye.com/upload/attachment/75906/e0d2970b-943e-37a6-915b-2dd5b321bad8.jpg" _counted="undefined"  alt="" /> <br />
<br />
<img src="http://www.javaeye.com/upload/attachment/75907/dc1c3752-14fc-3744-a5c4-8e81bad46173.jpg" _counted="undefined"  alt="" /> <br />
<br />
<img src="http://www.javaeye.com/upload/attachment/75910/0ee5d589-9aa2-3606-bdf0-10bce940072b.jpg" _counted="undefined"  alt="" /> <br />
<br />
<img src="http://www.javaeye.com/upload/attachment/75915/14b8f19a-6a9d-3b34-b984-30564891783d.jpg" _counted="undefined"  alt="" /> <br />
<br />
<img src="http://www.javaeye.com/upload/attachment/75919/5cfcdc00-e1f9-35be-93ff-bd8849be2a90.jpg" _counted="undefined"  alt="" /> <br />
<br />
<img src="http://www.javaeye.com/upload/attachment/75923/82cb2659-ae30-3e91-9362-0f9d28811d11.jpg" _counted="undefined"  alt="" /> <br />
<br />
<img src="http://www.javaeye.com/upload/attachment/75924/977666c9-18ef-3a54-81b1-cd1f0a97f5f8.jpg" _counted="undefined"  alt="" /> <br />
<br />
<img src="http://www.javaeye.com/upload/attachment/75930/c24dc454-f783-3279-b76b-e31f0eea61ed.jpg" _counted="undefined"  alt="" /> <br />
<br />
<img src="http://www.javaeye.com/upload/attachment/75933/eb4729ff-dc9a-3a49-8b3f-4494946a228f.jpg" _counted="undefined"  alt="" /> <br />
<br />
从上面的结果来看，对于原生类型的序列化和反序列化，PHPRPC 和 Hessian 的效率差不多，对于字节流的序列化，PHPRPC 具有绝对优势，对于容器类型，来说，如果具有重复元素的话，PHPRPC 要远远好于 Hessian，对于没有重复元素的，则效率上不相上下，对于自定义类型来说，PHPRPC 也比 Hessian 效率高不少。而 Java 本身的序列化，效率对比来说波动太大，原生类型要慢好多，而复杂类型和自定义类型稍微好一些。所以总体来说，PHPRPC 在平均效能上算是这几个当中最好的了。 <br />
<br />
本来还想加入 JSON、SOAP 这些序列化方式的对比，但是找了好久都没有找到能够支持 Java 基本类型和容器类型的 JSON、SOAP 序列化的工具包。不过这两种格式的效率要比现在对比的这几种效率上低很多倍，从 <a href="http://www.javaeye.com/topic/301613" target="_blank">.NET 版本</a>的相关对比上就可以看到出来。 <br />
<br />
其实这个评测对 PHPRPC 来说，还是不公平的，因为 PHPRPC 现在是按照 Java 1.2 兼容格式编写的，因此要比那些专门为 Java 5+ 编写的代码效率要低。但是在这种情况下，仍然能够胜出，足以说明 PHPRPC 的优秀。 <br />
<br />
PHPRPC for Java 下一步的计划就是编写专门针对 Java 5+ 的优化版本，让使用 Java 5+ 的用户能够得到更高的执行效率。 
<img src ="http://www.blogjava.net/conans/aggbug/255094.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2009-02-17 14:58 <a href="http://www.blogjava.net/conans/articles/255094.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>推荐15个有用的在浏览器内的web开发工具</title><link>http://www.blogjava.net/conans/articles/241988.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Sat, 22 Nov 2008 09:32:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/241988.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;只有注册用户登录后才能阅读该文。<a href='http://www.blogjava.net/conans/articles/241988.html'>阅读全文</a><img src ="http://www.blogjava.net/conans/aggbug/241988.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-11-22 17:32 <a href="http://www.blogjava.net/conans/articles/241988.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>session串的问题</title><link>http://www.blogjava.net/conans/articles/219469.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Fri, 01 Aug 2008 14:00:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/219469.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;只有注册用户登录后才能阅读该文。<a href='http://www.blogjava.net/conans/articles/219469.html'>阅读全文</a><img src ="http://www.blogjava.net/conans/aggbug/219469.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-08-01 22:00 <a href="http://www.blogjava.net/conans/articles/219469.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>给 GLASSFISH 里里外外做了个交代</title><link>http://www.blogjava.net/conans/articles/214799.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Mon, 14 Jul 2008 11:28:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/214799.html</guid><description><![CDATA[<div id="news_content">今天读到同事写的一篇博文，非常有系统地把GLASSFISH里里外外做了个交代，一共给了20个链接，如果你一个个点击下去，你一定会对 GLASSFISH 有个完整的收获 ！ <br />
<br />
<br />
这是这篇博文GlassFish for Enterprise的网址： <br />
http://blogs.sun.com/quality/entry/glassfish_for_enterprise <br />
<br />
<br />
下面是博文翻译： <br />
<br />
<br />
GlassFish 有很广大的用户，仅仅一年之内就有4.5万次下载，这是一些文摘： <br />
<a href="http://www.sun.com/featured-articles/2008-0610/feature/index.jsp" target="_blank">http://www.sun.com/featured-articles/2008-0610/feature/index.jsp</a> <br />
<br />
GlassFish 有很广泛的社区，这是社区论坛网站, 你能在论坛讨论问题<a href="http://forums.java.net/jive/forum.jspa?forumID=56&amp;start=0" target="_blank">http://forums.java.net/jive/forum.jspa?forumID=56&amp;start=0</a> <br />
<br />
<br />
有这么多人下载，这么多人安装和设置GlassFish，使GlassFish在不同的电脑和操作系统上得到了有效的测试，这样你就不会碰到基本的故障，又因为GlassFish在网络有很多的信息，你只要在google搜索&#8220;GlassFish issue&#8221;，你多半都能够得到满意的答复。 <br />
<br />
<br />
GlassFish 据有企业功能，能应用到企业生产线上，在这个博文里我会向你推荐一些GlassFish 企业功能 <br />
<br />
你能在下面这个链接免费下载GlassFish：<a href="https://glassfish.dev.java.net/downloads/v2ur2-b04.html" target="_blank">https://glassfish.dev.java.net/downloads/v2ur2-b04.html</a> <br />
<br />
这是GlassFish简便操作指南：<a href="https://glassfish.dev.java.net/downloads/quickstart/index.html" target="_blank">https://glassfish.dev.java.net/downloads/quickstart/index.html</a> <br />
<br />
你能用GlassFish管理平台很方便来管理 GlassFish 多种功能，可以部署。可以修改，然后再部署。 <br />
<br />
如果你要用集群，用下面这个步骤来安装，然后用下面推荐的HA文档来构架。 <br />
<br />
<a href="https://glassfish.dev.java.net/javaee5/build/GlassFish_LB_Cluster.html" target="_blank">https://glassfish.dev.java.net/javaee5/build/GlassFish_LB_Cluster.html</a> <br />
<br />
<a href="http://wiki.glassfish.java.net/Wiki.jsp?page=GlassFishV2Architecture" target="_blank">http://wiki.glassfish.java.net/Wiki.jsp?page=GlassFishV2Architecture</a> <br />
<br />
下面是一篇非常好的关于GlassFish集群文章 <br />
<a href="http://developers.sun.com/appserver/reference/techart/glassfishcluster/" target="_blank">http://developers.sun.com/appserver/reference/techart/glassfishcluster/</a> <br />
<br />
<br />
我们还有High Availability操作指南 <br />
<a href="http://docs.sun.com/app/docs/doc/819-3679" target="_blank">http://docs.sun.com/app/docs/doc/819-3679</a> <br />
<br />
GlassFish 有两种high availability，一种是in-memory，GlassFish 的原装用的是in-memory <br />
<br />
如果你需要高availability，你可以免费下载有HADB组装的功能 <br />
<a href="http://www.sun.com/download/products.xml?id=46df3223" target="_blank">http://www.sun.com/download/products.xml?id=46df3223</a> <br />
<br />
<br />
GlassFish支持软件和硬件Loadbalancer <br />
<a href="http://blogs.sun.com/Prashanth/entry/load_balancing_glassfish_v2_with" target="_blank">http://blogs.sun.com/Prashanth/entry/load_balancing_glassfish_v2_with</a> <br />
<br />
用GlassFish Enterprise bits 来组装loadbalancer plugin，我们有自动组装的方法，这是操作指南 <br />
<a href="http://docs.sun.com/app/docs/doc/819-3193" target="_blank">http://docs.sun.com/app/docs/doc/819-3193</a> <br />
<br />
看到这里，你是否被我搞糊涂了，搞不清GlassFish和GlassFish enterprise 的区别，下面是它们的不同之处 <br />
<a href="http://wiki.glassfish.java.net/Wiki.jsp?page=FaqGlassFishV2vsSJSAS91" target="_blank">http://wiki.glassfish.java.net/Wiki.jsp?page=FaqGlassFishV2vsSJSAS91</a> <br />
<br />
如果你需要SSL。GlassFish有全套的支持， <br />
<a href="http://blogs.sun.com/enterprisetechtips/entry/using_ssl_with_glassfish_v2" target="_blank">http://blogs.sun.com/enterprisetechtips/entry/using_ssl_with_glassfish_v2</a> <br />
<br />
如果你想知道有哪些企业推荐，这里可以找到许多GlassFish用户的成功故事 <br />
<a href="http://blogs.sun.com/stories" target="_blank">http://blogs.sun.com/stories</a> <br />
<br />
<br />
如果你想知道ISV，GlassFish有很多成功的合作夥伴 <br />
<a href="http://www.sun.com/software/products/appsrvr/gf-isv-partners.jsp" target="_blank">http://www.sun.com/software/products/appsrvr/gf-isv-partners.jsp</a> <br />
<br />
如果你要用GlassFish放在企业工作系统，你并且需要有及时的用户支持，你可以来买GlassFish的用户收费支持 <br />
<a href="http://globalspecials.sun.com/servlet/ControllerServlet?Action=DisplayPage&amp;Env=BASE&amp;Locale=en_US&amp;SiteID=sunstor&amp;id=ProductDetailsPage&amp;productID=81508900" target="_blank">http://globalspecials.sun.com/servlet/ControllerServlet?Action=DisplayPage&amp;Env=BASE&amp;Locale=en_US&amp;SiteID=sunstor&amp;id=ProductDetailsPage&amp;productID=81508900</a></div>
<br />
<img src ="http://www.blogjava.net/conans/aggbug/214799.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-14 19:28 <a href="http://www.blogjava.net/conans/articles/214799.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> session对象在web开发中的创建以及sessionId生成并返回客户端的运行机制</title><link>http://www.blogjava.net/conans/articles/214798.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Mon, 14 Jul 2008 11:28:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/214798.html</guid><description><![CDATA[session对象当客户端首次访问时，创建一个新的session对象。并同时生成一个sessionId，并在此次响应中将sessionId 以响应报文的方式些回客户端浏览器内存或以重写url方式送回客户端，来保持整个会话，只要sever端的这个session对象没有销毁，以后再调用 request.getSession（）时就直接根据客户端的sessionId来检索 server端生成的session对象并返回，不会再次去新建，除非根据此sessionId没有检索到session对象。
<p>　　下面是在IE下测试，因为IE6.0的一个BUG就是IE的隐私设置即使是阻止所有cookie时，也还是会以会话cookie来保存sessionId.所以下面都是以会话cookie来讨论的，</p>
<p>　　（1）在server没有关闭，并在session对象销毁时间内，当客户端再次来请求server端的servlet或jsp时，将会将在第 一次请求时生成的sessionId并附带在请求信息头中并向server端发送， server端收到sessionId后根据此sessionId会去搜索（此过程是透明的）server对应的session对象并直接返回这个 session对象，此时不会重新去建立一个新的session对象。</p>
<p>　　（2）当server关闭（之前产生的session对象也就消亡了），或 session对象过了其销毁时间后，浏览器窗口不关，并在本浏览器窗口再次去请求sever端的servlet和jsp时，此时同样会将 sessionId（server关闭或session销毁时生成的sessionId）发送到server端，server根据sessionId去找 其对应的session对象，但此时session对象已经不存在，此时会重新生成一个新的session对象，并生成新的sessionId并同样将这 个新生成的sessionId以响应报文的形式送到浏览器内存中。</p>
<p>　　（3）当server没有关闭，并session对象在其销毁时间内，当请求一个 jsp页面回客户端后，关闭此浏览器窗口，此时其内存中的sessionId也就随之销毁，在重新去请求sever端的servlet或jsp时，会重新 生成一个sessionId给客户端浏览器，并存在浏览内存中。</p>
<img src ="http://www.blogjava.net/conans/aggbug/214798.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-14 19:28 <a href="http://www.blogjava.net/conans/articles/214798.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>web.xml 学习小进步</title><link>http://www.blogjava.net/conans/articles/214467.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Sat, 12 Jul 2008 11:17:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/214467.html</guid><description><![CDATA[<div class="cnt">
<p>web.xml里面可以定义两种参数： (1)application范围内的参数，存放在servletcontext中，在web.xml中配置如下：</p>
<div style="border-right: windowtext 0.5pt solid; padding-right: 5.4pt; border-top: windowtext 0.5pt solid; padding-left: 5.4pt; background: rgb(230,230,230) 0% 50%; padding-bottom: 4px; border-left: windowtext 0.5pt solid; width: 95%; padding-top: 4px; border-bottom: windowtext 0.5pt solid; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" _counted="undefined" /><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">&lt;</span><span style="color: rgb(128,0,0)">context-param</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)"> <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" _counted="undefined" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">&lt;</span><span style="color: rgb(128,0,0)">param-name</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)">context/param</span><span style="color: rgb(0,0,255)">&lt;/</span><span style="color: rgb(128,0,0)">param-name</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)"> <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" _counted="undefined" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">&lt;</span><span style="color: rgb(128,0,0)">param-value</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)">avalible during application</span><span style="color: rgb(0,0,255)">&lt;/</span><span style="color: rgb(128,0,0)">param-value</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)"> <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" _counted="undefined" />&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">&lt;/</span><span style="color: rgb(128,0,0)">context-param</span><span style="color: rgb(0,0,255)">&gt;</span></div>
</div>
<p>(2)servlet范围内的参数，只能在servlet的init()方法中取得，在web.xml中配置如下：</p>
<div style="border-right: windowtext 0.5pt solid; padding-right: 5.4pt; border-top: windowtext 0.5pt solid; padding-left: 5.4pt; background: rgb(230,230,230) 0% 50%; padding-bottom: 4px; border-left: windowtext 0.5pt solid; width: 95%; padding-top: 4px; border-bottom: windowtext 0.5pt solid; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" _counted="undefined" /><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">&lt;</span><span style="color: rgb(128,0,0)">servlet</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)"> <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" _counted="undefined" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">&lt;</span><span style="color: rgb(128,0,0)">servlet-name</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)">MainServlet</span><span style="color: rgb(0,0,255)">&lt;/</span><span style="color: rgb(128,0,0)">servlet-name</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)"> <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" _counted="undefined" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">&lt;</span><span style="color: rgb(128,0,0)">servlet-class</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)">com.wes.controller.MainServlet</span><span style="color: rgb(0,0,255)">&lt;/</span><span style="color: rgb(128,0,0)">servlet-class</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)"> <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" _counted="undefined" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">&lt;</span><span style="color: rgb(128,0,0)">init-param</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)"> <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" _counted="undefined" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">&lt;</span><span style="color: rgb(128,0,0)">param-name</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)">param1</span><span style="color: rgb(0,0,255)">&lt;/</span><span style="color: rgb(128,0,0)">param-name</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)"> <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" _counted="undefined" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">&lt;</span><span style="color: rgb(128,0,0)">param-value</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)">avalible in servlet init()</span><span style="color: rgb(0,0,255)">&lt;/</span><span style="color: rgb(128,0,0)">param-value</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)"> <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" _counted="undefined" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">&lt;/</span><span style="color: rgb(128,0,0)">init-param</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)"> <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" _counted="undefined" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">&lt;</span><span style="color: rgb(128,0,0)">load-on-startup</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,255)">&lt;/</span><span style="color: rgb(128,0,0)">load-on-startup</span><span style="color: rgb(0,0,255)">&gt;</span><span style="color: rgb(0,0,0)"> <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" _counted="undefined" /> </span><span style="color: rgb(0,0,255)">&lt;/</span><span style="color: rgb(128,0,0)">servlet</span><span style="color: rgb(0,0,255)">&gt;</span></div>
</div>
<p>在servlet中可以通过代码分别取用：</p>
<div style="border-right: windowtext 0.5pt solid; padding-right: 5.4pt; border-top: windowtext 0.5pt solid; padding-left: 5.4pt; background: rgb(230,230,230) 0% 50%; padding-bottom: 4px; border-left: windowtext 0.5pt solid; width: 95%; padding-top: 4px; border-bottom: windowtext 0.5pt solid; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" _counted="undefined" /><span style="color: rgb(0,0,255)">package</span><span style="color: rgb(0,0,0)"> com.wes.controller; <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" _counted="undefined" /> <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" _counted="undefined" /></span><span style="color: rgb(0,0,255)">import</span><span style="color: rgb(0,0,0)"> javax.servlet.ServletException; <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" _counted="undefined" /></span><span style="color: rgb(0,0,255)">import</span><span style="color: rgb(0,0,0)"> javax.servlet.http.HttpServlet; <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" _counted="undefined" /> <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif" align="top" _counted="undefined" /><img style="display: none" alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif" align="top" _counted="undefined" /></span><span style="color: rgb(0,0,255)">public</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">class</span><span style="color: rgb(0,0,0)"> MainServlet </span><span style="color: rgb(0,0,255)">extends</span><span style="color: rgb(0,0,0)"> HttpServlet </span><span style="border-right: rgb(128,128,128) 1px solid; border-top: rgb(128,128,128) 1px solid; display: none; border-left: rgb(128,128,128) 1px solid; border-bottom: rgb(128,128,128) 1px solid; background-color: rgb(255,255,255)">...</span><span><span style="color: rgb(0,0,0)">{ <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top" _counted="undefined" /> <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" _counted="undefined" /><img style="display: none" alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif" align="top" _counted="undefined" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">public</span><span style="color: rgb(0,0,0)"> MainServlet() </span><span style="border-right: rgb(128,128,128) 1px solid; border-top: rgb(128,128,128) 1px solid; display: none; border-left: rgb(128,128,128) 1px solid; border-bottom: rgb(128,128,128) 1px solid; background-color: rgb(255,255,255)">...</span><span><span style="color: rgb(0,0,0)">{ <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top" _counted="undefined" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">super</span><span style="color: rgb(0,0,0)">(); <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" _counted="undefined" />&nbsp;&nbsp;&nbsp;&nbsp; }</span></span><span style="color: rgb(0,0,0)"> <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" _counted="undefined" /><img style="display: none" alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif" align="top" _counted="undefined" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">public</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">void</span><span style="color: rgb(0,0,0)"> init() </span><span style="color: rgb(0,0,255)">throws</span><span style="color: rgb(0,0,0)"> ServletException </span><span style="border-right: rgb(128,128,128) 1px solid; border-top: rgb(128,128,128) 1px solid; display: none; border-left: rgb(128,128,128) 1px solid; border-bottom: rgb(128,128,128) 1px solid; background-color: rgb(255,255,255)">...</span><span><span style="color: rgb(0,0,0)">{ <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top" _counted="undefined" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">下面的两个参数param1是在servlet中存放的</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">); <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top" _counted="undefined" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(</span><span style="color: rgb(0,0,255)">this</span><span style="color: rgb(0,0,0)">.getInitParameter(</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">param1</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">));</span><span style="color: rgb(0,0,0)"> <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top" _counted="undefined" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">下面的参数是存放在servletcontext中的</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">); <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top" _counted="undefined" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(getServletContext().getInitParameter(</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">context/param</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">)); <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" _counted="undefined" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></span><span style="color: rgb(0,0,0)"> <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif" align="top" _counted="undefined" />}</span></span><span style="color: rgb(0,0,0)"> <img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" _counted="undefined" /></span></div>
</div>
</div>
<img src ="http://www.blogjava.net/conans/aggbug/214467.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-12 19:17 <a href="http://www.blogjava.net/conans/articles/214467.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>自己整理的分页工具 </title><link>http://www.blogjava.net/conans/articles/214094.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Thu, 10 Jul 2008 11:37:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/214094.html</guid><description><![CDATA[<p>今天自己整理了一个分页工具(刚做还有很多没完善的地方)，把它放上来。<br />
因为个人水平有限，有不对的地方，望大家见谅。也希望大家提出你们宝贵的意见或建议。<br />
<br />
<a href="http://www.blogjava.net/Files/siyn/siyn-pager.rar">源码siyn-pager.rar下载<br />
</a><br />
下面主要介绍一下其使用方法:</p>
<p>1.把siyn-pager.jar放到lib下，<br />
2.把siyn-pager.tld放到/WEB-INF/下,<br />
3.修改web.xml文件,添加tld配置 </p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /><span style="color: #0000ff">&lt;</span><span style="color: #800000">jsp-config</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">taglib</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">taglib-uri</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">http://www.siyn.org/siyn-pager.tld</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">taglib-uri</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">taglib-location</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">/WEB-INF/siyn-pager.tld</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">taglib-location</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">taglib</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /></span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">jsp-config</span><span style="color: #0000ff">&gt;</span></div>
4.action <br />
4.1通过PageControlUtil.getPageControl(request)得到pageControl；<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /><span style="color: #000000">PageControl&nbsp;pageControl&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;PageControlUtil.getPageControl(request);</span></div>
4.2如果还没有获得总记录数，通过调用service的方法获得总记录数<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /><span style="color: #0000ff">if</span><span style="color: #000000">(pageControl.getRowcount()&nbsp;</span><span style="color: #000000">&lt;=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">)<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pageControl.setRowcount(service.getSize());</span></div>
4.3通过调用service的方法得到结果集<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /><span style="color: #000000">List&nbsp;list&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;service.getData(pageControl);</span></div>
4.4将结果集＆分页控制bean（pageControl）放入request<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /><span style="color: #000000">request.setAttribute(</span><span style="color: #000000">"</span><span style="color: #000000">list</span><span style="color: #000000">"</span><span style="color: #000000">,&nbsp;list);<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;request.setAttribute(<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;org.siyn.common.web.struts.taglib.page.Constants.PAGE_CONTROL_MODEL,<br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pageControl);</span></div>
4.5跳转页面<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;mapping.findForward(</span><span style="color: #000000">"</span><span style="color: #000000">success</span><span style="color: #000000">"</span><span style="color: #000000">);</span></div>
5.jsp页面 <br />
5.1导入标签库<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /><span style="color: #000000">&lt;%</span><span style="color: #000000">@&nbsp;taglib&nbsp;uri</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">http://www.siyn.org/siyn-page.tld</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;prefix</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">page</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">%&gt;</span></div>
5.2显示list数据<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /><span style="color: #000000">&lt;</span><span style="color: #000000">logic:iterate&nbsp;id</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">data</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;name</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">list</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;&nbsp;indexId</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">i</span><span style="color: #000000">"</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">ul</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">li</span><span style="color: #000000">&gt;&lt;</span><span style="color: #000000">bean:write&nbsp;name</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">data</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;property</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">x</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">/&gt;&lt;/</span><span style="color: #000000">li</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">li</span><span style="color: #000000">&gt;&lt;</span><span style="color: #000000">bean:write&nbsp;name</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">data</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;property</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">xx</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">/&gt;&lt;/</span><span style="color: #000000">li</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">li</span><span style="color: #000000">&gt;&lt;</span><span style="color: #000000">bean:write&nbsp;name</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">data</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;property</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">xxx</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">/&gt;&lt;/</span><span style="color: #000000">li</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">&lt;/</span><span style="color: #000000">ul</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />
<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /></span><span style="color: #000000">&lt;/</span><span style="color: #000000">logic:iterate</span><span style="color: #000000">&gt;</span></div>
5.3显示导航控制<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /><span style="color: #000000">&lt;</span><span style="color: #000000">pager:navigator&nbsp;actionPath</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">xxx.do?Op=showlist</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;shownum</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">3</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;template</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">template.jsp</span><span style="color: #000000">"</span><span style="color: #000000">/&gt;</span><span style="color: #000000">&nbsp;</span></div>
这个navigator有三个属性，<br />
&nbsp;&nbsp;&nbsp; actionPath为必须的，请求数据的action地址<br />
&nbsp;&nbsp;&nbsp; shownum可选，导航栏除了首页，上页，下页，末页外，中间的数字页显示几个，默认显示5个<br />
&nbsp;&nbsp;&nbsp; template&nbsp; 可选，为导航栏的模板路径(相对于classes目录)，自己可以修改以显示不同风格，默认为org/siyn/common/web/struts/taglib/page/pageControlTemplate.jsp<br />
<img src ="http://www.blogjava.net/conans/aggbug/214094.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-10 19:37 <a href="http://www.blogjava.net/conans/articles/214094.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【译】构建可扩展的Java EE应用（二） </title><link>http://www.blogjava.net/conans/articles/214093.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Thu, 10 Jul 2008 11:36:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/214093.html</guid><description><![CDATA[原文地址：http://www.theserverside.com/tt/articles/article.tss?l=ScalingYourJavaEEApplicationsPart2<br />
<br />
当并发用户数明显的开始增长，你可能会不满意一台机器所能提供的性能，或者由于单个JVM实例gc的限制，你没法扩展你的java应用，在这样的情况下你可以做的另外的选择是在多个JVM实例或多台服务器上运行你的系统，我们把这种方法称为水平扩展。<br id="jsdn3" />
<p id="w9.21">请注意，我们相信能够在一台机器的多个JVM上运行系统的扩展方式是水平扩展方式，而非垂直扩展方式。JVM实例之间的IPC机制是有限的，两个JVM实例之间无法通过管道、共享内存、信号量或指令来进行通讯，不同的JVM进程之间最有效的通讯方式是socket。简而言之，如果Java EE应用如果扩展到多个JVM实例中运行，那么大多数情况下它也可以扩展到多台服务器上运行。<br id="w9.22" />
</p>
<p id="h2o41">随着计算机越来越便宜，性能越来越高，通过将低成本的机器群组装为集群可以获得超过那些昂贵的超级计算机所具备的计算能力。不过，大量的计算机也意味着增加了管理的复杂性以及更为复杂的编程模型，就像服务器节点之间的吞吐量和延时等问题。</p>
<p id="foim1">Java EE集群是一种成熟的技术，我在TSS上写了一篇名为&#8220;<a id="yqcr" href="http://www.theserverside.com/tt/articles/article.tss?l=J2EEClustering" target="_blank">Uncover the Hood of J2EE Clustering</a>&#8221;的文章来描述它的内部机制。<br id="foim2" />
</p>
<p id="mp-e1"><font id="mp-e" size="4"><strong id="jsdn12"></strong></font><font id="mp-e2" size="4"><strong id="mp-e3">从失败的项目中吸取的教训<br id="yqcr0" />
</strong></font></p>
<p id="yqcr8"><strong id="yqcr9"><font id="mp-e4" size="3">采用无共享的集群架构</font><br id="yqcr10" />
</strong></p>
<p id="jsdn13" align="center"><strong id="jsdn14"><img id="jsdn15" height="142" alt="" src="http://www.theserverside.com/tt/articles/content/ScalingYourJavaEEApplicationsPart2//clip_image002.jpg" width="358" /><br id="jsdn16" />
<em id="jsdn17">Figure 3: share nothing cluster</em></strong></p>
<p id="ose01">最具备扩展性的架构当属无共享的集群架构。在这样的集群中，每个节点具备完全相同的功能，并且不需要知道其他节点存在与否。负载均衡器(Load Balancer)来完成如何将请求分发给这些后台的服务器实例。由于负载均衡器只是做一些简单的工作，例如分派请求、健康检查和保持session，因此负载均衡器很少会成为瓶颈。如果后端的数据库系统或其他的信息系统足够的强大，那么通过增加更多的节点，集群的计算能力可以得到线性的增长。<br id="jsdn19" />
</p>
<p id="ose01">几乎所有的Java EE提供商在他们的集群产品中都实现了HttpSession的failover功能，这样即使在某些服务器节点不可用的情况下也仍然能够保证客户端的请求中的session信息不丢失，但这点其实是打破了无共享原则的。为了实现failover，同样的session数据将会被两个或多个节点共享，在我之前的文章中，我曾经推荐除非是万不得已，不要使用session failover。就像我文章中提到的，当失败发生时，session failover功能并不能完全避免错误，而且同时还会对性能和可扩展性带来损失。<br id="ose02" />
</p>
<p id="l8n31"><font id="mp-e5" size="3"><strong id="mp-e6">使用可扩展的session复制机制</strong></font><br id="l8n32" />
</p>
<p id="l8n38">为了让用户获得更友好的体验，有些时候可能必须使用session failover功能，这里最重要的在于选择可扩展的复制型产品或机制。不同的厂商会提供不同的复制方案 - 有些采用数据库持久，有些采用中央集中的状态服务器，而有些则采用节点间内存复制的方式。最具可扩展性的是成对节点的复制(paired node replication)，这也是现在大部分厂商采用的方案，包括BEA Weblogic、JBoss和IBM Websphere，Sun在Glassfish V2以及以上版本也实现了成对节点的复制。最不可取的方案是数据库持久session的方式。在我们实验室中曾经测试过一个采用数据库持久来实现 session复制的项目，测试结果表明如果session对象频繁更新的话，节点在三到四个时就会导致数据库崩溃。<br id="l8n39" />
</p>
<p id="vgms1"><font id="mp-e7" size="3"><strong id="mp-e8">采用collocated部署方式来取代分布式</strong></font><br id="vgms2" />
</p>
<p id="px4p1">Java EE技术，尤其是EJB，天生就是用来做分布式计算的。解耦业务功能和重用远程的组件使得多层的应用模型得以流行。但对于可扩展性而言，减少分布式的层次可能是一个好的选择。<br id="jsdn27" />
</p>
<p id="px4p1">在我们实验室曾经以一个政府的项目测试过这两种方式在同样的服务器数量上的部署 - 一种是分布式的，一种是collocated方式的，如下图所示：<br id="px4p2" />
</p>
<table class="zeroBorder" id="jsdn29" width="600" align="center" border="0" classname="zeroBorder">
    <tbody id="jsdn30">
        <tr id="jsdn31">
            <td id="jsdn32">
            <div id="jsdn33" align="center"><img id="jsdn34" height="159" alt="" src="http://www.theserverside.com/tt/articles/content/ScalingYourJavaEEApplicationsPart2//clip_image004.jpg" width="210" /><br id="jsdn35" />
            <strong id="jsdn36"><em id="jsdn37">Figure 4: distributed structure </em></strong></div>
            </td>
            <td id="jsdn38">
            <div id="jsdn39" align="center"><strong id="jsdn40"><em id="jsdn41"><img id="jsdn42" height="153" alt="" src="http://www.theserverside.com/tt/articles/content/ScalingYourJavaEEApplicationsPart2//clip_image006.jpg" width="208" /><br id="jsdn43" />
            </em></strong><strong id="jsdn44"><em id="jsdn45">Figure 5: collocated structure</em></strong></div>
            </td>
        </tr>
    </tbody>
</table>
<br id="mp-e9" />
<p id="b_ta2">结果表明collocated式的部署方式比分布式的方式更具备可扩展性。假设你应用中的一个方法调用了一堆的EJB，如果每个EJB的调用都需要load balance，那么有可能会因为需要分散到不同的服务器上进行调用导致你的应用崩溃，这样的结果就是，你可能做了很多次无谓的跨服务器的调用。来看更糟糕的情况，如果你的方法是需要事务的，那么这个事务就必须跨越多个服务器，而这对于性能是会产生很大的损害的。<br id="b_ta3" />
</p>
<p id="u6g91"><font id="mp-e10" size="3"><strong id="mp-e11">共享资源和服务</strong></font><br id="u6g92" />
</p>
<p id="u6g96">对于用于支撑并发请求的Java EE集群系统而言，其扩展后的性能取决于对于那些不支持线性扩展的共享资源的操作。数据库服务器、JNDI树、LDAP服务器以及外部的文件系统都有可能被集群中的节点共享。<br id="u6g97" />
</p>
<p id="opr52">尽管Java EE规范中并不推荐，但为了实现各种目标，通常都会采用外部的I/O操作。例如，在我们实验室测试的应用中有用文件系统来保存用户上传的文件的应用，或动态的创建xml配置文件的应用。在集群内，应用服务器节点必须想办法来复制这些文件到其他的节点，但这样做是不利于扩展的。随着越来越多节点的加入，节点间的文件复制会占用所有的网络带宽和消耗大量的CPU资源。在集群中要达到这样的目标，可以采用数据库来替代外部文件，或采用SAN作为文件的集中存储，另外一个可选的方案是采用高效的分布式文件系统，例如Hadoop DFS(http://wiki.apache.org/hadoop/)。<br id="opr53" />
</p>
<p id="nq3v2">在集群环境中共享服务很常见，这些服务不会部署到集群的每个节点，而是部署在专门的服务器节点上，例如分布式的日志服务或时间服务。分布式锁管理器 (DLM)来管理集群中的应用对这些共享服务的同步访问，即使在网络延时和系统处理失败的情况下，锁管理器也必须正常操作。举例来说，在我们的实验室中测试的一个ERP系统就碰到了这样的问题，他们写了自己的DLM系统，最终发现当集群中持有锁的节点失败时，他们的lock system将会永远的持有锁。<br id="nq3v3" />
</p>
<p id="mp-e13"><font id="mp-e14" size="4"><strong id="mp-e15">分布式缓存</strong></font><br id="rqyc" />
</p>
<p id="k9:21">我所碰到过的几乎所有的Java EE项目都采用了对象缓存来提升性能，同样所有流行的应用服务器也都提供了不同级别的缓存来加速应用。但有些缓存是为单一运行的环境而设计的，并且只能在单JVM实例中正常的运行。由于有些对象的创建需要耗费大量的资源，我们需要缓存，因此我们维护对象池来缓存对象的实例。如果获取维护缓存较之创建对象而言更划算，那么我们就提升了系统的性能。在集群环境中，每个jvm实例维护着自己的缓存，为了保持集群中所有服务器状态的一致，这些缓存对象需要进行同步。有些时候这样的同步机制有可能会比不采用缓存的性能还差，对于整个集群的扩展能力而言，一个可扩展的分布式缓存系统是非常重要的。<br id="k9:22" />
</p>
<p id="c5-w1">如今很多分布式缓存相关的开源java产品已经非常流行，在我们实验室中有如下的一些测试：</p>
<ul id="nggw">
    <li id="nggw0">1个基于JBoss Cache的项目的测试；
    <li id="nggw1">3个基于Terracotta的项目的测试；
    <li id="nggw2">9个基于memcached的项目的测试； </li>
</ul>
测试结果表明Terracotta可以很好的扩展到10个节点，并且在不超过5个节点时拥有很高的性能，但memcached则在超过20个服务器节点时会扩展的非常好。<br />
<br id="nggw3" />
<h1 id="jsdn64"><strong><span style="color: #000000">Memcached</span></strong> </h1>
<p id="hv3g1"><a id="hv3g2" href="http://www.danga.com/memcached/" target="_blank">Memcached</a>是一个高性能的分布式对象缓存系统，经常被用于降低数据库load，同时提升动态web应用的速度。Memcached的奇妙之处在于它的两阶段hash的方法，它通过一个巨大的hash表来查找key = value对，给它一个key，就可以set或get数据了。当进行一次memcached查询时，首先客户端将会根据整个服务器的列表来对key进行 hash，在找到一台服务器后，客户端就发送请求，服务器端在接收到请求后通过对key再做一次内部的hash，从而查找到实际的数据项。当处理巨大的系统时，最大的好处就是memcached所具备的良好的水平扩展能力。由于客户端做了一层hashing，这使得增加N多的节点到集群变得非常的容易，并不会因为节点的互连造成负载的增高，也不会因为多播协议而造成网络的洪水效应。<br id="hv3g3" />
</p>
<p id="jsdn67">实际上Memcached并不是一款java产品，但它提供了Java client API，这也就意味着如果你需要在Java EE应用中使用memcached的话，并不需要做多大的改动就可以从cache中通过get获取值，或通过put将值放入cache中。使用 memcached是非常简单的，不过同时也得注意一些事情避免对扩展性和性能造成损失：<br id="q60s" />
</p>
<ul id="cwqx">
    <li id="cwqx0">不要缓存写频繁的对象。Memcached是用来减少对数据库的读操作的，而非写操作，在使用Memcached前，应先关注对象的读/写比率，如果这个比率比较高，那么采用缓存才有意义。
    <li id="xyr4">尽量避免让运行的memcached的节点互相调用，对于memcached而言这是灾难性的。
    <li id="pnxf">尽量避免行方式的缓存，在这样的情况下可采用复杂的对象来进行缓存，这对于memcached来说会更为有效。
    <li id="g:o1">选 择合适的hashing算法。在默认的算法下，增加或减少服务器会导致所有的cache全部失效。由于服务器的列表hash值被改变，可能会造成大部分的 key都要hash到和之前不同的服务器上去，这种情况下，可以考虑采用持续的hashing算法(http://weblogs.java.net /blog/tomwhite/archive/2007/11/consistent_hash.html) 来增加和减少服务器，这样做可以保证你大部分缓存的对象仍然是有效的。<br id="g:o10" />
    </li>
</ul>
<h1 id="jsdn73"><strong><span style="color: #000000">Terracotta</span></strong> </h1>
<p id="nowt1">Terracotta(http://www.terracottatech.com/)是一个企业级的、开源的、JVM级别的集群解决方案。JVM级的集群方案意味着可以支撑将企业级的Java应用部署部署到多JVM上，而且就像是运行在同一个JVM中。 Terracotta扩展了JVM的内存模型，各虚拟机上的线程通过集群来与其他虚拟机上的线程进行交互(Terracotta extends the Java Memory Model of a single JVM to include a cluster of virtual machines such that threads on one virtual machine can interact with threads on another virtual machine as if they were all on the same virtual machine with an unlimited amount of heap.)。<br id="nowt2" />
</p>
<p id="nowt3"><br id="nowt4" />
</p>
<p id="jsdn75" align="center"><img id="jsdn76" height="335" alt="" src="http://www.theserverside.com/tt/articles/content/ScalingYourJavaEEApplicationsPart2//clip_image008.jpg" width="510" /><br id="jsdn77" />
<strong id="jsdn78"><em id="jsdn79">Figure 6: Terracotta JVM clustering</em></strong></p>
<br id="j.7e" />
<p id="j_.42">采用Terracotta来实现集群应用的编程方式和编写单机应用基本没有什么差别，Terrocotta并没有特别的提供开发者的API，Terracotta采用字节码织入的方式（很多AOP软件开发框架中采用的技术，例如AspectJ和AspectWerkz）来将集群方式的代码插入到已有的java语言中。<br id="j_.43" />
</p>
<p id="bvl_1">我猜想Terrocotta是通过某种互连的方式或多播协议的方式来实现服务器和客户端JVM实例的通讯的，可能是这个原因导致了在我们实验室测试时的效果：当超过20个节点时Terracotta扩展的并不是很好。（注：这个测试结果仅为在我们实验室的测试结果，你的结果可能会不同。）<br id="bvl_2" />
</p>
<font id="j.7e1" size="4"><strong id="j.7e2">并行处理</strong></font><br id="onm7" />
<p id="ob431">我之前说过，单线程的任务会成为系统可扩展性的瓶颈。但有些单线程的工作（例如处理或生成巨大的数据集）不仅需要多线程或多进程的运行，还会有扩展到多节点运行的需求。例如，在我们实验室测试的一个Java EE项目有一个场景是这样的：根据他们站点的日志文件分析URL的访问规则，每周产生的这些日志文件通常会超过120GB，当采用单线程的Java应用去分析时需要耗费四个小时，客户改为采用Hadoop Map-Reduce使其能够水平扩展从而解决了这个问题，如今这个分析URL访问规则的程序不仅运行在多进程模式下，同时还并行的在超过10个节点上运行，而完成所有的工作也只需要7分钟了。<br id="ob432" />
</p>
<p id="g8.y1">有很多的框架和工具可以帮助Java EE开发人员来让应用支持水平扩展。除了Hadoop，很多MPI的Java实现也可以用来将单线程的任务水平的扩展到多个节点上并行运行。<br id="g8.y2" />
</p>
<h1 id="jsdn86"><strong><span style="color: #000000">MapReduce</span></strong> </h1>
<p id="sezi2">MapReduce由Google的Jeffrey Dean和Sanjay Ghemawat提出，是一种用于在大型集群环境下处理巨量数据的分布式编程模型。MapReduce由两个步骤来实现 - Map：对集合中所有的对象进行操作并基于处理返回一系列的结果，Reduce：通过多线程、进程或独立系统并行的从两个或多个Map中整理和获取结果。Map()和Reduce()都是可以并行运行的，不过通常来说没必要在同样的系统同样的时间这么来做。<br id="sezi3" />
</p>
<p id="m25n1"><a id="dwmn" href="http://hadoop.apache.org/" target="_blank">Hadoop</a>是一个开源的、点对点的、纯Java实现的MapReduce。它是一个用于将分布式应用部署到大型廉价集群上运行的Lucene-derived框架，得到了全世界范围开源人士的支持以及广泛的应用，Yahoo的Search Webmap、Amazon EC2/S3服务以及Sun的网格引擎都可运行在Hadoop上。<br id="hpul" />
</p>
<p id="pt_l2">简单来说，通过使用&#8220;Hadoop Map-Reduce&#8221;，"URL访问规则分析"程序可以首先将日志文件分解为多个128M的小文件，然后由Hadoop将这些小文件分配到不同的Map()上去执行。Map()会分析分配给它的小文件并产生临时的结果，Map()产生的所有的临时结果会被排序并分配给不同的Reduce()，Reduce()合并所有的临时结果产生最终的结果，这些Map和Reduce操作都可以由Hadoop框架控制来并行的运行在集群中所有的节点上。<br id="pt_l3" />
</p>
<p id="ocal1">MapReduce对于很多应用而言都是非常有用的，包括分布式检索、分布式排序、web link-graph reversal、term-vector per host、web访问日志分析、索引重建、文档集群、机器智能学习、statistical machine translation和其他领域。 </p>
<p id="j.7e4"><strong id="j.7e5"><font id="j.7e6" size="4">MPI</font></strong><br id="uch2" />
</p>
<p id="uch25">MPI是一种语言无关、用于实现并行运行计算机间交互的通讯协议，目前已经有很多Java版本的MPI标准的实现，mpiJava和MPJ是其中的典型。mpiJava 基于JNI绑定native的MPI库来实现，MPJ是100%纯java的MPI标准的实现。mpiJava和MPJ和MPI Fortran和C版本提供的API都基本一致，例如它们都对外提供了具备同样方法名和参数的Comm class来实现MPI的信息传递。<br id="uch26" />
</p>
<p id="jsdn98">CCJ是一个类似MPI通讯操作的java库。CCJ提供了barrier、broadcast、scatter、 gather、all-gather、reduce和all-reduce操作的支持（但不提供点对点的操作，例如send、receive和send- receive）。在底层的通讯协议方面，CCJ并没有自己实现，而是采用了Java RMI，这也就使得CCJ可以用来传递复杂的序列化对象，而不仅仅是MPI中的原始数据类型。进一步看，CCJ还可以从一组并行的processes中获取到复杂的集合对象，例如实现了CCJ的DividableDataObject接口的集合。<br id="j.7e7" />
</p>
<p id="j.7e8"><font id="j.7e9" size="4"><strong id="j.7e10">采用不同的方法来获取高扩展能力</strong></font><br id="tafg" />
</p>
<p id="pa9n2">有很多的书会教我们如何以OO的方式来设计灵活架构的系统，如何来使服务透明的被客户端使用以便维护，如何采用正常的模式来设计数据库schema以便集成。但有些时候为了获取高扩展性，需要采用一些不同的方法。<br id="pa9n3" />
</p>
<p id="m-gg1">Google设计了自己的高可扩展的分布式文件系统（GFS），它并不是基于POSIX API来实现的，不过GFS对于用户来说并不完全透明。为了使用GFS，你必须采用GFS的API包。Google也设计了自己的高可扩展的分布式数据库系统（Bigtable），但它并不遵循ANSI SQL标准，而且其中的概念和结构和传统的关系数据库几乎完全不同，但最重要的是GFS和Bigtable能够满足Google的存储要求、良好的扩展性要求，并且已经被Google的广泛的作为其存储平台而使用。<br id="m-gg2" />
</p>
<p id="kvjf1">传统方式下，我们通过使用更大型的、更快和更贵的机器或企业级的集群数据库（例如RAC）来将数据库扩展到多节点运行，但我有一个我们实验室中测试的social networking的网站采用了不同的方式，这个应用允许用户在网站上创建profiles、blogs，和朋友共享照片和音乐，此应用基于Java EE编写，运行在Tomcat和Mysql上，但不同于我们实验室中测试的其他应用，它只是希望在20多台便宜的PC Server上进行测试，其数据模型结构如下：<br id="kvjf2" />
</p>
<p id="jsdn101" align="center"><img id="jsdn102" height="225" alt="" src="http://www.theserverside.com/tt/articles/content/ScalingYourJavaEEApplicationsPart2/clip_image010.gif" width="419" /><br id="jsdn103" />
<strong id="jsdn104"><em id="jsdn105">Figure 7: Users data partitions</em></strong></p>
<br id="j.7e11" />
<p id="jkte0">这里比较特殊的地方子碍于不同的用户数据（例如profile、blog）可能会存储在不同的数据库实例上，例如，用户 00001存储在服务器A上，而用户20001存储在服务器C上，分库的规则以一张元信息的表的方式存储在专门的数据库上。当部署在Tomcat的 Java EE应用希望获取或更新用户信息时，首先它会从这张元信息的表中获取到需要去哪台服务器上获取这个用户，然后再连到实际的服务器上去执行查询或更新操作。</p>
<p id="spqc">用户数据分区和这种两步时的动作方式可以带来如下的一些好处：</p>
<ul id="spqc0">
    <li id="spqc1">扩展了写的带宽：对于这类应用而言，blogging、ranking和BBS将会使得写带宽成为网站的主要瓶颈。分 布式的缓存对于数据库的写操作只能带来很小的提升。采用数据分区的方式，可以并行的进行写，同样也就意味着提升了写的吞吐量。要支持更多的注册用户，只需 要通过增加更多的数据库节点，然后修改元信息表来匹配到新的服务器上。
    <li id="hdqw">高可用性：如果一台数据库服务器down了，那么只会有部分用户被影响，而其他大部分的用户可以仍然正常使用； </li>
</ul>
同时也会带来一些缺点：<br id="bw:3" />
<ul id="k_8a">
    <li id="k_8a0">由于数据库节点可以动态的增加，这对于在Tomcat中的Java EE应用而言要使用数据库连接池就比较难了；
    <li id="jjxz">由于操作用户的数据是两步式的，这也就意味着很难使用ORMapping的工具去实现；
    <li id="jjxz0">当要执行一个复杂的搜索或合并数据时，需要从多台数据库服务器上获取很多不同的数据。<br id="jjxz1" />
    </li>
</ul>
<p id="y5hf1">这个系统的架构师这么说：&#8220;我们已经知道这些缺点，并且准备好了应对它，我们甚至准备好了应对当元信息表的服务器成为瓶颈的状况，如果出现那样的状况我们将会把元信息表再次划分，并创建出一个更高级别的元信息表来指向众多的二级元信息表服务器实例。&#8220;<br id="y5hf2" />
</p>
<h1 id="jsdn117"><strong><font id="d.s7" size="4"><span style="color: #000000">参考</span></font></strong></h1>
<ol id="jsdn118">
    <li id="jsdn119">Scalability definition in wikipedia: <a id="jsdn120" href="http://en.wikipedia.org/wiki/Scalability" target="_blank">http://en.wikipedia.org/wiki<wbr id="jsdn121">/Scalability</a>
    <li id="jsdn122">Javadoc of atomic APIs: <a id="jsdn123" href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/atomic/package-summary.html" target="_blank">http://java.sun.com/j2se/1.5.0<wbr id="jsdn124">/docs/api/java/util/concurrent<wbr id="jsdn125">/atomic/package-summary.html</a>
    <li id="jsdn126">Alan Kaminsky. Parallel Java: A unified API for shared memory and cluster parallel programming in 100% Java: <a id="jsdn127" href="http://www.cs.rit.edu/%7Eark/20070326/pj.pdf" target="_blank">http://www.cs.rit.edu/~ark<wbr id="jsdn128">/20070326/pj.pdf</a>
    <li id="jsdn129">OMP-an OpenMP-like interface for Java: <a id="jsdn130" href="http://portal.acm.org/citation.cfm?id=337466" target="_blank">http://portal.acm.org/citation<wbr id="jsdn131">.cfm?id=337466</a>
    <li id="jsdn132">Google MapReduce white paper: <a id="jsdn133" href="http://labs.google.com/papers/mapreduce-osdi04.pdf" target="_blank">http://labs.google.com/papers<wbr id="jsdn134">/mapreduce-osdi04.pdf</a>
    <li id="jsdn135">Google Bigtable white paper: <a id="jsdn136" href="http://labs.google.com/papers/bigtable-osdi06.pdf" target="_blank">http://labs.google.com/papers<wbr id="jsdn137">/bigtable-osdi06.pdf</a>
    <li id="jsdn138">Hadoop MapReduce tutorial: <a id="jsdn139" href="http://hadoop.apache.org/core/docs/r0.17.0/mapred_tutorial.html" target="_blank">http://hadoop.apache.org/core<wbr id="jsdn140">/docs/r0.17.0/mapred_tutorial<wbr id="jsdn141">.html</a>
    <li id="jsdn142">Memcached FAQ: <a id="jsdn143" href="http://www.socialtext.net/memcached/index.cgi?faq" target="_blank">http://www.socialtext.net<wbr id="jsdn144">/memcached/index.cgi?faq</a>
    <li id="jsdn145">Terracotta: <a id="jsdn146" href="http://www.terracotta.org/" target="_blank">http://www.terracotta.org/</a> </li>
</ol>
<p id="jsdn148"><font id="d.s72" size="4"><strong id="d.s73">关于作者</strong></font><br id="plv1" />
</p>
Wang Yu目前在Sun的ISVE Group小组工作，担任的职位为Java工程师和架构咨询师，他承担的职责包括支持本地的ISVs，为一些重要的Java技术例如Java EE、EJB、JSP/Servlet、JMS和web services技术提供咨询，可以通过wang.yu@sun.com联系他。<br id="plv14" />
<img src ="http://www.blogjava.net/conans/aggbug/214093.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-10 19:36 <a href="http://www.blogjava.net/conans/articles/214093.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【译】构建可扩展的Java EE应用（一） </title><link>http://www.blogjava.net/conans/articles/214092.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Thu, 10 Jul 2008 11:36:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/214092.html</guid><description><![CDATA[原文地址： http://www.theserverside.com/tt/articles/article.tss?l=ScalingYourJavaEEApplications<br />
<br />
对于一个具备使用价值的应用而言，其使用者有可能会在一段时间内疯狂的增长。随着越来越多的关键性质的应用在Java EE上运行，很多的Java开发者也开始关注可扩展性的问题了。但目前来说，大部分的web 2.0站点是基于script语言编写的，对于Java应用可扩展能力，很多人都抱着质疑的态度。在这篇文章中，Wang Yu基于他本身在实验室项目的经验来展示如何构建可扩展的java应用，同时，基于一些在可扩展性上做的比较失败的项目给读者带来构建可扩展java应用的实践、理论、算法、框架和经验。<br id="llf.2" />
<p id="oe9t0">我一直为一家互联网性质的实验室工作，这个实验室采用我们公司最新的大型服务器环境为合作伙伴的产品和解决方案免费做性能测试，我工作的部分就是帮助他们在强大的CMT和SMP服务器上进行性能调优。<br id="oe9t1" />
</p>
<p id="lafd1">这些年来，我已经为不同的解决方案测试了数十种java应用。许多的产品都是为了解决同样的领域问题，因此这些产品的功能基本都是类似的，但在可扩展性上表现的却非常不同，其中有些不能扩展到64 CPU的服务器上运行，但可以扩展到20台服务器做集群运行，有些则只能运行在不超过2 CPU的机器上。<br />
</p>
<p id="lafd1">造成这些差别的原因在于设计产品时的架构愿景，所有的具备良好扩展性的java应用从需求需求阶段、系统设计阶段以及实现阶段都为可扩展性做了考虑，所以，你所编写的java应用的可扩展能力完全取决于你的愿景。<br id="lafd2" />
</p>
<p id="pn931">可扩展性作为系统的属性之一，是个很难定义的名词，经常会与性能混淆。当然，可扩展性和性能是有关系的，它的目的是为了达到高性能。但是衡量可扩展性和性能的方法是不一样的，在这篇文章中，我们采用wikipedia中的定义：<br id="pn932" />
</p>
<p id="jlay2">可扩展性是系统、网络或进程的可选属性之一，它表达的含义是可以以一种优雅的方式来处理不断增长的工作，或者以一种很明白的方式进行扩充。例如：它可以用来表示系统具备随着资源(典型的有硬件)的增加提升吞吐量的能力。<br id="jlay3" />
</p>
<p id="m4lu1">垂直扩展的意思是给系统中的单节点增加资源，典型的是给机器增加CPU或内存，垂直扩展为操作系统和应用模块提供了更多可共用的资源，因此它使得虚拟化的技术（应该是指在一台机器上运行多个虚拟机）能够运行的更加有效。<br id="m4lu2" />
</p>
<p id="cq3n2">水平扩展的意思是指给系统增加更多的节点，例如为一个分布式的软件系统增加新的机器，一个更清晰的例子是将一台web服务器增加为三台。随着计算机价格的不断降低以及性能的不断提升，以往需要依靠超级计算机来进行的高性能计算的应用（例如：地震分析、生物计算等）现在可以采用这种多个低成本的应用来完成。由上百台普通机器构成的集群可以达到传统的基于RISC处理器的科学计算机所具备的计算能力。<br id="cq3n3" />
</p>
<p id="yfvm1">这篇文章的第一部分来讨论下垂直扩展Java应用。<br id="yfvm2" />
</p>
<p id="q9ps0"><font id="q9ps1" size="4"><strong id="q9ps2">如何让Java EE应用垂直扩展<br id="yfvm3" />
</strong></font></p>
<p id="yfvm10">很多的软件设计人员和开发人员都认为功能是产品中最重要的因素，而性能和可扩展性是附加的特性和功能完成后才做的工作。他们中大部分人认为可以借助昂贵的硬件来缩小性能问题。<br id="yfvm11" />
</p>
<p id="z9tj2">但有时候他们是错的，上个月，我们实验室中有一个紧急的项目，合作伙伴提供的产品在他们客户提供的CPU的机器上测试未达到性能的要求，因此合作伙伴希望在更多CPU（8 CPU）的机器上测试他们的产品，但结果却是在8 CPU的机器上性能反而比4 CPU的机器更差。<br id="z9tj3" />
</p>
<p id="f.yh1">为什么会这样呢？首先，如果你的系统是多进程或多线程的，并且已经用尽了CPU的资源，那么在这种情况下增加CPU通常能让应用很好的得到扩展。<br id="f.yh2" />
</p>
<p id="a97y2">基于java技术的应用可以很简单的使用线程，Java语言不仅可以用来支持编写多线程的应用，同时JVM本身在对java应用的执行管理和内存管理上采用的也是多线程的方式，因此通常来说Java应用在多CPU的机器上可以运行的更好，例如Bea weblogic、IBM Websphere、开源的Glassfish和Tomcat等应用服务器，运行在Java EE应用服务器中的应用可以立刻从CMT和SMP技术中获取到好处。<br id="a97y3" />
</p>
<p id="s.wx2">但在我的实验室中，我发现很多的产品并不能充分的使用CPU，有些应用在8 CPU的服务器上只能使用到不到20%的CPU，像这类应用即使增加CPU也提升不了多少的。<br id="s.wx3" />
</p>
<p id="o9zm0"><font id="o9zm1" size="4"><strong id="o9zm2">热锁(Hot Lock)是可扩展性的关键障碍</strong></font><br id="mkel" />
</p>
<p id="jrop1">在Java程序中，用来协调线程的最重要的工具就是 synchronized这个关键字了。由于java所采用的规则，包括缓存刷新和失效，Java语言中的synchronized块通常都会其他平台提供的类似的机制更加的昂贵。即使程序只是一个运行在单处理器上的单线程程序，一个synchronized的方法调用也会比非同步的方法调用慢。<br id="jrop2" />
</p>
<p id="se052">要检查问题是否为采用synchronized关键字造成的，只需要像JVM进程发送一个QUIT指令（译者注：在linux上也可以用kill -3 PID的方式）来获取线程堆栈信息。如果你看到类似下面线程堆栈的信息，那么就意味着你的系统出现了热锁的问题：<br id="se053" />
</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000"><img alt="" src="http://www.blogjava.net/Images/dot.gif" /><img alt="" src="http://www.blogjava.net/Images/dot.gif" /><img alt="" src="http://www.blogjava.net/Images/dot.gif" />..<br />
</span><span style="color: #000000">"</span><span style="color: #000000">Thread-0</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;prio</span><span style="color: #000000">=</span><span style="color: #000000">10</span><span style="color: #000000">&nbsp;tid</span><span style="color: #000000">=</span><span style="color: #000000">0x08222eb0</span><span style="color: #000000">&nbsp;nid</span><span style="color: #000000">=</span><span style="color: #000000">0x9</span><span style="color: #000000">&nbsp;waiting&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">&nbsp;monitor&nbsp;entry&nbsp;[</span><span style="color: #000000">0xf927b000</span><span style="color: #000000">..</span><span style="color: #000000">0xf927bdb8</span><span style="color: #000000">]<br />
at&nbsp;testthread.WaitThread.run(WaitThread.java:</span><span style="color: #000000">39</span><span style="color: #000000">)<br />
</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;waiting&nbsp;to&nbsp;lock&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">0xef63bf08</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;(a&nbsp;java.lang.Object)<br />
</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;locked&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">0xef63beb8</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;(a&nbsp;java.util.ArrayList)<br />
at&nbsp;java.lang.Thread.run(Thread.java:</span><span style="color: #000000">595</span><span style="color: #000000">)<br />
<img alt="" src="http://www.blogjava.net/Images/dot.gif" /><img alt="" src="http://www.blogjava.net/Images/dot.gif" /><img alt="" src="http://www.blogjava.net/Images/dot.gif" /></span></div>
<p id="o0a-1">synchronized 关键字强制执行器串行的执行synchronized中的动作。如果很多线程竞争同样的同步对象，那么只有一个线程能够执行同步块，而其他的线程就只能进入blocked状态了，如果此时没有其他需要执行的线程，那么处理器就进入空闲状态了，在这种情况下，增加CPU也带来不了多少性能提升。<br id="o0a-2" />
</p>
<p id="urdx1">热锁可能会导致更多线程的切换和系统的调用。当多个线程竞争同一个monitor时，JVM必须维护一个竞争此monitor的线程队列（同样，这个队列也必须同步），这也就意味着更多的时间需要花费在JVM或OS的代码执行上，而更少的时间是用在你的程序上的。</p>
<p id="oe0-">要避免热锁现象，以下的建议能带来一些帮助：<br id="urdx2" />
</p>
<p id="oe0-1"><font id="q6gr" size="3"><strong id="q6gr0">尽可能的缩短同步块</strong></font><br id="oe0-2" />
</p>
<p id="tk7t1">当你将线程中持有锁的时间尽量缩短后，其他线程竞争锁的时间也就变得更短。因此当你需要采用同步块来操作共享的变量时，应该将线程安全的代码放在同步块的外面，来看以下代码的例子：</p>
<p id="tk7t1"><em id="pyvs36">Code list 1:</em><br />
</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">boolean</span><span style="color: #000000">&nbsp;updateSchema(HashMap&nbsp;nodeTree)&nbsp;{<br />
</span><span style="color: #0000ff">synchronized</span><span style="color: #000000">&nbsp;(schema)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;nodeName&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(String)nodeTree.get(</span><span style="color: #000000">"</span><span style="color: #000000">nodeName</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;nodeAttributes&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(List)nodeTree.get(</span><span style="color: #000000">"</span><span style="color: #000000">attributes</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(nodeName&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">null</span><span style="color: #000000">)&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">false</span><span style="color: #000000">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">else</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;schema.update(nodeName,nodeAttributes);<br />
}<br />
}</span></div>
<p id="ussu1">上面的代码片段是为了当更新"schema"变量时保护这个共享的变量。但获取attribute值部分的代码是线程安全的。因此我们可以将这部分移至同步块的外面，让同步块变得更短一些：</p>
<p id="ussu1"><em id="pyvs49">Code list 2:</em><br />
</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">boolean</span><span style="color: #000000">&nbsp;updateSchema(HashMap&nbsp;nodeTree)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;nodeName&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(String)nodeTree.get(</span><span style="color: #000000">"</span><span style="color: #000000">nodeName</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;nodeAttributes&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(List)nodeTree.get(</span><span style="color: #000000">"</span><span style="color: #000000">attributes</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">synchronized</span><span style="color: #000000">&nbsp;(schema)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(nodeName&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">null</span><span style="color: #000000">)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">false</span><span style="color: #000000">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">else</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;schema.update(nodeName,nodeAttributes);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></div>
<pre id="pyvs48"></pre>
<p id="pnji0"><font id="q6gr1" size="3"><strong id="q6gr2">减小锁的粒度</strong></font><br id="klg1" />
</p>
<p id="klg14">当你使用"synchronized"时，有两种粒度可选择："方法锁"或"块锁"。如果你将"synchronized"放在方法上，那么也就意味着锁定了"this"对象。</p>
<p id="klg14"><em id="pyvs64">Code list 3:</em><br />
</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;SchemaManager&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;HashMap&nbsp;schema;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;HashMap&nbsp;treeNodes;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img alt="" src="http://www.blogjava.net/Images/dot.gif" />.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">boolean</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">synchronized</span><span style="color: #000000">&nbsp;updateSchema(HashMap&nbsp;nodeTree)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;nodeName&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(String)nodeTree.get(</span><span style="color: #000000">"</span><span style="color: #000000">nodeName</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;nodeAttributes&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(List)nodeTree.get(</span><span style="color: #000000">"</span><span style="color: #000000">attributes</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(nodeName&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">null</span><span style="color: #000000">)&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">false</span><span style="color: #000000">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">else</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;schema.update(nodeName,nodeAttributes);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">boolean</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">synchronized</span><span style="color: #000000">&nbsp;updateTreeNodes()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img alt="" src="http://www.blogjava.net/Images/dot.gif" /><img alt="" src="http://www.blogjava.net/Images/dot.gif" /><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></div>
<pre id="pyvs86">对比Code list 2中的代码，这段代码就显得更糟糕些了，因为当调用"updateSchema"方法时，它锁定了整个<br />
对象，为了获得更好的粒度控制，应该仅仅锁定"schema"变量来替代锁定整个对象，这样其他不同的方法就可<br />
以保持并行执行了。<br />
<br />
<font id="q6gr4" size="3"><strong id="q6gr5">避免在static方法上加锁</strong></font><br />
<br />
最糟糕的状况是在static方法上加"synchronized"，这样会造成锁定这个class的所有实例对象。<br />
</pre>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000">--------------------------------</span><span style="color: #000000"><br />
at&nbsp;sun.awt.font.NativeFontWrapper.initializeFont(Native&nbsp;Method)<br />
</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;waiting&nbsp;to&nbsp;lock&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">0xeae43af0</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;(a&nbsp;java.lang.Class)<br />
at&nbsp;java.awt.Font.initializeFont(Font.java:</span><span style="color: #000000">316</span><span style="color: #000000">)<br />
at&nbsp;java.awt.Font.readObject(Font.java:</span><span style="color: #000000">1185</span><span style="color: #000000">)<br />
at&nbsp;sun.reflect.GeneratedMethodAccessor147.invoke(Unknown&nbsp;Source)<br />
at&nbsp;sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:</span><span style="color: #000000">25</span><span style="color: #000000">)<br />
at&nbsp;java.lang.reflect.Method.invoke(Method.java:</span><span style="color: #000000">324</span><span style="color: #000000">)<br />
at&nbsp;java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:</span><span style="color: #000000">838</span><span style="color: #000000">)<br />
at&nbsp;java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:</span><span style="color: #000000">1736</span><span style="color: #000000">)<br />
at&nbsp;java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:</span><span style="color: #000000">1646</span><span style="color: #000000">)<br />
at&nbsp;java.io.ObjectInputStream.readObject0(ObjectInputStream.java:</span><span style="color: #000000">1274</span><span style="color: #000000">)<br />
at&nbsp;java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:</span><span style="color: #000000">1835</span><span style="color: #000000">)<br />
at&nbsp;java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:</span><span style="color: #000000">1759</span><span style="color: #000000">)<br />
at&nbsp;java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:</span><span style="color: #000000">1646</span><span style="color: #000000">)<br />
at&nbsp;java.io.ObjectInputStream.readObject0(ObjectInputStream.java:</span><span style="color: #000000">1274</span><span style="color: #000000">)<br />
at&nbsp;java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:</span><span style="color: #000000">1835</span><span style="color: #000000">)<br />
at&nbsp;java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:</span><span style="color: #000000">452</span><span style="color: #000000">)<br />
at&nbsp;com.fr.report.CellElement.readObject(Unknown&nbsp;Source)<br />
<img alt="" src="http://www.blogjava.net/Images/dot.gif" /><img alt="" src="http://www.blogjava.net/Images/dot.gif" /><img alt="" src="http://www.blogjava.net/Images/dot.gif" /></span></div>
<br />
<p id="q2z32">当使用Java 2D来为报表生成字体对象时，开发人员放了一个native的static锁在"initialize"方法上，不过这是sun JDK 1.4中才会出现的，在JDK 5.0中，这个static lock就消失了。<br id="q2z33" />
</p>
<p id="q2z37"><font id="q6gr6" size="3"><strong id="q6gr7">在Java SE 5.0中使用lock free的数据结构</strong></font><br id="q2z38" />
</p>
<p id="q2z314">在Java中，"synchronized"关键字是一个较简单、并且相对来说比较好用的协作机制，不过同时对于管理一个简单的操作（例如增加统计值或更新一个值）来说就显得比较重量级了，就像以下的代码：<em id="pyvs111"><br />
</em></p>
<p id="q2z314"><em id="pyvs111">Code list 4:</em><br />
</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;OnlineNumber&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;totalNumber;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">synchronized</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;getTotalNumber()&nbsp;{&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;totalNumber;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">synchronized</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;increment()&nbsp;{&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">++</span><span style="color: #000000">totalNumber;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">synchronized</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;decrement()&nbsp;{&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">--</span><span style="color: #000000">totalNumber;&nbsp;}<br />
}</span></div>
<br />
<p id="ns9d2">以上的代码只是用来锁定非常简单的操作，"synchronized"块也是非常的短。但是锁是非常重量级（当锁被其他线程持有时，线程会去频繁尝试获取锁）的，吞吐量会下降，并且同步锁的竞争也是很昂贵的。<br id="ns9d3" />
</p>
<p id="kd-s1">幸运的是，在Java SE 5.0或以上版本，你可以在不使用native代码的情况下使用硬件级同步语义的wait-free、lock-free的算法。几乎所有现代的处理器都具有检测和防止其他处理器并发修改变量的基础设施。这些基础设施称为比较并交换，或CAS。<br id="kd-s2" />
</p>
<p id="ig9m1">一个CAS操作包含三个参数 -- 一个内存地址，期待的旧的值以及新的值。 如果内存地址上的值和所期待的旧的值是同一个的话，处理器将此地址的值更新为新的值；否则它就什么都不做，同时它会返回CAS操作前内存地址上的值。一个使用CAS来实现同步的例子如下：</p>
<p id="ig9m1"><em id="pyvs122">Code list 5:</em><br />
</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;increment()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;oldValue&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;value.getValue();<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;newValue&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;oldValue&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">1</span><span style="color: #000000">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">while</span><span style="color: #000000">&nbsp;(value.compareAndSwap(oldValue,&nbsp;newValue)&nbsp;</span><span style="color: #000000">!=</span><span style="color: #000000">&nbsp;oldValue)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oldValue&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;value.getValue();<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;oldValue&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">1</span><span style="color: #000000">;<br />
}</span></div>
<br />
<p id="e8l:1">首先，我们从地址上读取一个值，然后执行几步操作来产生新的值（例子中只是做加1的操作），最后使用CAS方式来将地址中的旧值改变为新值。如果在时间片段内地址上的值未改变，那么CAS操作将成功。如果另外的线程同时修改了地址上的值，那么CAS操作将失败，但会检测到这个操作失败，并在while循环中进行重试。CAS最好的原因在于它是硬件级别的实现并且非常轻量级，如果100个线程同时执行这个increment()方法，最糟糕的情况是在 increment方法执行完毕前每个线程最多尝试99次。<br id="e8l:2" />
</p>
<p id="hh.51">在Java SE 5.0和以上版本的java.util.concurrent.atomic包中提供了在单个变量上lock-free和线程安全操作支持的类。这些原子变量的类都提供了比较和交换的原语，它基于各种平台上可用的最后的native的方式实现，这个包内提供了九种原子变量，包括：AtomicInteger；AtomicLong；AtomicReference；AtomicBoolean；array forms of atomic integer、long、reference；和atomic marked reference和stamped reference类。<br id="hh.52" />
</p>
<p id="ktmo1">使用atomic包非常容易，重写上面code list 5的代码片段：</p>
<p id="ktmo1"><em id="pyvs135">Code list 6:</em><br />
</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.util.concurrent.atomic.</span><span style="color: #000000">*</span><span style="color: #000000">;<br />
<img alt="" src="http://www.blogjava.net/Images/dot.gif" />.<br />
<br />
</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;AtomicInteger&nbsp;value&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;AtomicInteger(</span><span style="color: #000000">0</span><span style="color: #000000">);<br />
</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;increment()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;value.getAndIncrement();<br />
}<br />
<img alt="" src="http://www.blogjava.net/Images/dot.gif" />.</span></div>
<pre id="pyvs134">几乎java.util.concurrent包中所有的类都直接或间接的采用了原子变量来替代synchronized。像<br />
ConcurrentLinkedQueue采用了原子变量来直接实现wait-free算法，而像ConcurrentHashMap则采用<br />
ReentrantLock来实现必要的锁，而ReentrantLock则是采用原子变量来维护所有等待锁的线程队列。</pre>
<p id="gni12">在我们实验室中一个最成功的关于lock free算法的案例发生在一个金融系统中，当将"Vector"数据结构替换为"ConcurrentHashMap"后，在我们的CMT机器（8核）性能提升了超过3倍。<br id="gni13" />
</p>
<p id="jwtp0"><font id="jwtp1" size="4"><strong id="jwtp2">竞争条件也会导致可扩展性出现问题</strong></font><br id="iyib" />
</p>
<p id="avul1">太多的"synchronized"关键字会导致可扩展性出现问题。但在某些场合，缺少"synchronized"也会导致系统无法垂直扩展。缺少"synchronized"会产生竞争场景，在这种场景下允许两个线程同时修改共享的资源，这有可能会造成破坏共享数据，为什么我说它会导致可扩展性出现问题呢？<br id="avul2" />
</p>
<p id="up:s1">来看一个实际的例子。这是一个制作业的ERP系统，当在我们最新的一台CMT服务器（2CPU、16核、128芯）上进行性能测试时，我们发现CPU的使用率超过90%，这非常让人惊讶，因为很少有应用能够在这款机器上扩展的这么好。但我们仅仅兴奋了5分钟，之后我们发现平均响应时间非常的慢，同时吞吐量也降到不可思议的低。那么这些CPU都在干嘛呢？它们不是在忙吗，那么它们到底在忙些什么呢？通过OS的跟踪工具，我们发现几乎所有的CPU都在干同一件事-- "HashMap.get()"，看起来所有的CPU都进入了死循环，之后我们在不同数量的CPU的服务器上再测试了这个应用，结果表明，服务器拥有越多CPU，那么产生死循环的概率就会越高。<br id="up:s2" />
</p>
<p id="tmkc1">产生这个死循环的根源在于对一个未保护的共享变量 -- 一个"HashMap"数据结构的操作。当在所有操作的方法上加了"synchronized"后，一切恢复了正常。检查"HashMap"(Java SE 5.0)的源码，我们发现有潜在的破坏其内部结构最终造成死循环的可能。在下面的代码中，如果我们使得HashMap中的entries进入循环，那么"e.next()"永远都不会为null。</p>
<p id="tmkc1"><em id="pyvs151">Code list 7:</em><br />
</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;V&nbsp;get(Object&nbsp;key)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(key&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">null</span><span style="color: #000000">)&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;getForNullKey();<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;hash&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;hash(key.hashCode());<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">&nbsp;(Entry</span><span style="color: #000000">&lt;</span><span style="color: #000000">K,V</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;e&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;table[indexFor(hash,&nbsp;table.length)];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e&nbsp;</span><span style="color: #000000">!=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">null</span><span style="color: #000000">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;e.next)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;k;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(e.hash&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;hash&nbsp;</span><span style="color: #000000">&amp;&amp;</span><span style="color: #000000">&nbsp;((k&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;e.key)&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;key&nbsp;</span><span style="color: #000000">||</span><span style="color: #000000">&nbsp;key.equals(k)))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;e.value;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">null</span><span style="color: #000000">;<br />
}</span></div>
<p id="vgbz2">不仅get()方法会这样，put()以及其他对外暴露的方法都会有这个风险，这算jvm的bug吗？应该说不是的，这个现象很早以前就报告出来了（详细见：<a id="g4az" href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6423457" target="_blank">http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6423457</a>）。Sun的工程师并不认为这是bug，而是建议在这样的场景下应采用"ConcurrentHashMap"，在构建可扩展的系统时应将这点纳入规范中。<br id="vgbz3" />
</p>
<p id="jwtp4"><font id="jwtp5" size="4"><strong id="jwtp6">非阻塞 IO vs. 阻塞IO</strong></font><br id="z.kv" />
</p>
<p id="z.kv5">Java 1.4中引入的java.nio包，允许开发人员在进行数据处理时获取更好的性能并提供更好的扩展性。NIO提供的非阻塞IO操作允许java应用像其他底层语言（例如c）一样操作IO。目前已经有很多NIO的框架（例如Apache的Mina、Sun的Grizzly）了被广泛的使用在很多的项目和产品中。<br id="z.kv6" />
</p>
<p id="s5ed2">在最近的5个月内，我们实验室有两个Java EE项目测试对比了基于传统的阻塞I/O构建的服务器和非阻塞I/O构建的服务器上的性能。他们选择了Tomcat 5作为基于阻塞I/O的服务器，Glassfish作为基于非阻塞I/O的服务器。<br id="s5ed3" />
</p>
<p id="pyvs169">首先，他们测试了一些简单的JSP页面和servlets，得到如下结果：（在一台4 CPU的服务器上）</p>
<table id="pyvs170" bordercolor="#000000" cellspacing="0" cellpadding="4" align="center" border="1">
    <tbody id="pyvs171">
        <tr id="pyvs172">
            <td id="pyvs173" rowspan="2">
            <div id="pyvs174" align="center"><strong id="pyvs175">Concurrent Users</strong></div>
            </td>
            <td id="pyvs176" colspan="2">
            <div id="pyvs177" align="center"><strong id="pyvs178">Average Response Time (ms)</strong></div>
            </td>
        </tr>
        <tr id="pyvs179">
            <td id="pyvs180">
            <div id="pyvs181" align="center"><strong id="pyvs182">Tomcat</strong></div>
            </td>
            <td id="pyvs183">
            <div id="pyvs184" align="center"><strong id="pyvs185">Glassfish</strong></div>
            </td>
        </tr>
        <tr id="pyvs186">
            <td id="pyvs187">
            <div id="pyvs188" align="center">5</div>
            </td>
            <td id="pyvs189">
            <div id="pyvs190" align="center">30</div>
            </td>
            <td id="pyvs191">
            <div id="pyvs192" align="center">138</div>
            </td>
        </tr>
        <tr id="pyvs193">
            <td id="pyvs194">
            <div id="pyvs195" align="center">15</div>
            </td>
            <td id="pyvs196">
            <div id="pyvs197" align="center">35</div>
            </td>
            <td id="pyvs198">
            <div id="pyvs199" align="center">142</div>
            </td>
        </tr>
        <tr id="pyvs200">
            <td id="pyvs201">
            <div id="pyvs202" align="center">30</div>
            </td>
            <td id="pyvs203">
            <div id="pyvs204" align="center">37</div>
            </td>
            <td id="pyvs205">
            <div id="pyvs206" align="center">142</div>
            </td>
        </tr>
        <tr id="pyvs207">
            <td id="pyvs208">
            <div id="pyvs209" align="center">50</div>
            </td>
            <td id="pyvs210">
            <div id="pyvs211" align="center">41</div>
            </td>
            <td id="pyvs212">
            <div id="pyvs213" align="center">151</div>
            </td>
        </tr>
        <tr id="pyvs214">
            <td id="pyvs215">
            <div id="pyvs216" align="center">100</div>
            </td>
            <td id="pyvs217">
            <div id="pyvs218" align="center">65</div>
            </td>
            <td id="pyvs219">
            <div id="pyvs220" align="center">155</div>
            </td>
        </tr>
    </tbody>
</table>
<p id="pyvs221"><br id="y0vp" />
</p>
从测试结果来看，Glassfish的性能远低于Tomcat。客户对非阻塞I/O能够带来的提升表示怀疑，但为什么那么多的文章以及技术报告都告诉大家NIO具备更好的性能和可扩展性呢？<br id="y0vp8" />
<p id="t-8v1">当在更多的场景进行测试后，随着NIO的能力逐步的展现出来，他们改变了观点，他们做了以下的测试：</p>
<p id="linz">1、比简单的JSP、servlet更为复杂的场景，包括EJB、数据库、文件IO、JMS和事务；</p>
<p id="qgn-">2、模拟更多的并发用户，从1000到10000；</p>
<p id="qgn-0">3、在不同的硬件环境上进行测试，从2 CPU、4 CPU到16 CPU。</p>
<p id="qgn-1">以下的图为在4 CPU服务器上的测试结果：<br id="t-8v2" />
</p>
<div id="pyvs228" align="center">
<table id="pyvs229" cellspacing="0" cellpadding="0">
    <tbody id="pyvs230">
        <tr id="pyvs231">
            <td id="pyvs232" valign="top" align="left">
            <p id="pyvs233"><img id="pyvs234" height="276" alt="" src="http://www.theserverside.com/tt/articles/content/ScalingYourJavaEEApplications/clip_image002.gif" width="511" /></p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<p id="pyvs235" align="center"><strong id="pyvs236">Figure 1: Throughput in a 4CPU server <br id="d95c0" />
</strong></p>
<p id="cm9u2"><strong id="d95c2"></strong>传统的阻塞I/O为每个请求分配一个工作线程，这个工作线程负责请求的整个过程的处理，包括从网络读取请求数据、解析参数、计算或调用其他的业务逻辑、编码结果并将其返回给请求者，然后这个线程将返回到线程池中供其他线程复用。Tomcat 5采用的这种方式在应对完美的网络环境、简单的逻辑以及小量的并发用户时是非常高效的。<br id="cm9u3" />
</p>
<p id="owzc2">但如果请求包括了复杂的逻辑、或需要和外部的系统（例如文件系统、数据库或消息服务器）进行交互时，工作线程在其处理的大部分时间都会处于等待同步的调用或网络传输返回的状态中，这个阻塞的线程会被请求持有直到请求处理完毕，但操作系统需要暂停线程来保证CPU能够处理其他的请求，如果客户端和服务器端的网络状况不太好的话，网络的延时会导致线程被阻塞更长时间，在更糟的状况下，当需要keep-alive的话，当前的工作线程会在请求处理完毕后阻塞很长一段时间，在这样的情况下，为了更好的使用CPU，就必须增加更多的工作线程了。<br id="owzc3" />
</p>
<p id="hzd91">Tomcat采用了一个线程池，每个请求都会被线程池中一个空闲的线程进行处理。"maxThreads"表示Tomcat 能创建的处理请求的最大线程数。如果我们把"maxThreads"设置的太小的话，就不能充分的使用CPU了，更为重要的是，随着并发用户的增长，会有很多请求被服务器抛弃和拒绝。在此次测试中，我们将"maxThreads"设置为了1000（这对于Tomcat来说有些太大了），在这样的设置下，当并发用户增长到较高数量时，Tomcat会创建很多的线程。大量的Java线程会导致JVM和OS忙于执行和维护这些线程，而不是执行业务逻辑处理，同时，太多的线程也会消耗更多的JVM heap内存（每个线程堆栈需要占用一些内存），并且会导致更为频繁的gc。<br id="hzd92" />
</p>
<p id="crca1">Glassfish不需要这么多的线程，在非阻塞IO中，一个工作线程并不会绑定到一个特定的请求上，如果请求被某些原因所阻塞，那么这个线程将被其他的请求复用。在这样的方式下，Glassfish可以用几十个工作线程来处理几千的并发用户。通过限制线程资源，非阻塞IO拥有了更好的可扩展性，这也是Tomcat 6采用非阻塞IO的原因了。<br id="crca2" />
</p>
<div id="pyvs242" align="center">
<table id="pyvs243" cellspacing="0" cellpadding="0">
    <tbody id="pyvs244">
        <tr id="pyvs245">
            <td id="pyvs246" valign="top" align="left">
            <p id="pyvs247"><img id="pyvs248" height="290" alt="" src="http://www.theserverside.com/tt/articles/content/ScalingYourJavaEEApplications/clip_image002_0000.gif" width="501" /></p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<p id="pyvs249" align="center"><strong id="pyvs250">Figure 2: scalability test result</strong></p>
<br id="d95c4" />
<p id="pyvs252"><font id="d95c5" size="4"><strong id="d95c6">单线程任务问题<br id="dh7x" />
</strong></font></p>
<p id="cc-t1">几个月前我们实验室测试了一个基于Java EE的ERP系统，它其中的一个测试场景是为了产生非常复杂的分析报告，我们在不同的服务器上测试了这个应用场景，发现竟然是在最便宜的AMD PC服务器上拥有最好的性能。这台AMD的服务器只有两个2.8HZ的CPU以及4G的内存，但它的性能竟然超过了昂贵的拥有8 CPU和32G内存的SPARC服务器。<br id="cc-t2" />
</p>
<p id="d6vc1">原因就在于这个场景是个单线程的任务，它同时只能被一个用户运行（并发的多用户执行在这个案例中毫无意义），因此当运行时它只使用了一个CPU，这样的任务是没法扩展到多个处理器的，在大多数时候，这种场景下的性能仅取决于CPU的运行速度。<br id="d6vc2" />
</p>
<p id="bjdu2">并行是解决这个问题的方案。为了让一个单线程的任务并行执行，你需要按顺序找出这个操作的过程中从某种程度上来讲不依赖的操作，然后采用多线程从而实现并行。在上面的案例中，客户重新定义了"分析报告产生"的任务，改为先生成月度报告，之后基于产生的这些12个月的月度报告来生成分析报告，由于最终用户并不需要&#8220;月度报告&#8221;，因此这些&#8220;月度报告&#8221;只是临时产生的结果，但"月度报告"是可以并行生成的，然后用于快速的产生最后的分析报告，在这样的方式下，这个应用场景可以很好的扩展到4 CPU的SPARC服务器上运行，并且在性能上比在AMD Server高80%多。<br id="bjdu3" />
</p>
<p id="yppw1">重新调整架构和重写代码的解决方案是一个耗时并且容易出现错误的工作。在我们实验室中的一个项目中采用了JOMP来为其单线程的任务获得并行性。JOMP是一个基于线程的SMP并行编程的Java API。就像OpenMP，JOMP也是根据编译指示来插入并行运行的代码片段到常规的程序中。在Java程序中，JOMP 通过//omp这样的指示方式来表示需要并行运行的部分。JOMP程序通过运行一个预编译器来处理这些//omp的指示并生成最终的java代码，这些 java代码再被正常的编译和执行。JOMP支持OpenMP的大部分特性，包括共享的并行循环和并行片段，共享变量，thread local变量以及reduction变量。以下的代码为JOMP程序的示例：</p>
<p id="yppw1"><em id="pyvs258">Code list 8:</em><br />
</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000">Li&nbsp;n&nbsp;k&nbsp;e&nbsp;dLi&nbsp;s&nbsp;t&nbsp;c&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Li&nbsp;n&nbsp;k&nbsp;e&nbsp;dLi&nbsp;s&nbsp;t&nbsp;(&nbsp;)&nbsp;;<br />
c&nbsp;.&nbsp;add&nbsp;(&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;t&nbsp;h&nbsp;i&nbsp;s&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;)&nbsp;;<br />
c&nbsp;.&nbsp;add&nbsp;(&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;i&nbsp;s&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;)&nbsp;;<br />
c&nbsp;.&nbsp;add&nbsp;(&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;a&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;)&nbsp;;<br />
c&nbsp;.&nbsp;add&nbsp;(&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">demo</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;)&nbsp;;<br />
</span><span style="color: #000000">/</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">/</span><span style="color: #000000">&nbsp;#omp&nbsp;p&nbsp;a&nbsp;r&nbsp;a&nbsp;l&nbsp;l&nbsp;e&nbsp;l&nbsp;i&nbsp;t&nbsp;e&nbsp;r&nbsp;a&nbsp;t&nbsp;o&nbsp;r<br />
f&nbsp;o&nbsp;r&nbsp;(&nbsp;S&nbsp;t&nbsp;r&nbsp;i&nbsp;n&nbsp;g&nbsp;s&nbsp;:&nbsp;c&nbsp;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;System&nbsp;.&nbsp;o&nbsp;u&nbsp;t&nbsp;.&nbsp;p&nbsp;r&nbsp;i&nbsp;n&nbsp;t&nbsp;l&nbsp;n&nbsp;(&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;s&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;)&nbsp;;<br />
</span></div>
<p id="f0_v1">就像大部分的并行编译器，JOMP也是关注于loop-level和集合的并行运算，研究如何同时执行不同的迭代。为了并行化，两个迭代之间不能产生任何的数据依赖，这也就是说，不能依赖于其他任何一个执行后产生的计算结果。要编写一个JOMP程序并不是容易的事。首先，你必须熟练使用OpenMP的指示，同时还得熟悉JVM对于这些指示的内存模型映射，最后你需要知道在你的业务逻辑代码的正确的地方放置正确的指示。<br id="f0_v2" />
</p>
<p id="xbc01">另外一个选择是采用Parallel Java。Parallel Java，就像JOMP一样，也支持OpenMP的大部分特性；但又不同于JOMP，PJ的并行结构部分是通过在代码中调用PJ的类来实现，而不是通过插入预编译的指示，因此，"Parallel Java"不需要另外的预编译过程。Parallel Java不仅对于在多CPU上并行有效，对于多节点的扩展能力上也同样有效。以下的代码是"Parallel Java"程序的示例：</p>
<p id="xbc01"><em id="pyvs272">Code list 9:</em><br />
</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">double</span><span style="color: #000000">[][]&nbsp;d;<br />
</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;ParallelTeam().execute&nbsp;(</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;ParallelRegion()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;run()&nbsp;</span><span style="color: #0000ff">throws</span><span style="color: #000000">&nbsp;Exception<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;ii&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;&nbsp;ii&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">&nbsp;n;&nbsp;</span><span style="color: #000000">++</span><span style="color: #000000">&nbsp;ii)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">final</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;ii;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;execute&nbsp;(</span><span style="color: #000000">0</span><span style="color: #000000">,&nbsp;n</span><span style="color: #000000">-</span><span style="color: #000000">1</span><span style="color: #000000">,&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;IntegerForLoop()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;run&nbsp;(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;first,&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;last)<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;{<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;</span><span style="color: #0000ff">for</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;r&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;first;&nbsp;r&nbsp;</span><span style="color: #000000">&lt;=</span><span style="color: #000000">&nbsp;last;&nbsp;</span><span style="color: #000000">++</span><span style="color: #000000">&nbsp;r)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;c&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;&nbsp;c&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">&nbsp;n;&nbsp;</span><span style="color: #000000">++</span><span style="color: #000000">&nbsp;c)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d[r][c]&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;Math.min&nbsp;(d[r][c],<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d[r][i]&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;d[i][c]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<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;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />
<br />
</span></div>
<p id="pyvs299"><font id="d95c7" size="4"><strong id="d95c8">扩展使用更多的内存</strong></font><br id="h_:l" />
</p>
<p id="h_:l5">内存是应用的重要资源。足够的内存对于任何应用而言都是关键的，尤其是数据库系统和其他I/O操作频繁的系统。更多的内存意味着更大的共享内存空间以及更大的数据缓冲，这也就使得应用能够更多的从内存中读取数据而不是缓慢的磁盘中读取。<br id="h_:l6" />
</p>
<p id="h_:l11">Java gc将程序员从繁琐的内存分配和回收中解脱了出来，从而使得程序员能够更加高效的编写代码。但gc不好的地方在于当gc运行时，几乎所有工作的线程都会被挂起。另外，在gc环境下，程序员缺少调度CPU来回收那些不再使用的对象的控制能力。对于那些几乎实时的系统而言，例如电信系统和股票交易系统，这种延迟和缺少控制的现象是很大的风险。<br id="h_:l12" />
</p>
<p id="uxk61">回到Java应用在給予更多的内存时是否可以扩展的问题上，答案是有些时候是的。太小的内存会导致gc频繁的执行，足够的内存则保证JVM花费更多的时间来执行业务逻辑，而不是进行gc。<br id="uxk62" />
</p>
<p id="u-.z1">但它并不一定是这样的，在我们实验室中出现的真实例子是一个构建在64位JVM上的电信系统。使用64位JVM，应用可以突破32位JVM中4GB内存的限制，测试时使用的是一台4 CPU/16G内存的服务器，其中12GB的内存分配给了java应用使用，为了提高性能，他们在初始化时就缓存了超过3,000,000个的对象到内存中，以免在运行时创建如此多的对象。这个产品在第一个小时的测试中运行的非常快，但突然，系统差不多停止运行了30多分钟，经过检测，发现是因为gc导致了系统停止了半个小时。<br id="u-.z2" />
</p>
<p id="qqit1">gc是从那些不再被引用的对象回收内存的过程。不被引用的对象是指应用中不再使用的对象，因为所有对于这些对象的引用都已经不在应用的范围中了。如果一堆巨大的活动的对象存在在内存中（就像3,000,000个缓存的对象），gc需要花费很长的时间来检查这些对象，这就是为什么系统停止了如此长乃至不可接受的时间。<br id="qqit2" />
</p>
<p id="qqit3">在我们实验室中测试过的以内存为中心的Java应用中，我们发现具备有如下特征：<br id="ypr00" />
</p>
1、每个请求的处理过程需要大量和复杂的对象；<br id="ypr01" />
2、在每个会话的HttpSession对象中保存了太多的对象；<br id="ypr02" />
3、HttpSession的timeout时间设置的太长，并且HttpSession没有显示的invalidated；<br id="ypr03" />
4、线程池、EJB池或其他对象池设置的太大；<br id="vvvl" />
5、对象的缓存设置的太大。<br id="ypr04" />
<br id="mvg4" />
<p id="k9em1">这样的应用是不好做扩展的，当并发的用户数增长时，这些应用所使用的内存也会大幅度的增长。如果大量的活动对象无法被及时的回收，JVM将会在gc上消耗很长的时间，另外，如果給予了太大的内存（在64位JVM上），在运行了相对较长的时间后，jvm会花费相当长的一段时间在 gc上，因此结论是如果给jvm分配了太多的内存的话，java应用将不可扩展。在大部分场合下，给jvm分配3G内存(通过"-Xmx"属性)是足够 (在windows和linux中，32位的系统最多只能分配2G的内存)的。如果你拥有更多的内存，请将这些内存分配给其他的应用，或者就将它留给OS 使用，许多OS都会使用空闲的内存来作为数据的缓冲和缓存来提升IO性能。实时JVM(JSR001)可以让开发人员来控制内存的回收，应用基于此特性可以告诉JVM：&#8220;这个巨大的内存空间是我的缓存，我将自己来管理它，请不要自动对它进行回收&#8221;，这个功能特性使得Java应用也能够扩展来支持大量的内存资源，希望JVM的提供者们能将这个特性在不久的将来带入到免费的JVM版本中。</p>
<p id="antm">为了扩展这些以内存为中心的java应用，你需要多个jvm实例或者多台机器节点。<br id="k9em2" />
</p>
<p id="mgml0"><font id="mgml1" size="4"><strong id="mgml2">其他垂直扩展的问题</strong></font><br id="qy:0" />
</p>
<p id="qy:04">有些Java EE应用的扩展性问题并不在于其本身，有些时候外部系统的限制会成为系统扩展能力的瓶颈，这些瓶颈可能包括：</p>
<ul id="tz-g">
    <li id="tz-g0">数据库系统：这在企业应用和web 2.0应用中是最常见的瓶颈，因为数据库通常是jvm线程中共享的资源。因此数据库执行的效率、数据库事务隔离的级别将会很明显的影响系统的扩展能力。我 们看到很多的项目将大部分的业务逻辑以存储过程的方式放在数据库中，而web层则非常的轻量，只是用来执行下数据的过滤等，这样的架构在随着请求数的增长 后会出现很多的扩展性问题。
    <li id="o4vw">磁盘IO和网络IO。
    <li id="o4vw0">操作系统：有些时候系统扩展能力的瓶颈可能会出现在操作系统的限制上，例如，在同一个目录下放了太多的文件，导致文件系统在创建和查找文件时变得非常的慢；
    <li id="yas5">同步logging：这是一个可扩展性的常见问题。在有些案例中，可以通过采用Apache log4j来解决，或者采用jms消息来将同步的logging转为异步执行。<br id="yas50" />
    </li>
</ul>
<p id="yas53">这些不仅仅是Java EE应用的问题，对于所有平台的所有系统而言同样如此。为了解决这些问题，需要从系统的各个层面来从数据库管理员、系统工程师和网络分析人员处得到帮助。</p>
<p id="xjom">这篇文章的第二个部分将来探讨水平扩展的问题。<br id="yas54" />
</p>
<img src ="http://www.blogjava.net/conans/aggbug/214092.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-10 19:36 <a href="http://www.blogjava.net/conans/articles/214092.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>源代码解读Cas实现单点登出(single sign out)功能实现原理 </title><link>http://www.blogjava.net/conans/articles/214078.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Thu, 10 Jul 2008 11:17:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/214078.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 声明：本博客属作者原创，如果任何网站转载本文，请注明作者及引用来源，谢谢合作！关于Cas实现单点登入(single sing on)功能的文章在网上介绍的比较多，想必大家多多少少都已经有所了解，在此就不再做具体介绍。如果不清楚的，那只能等我把single sign on这块整理出来后再了解了。当然去cas官方网站也是有很多的文章进行介绍。cas官网http://www.ja-sig.org...&nbsp;&nbsp;<a href='http://www.blogjava.net/conans/articles/214078.html'>阅读全文</a><img src ="http://www.blogjava.net/conans/aggbug/214078.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-10 19:17 <a href="http://www.blogjava.net/conans/articles/214078.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>持续集成工具hudson </title><link>http://www.blogjava.net/conans/articles/213462.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Tue, 08 Jul 2008 15:01:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/213462.html</guid><description><![CDATA[<h4>一.什么是持续集成</h4>
<h4><span class="atitle"><span style="font-family: 宋体">持续集成的核心概念</span></span></h4>
<h4><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">CI 过程会经常构建软件组件；在许多情况下，每当源代码存储库（比如 Subversion 或 ClearCase）中的代码发生变化时，都要构建软件组件。CI 的好处是：经常构建软件可以确保尽早遇到问题（比如代码缺陷），避免问题在软件开发周期晚期变复杂时才被发现。</span></span></span></span></h4>
<h4><a name="N10122"><span class="smalltitle"><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">工具与过程</span></span></span></span></span></a></h4>
<h4><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">尽管 CI 实际上是一个过程，但是<em>持续集成</em> 这个词常常与一个或多个工具相关联。在本教程中，讲解如何安装、配置和使用 Hudson 作为 CI 服务器，但是要记住，CI 远不只是个工具。实际上，使用的工具可能是 CI 比较次要的方面，因为 CI 工具所做的仅仅是在代码存储库中探测到修改时运行构建。构建过程本身比用来运行它的工具重要得多。</span></span></span></span></h4>
<h4><a name="N1012F"><span class="smalltitle"><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">开始使用 CI</span></span></span></span></span></a></h4>
<h4><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">开始使用 CI 需要三个组件： </span></span></span></span></h4>
<ul>
    <li><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt"><strong>用 Ant 或 Maven 等工具建立的自动构建过程 </strong></span></span></span></span>
    <li><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt"><strong>一个代码存储库，比如 CVS 或 Subversion </strong></span></span></span></span>
    <li><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt"><strong>一个 CI 服务器，比如 Hudson，但是 cron 作业也可以满足需要</strong> </span></span></span></span></li>
</ul>
<h4><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">我们来详细讨论这些组件。</span></span></span></span></h4>
<h4><a name="N10147"><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">自动的构建</span></span></span></span></a></h4>
<h4><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">CI 过程会经常集成软件，这需要通过构建来完成。在 Java 环境中，Ant 是常用的构建平台。可以使用 Ant 可靠地自动执行编译、测试等任务，甚至可以执行软件检查和部署。在掌握了 CI 的所有组件之后，您会发现构建策略是成功的 CI 过程最重要的方面。如果缺少适当的构建过程，CI 就难以发挥作用。</span></span></span></span></h4>
<h4><a name="N10150"><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">源代码管理</span></span></span></span></a></h4>
<h4><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">为了让 CI 正确地发挥作用，需要一个源代码管理（SCM）系统或存储库，比如 Subversion 或 CVS。CI 服务器向 SCM 存储库查询代码修改。在找到修改时，CI 服务器执行签出（即更新本地沙箱）并执行构建。除了执行得更频繁之外，构建过程与在本地环境中执行的构建相同。 </span></span></span></span></h4>
<h4><a name="N10159"><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">CI 服务器</span></span></span></span></a></h4>
<h4><span style="font-family: 宋体"><span><span style="font-size: 8pt"><span style="font-size: 10pt">对于成功的 CI 过程，需要用一个自动的过程监视 SCM 存储库并在探测到修改时运行构建，这也非常重要。对于 Java 平台，有许多可用的 CI 服务器，包括开放源码软件和商业产品。它们的基本配置都很相似，适合监视特定的 SCM 并在探测到修改时运行构建。所有 CI 服务器都有自己的优缺点。Hudson 尤其让人感兴趣，因为它容易配置而且具有强大的插件，这些插件可以显示测试结果趋势等信息。<br />
<p><span class="atitle">二.Hudson 简介</span></p>
<p><span style="font-size: 10pt">Hudson 是一种革命性的开放源码 CI 服务器，它从以前的 CI 服务器吸取了许多经验教训。Hudson 最吸引人的特性之一是它很容易配置：很难找到更容易设置的 CI 服务器，也很难找到开箱即用特性如此丰富的 CI 服务器。Hudson 容易使用的第二个原因是它具有强大的插件框架，所以很容易添加特性。例如，一个 Hudson 插件可以随时间的推移跟踪 FindBugs 和代码覆盖。它还可以报告测试结果的趋势（来自 JUnit 或 TestNG）以及构建结果和对应的执行时间。 </span></p>
<p><span style="font-size: 10pt">Hudson 需要运行 Java 5。如果需要使用 Hudson 附带的嵌入式容器（Winstone）之外的其他容器，那么只需使用一种 Servlet 2.4 容器。对于大多数情况，Winstone 就足够了。<br />
</span></p>
<p><span class="atitle">三.Hudson使用</span></p>
<p><span style="font-size: 10pt">CI 过程的最后一个方面是 CI 服务器本身。CI 服务器在整个开发过程中的主要作用是控制者：当服务器在代码存储库中探测到修改时，它将运行构建的任务委托给构建过程本身。如果构建失败了，那么 CI 服务器将通知相关方面，然后继续监视存储库。它的角色看起来是被动的；但是，它是快速反映问题的关键。</span></p>
<p><a name="N10326"><span class="smalltitle"><span style="font-size: 10pt">安装 Hudson</span></span></a></p>
<p><span style="font-size: 10pt">使用 Hudson 的主要好处之一是它的设置很简单。在最简单的情况下，Hudson 只需要两个步骤：</span></p>
<ol>
    <li><span style="font-size: 10pt">下载最新的版本（它打包为一个 WAR 文件）。 hudson官方网址:https://hudson.dev.java.net/</span>
    <li><span style="font-size: 10pt">运行 <code>java -jar hudson.war</code>。 </span></li>
</ol>
<p><span style="font-size: 10pt">这样就可以了。因为下载的是一个 WAR 文件，所以如果愿意，可以将它部署在 Tomcat 或 JBoss 等容器中。这完全由您自己决定。当然，Hudson 假设在安装它的机器上运行着 Java 5，而且如果定义了 <code>JAVA_HOME</code> 环境变量，Hudson 就会使用它。（正如前面提到的，Hudson 需要 Java 5。）</span></p>
<p><span style="font-size: 10pt">在安装并运行 Hudson 之后（将 WAR 文件部署到 servlet 容器或从命令行执行 <code>java -jar hudson.war</code>），启动浏览器并访问默认安装位置。如果通过命令行运行 Hudson 而且您在本地机器上，那么可以访问 <code>http://localhost:8080/</code>。</span></span></span></span></span></p>
</h4>
<img alt="" src="http://www.blogjava.net/images/blogjava_net/xiaodu/d.JPG" border="0" /><br />
<strong><span style="font-size: 10pt">如果一切正常（实际上不太可能出问题），应该会看到图 2 所示的 Hudson 启动页面。</span><br />
</strong>
<p><a name="N10360"><span class="smalltitle"><span style="font-size: 10pt"><strong>配置 Hudson</strong></span></span></a></p>
<p><span style="font-size: 10pt"><strong>如果访问 Hudson 主页的本地实例并单击左上角的 Manage Hudson 链接，应该会看到图 3 所示的可配置选项列表。</strong></span></p>
<a name="figure3"><strong><span style="font-size: 10pt">图 3. 配置 Hudson 非常容易</span></strong></a><br />
<img height="625" alt="" src="http://www.blogjava.net/images/blogjava_net/xiaodu/e.JPG" width="1000" border="0" /><br />
<p><span style="font-size: 10pt"><strong>参数说明:<br />
system.message 填写一些说明信息<br />
Quiet period:hudson定时构建工程的时间(秒)<br />
&nbsp;<label class="attach-previous">Enable security</label>:设置hudson登陆的规则(默认为匿名登陆)<br />
TCP port for JNLP slave agents:不了解JNLP不敢胡写总之就是三种方式:固定(fixed) 随机(Radom) 不使用(disabled),使用固定时可以填入JNLP信息</strong></span></p>
<span style="font-size: 10pt"><strong>security realm:可以使用中间件容器,数据库,LDAP来验证安全,具体怎样用法没用过,以后会有更新,研究中.<br />
authorized:可以设置身份的验证方法:系统用户,匿名用户,自定义用户,还有继承用户(此处也在研究中,建议使用匿名用户)<br />
JDK installations:设置JDK的安装路径<br />
Shell executable:设置window shell命令<br />
Ant installation:设置ant 的安装路径<br />
mave installation设置mave的安装路径<br />
cvs executable:设置cvsnt执行进程的路径(cvs.exe)<br />
.cvspass file:设置cvsnt管理员文件的路径(passwd文件)<br />
e-mail notification:设置当发生错误时发送的邮箱地址<br />
hudson url:就是hudson的默认地址<br />
</strong></span>
<p><span style="font-size: 10pt"><strong>还可以配置服务器的其他几个方面，比如向 Hudson 提供一个电子邮件服务器的位置，以便在构建失败时接收电子邮件。根据您的组织设置电子邮件的方式，可能需要让系统管理员帮助设置这个特性。设置电子邮件并不是必需的；Hudson 还支持以 RSS 作为通知机制，对于某些人来说，这种方式比电子邮件更好。究竟选择哪些通知机制完全取决于您。（注意，这里说的是 &#8220;哪些&#8221;，也就是说，可以同时使用多种通知机制！）</strong></span></p>
<span style="font-size: 10pt">
<p><a name="N103A5"><span class="smalltitle"><span style="font-size: 10pt"><strong>在 Hudson 中配置项目</strong></span></span></a></p>
<span style="font-size: 10pt">
<p><span style="font-size: 10pt"><strong>既然 Hudson 已经能够与 SCM 存储库通信了，就该配置项目了。这个示例所用的项目称为 <code>solar-ci</code>。在 Hudson 主页上单击左上角的 New Job 链接。这时会看到图 5 所示的屏幕：</strong> </span></p>
<img alt="" src="http://www.blogjava.net/images/blogjava_net/xiaodu/f.JPG" border="0" /><br />
<br />
<p class="MsoNormal"><strong><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">该页面可以使我们通过</span><span lang="EN-US">hudson</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">来管理</span><span lang="EN-US">cvs</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">里的一个对应的工程</span></strong></p>
<p class="MsoNormal"><strong><span lang="EN-US">Project name:</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">工程名称</span></strong></p>
<p class="MsoNormal"><strong><span lang="EN-US">Description:</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">描述信息</span></strong></p>
<p class="MsoNormal"><strong><span lang="EN-US">Discard build:</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如果选择此项可以设置</span><span lang="EN-US">build</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">记录保存的天数</span><span lang="EN-US">,</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">或者</span><span lang="EN-US">build</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">记录保存的数理</span><span lang="EN-US">,</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">或者只保存最新的</span><span lang="EN-US">build</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">记录</span><span lang="EN-US">,</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">一般不需填写</span></strong></p>
<p class="MsoNormal"><strong><span lang="EN-US">Advance project options:</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">可以设置</span><span lang="EN-US">hudson</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">定时检查</span><span lang="EN-US">cvs</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">工程的时间间隔</span><span lang="EN-US">,</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">还可以指定</span><span lang="EN-US">cvs</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">工程</span><span lang="EN-US">check out</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">到本地的工程路径</span><span lang="EN-US">,</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">一般不需要填写</span></strong></p>
<p class="MsoNormal"><strong><span lang="EN-US">Source code management:</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">我们选择</span><span lang="EN-US">cvs</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">将出现以下参数</span><span lang="EN-US">:</span></strong></p>
<strong><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">Cvsroot:</span><span style="font-size: 10.5pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'">将写</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">cvs</span><span style="font-size: 10.5pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'">登陆字符串</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">,</span><span style="font-size: 10.5pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-family: 'Times New Roman'">格式</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">(</span><tt><span lang="EN-US" style="font-size: 12pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">:protocol:user:password@host:path),</span><span style="font-size: 12pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">例如<span lang="EN-US">:</span></span></tt><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"> </span><tt><span lang="EN-US" style="font-size: 12pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">:pserver:cvsadmin:1@127.0.0.1:2401:/CVSNT/Repository,</span><span style="font-size: 12pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">使用<span lang="EN-US">cvs</span>必填</span></tt><br />
&nbsp; </strong>
<p class="MsoNormal" style="mso-outline-level: 1"><a name="_Toc203280766"><tt><span lang="EN-US" style="font-size: 12pt"><strong>Modules:</strong></span></tt></a><strong><span style="mso-bookmark: _Toc203280766"><tt><span style="font-size: 12pt">填写<span lang="EN-US">cvs</span>仓库下的具体工程名<span lang="EN-US">, </span>使用<span lang="EN-US">cvs</span>必填</span></tt></span><tt><span lang="EN-US" style="font-size: 12pt"><O:P></O:P></span></tt></strong></p>
<strong><tt><span lang="EN-US" style="font-size: 12pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">Branch:</span><span style="font-size: 12pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">填写分支名称<span lang="EN-US">,</span>也可以勾选<span lang="EN-US">this is a tag,no a branch</span>指定标记名称</span></tt><br />
&nbsp; </strong>
<p class="MsoNormal"><tt><span style="font-size: 12pt"><strong>选择<span lang="EN-US">subversion</span>可以进行相应的<span lang="EN-US">subversion</span>设置<span lang="EN-US"><O:P></O:P></span></strong></span></tt></p>
<p class="MsoNormal"><strong><tt><span lang="EN-US" style="font-size: 12pt">Build trigger</span></tt><tt><span style="font-size: 12pt">可以设置<span lang="EN-US">hudson</span>自动执行的一些动作<span lang="EN-US">,build after others projects are built</span>指定<span lang="EN-US">hudson</span>构建完成后需要继续构建的工程名<span lang="EN-US"><O:P></O:P></span></span></tt></strong></p>
<p class="MsoNormal"><strong><tt><span lang="EN-US" style="font-size: 12pt">Build periodically </span></tt><tt><span style="font-size: 12pt">根据<span lang="EN-US">hudson</span>定义的语法规则来设定自动构建工程的时间间隔<span lang="EN-US"><O:P></O:P></span></span></tt></strong></p>
<p class="MsoNormal" style="mso-outline-level: 1"><a name="_Toc203280767"><tt><span lang="EN-US" style="font-size: 12pt"><strong>Post-build actions</strong></span></tt></a><tt><span lang="EN-US" style="font-size: 12pt"><strong> <O:P></O:P></strong></span></tt></p>
<p class="MsoNormal"><tt><span style="font-size: 12pt"><strong>设置一些构建完成后的动作<span lang="EN-US">,</span>如放邮件<span lang="EN-US">,</span>打包<span lang="EN-US">,</span>产生测试报告<span lang="EN-US">,</span>产生<span lang="EN-US">java doc </span>等<span lang="EN-US">.<O:P></O:P></span></strong></span></tt></p>
<p class="MsoNormal"><tt><span style="font-size: 12pt"><strong>点击<span lang="EN-US">ok</span>保存设置<span lang="EN-US"><O:P></O:P></span></strong></span></tt></p>
<strong>使用hudson<br />
<tt><span style="font-size: 12pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">进入刚配置的项目<span lang="EN-US">,</span>可以在左侧<span lang="EN-US">build history</span>看到历史的<span lang="EN-US">build</span>记录<span lang="EN-US">,</span>点击<span lang="EN-US">build now </span>可以手动执行构建动作<span lang="EN-US">,</span>完成后可以通过记录标记的颜色来看是否出错<span lang="EN-US">,</span>红色有错<span lang="EN-US">,</span>蓝色成功<span lang="EN-US">.</span>点击记录查看详细信息<span lang="EN-US">,</span>如果有变化<span lang="EN-US">hudson</span>将列出类信息</span></tt></strong></span></span> <br />
<br />
<strong>elipse插件应用<br />
eclipse updatesite:http://code.google.com/p/hudson-eclipse/<br />
重新打开eclipse在windows-&gt;preferences下将出现hudson选项,设置默认的hudson url保存.<br />
然后选择windows-&gt;open view打开hudson view<br />
如果你己经配置hudson项目将列出hudson的项目名称,右键菜单可以看到所有的执行菜单,使用还是很方便的,希望大家来完善这篇文章.<br />
</strong>
<img src ="http://www.blogjava.net/conans/aggbug/213462.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-08 23:01 <a href="http://www.blogjava.net/conans/articles/213462.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSP的Request session的有效时间应合理设置 </title><link>http://www.blogjava.net/conans/articles/212859.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Sun, 06 Jul 2008 07:04:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/212859.html</guid><description><![CDATA[之前写了个简单的jsp做压力测试，没想到出现的一个问题是当压力比较大的情况，运行比较久的话会出现一个现象，就是jvm的内存几乎被耗尽，用jprofiler查看会发现是有一个ConcurrentHashMap对象的内存一直在增长，而且没有释放的迹象，随后进入Debug模式，跟踪查找都有谁new了ConcurrentHashMap，因为测试场景中是个非常简单的jsp页面，发现只有jsp的Request session会创建这个ConcurrentHashMap，很久没写jsp了，猜测是request session的默认超时时间太长，所以导致高压力下(200并发，总共连续访问50万次，jvm内存1G)会出现内存一直没有回收的问题，后来打印了一下request session的默认超时(AS是jboss 4.2.2)，是半小时，如果这样的话确实是会有造成上面内存一直被占用的现象。<br />
这个jsp是这样的，非常简单：<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000">&lt;%</span><span style="color: #000000">@&nbsp;page&nbsp;contentType</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">text/html;charset=GBK</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">%&gt;</span><span style="color: #000000"><br />
Just&nbsp;Test.</span></div>
造成这个问题的具体原因需要结合session的机制来讲了，讲session机制的文章相当多，感兴趣的话可以参见以下两篇文章：<br />
http://www.builder.com.cn/2007/1123/650439.shtml<br />
http://bbs.chinaunix.net/viewthread.php?tid=1178466<br />
<br />
这个问题怎么说呢，只能说session用的时候要非常注意吧，毕竟是消耗内存资源的，而且通常session都不会去配置成即时invalidate，都是有一定的超时时间的，在这样的情况下，如果在超时时间范围内出现高访问量的话，是很有可能会造成问题的，因此超时时间的合理设置非常重要。<br />
<br />
ps: 好久没玩过jsp和session了，确实没太注意这种状况，对于熟悉jsp和session机制的人来说也许这是常识<br />
了，^_^，见谅见谅。<br />
如果页面上不需要session的话，可以这么做：<br />
&lt;%@ page session="false" %&gt;<br />
<img src ="http://www.blogjava.net/conans/aggbug/212859.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-07-06 15:04 <a href="http://www.blogjava.net/conans/articles/212859.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CAS 学习第一篇 </title><link>http://www.blogjava.net/conans/articles/211533.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Sun, 29 Jun 2008 14:21:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/211533.html</guid><description><![CDATA[CAS (Central Authentication Service)是Yale大学的ITS开发的一套JAVA实现的开源<br />
的SSO(single sign-on)的服务，CAS 分为服务端和客户端，在服务端开启SSL，服务器下发证书安装到各个客户端中，客户端在与服务器进行通讯验证时，将检验二者的证书是否一致。<br />
<br />
<strong>STEP 1，搭建Java Web服务器环境</strong> <br />
安装 JDK + Tomcat 6.0.14 ， HTTP端口8080 ， HTTPS端口8443 <br />
JAVA_HOME = D:\Java\jdk1.6.0_04 <br />
CATALINA_HOME = D:\Java\apache-tomcat-6.0.14 <br />
安装完毕，启动Tomcat ，在浏览器上 测试 http://Linly:8080/ <br />
<img alt="" src="http://linliangyi2007.javaeye.com/upload/picture/pic/8412/ba32f1af-7d93-3e62-8025-c6030be36e14.gif" _counted="undefined" /> <br />
出现上述界面，表明系统STEP1成功搭建。 <br />
<br />
<strong>STEP 2，使用Java Keytool工具为系统生成HTTPS证书，并为系统注册</strong> <br />
（Java Keytool相关资料可参阅：Java keytool 安全证书学习笔记）， 在DOS窗体运行以下指令（建议编写一个BAT批处理文件执行） <br />
[quote] <br />
cls <br />
rem please set the env JAVA_HOME before run this bat file <br />
rem delete alia tomcat if it is existed <br />
keytool -delete -alias tomcatsso -keystore %JAVA_HOME%/jre/lib/security/cacerts -storepass changeit <br />
keytool -delete -alias tomcatsso -storepass changeit <br />
<span style="color: blue">（注释： 清除系统中可能存在的名字为tomcatsso 的同名证书）</span> <br />
rem list all alias in the cacerts <br />
keytool -list -keystore %JAVA_HOME%/jre/lib/security/cacerts -storepass changeit <br />
<span style="color: blue">（注释： 列出系统证书仓库中存在证书名称列表）</span> <br />
rem generator a key <br />
keytool -genkey -keyalg RSA -alias tomcatsso -dname "cn=linly" -storepass changeit <br />
<span style="color: blue">（注释：指定使用RSA算法，生成别名为tomcatsso的证书，存贮口令为changeit，证书的DN为"cn=linly" ，这个DN必须同当前主机完整名称一致哦，切记！！！）</span>rem export the key <br />
keytool -export -alias tomcatsso -file %java_home%/jre/lib/security/tomcatsso.crt -storepass changeit <br />
<span style="color: blue">（注释： 从keystore中导出别名为tomcatsso的证书，生成文件tomcatsso.crt）</span>rem import into trust cacerts <br />
keytool -import -alias tomcatsso -file %java_home%/jre/lib/security/tomcatsso.crt -keystore %java_home%/jre/lib/security/cacerts -storepass changeit <br />
<span style="color: blue">（注释：将tomcatsso.crt导入jre的可信任证书仓库。注意，安装JDK是有两个jre目录，一个在jdk底下，一个是独立的jre，这里的目录必须同Tomcat使用的jre目录一致，否则后面Tomcat的HTTPS通讯就找不到证书了）</span> <br />
rem list all alias in the cacerts <br />
keytool -list -keystore %JAVA_HOME%/jre/lib/security/cacerts -storepass changeit <br />
<span style="color: blue">（注释：列出jre可信任证书仓库中证书名单，验证先前的导入是否成功，如果导入成功，应该在列表中能找到tomcatsso这个别名，如下图）[/</span>quote] <br />
<img alt="" src="http://linliangyi2007.javaeye.com/upload/picture/pic/8414/638423f6-375e-3e46-aa9d-dbff289ab02b.gif" _counted="undefined" /> <br />
同时，在D:\Java\jdk1.6.0_04\jre\lib\security目录下能找到&#8220;tomcatsso.crt&#8221;这个文件；在C:\Documents and Settings\Linly目录下能找到&#8220;.keystore&#8221;文件。 <br />
满足上述条件则STEP2部署完成。 <br />
<br />
<strong>STEP 3，配置Tomcat的HTTPS服务</strong> <br />
编辑D:\Java\apache-tomcat-6.0.14\conf下的server.xml文件，在connector的配置位置添加以下的配置： <br />
[quote]&lt;Connector protocol="org.apache.coyote.http11.Http11Protocol" <br />
port="8443" minSpareThreads="5" maxSpareThreads="75" <br />
enableLookups="true" disableUploadTimeout="true" <br />
acceptCount="100" maxThreads="200" <br />
scheme="https" secure="true" SSLEnabled="true" <br />
keystoreFile="C:/Documents and Settings/new/.keystore" keystorePass="changeit" <br />
truststoreFile="D:/Java/jdk1.6.0_04/jre/lib/security/cacerts" <br />
clientAuth="false" sslProtocol="TLS"/&gt;[/quote] <br />
<br />
启动Tomcat，访问https://linly:8443/，出现以下界面说明HTTPS配置生效： <br />
<img alt="" src="http://linliangyi2007.javaeye.com/upload/picture/pic/8416/7aada184-731a-390e-bcb2-a5c538fdd4bf.gif" _counted="undefined" /> <br />
<br />
<strong>STEP 4，为HelloWorldExample程序配置CAS过滤器</strong> <br />
访问http://linly:8080/examples/servlets/servlet/HelloWorldExample，出现以下界面说明应用正常启动： <br />
<img alt="" src="http://linliangyi2007.javaeye.com/upload/picture/pic/8418/7beec055-6090-354c-ae06-61776ab4e42c.gif" _counted="undefined" /> <br />
编辑D:\Java\apache-tomcat-6.0.14\webapps\examples\WEB-INF下的web.xml文件，添加如下信息： <br />
[quote]&lt;filter&gt; <br />
&lt;filter-name&gt;CAS Filter&lt;/filter-name&gt; <br />
&lt;filter-class&gt;edu.yale.its.tp.cas.client.filter.CASFilter&lt;/filter-class&gt; <br />
&lt;init-param&gt; <br />
&lt;param-name&gt;edu.yale.its.tp.cas.client.filter.loginUrl&lt;/param-name&gt; <br />
&lt;param-value&gt;https://Linly:8443/cas/login&lt;/param-value&gt; <br />
&lt;/init-param&gt; <br />
&lt;init-param&gt; <br />
&lt;param-name&gt;edu.yale.its.tp.cas.client.filter.validateUrl&lt;/param-name&gt; <br />
&lt;param-value&gt;https://Linly:8443/cas/serviceValidate&lt;/param-value&gt; <br />
&lt;/init-param&gt; <br />
&lt;init-param&gt; <br />
&lt;param-name&gt;edu.yale.its.tp.cas.client.filter.serverName&lt;/param-name&gt; <br />
&lt;param-value&gt;Linly:8080&lt;/param-value&gt; <br />
&lt;/init-param&gt; <br />
&lt;/filter&gt; <br />
[/quote] <br />
<br />
[quote] <br />
&lt;filter-mapping&gt; <br />
&lt;filter-name&gt;CAS Filter&lt;/filter-name&gt; <br />
&lt;url-pattern&gt;/servlets/servlet/HelloWorldExample&lt;/url-pattern&gt; <br />
&lt;/filter-mapping&gt; <br />
[/quote] <br />
<br />
拷贝casclient.jar文件到目录D:\Java\apache-tomcat-6.0.14\webapps\examples\WEB-INF\lib下。 <br />
由于我们使用的是Tomcat6.0.14，因此，还要拷贝commons-logging-1.0.4.jar到该目录下。 <br />
<br />
<strong>STEP 5，部署JA-SIG（CAS）服务器</strong> <br />
拷贝cas.war到D:\Java\apache-tomcat-6.0.14\webapps目录下。启动Tomcat，访问网址http://linly:8080/cas/index.jsp,出现以下画面： <br />
<img alt="" src="http://linliangyi2007.javaeye.com/upload/picture/pic/8420/19fcb758-d705-3445-b6d4-9e883dc2f0e5.gif" _counted="undefined" /> <br />
输入用户名/密码 ：linly/linly（任意两个相同的字窜），点击&#8220;登录&#8221;，出现以下画面： <br />
<img alt="" src="http://linliangyi2007.javaeye.com/upload/picture/pic/8422/2dbb6405-2cd2-3bb6-92bf-2a13404fab37.gif" _counted="undefined" /> <br />
表示CAS服务器配置运行成功。 <br />
<br />
<br />
<strong>STEP 6，测试JA-SIG（CAS）部署结果</strong> <br />
启动Tomcat。 <br />
测试使用浏览器登陆以下网址：http://linly:8080/examples/servlets/servlet/HelloWorldExample，页面将弹出以下认证框，点击&#8220;确定&#8221; <br />
<img alt="" src="http://linliangyi2007.javaeye.com/upload/picture/pic/8424/c93c4ce6-b32f-3581-8a24-d26e62bdb8cd.gif" _counted="undefined" /> <br />
<br />
页面将重定向到JA-SIG的SSO登录认证页面 <br />
<br />
<img alt="" src="http://linliangyi2007.javaeye.com/upload/picture/pic/8426/dfcedb9b-e2e7-308a-8a77-f36b5f4da310.gif" _counted="undefined" /> <br />
<br />
输入用户名=密码，如：linly/linly，则通过验证，进入应用的入口界面，如下： <br />
<img alt="" src="http://linliangyi2007.javaeye.com/upload/picture/pic/8428/819ae74c-e01c-3057-834f-7f1fac2649b5.gif" _counted="undefined" /> <br />
<br />
细心的用户将发现，此时的URL不再是： <br />
http://linly:8080/examples/servlets/servlet/HelloWorldExample， <br />
URL的尾端带上了一个ticket参数： <br />
http://linly:8080/examples/servlets/servlet/HelloWorldExample?ticket=ST-2-qTcfDrdFb0bWndWgaqZD <br />
到此，JA-SIG（CAS）服务器的初步SSO部署宣告成功
<img src ="http://www.blogjava.net/conans/aggbug/211533.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-06-29 22:21 <a href="http://www.blogjava.net/conans/articles/211533.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>中小型企业遗留系统转换指南</title><link>http://www.blogjava.net/conans/articles/210661.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Wed, 25 Jun 2008 11:46:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/210661.html</guid><description><![CDATA[<p><a name="N1005B"><span class="atitle">引言</span></a></p>
<p>成功的大型企业需要其 IT 部门通过跟上技术发展来保持高水准的竞争力。这通常需要代价很高的经常性投资以维护当前的 IT 投资和增添新的投资。然而，中小型企业通常只有有限的预算来设法现代化其 IT 基础设施和资产。通常可以注意到，中小型企业只有在充分利用当前 IT 投资以后才会考虑重大的升级。他们每隔几年进行一次较大规模的现代化投资，而不是连续地进行投资。 </p>
<p>&#8220;中小型企业&#8221;（small and medium business，SMB）这个术语非常主观并取决于若干因素，例如年度营业额、员工数量、业务的地理分布等等。就本文而言，我们的虚构公司 Mod Communications , Inc.（以下也称为&#8220;该公司&#8221;）是一家为中西部若干个城区的家庭客户和当地企业提供高速 Internet 接入、有线电视、本地和长途电话以及无线通信服务的电信服务提供商。该公司是需要现代化其 IT 系统的中小型企业的代表。该公司拥有 200 名员工，已有 20 年的经营历史，分支机构不超过 10 个，并拥有大约 75 名 IT 人员维护其当前的 IT 解决方案。</p>
<p>面对新的竞争，他们感觉到了为当前客户维持较高服务级别的压力。该公司希望着手进行遗留系统转换活动。该公司准备为转换活动做出重大投资，并正在寻求现代化路线图规划方面的帮助。本文是为 IT 顾问、架构师和解决方案开发人员准备的，并解释了如何分析该公司的当前现状、组织动力和挑战，并提供了一组 IT 转换活动建议。本文还演示了一些可在该解决方案开发过程中提供帮助的 IBM 产品和服务。</p>
<p>Mod Communications Inc. 的大多数应用程序都是客户信息控制系统（Customer Information Control System，CICS&#174;）应用程序，这些应用程序使用 COBOL 编写并运行在 IBM System z&#8482; 系列中的 IBM 中端大型机系统上。虽然这些应用程序继续尽最大可能地提供核心业务服务，但是它们非常庞大、独立并且难于修改。替换或从头重新构建这些应用程序会对当前业务流程产生破坏性的影响，并需要收集在过去 15 年里加入到系统中的业务智能和规则。采用某个基于面向服务的体系结构原则的渐进式遗留系统转换过程，是有选择地替换该公司的应用程序组合的更加经济合算和风险更低的方法。此方法的一个示例是使用 Java EE (Java&#8482; Enterprise Edition) 来开发将在诸如 IBM 推出的 Websphere&#174; Application Server 等应用程序服务器上运行的应用程序。新的应用程序将在可能和适当的任何场合重用现有的功能。在构建和部署新组件时，其使用范围超出目前应用程序的部分组件将公开为服务，以便在以后的开发工作中重用。</p>
<p>下面几个部分将解释 IT 架构师或顾问如何执行数据收集、分析和建议活动，并将遗留系统转换过程告知公司的重要高层管理人员。下面将从数据收集期间的各个步骤、分析阶段得出的各种输出、所确定的建议备选解决方案和针对转换规划的指示等方面对相关活动进行描述。</p>
<p><a name="N10079"><span class="atitle">数据收集</span></a></p>
<p>数据收集的重点在于获得关于业务活动、所使用的 IT 技术和 IT 投资等事项的当前状态的信息。然后可以分析该数据以确定转换机会。以下步骤将准备并执行有效的数据收集工作：</p>
<p><a name="N10083"><span class="smalltitle">步骤 A. 获得或准备公司的组织结构图</span></a></p>
<p>务必要了解公司的组织结构图，以便确定重要的团队成员和权力人物。Mod Communications, Inc. 的组织结构图表明，总裁和首席运营官（Chief Operating Officer，COO）以及执行副总裁（Executive Vice President ）将负责监督重要的业务和技术活动以及投资。对于日常职能和活动，该组织拥有诸如&#8220;操作组&#8221;、&#8220;业务服务组&#8221;、&#8220;财务服务组&#8221;和&#8220;通用开发组&#8221;等小组。其中每个小组都具有业务和技术人员。这些小组的负责人将向执行副总裁报告，并且是主要的业务和技术相关决策的权力人物。</p>
<p><a name="N1008D"><span class="smalltitle">步骤 B. 获得有关公司经营的初步信息</span></a></p>
<p>此步骤将为准备用于数据收集的详细问题集奠定基础。起初，可以从与高级人员进行的讨论中获得有关公司经营的粗略概况。在非正式的气氛中提出有关公司背景、公司发展、公司所属行业、优势、弱点、新机会、察觉到的竞争威胁、所获奖项以及类似主题的诱导性问题。</p>
<p>在 Mod Communications, Inc. 进行的有关转换活动的总体目标的讨论过程中，一名高级员工提到该公司作为中小型企业区段中的最佳员工工作场所之一而感到自豪。大多数员工都已经为该公司工作了 15 年以上。另一位高层管理人员提到实现面向服务的体系结构在公司日程上处于优先位置。该信息可以在分析阶段中提供重要的输入，以评估关于组织更改和准备情况的可能建议所具有的影响。</p>
<p><a name="N1009A"><span class="smalltitle">步骤 C. 准备用于详细信息收集的问卷调查</span></a></p>
<p>此类问卷上的问题应该跨越广泛的主题，例如业务目标、当前流程评估、应用程序组合评估、企业数据体系结构、基础设施和操作体系结构、面向服务的体系结构，以及治理。以下问题类似于一个样本集。</p>
<ul>
    <li>Mod Communications, Inc. 在未来三至五年的业务目标是什么？
    <li>当前用于为各方（例如客户、供应商等等）提供价值的业务流程（由人员和/或系统执行的活动集）是什么？请列出并提供简要的叙述。
    <li>业务流程是否具有文档记录？其中每个业务流程是否存在端到端的业务流程视图？
    <li>为未来三至五年计划的主要业务目标和远景是什么？其中一些示例包括改进服务请求周转时间、收入增加 <em>x</em> 倍、操作成本降低 <em>y</em> 倍、改进客户满意度指标等等。
    <li>所确定和分析的业务流程是否与业务目标和远景持续一致？当前，哪些业务流程可以认为是与业务目标和远景保持一致的，哪些是不一致的？
    <li>当前的应用程序是什么，它们支持哪些业务流程？
    <li>是否计划在即将到来的一年里设计、开发或实现任何新应用程序？请根据情况提供详细信息。
    <li>在当前应用程序中，业务逻辑关注事项是否与操作关注事项分离，从而支持操作上的松散耦合并促进软件和信息资产的重用？
    <li>是否存在针对遗留应用程序或功能子集的既定策略？遗留代码中是否存在将导致难于随时间推移而停用遗留系统的代码依赖性？
    <li>请提供有关当前企业数据体系结构、数据模型、维护以及增强方法、数据管理方面、数据仓库等的详细信息。
    <li>对于您的操作的某些方面，您是否必须依赖批处理数据传输？如果是，请详述。
    <li>请提供有关当前存在的硬件和软件基础设施的详细信息。
    <li>提供当前网络界面方法的详细信息。什么功能通过网络提供，以及在使用什么体系结构和产品？为将来的网络界面计划了什么附加功能？
    <li>请提供当前的设计、开发、测试和生产应用环境的详细信息。
    <li>是否准备了足够和有效的流程来处理以下有关当前操作环境的事项？这将包括用于变更管理、引入新技术和服务管理（如果适用的话）的流程。
    <li>您是否与第三方服务提供商或代理建立连接？如果是，该连接的性质是什么（例如，同步、异步、单向、双向）？
    <li>是否存在促进基于服务的体系结构的基础设施（例如，帮助实现应用程序之间的消息交换、消息转换、独立服务查找等技术）？如果是，请详述。
    <li>是否有团体在考虑跨功能应用程序的可重用性？
    <li>您关注 SOA 采用的动机是什么？是定位于实现附加的收入产生渠道（例如实现更快的新产品上市或获取新客户），还是通过促进当前应用程序及系统的更好可重用性和维护来降低成本？
    <li>您当前的 SOA 方向是什么？您计划将要使用的技术是什么？是否存在任何用于目标 SOA 体系结构的现有高级设计？
    <li>您是否有任何现有的 Web 服务实现？如果是，请提供详细信息。 </li>
</ul>
<p>来自 Mod Communications, Inc. 的高级人员群策群力，一起合作回答上述问题。</p>
<p><a name="N100EF"><span class="smalltitle">步骤 D. 计划安排与重要客户端团队成员的后续访谈</span></a></p>
<p>从问卷答案中，确定进一步的信息需求领域，并计划安排与重要人员的后续访谈。使用组织结构图来确定要访谈的其他人员。完成后续访谈时，数据收集阶段差不多就完成了。随后的解释说明可以通过电子邮件或电话来获得。</p>
<p>对于 Mod Communications, Inc.，将准备一个关于访谈成果的报告。该报告提供了公司 IT 环境和基础设施、IT 组织、主要角色和职责的当前状态摘要、应用程序组合概述、系统和功能摘要，以及当前治理、未来三至五年的业务远景和目标的简要概述。这可用作将来的所有工作的参考。</p>
<p><a name="N100FC"><span class="atitle">数据分析</span></a></p>
<p>在数据分析过程中，研究收集到的相关资料和文档信息，以分析各种备选解决方案，从而提供建议。按以下几个方面对信息进行组织：</p>
<ul>
    <li>对 IT 转换的成功最重要和最关键的业务远景和目标，以及指标。
    <li>难点。这些是公司正在尝试解决的关键业务和技术问题。
    <li>解决方案建议所要考虑的约束。
    <li>应用程序组合分析的发现结果。 </li>
</ul>
<p>对于 Mod Communications, Inc.，以下是重要的业务远景和目标：</p>
<ul>
    <li>实现业务各方之间改进的信息流，包括客户、客户服务代表、技术人员以及销售和市场代表。计划通过此目标削减 7 - 10% 的业务开支。
    <li>通过现代化活动和新技术采用来处理公司的客户保留问题。创建现代化路线图。向重要客户和员工传达该路线图。
    <li>提高软件和应用程序开发这个重要流程的效率。公司需要简化活动和任务，以推动更高的团队成员效益和工作效率。目前，预计要发布的实际软件或应用程序要在发布日期之前一个星期才能准备就绪。通过提高流程效率将此时间提前为两个星期。满足此目标可以降低压力级别，同时还可以提供更多的时间进行有关该发布的附加测试、交流和其他活动。
    <li>通过新技术和更好的直观用户界面降低培训和支持成本。预计通过此目标将培训成本削减 15%。
    <li>最近的一项调查表明，该公司的内部应用程序供应感觉非常缓慢，尽管该解决方案所提供的全面功能获得了好评。开发团队需要使用最新技术使业务解决方案对用户更有吸引力。公司应该通过更好的用户界面设计来促进易用性和工作职能效率改进。
    <li>提高市场竞争地位，同时吸引更多销售潜力。通过遗留资产的现代化，使销售主管能够吸引更多销售潜力并赢得更多业务。 </li>
</ul>
<p>基于与团队成员进行的有关该公司使用的当前流程和实践的详细讨论，以下是重要的难点和问题场景：</p>
<ul>
    <li>随着时间推移，代码变得日益难于维护。因此，引入更改将要花更多的时间。这导致维护成本增加，给定版本所接受的增强功能请求数量减少。开发人员的工作效率有待提高。
    <li>公司不能容易地招募新的开发人员来从事 COBOL 方面的工作，COBOL 是目前使用的主要编程语言。此外，要让新的开发人员在短期内高效地工作也非常困难。
    <li>技术文档和信息非常有限，并且构建和发布过程很不可靠。
    <li>需求、设计以及代码和测试需求之间的可跟踪性非常有限。这导致维护和代码修改工作非常耗时，并且无法准确预测时间和成本。
    <li>公司拥有几名对公司的业务、遗留系统和数据库非常了解的过程开发人员，但他们不具备使用现代编程语言所必需的面向对象技能。
    <li>公司缺乏用于测试发布准备情况的测试用例主集，并且缺陷跟踪也不够全面。缺陷的根源分析跟踪非常随意，没有进行广泛的文档记录。 </li>
</ul>
<p>对于 Mod Communications, Inc.，解决方案建议需要考虑的各种约束如下：</p>
<ul>
    <li>公司在技术方面拥有几名非常了解业务方面、代码结构和数据库的团队成员。然而，由于目前的应用程序维护和对增强功能的承诺，不能期待这些资源在转换工作期间的大规模可用性和参与。
    <li>该公司的几乎所有技术团队成员在 COBOL 编程方面都非常优秀。然而，他们缺乏有关面向对象的方法和最新技术的知识。该公司希望保留大多数技术人员，因为他们非常了解该业务解决方案。该公司还因为善待员工而获奖，据行业调查表明这是个工作的好地方。
    <li>该公司的代码文档非常有限。 </li>
</ul>
<p>该公司的应用程序组合分析提供了以下信息： </p>
<ul>
    <li>应用程序主要基于大型机。
    <li>20 个主要应用程序。
    <li>15 个应用程序有 7 年以上的历史。
    <li>所有应用程序都随着时间推移而进行了大量的自定义。 </li>
</ul>
<p>该公司一直使用 IBM Host Access Transformation Services (HATS) 来将某些应用程序从已有基于字符的屏幕界面转换为 Web 用户界面。这使该公司可以快速将现有的基于字符的屏幕界面转换为网页和表单，从而将 Web 通道用于其遗留应用程序。该公司应该通过创建基于最终用户输入、易用性、导航和上下文内容呈现的新用户界面来对此进行改进。</p>
<p><a name="N10169"><span class="atitle">解决方案建议</span></a></p>
<p>下一步是为客户交付一组解决方案建议。</p>
<p>基于对信息的分析，为重要的 Mod Communications, Inc. 高层管理人员准备一个解决方案建议，以从资金和项目决策方面说明后续步骤。</p>
<p>核心建议是让公司在保留其当前遗留应用程序组合的价值的同时，逐渐地迁移到可促进松散耦合的体系结构的新技术。一个建议是采用 Java Enterprise Edition (Java EE) 作为进行遗留系统转换的合适应用程序技术。Java EE 方法使公司可以开发能够提供出色的图形和多通道用户界面的应用程序，同时还为面向服务的体系结构做好定位。这导致对各种方法进行分析以实现 Java EE 环境。这些方法如下：</p>
<p><strong>a) 替换：</strong>将诸如服务订单管理、问题报告和管理及计费系统等当前核心应用程序替换为商业化现成（commercial off-the-shelf，COTS）应用程序。然后自定义和配置该应用程序和界面。这是实现转换的快速方法，但它在客户接受、对现有业务流程和功能的影响、组织变更和培训需求方面引入了风险。</p>
<p><strong>b) 重新编写：</strong>使用 Java EE 方法重新编写应用程序。优先重新编写将经历转换的应用程序。对这些应用程序执行基于方法的完整软件生命周期开发，包括需求分析、设计以及开发和测试。已知当前应用程序的数据库层结构非常良好和高效。在可能的情况下，新组件可以重用数据库层的功能。 </p>
<p><strong>c) 大规模转换然后客户化定制：</strong>这是选项 b) 的一种变化形式。在此情况下，将使用自动化的工具执行所有应用程序到 Java EE 组件的大规模转换。然后修改所得到的组件以适合需求。 </p>
<p><strong>d) 渐进地转换到目标平台组件：</strong>使用基于 Java EE 的体系结构来构建过渡环境。从当前遗留系统中公开的&#8220;幕后&#8221;模块将提供实现。渐进地在目标平台上编写代码以取代对遗留模块的依赖。 </p>
<p><strong>e) 使用第 4 代语言（4th Generation Language，4GL）方法渐进地转换：</strong>在此情况下，将使用某种 4GL 语言来定义应用程序。使用工具将 4GL 结构自动转换为 Jave EE 组件，然后将后者部署在目标平台上。例如，此方法可以使用 IBM 企业生成语言（Enterprise Generation Language，EGL）来实现，并且很适合于非常精通诸如 COBOL 等程序语言的程序员，他们将不必学习诸如 Java 等面向对象的语言。</p>
<p>从诸如成本、工作量、时间和复杂性等方面分析上述建议，然后按照下面图 1 所示的方式对这些建议进行归类：每个参数都具有一个优先级名称——&#8220;高 (H)&#8221;、&#8220;中 (M)&#8221;或&#8220;低 (L)&#8221;。</p>
<br />
<a name="fig1"><strong>图 1. 对各种备选解决方案方法建议的分析</strong></a><br />
<img height="376" alt="各种备选解决方案的分析图解" src="http://www.ibm.com/developerworks/cn/architecture/ar-legtrans/AlternativeAnalysis.gif" width="482" /> <br />
<p>下面是一些补充建议：</p>
<ol>
    <li>采用模型-视图-控制器（Model-View-Controller，MVC）体系结构模式以确保体系结构的灵活性。使用此方法，数据（模型）和用户界面（视图）将彼此分离，以便对一个方面的更改不会影响另一个方面。控制器处理并响应用户操作。
    <li>优先考虑要转换的应用程序，以便在对业务具有最少中断的情况下获得递增的业务好处。优先考虑影响客户感受的应用程序，例如服务订单管理、故障单管理和新服务的供应。这样可以将重点充分集中在从客户和业务用户角度看来最重要的应用程序上。这样可以帮助获得客户信任、采用、保留和改进的满意度。
    <li>建立 IT 治理管理委员会，确保 IT 投资处于正轨，以在可接受的风险预测内产生预期的投资回报。该委员会应该监督技术活动、重要参与者之间的交流、标准化活动和体系结构审核。
    <li>采用方法驱动的步骤进行软件开发。这会提供更好地规划和管理各种转换项目的任务、日程安排、预算的能力。这还有助于更好地管理风险，例如成本超支、时间和功能覆盖率风险。IBM GS-Method 和 Rational&#174; Unified Process (RUP) 就是此类方法的示例。
    <li>对于从需求到设计以至开发和测试的每个开发生命周期阶段采用最新的工具。这可以实现更好的文档、可跟踪性和控制，并具体化方法驱动的步骤。IBM Rational 产品和工具组合具有满足软件开发生命周期和治理需求的丰富工具集。请参见<a href="http://www.ibm.com/developerworks/cn/architecture/ar-legtrans/?ca=drs-tp2508#resources" cmimpressionsent="1">参考资料</a>部分以获得指向更多信息的链接。
    <li>构建和主动管理服务模型：各种应用程序组件将是在其他应用程序中重用的直接候选组件。通过主动辨别跨部门边界所需的服务，将来的开发和维护工作将会得益不少。这还可以推动功能的重用。
    <li>执行遗留资产的审核：这可以帮助从当前系统中获得重要信息，例如业务规则。它还有助于了解业务功能和模块化工作。一些现有的遗留代码可以组件化，并公开为服务以供新系统使用，直到将遗留代码替换为新组件。
    <li>对于中长期而言，应评估可在应用程序之间的消息交换、消息变换和转换以及独立服务查找方面，进一步促进整个组织中的面向服务的基础设施软件的采用。在这方面，IBM WebSphere 组合提供了若干个产品。请参见<a href="http://www.ibm.com/developerworks/cn/architecture/ar-legtrans/?ca=drs-tp2508#resources" cmimpressionsent="1">参考资料</a>部分以获得指向有关这些产品的网页的链接。
    <li>评估规则引擎技术的采用，以在捕获和使用业务规则方面引入效率。目前，该公司的代码资产非常脆弱，因为在这些年来，代码中已引入了各种对业务规则的更改。目前，业务规则与主代码紧密耦合，使得在做出更改时必须小心谨慎，同时还增加了测试需求。
    <li>在初始项目中利用外部专家或顾问：这允许更好地集中于现代化工作，并为现有人员提供更多时间来跟上新技术的发展步伐。在现代化工作期间，完全使用现有人员也许无法应付过去，因为团队成员将会忙于满足当前承诺。此建议可以通过与服务提供商的一个或多个服务约定来实现。例如，IBM Global Services 就拥有这方面的各种解决方案。 </li>
</ol>
<p>提供一组在现代化期间优化内部操作的建议，以便为当前人员提供更多参与机会。这些建议包括：</p>
<ol>
    <li>减少软件发布周期数量，同时将重点更改为仅集中于最关键的增强功能领域：这允许将资源集中于对客户满意度、保留和获取非常关键的领域。
    <li>根据逻辑相关的领域对维护项目进行分组：这有助于提高开发人员的工作效率。
    <li>创建并使用一套全面的测试用例：在开发和维护周期中，会发生以下一种或多种情况：1) 更改现有的功能/数据结构，2) 引入新的功能/数据结构，3) 在完成项目 1 和/或 2 的同时确定并修复错误。由于应用程序具有如此多相互关联的部分，必须以有组织的方式执行测试以实现全面的覆盖率。在这方面，全面的测试套件可以提供好处。
    <li>评估所要采用的帮助台工具：以便提高快速查找、分析和解决问题的能力。此类工具还可以通过分析问题趋势，从而帮助确定问题正在增多的应用程序领域。用于处理问题的知识库的更好文档记录和创建也是非常有益的成果。 </li>
</ol>
<p>请注意，这些建议会因情况而异，并且应该基于与某个情形有关的相关信息。上述案例研究只是一个用作指导原则的示例。</p>
<p><a name="N101EC"><span class="atitle">转换规划</span></a></p>
<p>基于所选的建议，为执行团队草拟出详细的转换计划。这包括短期（一至两年）、中期（两至三年）和长期（五年）的项目计划。创建活动（项目）、活动的业务价值、持续时间、大致成本和资源需求的摘要。这有助于推动资金分配决策和成果。</p>
<p>转换规划期间的重要考虑事项之一涉及到硬件或遗留平台的现代化。在这一点上，评估重用可能性也是最有利的。例如，客户拥有一个 System z 系列中的 IBM 中端大型机系统。该系统的功能之一是能够在运行 AIX&#174; 和 WebSphere Application Server 的单独分区上运行 Java 工作负载。该系统的此功能可用于实现重用，并且是确定投资需求时的一个重要考虑事项。请参见<a href="http://www.ibm.com/developerworks/cn/architecture/ar-legtrans/?ca=drs-tp2508#resources" cmimpressionsent="1">参考资料</a>部分以获得指向更多信息的链接。</p>
<p><a name="N101FF"><span class="atitle">结束语</span></a></p>
<p>本文提供了深入的见解，说明了如何为中小型企业的主要高层管理人员提供遗留系统转换和现代化活动的建议和指导。本文介绍了如何通过执行数据收集、分析和建议步骤，并提供转换规划信息以支持资金分配决策，从而有条不紊地完成该任务。</p>
<img src ="http://www.blogjava.net/conans/aggbug/210661.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-06-25 19:46 <a href="http://www.blogjava.net/conans/articles/210661.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>OSGi起步(OSGi for Beginners) </title><link>http://www.blogjava.net/conans/articles/210660.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Wed, 25 Jun 2008 11:45:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/210660.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 一年一度的Ig Nobel prize典礼都都会带来一些非常新颖的观点、发现，这些内容甚至超过了Ig Nobel prizes本身。每位获奖者在做完七个字的总结后，还有机会利用24秒的时间对自己的新观点、新发现进行阐述。 &nbsp; 这是一个极其绝妙的主意，这对每位获奖者都是一个需要完成的挑战。 &nbsp; OSGi 是近来业界经常提到的事物，随着Equinox成为Eclips...&nbsp;&nbsp;<a href='http://www.blogjava.net/conans/articles/210660.html'>阅读全文</a><img src ="http://www.blogjava.net/conans/aggbug/210660.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-06-25 19:45 <a href="http://www.blogjava.net/conans/articles/210660.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 用 Firebug 动态调试和优化应用程序</title><link>http://www.blogjava.net/conans/articles/209619.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Fri, 20 Jun 2008 15:26:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/209619.html</guid><description><![CDATA[<p><a name="N10053"><span class="atitle">简介</span></a></p>
<p>Firebug 是 Mozilla Firefox 浏览器的开源扩展，提供了很多工具，可以监视、编辑和调试任何 Web 站点的级联样式表（CSS）、HTML、文档对象模型（DOM）和 JavaScript。Firebug 包括一个 JavaScript 控制台、一个日志记录 API 以及一种有用的网络监视器。借助 Firebug，可以很轻松地调试和优化 Web 和 Ajax 应用程序。</p>
<p>本文将帮助您熟悉所如下的 Firebug 特性： </p>
<ul>
    <li>编辑活动 Web 页面的 HTML、CSS 和 JavaScript
    <li>调试和剖析报告
    <li>进行日志记录以测试执行时间
    <li>使用 Network Monitor 分析 Web 页面的加载时间
    <li>错误报告 </li>
</ul>
<p>&nbsp;</p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="N10077"><span class="atitle">立即开始</span></a></p>
<p>使用 Firefox，<a href="http://www.getfirebug.com/" cmimpressionsent="1"><font color="#5c81a7">下载 Firebug</font></a>。通过单击页面右侧的橙色按钮 <strong>Install Firebug</strong> 安装此扩展。 </p>
<p>Firefox 安装了此扩展后，重启浏览器。要使用 Firebug： </p>
<ol>
    <li>转到任何一个 Web 页面并按 <strong>F12</strong> 在浏览器窗口打开 Firebug。
    <li>按 <strong>CTRL-F12</strong> 在另一个窗口打开 Firebug（如果有两个监视器，这是一个很好的特性）。
    <p>本文使用了第一种方法在相同的浏览器窗口中打开 Firebug，如图 1 所示：</p>
    </li>
</ol>
<p>&nbsp;</p>
<br />
<a name="fig1"><strong>图 1. 安装后的 Firebug</strong></a><br />
<img height="608" alt="安装后的 Firebug" src="http://www.ibm.com/developerworks/cn/web/wa-aj-firebug/firebug1.jpg" width="543" /> <br />
<p>安装后，Firebug 是禁用的。单击 <strong>Enable Firebug</strong> 启用它，如图 2 所示：</p>
<br />
<a name="fig2"><strong>图 2. Firebug 显示了 developerWorks 的首页</strong></a><br />
<img height="769" alt="Firebug 显示了 developerWorks 的首页" src="http://www.ibm.com/developerworks/cn/web/wa-aj-firebug/firebug2.jpg" width="572" /> <br />
<p>本文的后面的内容将讨论 Firebug 的特性。 </p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="N100CF"><span class="atitle">HTML 和 CSS 工具</span></a></p>
<p>HTML 和 CSS 工具包括：HTML 检查和编辑、CSS 编辑和 CSS 可视化。 </p>
<p><a name="N100D8"><span class="smalltitle"><strong><font size="3">检查和编辑 HTML</font></strong></span></a></p>
<p>可以使用 HTML 检查特性在源代码中定位可视 HTML。</p>
<ol>
    <li>在 Firebug 窗口，单击 <strong>Inspect</strong>。
    <li>将鼠标移到任何一个 HTML 组件之上。这样就可以在 Firebug 窗口上看到该 HTML 元素（被蓝色方框围绕）和 HTML 源代码。如图 3 的示例： <br />
    <br />
    <a name="fig3"><strong>图 3. 在 Firebug 检查 HTML</strong></a><br />
    <img height="773" alt="在 Firebug 检查 HTML" src="http://www.ibm.com/developerworks/cn/web/wa-aj-firebug/firebug3.jpg" width="567" /> <br />
    <br />
    <li>单击选中的 HTML 元素。有趣的是这会使此次检查&#8220;锁定&#8221;到所选定的元素。
    <li>可以转到 Firebug 窗口并单击 <strong>Edit</strong> 编辑选定的元素。
    <p>图 4 给出了 Firebug 编辑窗口以及浏览器窗口中已编辑的文本。&#8220;Editing with Firebug&#8221; 已经代替了原先的 Ajax 标题。</p>
    <br />
    <br />
    <a name="fig4"><strong>图 4. 编辑 HTML</strong></a><br />
    <img height="771" alt="编辑 HTML" src="http://www.ibm.com/developerworks/cn/web/wa-aj-firebug/firebug4.jpg" width="568" /> <br />
    <br />
    </li>
</ol>
<p>在检查元素时，将会看到 Firebug 窗口内的元素嵌套，如图 5 所示：</p>
<br />
<a name="fig5"><strong>图 5. 元素嵌套</strong></a><br />
<img height="30" alt="元素嵌套" src="http://www.ibm.com/developerworks/cn/web/wa-aj-firebug/firebug5.jpg" width="351" /> <br />
<p><a name="N10129"><span class="smalltitle"><strong><font size="3">编辑 CSS</font></strong></span></a></p>
<p>还可以通过检查这个 Web 页面进行 CSS 编辑。Inspection 视图会显示相关的 CSS 条目，包括继承样式。如图 6 的示例： </p>
<br />
<a name="fig6"><strong>图 6. CSS 检查</strong></a><br />
<img height="291" alt="CSS 检查" src="http://www.ibm.com/developerworks/cn/web/wa-aj-firebug/firebug6.jpg" width="566" /> <br />
<p>CSS 工具还可用来编辑 CSS 即时属性、禁用属性、自动完成和图片预览，如图 7 所示： </p>
<br />
<a name="fig7"><strong>图 7. CSS 图片预览</strong></a><br />
<img height="290" alt="CSS 图片预览" src="http://www.ibm.com/developerworks/cn/web/wa-aj-firebug/firebug7.jpg" width="567" /> <br />
<p><a name="N10153"><span class="smalltitle"><strong><font size="3">CSS 的可视化</font></strong></span></a></p>
<p>CSS 的可视化在检查 HTML（回顾 <a href="http://www.ibm.com/developerworks/cn/web/wa-aj-firebug/#fig3" cmimpressionsent="1"><font color="#996699">图 3</font></a> 中的蓝色边框）已经展示过了。Firebug Layout 选项卡显示了更多的信息，比如间隙、 偏移和其他相关的量度。图 8 中的布局窗口则显示了一个导航元素的量度： </p>
<br />
<a name="fig8"><strong>图 8. CSS 盒的量度</strong></a><br />
<img height="758" alt="CSS 盒的量度" src="http://www.ibm.com/developerworks/cn/web/wa-aj-firebug/firebug8.jpg" width="567" /> <br />
<p>图 9 展示了能即时编辑 CSS 盒的奇妙的 Firebug 特性： </p>
<br />
<a name="fig9"><strong>图 9. CSS 盒编辑</strong></a><br />
<img height="758" alt="CSS 盒编辑" src="http://www.ibm.com/developerworks/cn/web/wa-aj-firebug/firebug9.jpg" width="565" /> <br />
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="N10181"><span class="atitle">JavaScript 工具</span></a></p>
<p>现在，JavaScript 工具是 Web 开发中最有用的工具之一。Firebug 提供了调试、剖析、日志记录和命令行控制台特性。 </p>
<p><a name="N1018A"><span class="smalltitle"><strong><font size="3">调试和剖析</font></strong></span></a></p>
<p>Firebug JavaScript 工具包括断点、监视表达式和典型调试器中常见的其他一些工具。图 10 展示了断点和逐步调试的实际例子。请注意作为工具提示的主机变量的值。</p>
<br />
<a name="fig10"><strong>图 10. JavaScript 调试器</strong></a><br />
<img height="810" alt="JavaScript 调试器" src="http://www.ibm.com/developerworks/cn/web/wa-aj-firebug/firebug10.jpg" width="566" /> <br />
<p>有用的调试工具能： </p>
<ul>
    <li>直接导航到 JavaScript 中的特定行
    <li>监视表达式（可以是任意的 JavaScript 表达式）
    <li>以可视格式调用堆栈
    <li>条件断点
    <li>错误后进行调试的能力 </li>
</ul>
<p>&nbsp;</p>
<p>JavaScript 剖析非常有用。如 Firebug 中的其他特性一样，剖析也很容易使用。单击 Console 选项卡上的 <strong>Profile</strong> 启动剖析器，如图 11 所示： </p>
<br />
<a name="fig11"><strong>图 11. 启动 JavaScript 剖析器</strong></a><br />
<img height="109" alt="JavaScript 剖析器" src="http://www.ibm.com/developerworks/cn/web/wa-aj-firebug/firebug11.jpg" width="567" /> <br />
<p>剖析开始后，可以浏览一下此站点。单击 <strong>Profile</strong> 获得剖析报告，如图 12 所示： </p>
<br />
<a name="fig12"><strong>图 12. JavaScript 剖析器报告</strong></a><br />
<img height="812" alt="JavaScript 剖析器报告" src="http://www.ibm.com/developerworks/cn/web/wa-aj-firebug/firebug12.jpg" width="565" /> <br />
<p>该报告显示了花在函数上的时间和平均时间等等。 </p>
<p><a name="N101E4"><span class="smalltitle"><strong><font size="3">JavaScript 日志记录 </font></strong></span></a></p>
<p>对于更愿意使用老的日志记录（而非调试）方式的开发人员，Firebug 提供了日志记录功能。日志记录使用的是一种 Firebug JavaScript API。最简单的一种日志条目是 <code>console.log("logging");</code>。</p>
<p>Console API 包含其他一些功能，如清单 1 所示： </p>
<br />
<a name="listing1"><strong>清单 1. Firebug Console API 示例</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">
            console.time("test timer");
            console.log("Hello from ",document.title);
            console.info("This is info");
            console.warn("This is warning");
            console.error("This is error");
            console.timeEnd("test timer");
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>可以使用 <code>console.time</code> 和 <code>console.timeEnd</code> 来测量执行时间。在详细报告中显示结果的 <code>console.profile()</code> 和 <code>console.profileEnd()</code> （见清单 1）也可用来测量执行时间。</p>
<p>图 13 显示了这些结果。JavaScript 控制台日志测试功能被添加到由 Web 服务器提供服务的页面中。</p>
<br />
<a name="fig13"><strong>图 13. Console 日志</strong></a><br />
<img height="524" alt="Console 日志" src="http://www.ibm.com/developerworks/cn/web/wa-aj-firebug/firebug13.jpg" width="567" /> <br />
<p>Console API 内其他有用的特性还有堆栈跟踪、对象检查和字符串格式化。 </p>
<p><a name="N10226"><span class="smalltitle"><strong><font size="3">JavaScript 命令行</font></strong></span></a></p>
<p>Firebug 最为强大特性之一就是 JavaScript 命令行。这种命令行的使用方式与其他命令行一样；它执行您编写的所有 JavaScript 代码，好像它们就是页面的一部分一样。通过命令行，可以检查 DOM、获得属性等等。所有返回值都显示在控制台上。</p>
<p>命令行具有自动完成功能（使用 Tab 键）以及完善的文本编辑器（能够编写完整的函数而不仅仅是几行代码）等等。图 14 给出了一个简单的控制台会话。请注意 Web 页面左上角的徽标。这里也可以进行即时编辑。</p>
<br />
<a name="fig14"><strong>图 14. 命令行 JavaScript</strong></a><br />
<img height="812" alt="命令行 JavaScript" src="http://www.ibm.com/developerworks/cn/web/wa-aj-firebug/firebug14.jpg" width="569" /> <br />
<p>与控制台类似，命令行也有一个 API，它包含可用于 Firebug 的特殊函数，比如 <em>$(id)</em>。该函数能够返回带有给定 id 的元素。 </p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="N10247"><span class="atitle">网络监控</span></a></p>
<p>Firebug Network Monitor 特性可用来监视加载 Web 页面所花费的时间。使用 Net 选项卡可以看到进度栏，该进度栏显示了一个文件相对所有其他文件开始和停止加载的时间。Network Monitor 分开每个文件的流量，因此就可以查看加载图像、JavaScript、HTML 等各占用了多少时间。此外，还可以查看资源是否从浏览器缓存中加载。</p>
<p>对于本例中的 Ajax 开发，Firebug 在 Net 选项卡和 Console 选项卡中均显示了每个 XMLHttpRequest。 </p>
<p>图 15 显示了如何利用 Network Monitor 查看 HTTP 请求和响应头。要查看 HTTP 头，只需单击每个请求左侧的箭头将其展开。全部请求、已用时间和内容的大小均显示在 Firebug 窗口底部。</p>
<br />
<a name="fig15"><strong>图 15. Network Monitor</strong></a><br />
<img height="836" alt="Network Monitor" src="http://www.ibm.com/developerworks/cn/web/wa-aj-firebug/firebug15.jpg" width="566" /> <br />
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="N10265"><span class="atitle">其他特性</span></a></p>
<p>Firebug 的其他特性包括：</p>
<p><a name="N1026E"><span class="smalltitle"><strong><font size="3">错误报告</font></strong></span></a></p>
<p>一旦错误发生，Firebug 能够提供有用的：</p>
<ul>
    <li>状态栏指示器
    <li>行号、文件和堆栈跟踪
    <li>调试器集成
    <li>搜索和过滤器 </li>
</ul>
<p>Firebug 还会显示只与所查看的页面相关的错误。</p>
<p><a name="N10289"><span class="smalltitle"><strong><font size="3">DOM</font></strong></span></a></p>
<p>Document Object Model 是 Web 页面中的对象和函数的等级结构。Firebug DOM 包括所有定制的和标准的对象，而且 DOM explorer 能够分辨它们。这里同样可以进行 JavaScript 代码导航、自动完成和即时编辑。</p>
<p><a name="N10292"><span class="smalltitle"><strong><font size="3">定制</font></strong></span></a></p>
<p>Firebug 定制特性包括黑名单和白名单以及依据个人需要更改字体大小的功能。</p>
<img src ="http://www.blogjava.net/conans/aggbug/209619.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-06-20 23:26 <a href="http://www.blogjava.net/conans/articles/209619.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>连接各种数据库方式速查表</title><link>http://www.blogjava.net/conans/articles/209591.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Fri, 20 Jun 2008 15:05:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/209591.html</guid><description><![CDATA[1、Oracle8/8i/9i数据库（thin模式）<br />
Class.forName("oracle.jdbc.driver.Oracl<span id="S__699_ADDIV_2" onmouseover="S__699.SHOWFLOW('ED','2',event);this.style.textDecoration='none';" style="cursor: pointer; color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="S__699.SHOWFLOW('ED','2',event);" onmouseout="S__699.hidden('2');;this.style.textDecoration='underline';" oncontentextmenu="return false">ED</span>river").newInstance();<br />
String url="jdbc:oracle:thin:@localhost:1521:orcl"; //orcl为数据库的SID<br />
String user="scott";<br />
String password="tiger";<br />
Connection conn= DriverManager.getConnection(url,user,password);<br />
<br />
<br />
　　2、DB2数据库<br />
Class.forName("com.ibm.db2.jdbc.app.DB2Driver ").newInstance();<br />
String url="jdbc:db2://localhost:5000/sample"; //sample为你的数据库名<br />
String user="admin";<br />
String password="";<br />
Connection conn= DriverManager.getConnection(url,user,password);<br />
<br />
<br />
　　3、Sql Server7.0/2000数据库<br />
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance();<br />
String url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=mydb";<br />
//mydb为数据库<br />
String user="sa";<br />
String password="";<br />
Connection conn= DriverManager.getConnection(url,user,password);<br />
<br />
<br />
　　4、Sybase数据库<br />
Class.forName("com.sybase.jdbc.SybDriver").newInstance();<br />
String url =" jdbc:sybase:Tds:localhost:5007/myDB";//myDB为你的数据库名<br />
Properties sysProps = System.getProperties();<br />
SysProps.put("user","userid");<br />
SysProps.put("password","user_password");<br />
Connection conn= DriverManager.getConnection(url, SysProps);<br />
<br />
5、Informix数据库<br />
Class.forName("com.informix.jdbc.IfxDriver").newInstance();<br />
String url = "jdbc:informix-sqli://123.45.67.89:1533/myDB:INFORMIXSERVER=myserver;<br />
user=testuser;password=testpassword"; //myDB为数据库名<br />
Connection conn= DriverManager.getConnection(url);<br />
<br />
<br />
　　6、MySQL数据库<br />
Class.forName("org.gjt.mm.mysql.Driver").newInstance();<br />
String url ="jdbc:mysql://localhost/myDB?user=soft&amp;password=soft1234&amp;useUnicode=true&amp;characterEncoding=8859_1"<br />
//myDB为数据库名<br />
Connection conn= DriverManager.getConnection(url);<br />
<br />
<br />
　　7、PostgreSQL数据库<br />
Class.forName("org.postgresql.Driver").newInstance();<br />
String url ="jdbc:postgresql://localhost/myDB" //myDB为数据库名<br />
String user="myuser";<br />
String password="mypassword";<br />
Connection conn= DriverManager.getConnection(url,user,password);<br />
<br />
<br />
　　8、access数据库直连用ODBC的<br />
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver") ;<br />
String url="jdbc:odbc:Driver={MicroSoft Access Driver (*.mdb)};DBQ="+application.getRealPath("/Data/ReportDemo.mdb");<br />
Connection conn = DriverManager.getConnection(url,"","");<br />
Statement stmtNew=conn.createStatement() ;&nbsp;&nbsp;
<img src ="http://www.blogjava.net/conans/aggbug/209591.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-06-20 23:05 <a href="http://www.blogjava.net/conans/articles/209591.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Firefox: 开发人员必备的 6 个扩展</title><link>http://www.blogjava.net/conans/articles/209586.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Fri, 20 Jun 2008 15:02:00 GMT</pubDate><guid>http://www.blogjava.net/conans/articles/209586.html</guid><description><![CDATA[<p>如今，我相信任何一个网页开发人员的电脑中，Firefox 浏览器的重要程度和使用频率一定程度上会超过 Internet Explore。不仅因为它可以<a href="http://blog.istef.info/2007/07/19/open-addict-will-not-support-internet-explore-anymore/" target="_blank"><font style="background-color: #eaffcc" color="#336633">良好的支持标准</font></a>，而且众多强大的扩展已经把 Firefox 从一个单纯的测试平台转变为一个良好的调试平台。由于我平时也做一些 Web Dev 相关的工作，将几个我个人认为对开发很有用的扩展推荐给大家。</p>
<ol>
    <li><a href="https://addons.mozilla.org/en-US/firefox/addon/1843" target="_blank"><font style="background-color: #eaffcc" color="#336633">FireBug</font></a>：在 Web 调试工具中，FireBug 现在几乎已经成为了众多调试工具的标准，其强大程度绝对超乎你的想象。FireBug 可以快速分析出页面的 DOM 结构，并生成可折叠、展开的树状图。对于每一个元素，我们都可以通过 FireBug 来实时更改它的属性、值甚至 CSS，特别是对 CSS 的修改，结果会实时展现在页面上，这对 Web UI 人员来说绝对是个非常实用的功能。而对于开发人员来说，FireBug 可以为 Javascript 设定短点，可以通过简洁的函数监控变量、生成日志方便调试。FireBug 绝对无愧于 Firefox 中第一调试工具的称号。
    <li><a href="https://addons.mozilla.org/en-US/firefox/addon/60" target="_blank"><font style="background-color: #eaffcc" color="#336633">WebDeveloper</font></a>：老牌 Firefox 扩展调试工具，发展到现在，虽然功能明显不及 FireBug，但有些功能还是非常实用。例如根据预设调整窗口大小、显示 HTTP 相应报头、快速标准验证等都是非常实用的。对于 Web Developer 们还是个必不可少的扩展。
    <li><a href="https://addons.mozilla.org/en-US/firefox/addon/1122" target="_blank"><font style="background-color: #eaffcc" color="#336633">TabMixPlus</font></a>：Web Developer 们浏览器的一大特点，就是开得标签巨多无比。这时一个良好的标签管理扩展就必不可少了，在这方面，TabMixPlus 还是最为强大的。当然如果机器配置不好，可以用功能相对较少的 Tab Mix Lite CE 来代替。
    <li><a href="https://addons.mozilla.org/en-US/firefox/addon/655" target="_blank"><font style="background-color: #eaffcc" color="#336633">View Source Chart</font></a>：查看源码的好助手，不仅可以将 HTML 代码整理得非常易读，而且通过语法高亮进一步提高可读性。
    <li><a href="https://addons.mozilla.org/en-US/firefox/addon/1419" target="_blank"><font style="background-color: #eaffcc" color="#336633">IETab</font></a>：不管你怎么憎恨 IE，做出一个 Firefox Only 的网站还是会意味着失去 80% 的访客，因此最终成品在 IE 中测试一下还是很有必要的。有了这个扩展，你就不用再费力的去再开一个 IE 窗口了，直接一点击就可以切换（相当于为 Firefox 武装上了 IE 引擎）。
    <li><a href="https://addons.mozilla.org/en-US/firefox/addon/3895" target="_blank"><font style="background-color: #eaffcc" color="#336633">Personal Menu</font></a>：对于网页开发者来说，一个浏览器有尽可能大的工作区面积是非常重要的。Firefox 上的菜单多少有点鸡肋，用这个扩展既可以隐藏掉菜单，而且还可以毫不损失它的功能，非常爽。
    <div class="wlWriterSmartContent" id="0767317B-992E-4b12-91E0-4F059A8CECA8:6b751716-c296-4618-bf1d-9dd9d1875828" contenteditable="false" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"></div>
    </li>
</ol>
<img src ="http://www.blogjava.net/conans/aggbug/209586.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/conans/" target="_blank">CONAN</a> 2008-06-20 23:02 <a href="http://www.blogjava.net/conans/articles/209586.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>