﻿<?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-hengheng123456789-随笔分类-JAVA-Common</title><link>http://www.blogjava.net/hengheng123456789/category/18808.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 21 Dec 2010 06:57:26 GMT</lastBuildDate><pubDate>Tue, 21 Dec 2010 06:57:26 GMT</pubDate><ttl>60</ttl><item><title>云计算（转）</title><link>http://www.blogjava.net/hengheng123456789/archive/2010/12/20/341147.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Mon, 20 Dec 2010 03:45:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2010/12/20/341147.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/341147.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2010/12/20/341147.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/341147.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/341147.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转自：http://baike.baidu.com/view/1316082.htm简介　　云计算（Cloud Computing）是网格计算（Grid Computing）、分布式计算（Distributed Computing）、并行计算（Parallel Computing）、效用计算（Utility Com&nbsp;&nbsp;云计算puting）网络存储（N...&nbsp;&nbsp;<a href='http://www.blogjava.net/hengheng123456789/archive/2010/12/20/341147.html'>阅读全文</a><img src ="http://www.blogjava.net/hengheng123456789/aggbug/341147.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2010-12-20 11:45 <a href="http://www.blogjava.net/hengheng123456789/archive/2010/12/20/341147.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Text Format Covert Tool (UltraCodingSwitch)</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142352.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Mon, 03 Sep 2007 08:00:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142352.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/142352.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142352.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/142352.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/142352.html</trackback:ping><description><![CDATA[<br />
a good tool can convert text code to UTF8/GBK and so on. alse can convert Windows format to Unix.
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/142352.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-09-03 16:00 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142352.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Subversion(SVN)安装使用指南</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142351.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Mon, 03 Sep 2007 07:56:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142351.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/142351.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142351.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/142351.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/142351.html</trackback:ping><description><![CDATA[<p align="center">&nbsp; <br />
Subversion(SVN)安装使用指南</p>
<p>From：http://blog.csdn.net/mervyn/articles/928589.aspx</p>
<p>※简述※</p>
<p>Subversion是近期在开源社区中非常流行的一款版本控制软件，它是CVS的替代产物。</p>
<p>它的主要特征有：</p>
<p>CVS大部分的功能。 <br />
支持&#8220;目录&#8221;级别的版本管理，并且解决了CVS中迟迟未能解决的文件重命名和移动等问题。甚至对文件或文件夹的属性都提供了版本管理。 <br />
&#8220;提交（commit）&#8221;实现了真正意义上的原子操作。也就是类似数据库中的事务的功能。 <br />
版本号依据每次提交而改变，不再针对每个文件。日志信息也是针对每次提交而设置。所以看到版本号是几百或者几千也不用太惊讶，表示方式不一样罢了。 <br />
通过WebDAV/DeltaV协议，可以与Apache的网络服务无缝衔接（通过Apache来运行）。这样就能提供一些额外的功能，例如：认证，压缩传输，以及数据仓库（Repository，见下）的浏览等。 <br />
也可以作为独立服务器运行，但这样的话提供的功能较为简单薄弱。 <br />
两种运行模式都支持SSH（当然需要各自的支持和配置） <br />
降低了分支（Branch）和标签（tag）上的时间消耗。底层设计理念和实现上的不同，不细说了。 <br />
时间消耗依据的是文件改变部分的大小，而不是数据总量。 <br />
创建数据仓库时，用户可以指定是使用内嵌的 BerkeleyDB 数据库，还是特定格式的文件系统。 <br />
其他还有些零星的小功能，具体可以参阅： http://subversion.tigris.org/roadmap.html</p>
<p>这里解释一下数据仓库的概念：<br />
一个数据仓库对应的可以是一个项目，也可以是多个项目。SVN是基于数据仓库进行管理的。<br />
按照用户习惯，可以只在每个数据仓库内仅放置一个项目的内容。</p>
<p>※下载※</p>
<p>Subversion 1.2.3:<br />
http://subversion.tigris.org/project_packages.html<br />
（SVN的Server端，分不同操作系统的版本，这里我下载的是for windows及for linux的）</p>
<p>TortoiseSVN:<br />
http://tortoisesvn.tigris.org/download.html<br />
（windows下的SVN客户端，以shell方式集成在系统右键菜单中）</p>
<p>Apache 2.0.55:<br />
http://httpd.apache.org/download.cgi<br />
（视操作系统而下）</p>
<p>※安装使用※</p>
<p>下面说一下安装，分两种平台（windows，linux）及两种模式（与Apache绑定 vs. Stand-alone）<br />
具体在Apache上的配置倒是大同小异。</p>
<p>另外，SVN是支持SSL的，但是这个配置牵涉到其他太多东西，本文就不过多涉及了。真的有需要可以参考SVN的手册（英文）。</p>
<p>方便起见，用几个变量代表具体的值，请自行加以调整：</p>
<p>%SystemRoot% — windows的系统所在目录，一般类似这样：C:"WINNT<br />
%SVN_HOME% — SVN的安装目录<br />
%SVN_REPO_PARENT% — SVN所有数据仓库的根目录（就是存放全部版本文件的总目录）<br />
%PROJECT_NAME% — 项目名，严格的来说它对应的是一个数据仓库，但是这里遵从用户习惯，以项目名称方式来命名。<br />
%SERVER_NAME_OR_IP% — 服务器名或IP地址<br />
%APACHE_HOME% — Apache2的安装路径</p>
<p>另外，安装过程默认使用文件系统做后台数据库，文中不再加以说明。如需使用BerkeleyDB，请自行参考SVN文档。</p>
<p>Windows上的服务器端安装<br />
____________________________________________</p>
<p>1.双击下载得来的&#8221;svn-1.2.3-setup.exe&#8221;并安装到&#8221;%SVN_HOME%&#8221;</p>
<p>2.安装完毕后，&#8221;%SVN_HOME%"bin&#8221;应该已经自动加入到系统路径（%PATH%）中。如果没有，请手工添加。</p>
<p>3.用命令行来测试安装结果是否正确：</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd</p>
<p>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; svnadmin</p>
<p>如果返回这样的错误信息：&#8221;svnadmin.exe - Unable To Locate DLL&#8221;，那就需要尝试一下步骤的中的一种或几种：<br />
安装VC++ 6.0（主要是安装VC的运行库）<br />
或者直接从别的机器上拷贝一个&#8221;msvcp60.dll&#8221;文件到本机的&#8221;%SystemRoot%"system32&#8243;下</p>
<p>4.使用以下命令创建一个数据仓库，用来存放项目的源代码和其他文件：</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd</p>
<p>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; svnadmin create%SVN_REPO_PARENT%"%PROJECT_NAME%</p>
<p>5.其中%SVN_REPO_PARENT%是包含所有数据仓库的目录，%PROJECT_NAME%是所创建的数据仓库对应的项目名。</p>
<p><br />
*************************<br />
* 以 Stand-alone 模式运行 *<br />
*************************</p>
<p>6.从命令行启动SVN Server：</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd</p>
<p>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; svnserve -d -r %SVN_REPO_PARENT%</p>
<p>注意里面的参数 r 限定了浏览全部数据仓库的根目录</p>
<p>当然如果觉得每次这样启动太麻烦的话，也有SVN Serveice的包装程序（http://dark.clansoft.dk/~mbn/svnservice/）。通过它能够以windows service的方式运行SVN Server（其本质还是Stand-alone），运行起来相对比较方便。</p>
<p>7.创建用户数据库（其实就是一个txt文本，就叫它&#8221;users.conf&#8221;吧，你也可以改名），保存到<br />
%SVN_REPO_PARENT%"%PROJECT_NAME%"conf<br />
目录（那个conf子文件夹在创建数据仓库时已被自动创建好），然后在这个文件内添加需要的用户名和密码。基本的样例如下：</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [users]</p>
<p>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; your_username = your_password</p>
<p>注意这里密码是明文存放的，所以也是这种方式的不足之处。</p>
<p>8.在&#8221;%SVN_REPO_PARENT%"%PROJECT_NAME%"conf&#8221;目录下找到这个&#8221;svnserve.conf&#8221;文件，用任何文本编辑器打开，为刚才创建的那些用户添加读写权限：</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [general]</p>
<p>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; anon-access = none&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 匿名访问权限</p>
<p>3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; auth-access = write&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 认证用户的权限</p>
<p>4.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; password-db = users.conf&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 认证用户数据库</p>
<p>5.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; realm = Anything youwant, butgenerallyweuse "%PROJECT_NAME%"&nbsp;&nbsp; # 在用户认证界面上出现的提示语句</p>
<p>里面的&#8221;users.conf&#8221;就是刚才在第7步创建的用户文件。</p>
<p>9.最后，重启SVN Server（什么？你不知道怎么重启？关掉窗口再重新用命令行启动啦；包装成Service的话么就更加简单了）</p>
<p>现在已经可以使用客户端来连接SVN Server，进行import等操作了。<br />
连接Server的URL应该是类似这样的：</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; svn://%SERVER_NAME_OR_IP%/%PROJECT_NAME%</p>
<p>具体步骤，请参阅第20步。</p>
<p><br />
************************<br />
* 以Apache的模块方式运行 *<br />
************************</p>
<p>10.首先要了解的是SVN设计的时候只考虑了兼容Apache2.x，所以在Apache1.x下是不能正常工作的。</p>
<p>11.安装Apache2<br />
如果事先启动了IIS之类的其他webserver，请先停止那些服务（端口被占用会导致Apache安装失败）。<br />
其他问题可以参考Apache的安装手册。<br />
这里假设安装目录为：%APACHE_HOME%</p>
<p>12.检查Apache2的安装是否成功<br />
打开浏览器，访问： http://localhost/<br />
如果出现的是默认的欢迎页面，那就没有问题了。否则请仔细检查，重新安装。</p>
<p>13.打开Apache的配置文件： &#8220;%APACHE_HOME%"conf"httpd.conf&#8221;<br />
查找&#8221;LoadModule&#8221;这个关键字，找到导入模块的区块（section）<br />
反注释掉下面这样，从而加载Subversion所需要的DAV模块：</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # LoadModule dav_module modules/mod_dav.so</p>
<p>完成之后看起来应该是这样：</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LoadModuledav_modulemodules/mod_dav.so</p>
<p>另外在这行下面再添加两行（请注意把路径中的&#8221;"&#8221;替换成&#8221;/&#8221;）：</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LoadModuledav_svn_module%SVN_HOME%/bin/mod_dav_svn.so</p>
<p>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LoadModule authz_svn_module%SVN_HOME%/bin/mod_authz_svn.so</p>
<p>特别需要注意的是：由于模块依赖关系，这三行的出现顺序千万不能颠倒。</p>
<p>14.再来配置一下&#8221;httpd.conf&#8221;的其他部分，告诉Apache2 SVN的数据仓库所在。<br />
（为避免不必要的麻烦，所有路径中的&#8221;"&#8221;都请替换成&#8221;/&#8221;）<br />
注意：</p>
<p>按照下述配置，所有数据仓库将共享密码文件及权限文件 <br />
如果需要为每个数据仓库创建独立的设置，请查阅SVN的文档（&#8221;Authorization Option&#8221;章节） <br />
添加下述内容：</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Location /svn&gt;</p>
<p>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DAV svn</p>
<p>4.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SVNParentPath %SVN_REPO_PARENT%</p>
<p>5.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>6.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #设置通过浏览器访问Repository时的XML格式文件，可以省略</p>
<p>7.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SVNIndexXSLT "/svnindex.xsl"</p>
<p>8.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>9.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 存取权限控制文件所在地</p>
<p>10.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AuthzSVNAccessFile %SVN_REPO_PARENT%/AccessFile</p>
<p>11.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>12.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 先尝试匿名操作，如有必要再转向用户认证</p>
<p>13.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Satisfy Any</p>
<p>14.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Require valid-user</p>
<p>15.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>16.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 如何验证用户</p>
<p>17.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AuthType Basic</p>
<p>18.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AuthName "Anything youwant, butgenerallyweuse %PROJECT_NAME%"</p>
<p>19.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AuthUserFile %SVN_REPO_PARENT%/passwd</p>
<p>20.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>21.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #输出时调用Apache的Deflate模块，必须有启用此模块才能这样配，否则删除此行</p>
<p>22.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SetOutputFilter DEFLATE</p>
<p>23.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>24.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Location&gt;</p>
<p>这里涉及到两个文件: &#8220;%SVN_REPO_PARENT%/AccessFile&#8221; 及 &#8220;%SVN_REPO_PARENT%/passwd&#8221;.<br />
并不一定非要放到&#8221;%SVN_REPO_PARENT%&#8221;目录下，我图方便而已。觉得不安全可以移到另外地方。<br />
这两个文件里面具体内容的设置请参考第16和17步。</p>
<p>15.保存&#8221;httpd.conf&#8221;并退出，这里Apache2的配置告一段落。</p>
<p>16.&#8221;%SVN_REPO_PARENT%/AccessFile&#8221;文件的内容</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [/]</p>
<p>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * = r</p>
<p>3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; user1 = rw</p>
<p>4.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; user2 = r</p>
<p>5.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; admin = rw</p>
<p>6.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>7.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [%PROJECT_NAME%:/src/test]</p>
<p>8.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; user2 = rw</p>
<p>其中：</p>
<p>[/] 指代所有数据仓库的根目录，匿名用户默认的权限为只读。 <br />
对于&#8221;user1&#8243;和&#8221;admin&#8221;，他们对所有数据仓库都有读写权限。 <br />
对于&#8221;user2&#8243;，它对所有数据仓库仅有只读权限。但是下方又额外指定了他对&#8221;%PROJECT_NAME%:/src/test&#8221;目录具有读写权限。 <br />
综上，他对&#8217;test&#8217;目录及其子目录（自动继承，除非特别指定）具有读写权限，其他则均为只读权限。 <br />
你可以根据需要来设定不同的权限，更详细的说明还需要参考SVN文档中的权限设置章节。</p>
<p>17.&#8221;%SVN_REPO_PARENT%/passwd&#8221;文件的内容<br />
这个文件是通过&#8221;%APACHE_HOME%"bin"htpasswd.exe&#8221;自动生成的：</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd</p>
<p>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cd /D %APACHE_HOME%"bin</p>
<p>3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 参数c仅在第一次运行时使用，用来创建一个新文件</p>
<p>4.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; htpasswd &#8211;cm %SVN_REPO_PARENT%"passwd user1</p>
<p>5.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 以后添加用户可用此命令，参数m表明需要加密</p>
<p>6.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; htpasswd &#8211;m %SVN_REPO_PARENT%"passwd user2</p>
<p>此时用文本编辑器打开&#8221;%SVN_REPO_PARENT%/passwd&#8221;，可以看到里面内容是类似这样的：</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; admin:$apr1$HLWV7/..$upZwVGvge0sc28fEp7mGM0</p>
<p>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; user1:$apr1$8sbRo...$hNMdkTvO4t8POVmOkV3Vg.</p>
<p>3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; user2:$apr1$ZXzcE/..$5Ir0V8VQQtNYTNnnOp.EU1</p>
<p>18.把SVN自带的XSLT文件拷贝到网站根目录，<br />
然后设置合理权限（windows平台则不必考虑）</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #这里假设你的网站根目录是&nbsp; /var/www/html</p>
<p>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mv /tmp/subversion-1.2.3/tools/xslt/svnindex* /var/www/html</p>
<p>3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; chown apache:apache /var/www/html/svnindex*</p>
<p>4.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; chmod 644 /var/www/html/svnindex*</p>
<p>5.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>6.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #设置所有者和权限(将权限赋给apache运行的用户身份)</p>
<p>7.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; chown -R apache:apache%SVN_REPO_PARENT%</p>
<p>8.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; chmod -R 766%SVN_REPO_PARENT%</p>
<p>19. 重启Apache2服务：</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd</p>
<p>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; net stopApache2</p>
<p>3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; net startApache2</p>
<p>20.打开浏览器，访问：http://%SERVER_NAME_OR_IP%/svn/<br />
如果返回的页面是&#8221;403 Forbidden&#8221;，可能是由于Apache2默认没有打开目录的浏览权限（Option Indexes，参阅Apache2文档），但这并不影响使用。<br />
现在已经可以用客户端导入项目并开始使用了。<br />
具体步骤，请参阅第20步。</p>
<p><br />
***********************************************<br />
* 注意：以下步骤/命令需要在装有SVN客户端的机器上执行 *<br />
* Windows下安装服务器端的时候已经同时安装了客户端 *<br />
* Linux下尚待查证。 *<br />
***********************************************</p>
<p>21.和CVS一样，SVN在最初的时候需要将已有项目导入到数据库中。<br />
从命令行执行以下命令（Stand-alone）：</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; svnimportc:"temp"myprojectsvn://%SERVER_NAME_OR_IP%/%PROJECT_NAME% -m"initial import" --usernameyour_username --passwordyour_password</p>
<p>或者（Apache2 module）：</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; svnimportc:"temp"myprojecthttp://%SERVER_NAME_OR_IP%/svn/%PROJECT_NAME% -m"initial import" --usernameyour_username --passwordyour_password</p>
<p>其中：<br />
A) c:"temp"myproject里面包含了你所要导入的项目文件的内容<br />
B) %SERVER_NAME_OR_IP%是SVN Server的名字或者IP地址，上面存有第5步中创建的数据仓库<br />
C) %PROJECT_NAME%是要导入到的数据仓库名称，这里选择跟项目名一致<br />
D) 参数 m 表明此次导入操作的注释，SVN的注释是按每次提交来定义的，导入也是提交的一种。<br />
E) your_username和your_password是第7和17步创建的用户及密码，注意该用户必须对上面的%PROJECT_NAME%数据仓库有写权限才能成功。</p>
<p>22.然后，需要从Server端再次checkout到本地：<br />
（这点感觉不是太方便，为啥不做成import的时候有个选项，本地目录可以自动生成版本信息呢？）</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd</p>
<p>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cd /D anywhere_you_want_to_put_your_versioned_project_files</p>
<p>3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; svn co svn://myserver/myproject/trunk . --username your_username --passwordyour_password</p>
<p>注意：<br />
&#8220;co&#8221;是&#8221;checkout&#8221;的一个别名<br />
那个点[.]代表当前目录，checkout出来的文件会自动放到这个目录下。也可以改为某个绝对路径。</p>
<p>23.对于向SVN Serer增加，移动，删除，或者修改后提交某些文件，参考使用以下命令：</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Add:&nbsp;&nbsp;&nbsp; svnaddsrc/myfile.java -m"adding a file"</p>
<p>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Move:&nbsp;&nbsp;&nbsp; svn movesrc/myfile.javasrc/mynewfile.java -m"moved myfile.java to mynewfile.java"</p>
<p>3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Delete:&nbsp;&nbsp;&nbsp; svn deletesrc/myfile.java -m"removing a file"</p>
<p>4.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Commit:&nbsp;&nbsp;&nbsp; svn commitsrc/myfile.java -m"the message"</p>
<p>对于上面的客户端操作，如果安装了TortoiseSVN，一切就变得简单多了。<br />
不过这个就要抓图来说明了。等有空的时候再放上来。</p>
<p>※总结※</p>
<p>使用Eclipse的朋友还可以参考这里： http://subclipse.tigris.org/<br />
它以插件的形式向Eclipse提供了SVN的支持。</p>
<p>另外，具体的设置，参数说明等还是需要自己去查阅SVN的文档（在安装server端的时候已经附带）</p>
<p>参考文献及资料：<br />
_________________________________________</p>
<p>http://subversion.tigris.org/<br />
http://www-128.ibm.com/developerworks/cn/opensource/os-subversion/<br />
http://www.javayou.com/showlog.jspe?log_id=972<br />
</p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/142351.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-09-03 15:56 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142351.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java Crash</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142348.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Mon, 03 Sep 2007 07:52:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142348.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/142348.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142348.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/142348.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/142348.html</trackback:ping><description><![CDATA[&nbsp;
<p style="text-align: center" align="center">Java Crash</p>
<p style="background: white; text-align: left" align="left"><span style="font-size: 12pt; font-family: 宋体">如果是</span><span style="font-size: 12pt; font-family: Arial">Java</span><span style="font-size: 12pt; font-family: 宋体">进程不知道什么原因退出或被杀死，想要分析具体原因，一般来说分下面几步：</span></p>
<p style="margin-top: 7.5pt; background: white; text-align: left" align="left"><span style="font-size: 12pt; font-family: Arial">1 </span><span style="font-size: 12pt; font-family: 宋体">拿到</span><span style="font-size: 12pt; font-family: Arial">Java</span><span style="font-size: 12pt; font-family: 宋体">应用程序的日志文件。</span><span style="font-size: 12pt; font-family: Arial"><br />
</span><span style="font-size: 12pt; font-family: 宋体">一般来说日志文件中会有很应用相关的错误信息。</span><span style="font-size: 12pt; font-family: Arial">Java</span><span style="font-size: 12pt; font-family: 宋体">进程异常退出的原因最有可能就是应用程序本身的问题。因此检查</span><span style="font-size: 12pt; font-family: Arial">Java</span><span style="font-size: 12pt; font-family: 宋体">应用程序的日志文件可能是最快定位到错误的方法。</span></p>
<p style="margin-top: 7.5pt; background: white; text-align: left" align="left"><span style="font-size: 12pt; font-family: Arial">2 </span><span style="font-size: 12pt; font-family: 宋体">查找</span><span style="font-size: 12pt; font-family: Arial">JVM</span><span style="font-size: 12pt; font-family: 宋体">的致命错误日志</span><span style="font-size: 12pt; font-family: Arial"><br />
</span><span style="font-size: 12pt; font-family: 宋体">如果应用程序日志文件中没有发现什么线索。那么还可以查看</span><span style="font-size: 12pt; font-family: Arial"> JVM</span><span style="font-size: 12pt; font-family: 宋体">的致命错误日志。有些致命的错误，比如</span><span style="font-size: 12pt; font-family: Arial">JNI</span><span style="font-size: 12pt; font-family: 宋体">或虚拟机本身产生的错误，可能使得</span><span style="font-size: 12pt; font-family: Arial">Java</span><span style="font-size: 12pt; font-family: 宋体">应用程序来不及写日志就退出了。这时候可以查一个以</span><span style="font-size: 12pt; font-family: Arial"> "hs_err_pid" </span><span style="font-size: 12pt; font-family: 宋体">开头的日志名，例如</span><span style="font-size: 12pt; font-family: Arial">hs_err_pid1125.log</span><span style="font-size: 12pt; font-family: 宋体">，其中</span><span style="font-size: 12pt; font-family: Arial">1125</span><span style="font-size: 12pt; font-family: 宋体">是进程号。这个文件中也记录了一些宝贵的信息来提供一些线索，特别是</span><span style="font-size: 12pt; font-family: Arial">Java</span><span style="font-size: 12pt; font-family: 宋体">自身的一些</span><span style="font-size: 12pt; font-family: Arial">Bug</span><span style="font-size: 12pt; font-family: 宋体">。这个文件一般为于当前的工作目录中。用户可以用</span><span style="font-size: 12pt; font-family: Arial">find</span><span style="font-size: 12pt; font-family: 宋体">命令自己搜索到。</span></p>
<p style="margin-top: 7.5pt; background: white; text-align: left" align="left"><span style="font-size: 12pt; font-family: Arial">3 </span><span style="font-size: 12pt; font-family: 宋体">查找操作系统的</span><span style="font-size: 12pt; font-family: Arial">core dump</span><span style="font-size: 12pt; font-family: 宋体">文件</span><span style="font-size: 12pt; font-family: Arial"><br />
</span><span style="font-size: 12pt; font-family: 宋体">作为被操作系统所调度的进程，</span><span style="font-size: 12pt; font-family: Arial">Java</span><span style="font-size: 12pt; font-family: 宋体">进程也会在不同的信号下产生</span><span style="font-size: 12pt; font-family: Arial">Core Dump</span><span style="font-size: 12pt; font-family: 宋体">文件，例如</span><span style="font-size: 12pt; font-family: Arial">Sig_ill</span><span style="font-size: 12pt; font-family: 宋体">和</span><span style="font-size: 12pt; font-family: Arial">Seg_segv</span><span style="font-size: 12pt; font-family: 宋体">。这些非常严重的错误的确会使得</span><span style="font-size: 12pt; font-family: Arial">Java</span><span style="font-size: 12pt; font-family: 宋体">虚拟机根本来不及产生任何日志就宕了。拿到</span><span style="font-size: 12pt; font-family: Arial">core dump</span><span style="font-size: 12pt; font-family: 宋体">文件就可以使用很多工具来分析具体原因了，例如</span><span style="font-size: 12pt; font-family: Arial">jmap, jstack</span><span style="font-size: 12pt; font-family: 宋体">等等都可以友好的进行</span><span style="font-size: 12pt; font-family: Arial">Java</span><span style="font-size: 12pt; font-family: 宋体">进程的</span><span style="font-size: 12pt; font-family: Arial">Core</span><span style="font-size: 12pt; font-family: 宋体">文件的分析。一般来说，</span><span style="font-size: 12pt; font-family: Arial">Core</span><span style="font-size: 12pt; font-family: 宋体">文件也放到进程的当前工作目录，用户可以用</span><span style="font-size: 12pt; font-family: Arial">find</span><span style="font-size: 12pt; font-family: 宋体">命令搜索</span><span style="font-size: 12pt; font-family: Arial"> &#8220;core&#8221;</span><span style="font-size: 12pt; font-family: 宋体">。另外可以用</span><span style="font-size: 12pt; font-family: Arial">coreadm</span><span style="font-size: 12pt; font-family: 宋体">来预先指定</span><span style="font-size: 12pt; font-family: Arial">core</span><span style="font-size: 12pt; font-family: 宋体">文件存放的地方以及文件名的格式，例如：</span><span style="font-size: 12pt; font-family: Arial">coreadm -g /var/core/core.%f.%p.%t</span></p>
<p style="margin-top: 7.5pt; background: white; text-align: left" align="left"><span style="font-size: 12pt; font-family: Arial">4</span><span style="font-size: 12pt; font-family: 宋体">使用</span><span style="font-size: 12pt; font-family: Arial">Dtrace</span><span style="font-size: 12pt; font-family: 宋体">查找</span><span style="font-size: 12pt; font-family: Arial">&#8220;</span><span style="font-size: 12pt; font-family: 宋体">是谁杀死了</span><span style="font-size: 12pt; font-family: Arial">Java</span><span style="font-size: 12pt; font-family: 宋体">进程</span><span style="font-size: 12pt; font-family: Arial">&#8221;<br />
</span><span style="font-size: 12pt; font-family: 宋体">但是，有很多情况，进程被杀死的原因很复杂。有可能被别的进程以外杀掉，或被一些脚本不小心</span><span style="font-size: 12pt; font-family: Arial">kill</span><span style="font-size: 12pt; font-family: 宋体">掉，或者被管理员（或入侵者</span><span style="font-size: 12pt; font-family: Arial">kill -9</span><span style="font-size: 12pt; font-family: 宋体">）处理掉。这些情况都不会产生日志文件和</span><span style="font-size: 12pt; font-family: Arial">core dump</span><span style="font-size: 12pt; font-family: 宋体">文件。这些情况很难跟踪。但如果是</span><span style="font-size: 12pt; font-family: Arial">Solaris10</span><span style="font-size: 12pt; font-family: 宋体">下，可以使用下面的</span><span style="font-size: 12pt; font-family: Arial">Dtrace</span><span style="font-size: 12pt; font-family: 宋体">脚本来确定</span><span style="font-size: 12pt; font-family: Arial">&#8220;</span><span style="font-size: 12pt; font-family: 宋体">是谁杀死了</span><span style="font-size: 12pt; font-family: Arial">Java</span><span style="font-size: 12pt; font-family: 宋体">进程</span><span style="font-size: 12pt; font-family: Arial">&#8221;</span></p>
<p style="margin-top: 7.5pt; background: white; text-align: left" align="left"><span style="font-size: 12pt; font-family: Arial"><br />
#!/usr/sbin/dtrace -qs</span></p>
<p style="margin-top: 7.5pt; background: white; text-align: left" align="left"><span style="font-size: 12pt; font-family: Arial">proc:::signal-send<br />
/args[1]-&gt;pr_pid == $1/<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("%s(pid:%d) is sending signal %d to %s"n", execname, pid, args[2],args[1]-&gt;pr_fname);<br />
}</span></p>
<p><span style="font-size: 12pt; font-family: 宋体">如何运行（</span><span style="font-size: 12pt; font-family: Arial">1125</span><span style="font-size: 12pt; font-family: 宋体">）是进程号</span><span style="font-size: 12pt; font-family: Arial"><br />
$ ./sig1.d 1125<br />
sched(pid:0) is sending signal 24 to bc<br />
sched(pid:0) is sending signal 24 to bc<br />
bash(pid:3987) is sending signal 15 to bc<br />
bash(pid:3987) is sending signal 15 to bc<br />
bash(pid:3987) is sendg signal 9 to bc</span></p>
<p style="text-align: left" align="left"><span style="font-size: 12pt; font-family: 宋体">Java</span><span style="font-size: 12pt; font-family: 宋体">的应用有时候会因为各种原因Crash，这时候会产生一个类似java_errorpid.log的错误日志。可以拿到了这个日志，怎样分析Crash的原因呢？下面我们来详细讨论如何分析java_error<em>pid</em>.log的错误日志。<br />
一</span><span style="font-size: 12pt; font-family: sans-serif">. </span><span style="font-size: 12pt; font-family: 宋体">如何得到这个日志文件如果有一个严重的错误引起</span><span style="font-size: 12pt; font-family: serif">Java</span><span style="font-size: 12pt; font-family: 宋体">进程非正常退出，我们叫</span><span style="font-size: 12pt; font-family: serif">Crash</span><span style="font-size: 12pt; font-family: 宋体">，这时候会产生一个日志文件。缺省情况下，这个文件会产生在工作目录下。但是，可以在</span><span style="font-size: 12pt; font-family: serif">Java</span><span style="font-size: 12pt; font-family: 宋体">启动参数通过下面的设置，来改变这个文件的位置和命名规则。例如：</span><span style="font-size: 12pt; font-family: serif"><br />
java -XX:ErrorFile=/var/log/java/java_error_%p.log<br />
</span><span style="font-size: 12pt; font-family: 宋体">就将这个错误文件放在</span><span style="font-size: 12pt; font-family: serif">/var/log/java</span><span style="font-size: 12pt; font-family: 宋体">下，并且以</span><span style="font-size: 12pt; font-family: serif">java_error_<em>pid</em>.log</span><span style="font-size: 12pt; font-family: 宋体">的形式出现。<br />
<br />
二</span><span style="font-size: 12pt; font-family: sans-serif">.</span><span style="font-size: 12pt; font-family: 宋体">产生错误的原因造成严重错误的原因有多种可能性。</span><span style="font-size: 12pt; font-family: serif">Java</span><span style="font-size: 12pt; font-family: 宋体">虚拟机自身的</span><span style="font-size: 12pt; font-family: serif">Bug</span><span style="font-size: 12pt; font-family: 宋体">是原因之一，但是这种可能不是很大。在绝大多数情况下，是由于系统的库文件、</span><span style="font-size: 12pt; font-family: serif">API</span><span style="font-size: 12pt; font-family: 宋体">或第三方的库文件造成的；系统资源的短缺也有可能造成这种严重的错误。在发生了</span><span style="font-size: 12pt; font-family: serif">Crash</span><span style="font-size: 12pt; font-family: 宋体">之后，如果无法定位根本原因，也应该迅速找到</span><span style="font-size: 12pt; font-family: serif">Work Around</span><span style="font-size: 12pt; font-family: 宋体">的方法。<br />
<br />
三</span><span style="font-size: 12pt; font-family: sans-serif">.</span><span style="font-size: 12pt; font-family: 宋体">对日志文件的分析首先要检查日志的文件头：例如，下面是从一个客户发过来的错误日志的文件头<br />
－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－<br />
</span><span style="font-size: 12pt; font-family: serif">#<br />
# An unexpected error has been detected by HotSpot Virtual Machine:<br />
#<br />
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0815e87e, pid=7268, tid=4360<br />
#<br />
# Java VM: Java HotSpot(TM) Server VM (1.4.2_13-b06 mixed mode)<br />
# Problematic frame:<br />
# V [jvm.dll+0x15e87e]<br />
#<br />
</span><span style="font-size: 12pt; font-family: 宋体">－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－<br />
<br />
<br />
文件头中有很多有用的信息，&#8220;</span><span style="font-size: 12pt; font-family: serif">EXCEPTION_ACCESS_VIOLATION &#8221;</span><span style="font-size: 12pt; font-family: 宋体">意味着</span><span style="font-size: 12pt; font-family: serif">Java</span><span style="font-size: 12pt; font-family: 宋体">应用</span><span style="font-size: 12pt; font-family: serif">Crash</span><span style="font-size: 12pt; font-family: 宋体">的时候，正在运行</span><span style="font-size: 12pt; font-family: serif">JVM</span><span style="font-size: 12pt; font-family: 宋体">自己的代码，而不是外部的</span><span style="font-size: 12pt; font-family: serif">Java</span><span style="font-size: 12pt; font-family: 宋体">代码或其他类库代码。这种情况很可能是</span><span style="font-size: 12pt; font-family: serif">JVM</span><span style="font-size: 12pt; font-family: 宋体">的</span><span style="font-size: 12pt; font-family: serif">Bug</span><span style="font-size: 12pt; font-family: 宋体">，但是也不一定。除了&#8220;</span><span style="font-size: 12pt; font-family: serif">EXCEPTION_ACCESS_VIOLATION &#8221;</span><span style="font-size: 12pt; font-family: 宋体">，还有可能是别的信息，例如&#8220;</span><span style="font-size: 12pt; font-family: serif">SIGSEGV(0xb)&#8221;</span><span style="font-size: 12pt; font-family: 宋体">，意味着</span><span style="font-size: 12pt; font-family: serif">JVM</span><span style="font-size: 12pt; font-family: 宋体">正在执行本地或</span><span style="font-size: 12pt; font-family: serif">JNI</span><span style="font-size: 12pt; font-family: 宋体">的代码</span><span style="font-size: 12pt; font-family: serif">;[font=Thorndale, serif]&#8220;EXCEPTION_STACK_OVERFLOW&#8221;</span><span style="font-size: 12pt; font-family: 宋体">[/font]</span><span style="font-size: 12pt; font-family: 宋体">意味着这是个栈溢出的错误。<br />
<br />
<br />
另外一个有用的信息就是：<br />
</span><span style="font-size: 12pt; font-family: serif"># Problematic frame:<br />
# V [jvm.dll+0x15e87e]</span><span style="font-size: 12pt; font-family: 宋体"><br />
<br />
</span><span style="font-size: 12pt; font-family: 宋体">它说明</span><span style="font-size: 12pt; font-family: serif">Crash</span><span style="font-size: 12pt; font-family: 宋体">的时候，</span><span style="font-size: 12pt; font-family: serif">JVM</span><span style="font-size: 12pt; font-family: 宋体">正在从哪个库文件执行代码。除了&#8220;</span><span style="font-size: 12pt; font-family: serif">V&#8221;</span><span style="font-size: 12pt; font-family: 宋体">以外，还有可能是&#8220;</span><span style="font-size: 12pt; font-family: serif">C&#8221;</span><span style="font-size: 12pt; font-family: 宋体">、&#8220;</span><span style="font-size: 12pt; font-family: serif">j&#8221;</span><span style="font-size: 12pt; font-family: 宋体">、&#8220;</span><span style="font-size: 12pt; font-family: serif">v&#8221;</span><span style="font-size: 12pt; font-family: 宋体">、&#8220;</span><span style="font-size: 12pt; font-family: serif">J&#8221;</span><span style="font-size: 12pt; font-family: 宋体">。具体的表示意思如下：<br />
</span><span style="font-size: 12pt; font-family: serif">FrameType Description</span><span style="font-size: 12pt; font-family: 宋体">：</span><span style="font-size: 12pt; font-family: MyriadPro-SemiboldSemiCn"><br />
</span><span style="font-size: 12pt; font-family: serif">C: Native C frame<br />
j: Interpreted Java frame<br />
V: VMframe<br />
v: VMgenerated stub frame<br />
J: Other frame types, including compiled Java frames</span><span style="font-size: 12pt; font-family: 宋体"><br />
<br />
</span><span style="font-size: 12pt; font-family: 宋体">文件头之后，是当前线程的</span><span style="font-size: 12pt; font-family: serif">DUMP</span><span style="font-size: 12pt; font-family: 宋体">信息，线程之后是</span><span style="font-size: 12pt; font-family: serif">JVM</span><span style="font-size: 12pt; font-family: 宋体">进程的</span><span style="font-size: 12pt; font-family: serif">DUMP</span><span style="font-size: 12pt; font-family: 宋体">信息，包括所有线程的状态、地址和</span><span style="font-size: 12pt; font-family: serif">ID</span><span style="font-size: 12pt; font-family: 宋体">。最后还有</span><span style="font-size: 12pt; font-family: serif">JVM</span><span style="font-size: 12pt; font-family: 宋体">状态，</span><span style="font-size: 12pt; font-family: serif">Heap</span><span style="font-size: 12pt; font-family: 宋体">状态，动态连接库等等的信息。这些烦乱的信息中，包含有非常有用的信息。下面我们根据几个具体的实例来分析</span><span style="font-size: 12pt; font-family: serif">Java</span><span style="font-size: 12pt; font-family: 宋体">虚拟机</span><span style="font-size: 12pt; font-family: serif">Crash</span><span style="font-size: 12pt; font-family: 宋体">的典型例子。<br />
<br />
四</span><span style="font-size: 12pt; font-family: sans-serif">.</span><span style="font-size: 12pt; font-family: 宋体">内存回收引起的</span><span style="font-size: 12pt; font-family: sans-serif">Crash</span><span style="font-size: 12pt; font-family: 宋体">内存回收引起的</span><span style="font-size: 12pt; font-family: serif">Crash</span><span style="font-size: 12pt; font-family: 宋体">有以下的特点：在日志文件头一般有&#8220; </span><span style="font-size: 12pt; font-family: serif">EXCEPTION_ACCESS _VIOLATION&#8221;</span><span style="font-size: 12pt; font-family: 宋体">和&#8220;</span><span style="font-size: 12pt; font-family: serif"># Problematic frame: # V [jvm.dll+....&#8221;</span><span style="font-size: 12pt; font-family: 宋体">的信息，意味着这是在</span><span style="font-size: 12pt; font-family: serif">JVM</span><span style="font-size: 12pt; font-family: 宋体">内部处理，而且多半是</span><span style="font-size: 12pt; font-family: serif">JVM</span><span style="font-size: 12pt; font-family: 宋体">的</span><span style="font-size: 12pt; font-family: serif">Bug</span><span style="font-size: 12pt; font-family: 宋体">。对于这类问题，最快的方法就是绕过它。<br />
另外，在</span><span style="font-size: 12pt; font-family: serif">Thread</span><span style="font-size: 12pt; font-family: 宋体">的</span><span style="font-size: 12pt; font-family: serif">DUMP</span><span style="font-size: 12pt; font-family: 宋体">信息最后，还能看到有关内存回收的行为例如：<br />
</span><span style="font-size: 12pt; font-family: serif">--------------- T H R E A D ---------------<br />
Current thread (0x00a56668): VMThread [id=4360]<br />
siginfo: ExceptionCode=0xc0000005, reading address 0x00000057<br />
Registers:<br />
........<br />
<br />
Stack: [0x03cf0000,0x03d30000), sp=0x03d2fc18, free space=255k<br />
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)<br />
V [jvm.dll+0x15e87e]<br />
<br />
VM_Operation (0x063efbac): <span style="color: red">full generation collection</span>, mode: safepoint, requested by thread 0x040f83f8<br />
------------------------------------------------------------<br />
</span><span style="font-size: 12pt; font-family: 宋体"><br />
</span><span style="font-size: 12pt; font-family: 宋体">可以清楚的看到</span><span style="font-size: 12pt; font-family: serif">JVM</span><span style="font-size: 12pt; font-family: 宋体">正在做 &#8220;</span><span style="font-size: 12pt; color: red; font-family: serif">full generation collection</span><span style="font-size: 12pt; font-family: serif">&#8221;</span><span style="font-size: 12pt; font-family: 宋体">。另外还有可能看到，其他的回收行为：</span></p>
<ul type="disc">
    <li style="text-align: left; tab-stops: list 36.0pt"><span style="font-size: 12pt; font-family: serif">generation collection for allocation</span></li>
    <li style="text-align: left; tab-stops: list 36.0pt"><span style="font-size: 12pt; font-family: serif">full generation collection</span></li>
    <li style="text-align: left; tab-stops: list 36.0pt"><span style="font-size: 12pt; font-family: serif">parallel gc failed allocation</span></li>
    <li style="text-align: left; tab-stops: list 36.0pt"><span style="font-size: 12pt; font-family: serif">parallel gc failed permanent allocation</span></li>
    <li style="text-align: left; tab-stops: list 36.0pt"><span style="font-size: 12pt; font-family: serif">parallel gc system gc</span></li>
</ul>
<p><span style="font-size: 12pt; font-family: 宋体"><br />
</span><span style="font-size: 12pt; font-family: 宋体">对于内存回收的错误，一般采取改变回收的算法和参数的方法来绕过去。例如，来自客户的日志除了上面的日志信息，在日志中</span><span style="font-size: 12pt; font-family: serif">Heap</span><span style="font-size: 12pt; font-family: 宋体">信息中还能发现一些其他信息：<br />
--------------------------------------------------------------<br />
</span><span style="font-size: 12pt; font-family: serif">Heap<br />
def new generation total 22592K, used 19530K [0x10010000, 0x11890000, 0x138f0000)<br />
eden space 20096K, 97% used [0x10010000, 0x11322bd8, 0x113b0000)<br />
from space 2496K, 0% used [0x113b0000, 0x113b0000, 0x11620000)<br />
to space 2496K, 0% used [0x11620000, 0x11620000, 0x11890000)<br />
tenured generation total 190696K, used 100019K [0x138f0000, 0x1f32a000, 0x30010000)<br />
the space 190696K, 52% used [0x138f0000, 0x19a9cf38, 0x19a9d000, 0x1f32a000)<br />
<span style="color: red">compacting perm gen total 38656K, used 38588K </span>[0x30010000, 0x325d0000, 0x34010000)<br />
<span style="color: #ff6666">the space 38656K, 99% used</span> [0x30010000, 0x325bf038, 0x325bf200, 0x325d0000)<br />
----------------------------------------------------------------<br />
</span><span style="font-size: 12pt; font-family: 宋体"><br />
</span><span style="font-size: 12pt; font-family: 宋体">上面的信息能看出在</span><span style="font-size: 12pt; font-family: serif">Crash</span><span style="font-size: 12pt; font-family: 宋体">的时候，</span><span style="font-size: 12pt; font-family: serif">JVM</span><span style="font-size: 12pt; font-family: 宋体">的</span><span style="font-size: 12pt; font-family: serif">PermSize</span><span style="font-size: 12pt; font-family: 宋体">空间几乎已经消耗完了，并且回收算法在压缩Perm空间的时候出了错。因此，建议改变内存回收的算法，或扩大</span><span style="font-size: 12pt; font-family: serif">PermSize</span><span style="font-size: 12pt; font-family: 宋体">和</span><span style="font-size: 12pt; font-family: serif">MaxPermSize</span><span style="font-size: 12pt; font-family: 宋体">的数值。<br />
<br />
五</span><span style="font-size: 12pt; font-family: sans-serif">.</span><span style="font-size: 12pt; font-family: 宋体">栈溢出引起的</span><span style="font-size: 12pt; font-family: sans-serif">Crash</span><span style="font-size: 12pt; font-family: serif">Java</span><span style="font-size: 12pt; font-family: 宋体">代码引起的栈溢出，通常不会引起</span><span style="font-size: 12pt; font-family: serif">JVM</span><span style="font-size: 12pt; font-family: 宋体">的</span><span style="font-size: 12pt; font-family: serif">Crash</span><span style="font-size: 12pt; font-family: 宋体">，而是抛</span><span style="font-size: 12pt; font-family: 宋体">出一个</span><span style="font-size: 12pt; font-family: serif">[font=Thorndale, serif]Java</span><span style="font-size: 12pt; font-family: 宋体">[/font]</span><span style="font-size: 12pt; font-family: 宋体">异常：</span><span style="font-size: 12pt; font-family: serif">[font=Thorndale, serif]java.lang.StackOverflowError</span><span style="font-size: 12pt; font-family: 宋体">[/font]</span><span style="font-size: 12pt; font-family: 宋体">。但是在</span><span style="font-size: 12pt; font-family: serif">[font=Thorndale, serif]Java</span><span style="font-size: 12pt; font-family: 宋体">[/font]</span><span style="font-size: 12pt; font-family: 宋体">虚拟机中，</span><span style="font-size: 12pt; font-family: serif">[font=Thorndale, serif]Java</span><span style="font-size: 12pt; font-family: 宋体">[/font]</span><span style="font-size: 12pt; font-family: 宋体">的代码和本地</span><span style="font-size: 12pt; font-family: serif">[font=Thorndale, serif]C</span><span style="font-size: 12pt; font-family: 宋体">[/font]</span><span style="font-size: 12pt; font-family: 宋体">或</span><span style="font-size: 12pt; font-family: serif">[font=Thorndale, serif]C++</span><span style="font-size: 12pt; font-family: 宋体">[/font]</span><span style="font-size: 12pt; font-family: 宋体">代码公用相同的</span><span style="font-size: 12pt; font-family: serif">[font=Thorndale, serif]Stack</span><span style="font-size: 12pt; font-family: 宋体">[/font]</span><span style="font-size: 12pt; font-family: 宋体">。这样，在执行本地代码所造成的栈溢出，就有可能引起</span><span style="font-size: 12pt; font-family: serif">[font=Thorndale, serif]JVM</span><span style="font-size: 12pt; font-family: 宋体">[/font]</span><span style="font-size: 12pt; font-family: 宋体">的</span><span style="font-size: 12pt; font-family: serif">[font=Thorndale, serif]Crash</span><span style="font-size: 12pt; font-family: 宋体">[/font]</span><span style="font-size: 12pt; font-family: 宋体">了。</span><span style="font-size: 12pt; font-family: 宋体"><br />
</span><span style="font-size: 12pt; font-family: 宋体">栈溢出引起的</span><span style="font-size: 12pt; font-family: serif">Crash</span><span style="font-size: 12pt; font-family: 宋体">会在日志的文件头中看到</span><span style="font-size: 12pt; font-family: serif">&#8220;EXCEPTION_STACK_OVERFLOW&#8221;</span><span style="font-size: 12pt; font-family: 宋体">字样。另外，在当前线程的</span><span style="font-size: 12pt; font-family: serif">Stack</span><span style="font-size: 12pt; font-family: 宋体">信息中也能发现一些信息。例如下面的例子：</span><span style="font-size: 12pt; font-family: 宋体"><br />
</span><span style="font-size: 12pt; font-family: serif">-----------------------------------------------------------------------------------<br />
<br />
</span><span style="font-size: 12pt; font-family: 宋体">在上面的信息中，可以发现这是个栈溢出的错误。并且当前栈剩余的空间已经很小了</span><span style="font-size: 12pt; font-family: serif">(free space =4k)</span><span style="font-size: 12pt; font-family: 宋体">。因此建议将</span><span style="font-size: 12pt; font-family: serif">JVM</span><span style="font-size: 12pt; font-family: 宋体">的</span><span style="font-size: 12pt; font-family: serif">Stack</span><span style="font-size: 12pt; font-family: 宋体">的尺寸调大，主要设计两个参数：</span><span style="font-size: 12pt; font-family: serif">&#8220;-Xss&#8221; </span><span style="font-size: 12pt; font-family: 宋体">和</span><span style="font-size: 12pt; font-family: serif">&#8220;[font=Thorndale, serif]-XX:StackShadowPages=<em>n&#8221;</em>[/font]</span><span style="font-size: 12pt; font-family: 宋体">。</span><span style="font-size: 12pt; font-family: 宋体">但是，将栈的尺寸调大，也意味着在有限的内存资源中，能打开的最大线程数会减少。</span><span style="font-size: 12pt; font-family: serif"><br />
<br />
</span><span style="font-size: 12pt; font-family: 宋体">六</span><span style="font-size: 12pt; font-family: sans-serif">.</span><span style="font-size: 12pt; font-family: 宋体">动态编译引起的</span><span style="font-size: 12pt; font-family: sans-serif">Crash</span><span style="font-size: 12pt; font-family: 宋体">未完，待续</span></p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/142348.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-09-03 15:52 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142348.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java Excel API Beginning</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142346.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Mon, 03 Sep 2007 07:51:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142346.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/142346.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142346.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/142346.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/142346.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;Java Excel API Beginninghttp://www.yesky.com/18/1886018.shtml　　使用Windows操作系统的朋友对Excel（电子表格）一定不会陌生，但是要使用Java语言来操纵Excel文件并不是一件容易的事。在Web应用日益盛行的今天，通过Web来操作Excel文件的需求越来越强烈，目前较为流行的操作是在JSP或Servle...&nbsp;&nbsp;<a href='http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142346.html'>阅读全文</a><img src ="http://www.blogjava.net/hengheng123456789/aggbug/142346.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-09-03 15:51 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142346.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Docbook Beginning</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142345.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Mon, 03 Sep 2007 07:50:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142345.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/142345.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142345.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/142345.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/142345.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;Docbook Beginninghttp://blog.csdn.net/mickeyrat/archive/2005/02/04/281050.aspx编写技术文档，我想谁都遇到过。很多人都用MS Word，不可否认Word的功能确实非常强大，但是用Word有一些缺点无法避免：1) 写文档的时候，不得不兼顾文档的格式，这是件很头痛的事情，至少对我来说。经常是最后...&nbsp;&nbsp;<a href='http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142345.html'>阅读全文</a><img src ="http://www.blogjava.net/hengheng123456789/aggbug/142345.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-09-03 15:50 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142345.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java中文解决大全</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142343.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Mon, 03 Sep 2007 07:49:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142343.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/142343.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142343.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/142343.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/142343.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;java中文解决大全说明：本文为作者原创，作者联系地址为：josserchai@yahoo.com。由于Java编程中的中文问题是一个老生常谈的问题，在阅读了许多关于Java中文问题解决方法之后，结合作者的编程实践，我发现过去谈的许多方法都不能清晰地说明问题及解决问题，尤其是跨平台时的中文问题。于是我给出此篇文章，内容包括对控制台运行的class、Servelets、JSP及E...&nbsp;&nbsp;<a href='http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142343.html'>阅读全文</a><img src ="http://www.blogjava.net/hengheng123456789/aggbug/142343.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-09-03 15:49 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142343.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java 编程技术中汉字问题的分析及解决</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142342.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Mon, 03 Sep 2007 07:49:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142342.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/142342.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142342.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/142342.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/142342.html</trackback:ping><description><![CDATA[&nbsp;
<p style="text-align: center" align="center">Java <span style="font-family: 宋体">编程技术中汉字问题的分析及解决</span></p>
<p><span style="font-family: 宋体">现在</span> Java <span style="font-family: 宋体">编程语言已经广泛应用于互联网世界，早在</span> Sun <span style="font-family: 宋体">公司开发</span> Java <span style="font-family: 宋体">语言的时候，就已经考虑到对非英文字符的支持了。</span>Sun <span style="font-family: 宋体">公司公布的</span> Java <span style="font-family: 宋体">运行环境（</span>JRE<span style="font-family: 宋体">）本身就分英文版和国际版，但只有国际版才支持非英文字符。不过在</span> Java <span style="font-family: 宋体">编程语言的应用中，对中文字符的支持并非如同</span> Java Soft <span style="font-family: 宋体">的标准规范中所宣称的那样完美，因为中文字符集不只一个，而且不同的操作系统对中文字符的支持也不尽相同，所以会有许多和汉字编码处理有关的问题在我们进行应用开发中困扰着我们。有很多关于这些问题的解答，但都比较琐碎，并不能够满足大家迫切解决问题的愿望，关于</span> Java <span style="font-family: 宋体">中文问题的系统研究并不多，本文从汉字编码常识出发，分析</span> Java <span style="font-family: 宋体">中文问题，希望对大家解决这个问题有所帮助。</span></p>
<p><strong><span style="font-family: 宋体">汉字编码的常识</span></strong></p>
<p><span style="font-family: 宋体">我们知道，英文字符一般是以一个字节来表示的，最常用的编码方法是</span> ASCII <span style="font-family: 宋体">。但一个字节最多只能区分</span>256<span style="font-family: 宋体">个字符，而汉字成千上万，所以现在都以双字节来表示汉字，为了能够与英文字符分开，每个字节的最高位一定为</span>1<span style="font-family: 宋体">，这样双字节最多可以表示</span>64K<span style="font-family: 宋体">格字符。我们经常碰到的编码方式有</span> GB2312<span style="font-family: 宋体">、</span>BIG5<span style="font-family: 宋体">、</span>UNICODE <span style="font-family: 宋体">等。关于具体编码方式的详细资料，有兴趣的读者可以查阅相关资料。我肤浅谈一下和我们关系密切的</span> GB2312 <span style="font-family: 宋体">和</span> UNICODE<span style="font-family: 宋体">。</span>GB2312 <span style="font-family: 宋体">码，中华人民共和国国家标准汉字信息交换用编码，是一个由中华人民共和国国家标准总局发布的关于简化汉字的编码，通行于中国大陆地区及新加坡，简称国标码。两个字节中，第一个字节（高字节）的值为区号值加</span>32<span style="font-family: 宋体">（</span>20H<span style="font-family: 宋体">），第二个字节（低字节）的值为位号值加</span>32<span style="font-family: 宋体">（</span>20H<span style="font-family: 宋体">），用这两个值来表示一个汉字的编码。</span>UNICODE <span style="font-family: 宋体">码是微软提出的解决多国字符问题的多字节等长编码，它对英文字符采取前面加&#8220;</span>0<span style="font-family: 宋体">&#8221;字节的策略实现等长兼容。如</span> <span style="font-family: 宋体">&#8220;</span>A<span style="font-family: 宋体">&#8221;</span> <span style="font-family: 宋体">的</span> ASCII <span style="font-family: 宋体">码为</span>0x41<span style="font-family: 宋体">，</span>UNICODE <span style="font-family: 宋体">就为</span>0x00<span style="font-family: 宋体">，</span>0x41<span style="font-family: 宋体">。利用特殊的工具各种编码之间可以互相转换。</span></p>
<p><strong>Java </strong><strong><span style="font-family: 宋体">中文问题的初步认识</span></strong></p>
<p><span style="font-family: 宋体">我们基于</span> Java <span style="font-family: 宋体">编程语言进行应用开发时，不可避免地要处理中文。</span>Java <span style="font-family: 宋体">编程语言默认的编码方式是</span> UNICODE<span style="font-family: 宋体">，而我们通常使用的数据库及文件都是基于</span> GB2312 <span style="font-family: 宋体">编码的，我们经常碰到这样的情况：浏览基于</span> JSP <span style="font-family: 宋体">技术的网站看到的是乱码，文件打开后看到的也是乱码，被</span> Java <span style="font-family: 宋体">修改过的数据库的内容在别的场合应用时无法继续正确地提供信息。</span></p>
<p>String sEnglish = &#8220;apple&#8221;;</p>
<p>String sChinese = <span style="font-family: 宋体">&#8220;苹果&#8221;</span>;</p>
<p>String s = <span style="font-family: 宋体">&#8220;苹果</span> apple <span style="font-family: 宋体">&#8221;</span>;</p>
<p>sEnglish <span style="font-family: 宋体">的长度是</span>5<span style="font-family: 宋体">，</span>sChinese<span style="font-family: 宋体">的长度是</span>4<span style="font-family: 宋体">，而</span> s <span style="font-family: 宋体">默认的长度是</span>14<span style="font-family: 宋体">。对于</span> sEnglish<span style="font-family: 宋体">来说，</span> Java <span style="font-family: 宋体">中的各个类都支持得非常好，肯定能够正确显示。但对于</span> sChinese <span style="font-family: 宋体">和</span> s <span style="font-family: 宋体">来说，虽然</span> Java Soft <span style="font-family: 宋体">声明</span> Java <span style="font-family: 宋体">的基本类已经考虑到对多国字符的支持（默认</span> UNICODE <span style="font-family: 宋体">编码），但是如果操作系统的默认编码不是</span> UNICODE <span style="font-family: 宋体">，而是国标码等。从</span> Java <span style="font-family: 宋体">源代码到得到正确的结果，要经过</span> <span style="font-family: 宋体">&#8220;</span>Java <span style="font-family: 宋体">源代码</span>-&gt; Java <span style="font-family: 宋体">字节码</span>-&gt; ;<span style="font-family: 宋体">虚拟机</span>-&gt;<span style="font-family: 宋体">操作系统</span>-&gt;<span style="font-family: 宋体">显示设备&#8221;的过程。在上述过程中的每一步骤，我们都必须正确地处理汉字的编码，才能够使最终的显示结果正确。</span></p>
<p><span style="font-family: 宋体">&#8220;</span> Java <span style="font-family: 宋体">源代码</span>-&gt; Java <span style="font-family: 宋体">字节码&#8221;，标准的</span> Java <span style="font-family: 宋体">编译器</span> javac <span style="font-family: 宋体">使用的字符集是系统默认的字符集，比如在中文</span> Windows <span style="font-family: 宋体">操作系统上就是</span> GBK ,<span style="font-family: 宋体">而在</span> Linux <span style="font-family: 宋体">操作系统上就是</span>ISO-8859-1<span style="font-family: 宋体">，所以大家会发现在</span> Linux <span style="font-family: 宋体">操作系统上编译的类中源文件中的中文字符都出了问题，解决的办法就是在编译的时候添加</span> encoding <span style="font-family: 宋体">参数，这样才能够与平台无关。用法是</span></p>
<p>javac ?Cencoding GBK<span style="font-family: 宋体">。</span></p>
<p><span style="font-family: 宋体">&#8220;</span> Java <span style="font-family: 宋体">字节码</span>-&gt;<span style="font-family: 宋体">虚拟机</span>-&gt;<span style="font-family: 宋体">操作系统&#8221;，</span> Java <span style="font-family: 宋体">运行环境</span> <span style="font-family: 宋体">（</span>JRE<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">分英文版和国际版，但只有国际版才支持非英文字符。</span> Java <span style="font-family: 宋体">开发工具包</span> <span style="font-family: 宋体">（</span>JDK<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">肯定支持多国字符，但并非所有的计算机用户都安装了</span> JDK <span style="font-family: 宋体">。很多操作系统及应用软件为了能够更好的支持</span> Java <span style="font-family: 宋体">，都内嵌了</span> JRE <span style="font-family: 宋体">的国际版本，为自己支持多国字符提供了方便。</span></p>
<p><span style="font-family: 宋体">&#8220;操作系统</span>-&gt;<span style="font-family: 宋体">显示设备&#8221;，对于汉字来说，操作系统必须支持并能够显示它。英文操作系统如果不搭配特殊的应用软件的话，是肯定不能够显示中文的。</span></p>
<p><span style="font-family: 宋体">还有一个问题，就是在</span> Java <span style="font-family: 宋体">编程过程中，对中文字符进行正确的编码转换。例如，向网页输出中文字符串的时候，不论你是用</span></p>
<p>out.println(string);<span style="font-family: 宋体">还是用</span></p>
<p>&lt;%=string%&gt;<span style="font-family: 宋体">，都必须作</span> UNICODE <span style="font-family: 宋体">到</span> GBK <span style="font-family: 宋体">的转换，或者手动，或者自动。在</span> JSP 1.0<span style="font-family: 宋体">中，可以定义输出字符集，从而实现内码的自动转换。用法是</span></p>
<p>&lt;%@page contentType=&#8221;text/html;charset=gb2312&#8221; %&gt;</p>
<p><span style="font-family: 宋体">但是在一些</span> JSP <span style="font-family: 宋体">版本中并没有提供对输出字符集的支持，（例如</span> JSP 0.92<span style="font-family: 宋体">），这就需要手动编码输出了，方法非常多。最常用的方法是</span></p>
<p>String s1 = request.getParameter(&#8220;keyword&#8221;);</p>
<p>String s2 = new String(s1.getBytes(&#8220;ISO-8859-1&#8221;),&#8221;GBK&#8221;);</p>
<p>getBytes <span style="font-family: 宋体">方法用于将中文字符以&#8220;</span>ISO-8859-1<span style="font-family: 宋体">&#8221;编码方式转化成字节数组，而&#8220;</span>GBK<span style="font-family: 宋体">&#8221;</span> <span style="font-family: 宋体">是目标编码方式。我们从以</span>ISO-8859-1<span style="font-family: 宋体">方式编码的数据库中读出中文字符串</span> s1 <span style="font-family: 宋体">，经过上述转换过程，在支持</span> GBK <span style="font-family: 宋体">字符集的操作系统和应用软件中就能够正确显示中文字符串</span> s2 <span style="font-family: 宋体">。</span></p>
<p><strong>Java </strong><strong><span style="font-family: 宋体">中文问题的表层分析及处理</span></strong></p>
<p><span style="font-family: 宋体">背景</span>&nbsp;</p>
<p><span style="font-family: 宋体">开发环境</span>&nbsp;JDK1.15&nbsp;Vcafe2.0&nbsp;JPadPro&nbsp;</p>
<p><span style="font-family: 宋体">服务器端</span>&nbsp;NT IIS&nbsp;Sybase System&nbsp;Jconnect<span style="font-family: 宋体">（</span>JDBC<span style="font-family: 宋体">）</span>&nbsp;</p>
<p><span style="font-family: 宋体">客户端</span>&nbsp;IE5.0&nbsp;Pwin98&nbsp;?span &gt;&nbsp;</p>
<p>.CLASS <span style="font-family: 宋体">文件存放在服务器端，由客户端的浏览器运行</span> APPLET <span style="font-family: 宋体">，</span> APPLET <span style="font-family: 宋体">只起调入</span> FRAME <span style="font-family: 宋体">类等主程序的作用。界面包括</span> Textfield <span style="font-family: 宋体">，</span>TextArea<span style="font-family: 宋体">，</span>List<span style="font-family: 宋体">，</span>Choice <span style="font-family: 宋体">等。</span></p>
<p>I.<span style="font-family: 宋体">用</span> JDBC <span style="font-family: 宋体">执行</span> SELECT <span style="font-family: 宋体">语句从服务器端读取数据（中文）后，将数据用</span> APPEND <span style="font-family: 宋体">方法加到</span> TextArea<span style="font-family: 宋体">（</span>TA<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">，不能正确显示。但加到</span> List <span style="font-family: 宋体">中时，大部分汉字却可正确显示。</span></p>
<p><span style="font-family: 宋体">将数据按&#8220;</span>ISO-8859-1<span style="font-family: 宋体">&#8221;</span> <span style="font-family: 宋体">编码方式转化为字节数组，再按系统缺省编码方式</span> <span style="font-family: 宋体">（</span>Default Character Encoding<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">转化为</span> STRING <span style="font-family: 宋体">，即可在</span> TA <span style="font-family: 宋体">和</span> List <span style="font-family: 宋体">中正确显示。</span></p>
<p><span style="font-family: 宋体">程序段如下：</span></p>
<p>dbstr2 = results.getString(1);</p>
<p>//After reading the result from DB server<span style="font-family: 宋体">，</span>converting it to string.</p>
<p>dbbyte1 = dbstr2.getBytes(&#8220;iso-8859-1&#8221;);</p>
<p>dbstr1 = new String(dbbyte1); </p>
<p><span style="font-family: 宋体">在转换字符串时不采用系统默认编码方式，而直接采用&#8220;</span> GBK<span style="font-family: 宋体">&#8221;</span> <span style="font-family: 宋体">或者</span> <span style="font-family: 宋体">&#8220;</span>GB2312<span style="font-family: 宋体">&#8221;</span> ,<span style="font-family: 宋体">在</span> A <span style="font-family: 宋体">和</span> B <span style="font-family: 宋体">两种情况下，从数据库取数据都没有问题。</span></p>
<p>II.<span style="font-family: 宋体">处理方式与&#8220;取中文&#8221;相逆，先将</span> SQL <span style="font-family: 宋体">语句按系统缺省编码方式转化为字节数组，再按&#8220;</span>ISO-8859-1<span style="font-family: 宋体">&#8221;编码方式转化为</span> STRING <span style="font-family: 宋体">，最后送去执行，则中文信息可正确写入数据库。</span></p>
<p><span style="font-family: 宋体">程序段如下：</span></p>
<p>sqlstmt = tf_input.getText();</p>
<p>//Before sending statement to DB server<span style="font-family: 宋体">，</span>converting it to sql statement.</p>
<p>dbbyte1 = sqlstmt.getBytes();</p>
<p>sqlstmt = newString(dbbyte1,&#8221;iso-8859-1&#8221;);</p>
<p>_stmt = _con.createStatement();</p>
<p>_stmt.executeUpdate(sqlstmt);</p>
<p><span style="font-family: 宋体">&#8230;&#8230;</span></p>
<p><span style="font-family: 宋体">问题：如果客户机上存在</span> CLASSPATH <span style="font-family: 宋体">指向</span> JDK <span style="font-family: 宋体">的</span> CLASSES.ZIP <span style="font-family: 宋体">时（称为</span> A <span style="font-family: 宋体">情况），上述程序代码可正确执行。但是如果客户机只有浏览器，而没有</span> JDK <span style="font-family: 宋体">和</span> CLASSPATH <span style="font-family: 宋体">时（称为</span> B <span style="font-family: 宋体">情况），则汉字无法正确转换。</span></p>
<p><span style="font-family: 宋体">我们的分析：</span></p>
<p>1.<span style="font-family: 宋体">经过测试，在</span> A <span style="font-family: 宋体">情况下，程序运行时系统的缺省编码方式为</span> GBK <span style="font-family: 宋体">或者</span> GB2312 <span style="font-family: 宋体">。在</span> B <span style="font-family: 宋体">情况下，程序启动时浏览器的</span> JAVA <span style="font-family: 宋体">控制台中出现如下错误信息：</span></p>
<p>Can't find resource for sun.awt.windows.awtLocalization_zh_CN </p>
<p><span style="font-family: 宋体">然后系统的缺省编码方式为&#8220;</span>8859-1<span style="font-family: 宋体">&#8221;。</span></p>
<p>2.<span style="font-family: 宋体">如果在转换字符串时不采用系统缺省编码方式，而是直接采用</span> <span style="font-family: 宋体">&#8220;</span>GBK<span style="font-family: 宋体">&#8221;</span> <span style="font-family: 宋体">或&#8220;</span>GB2312<span style="font-family: 宋体">&#8221;，则在</span> A <span style="font-family: 宋体">情况下程序仍然可正常运行，在</span> B <span style="font-family: 宋体">情况下，系统出现错误：</span></p>
<p>UnsupportedEncodingException<span style="font-family: 宋体">。</span></p>
<p>3.<span style="font-family: 宋体">在客户机上，把</span> JDK <span style="font-family: 宋体">的</span> CLASSES.ZIP <span style="font-family: 宋体">解压后，放在另一个目录中，</span> CLASSPATH <span style="font-family: 宋体">只包含该目录。然后一边逐步删除该目录中的</span> .CLASS <span style="font-family: 宋体">文件，另一边运行测试程序，最后发现在一千多个</span> CLASS <span style="font-family: 宋体">文件中，只有一个是必不可少的，该文件是：</span></p>
<p>sun.io.CharToByteDoubleByte.class<span style="font-family: 宋体">。</span></p>
<p><span style="font-family: 宋体">将该文件拷到服务器端和其它的类放在一起，并在程序的开头</span> IMPORT <span style="font-family: 宋体">它，在</span> B <span style="font-family: 宋体">情况下程序仍然无法正常运行。</span></p>
<p>4.<span style="font-family: 宋体">在</span> A <span style="font-family: 宋体">情况下，如果在</span> CLASSPTH <span style="font-family: 宋体">中去掉</span> sun.io.CharToByteDoubleByte.class <span style="font-family: 宋体">，则程序运行时测得默认编码方式为&#8220;</span>8859-1<span style="font-family: 宋体">&#8221;，否则为</span> <span style="font-family: 宋体">&#8220;</span>GBK<span style="font-family: 宋体">&#8221;</span> <span style="font-family: 宋体">或</span> <span style="font-family: 宋体">&#8220;</span>GB2312<span style="font-family: 宋体">&#8221;</span> <span style="font-family: 宋体">。</span></p>
<p><span style="font-family: 宋体">如果</span> JDK <span style="font-family: 宋体">的版本为</span>1.2<span style="font-family: 宋体">以上的话，在</span> B <span style="font-family: 宋体">情况下遇到的问题得到了很好的解决，测试的步骤同上，有兴趣的读者可以尝试一下。</span></p>
<p><strong>Java </strong><strong><span style="font-family: 宋体">中文问题的根源分析及解决</span></strong></p>
<p><span style="font-family: 宋体">在简体中文</span> MS Windows 98 + JDK 1.3 <span style="font-family: 宋体">下，可以用</span> System.getProperties() <span style="font-family: 宋体">得到</span> Java <span style="font-family: 宋体">运行环境的一些基本属性，类</span> PoorChinese <span style="font-family: 宋体">可以帮助我们得到这些属性。</span></p>
<p><span style="font-family: 宋体">类</span> PoorChinese <span style="font-family: 宋体">的源代码：</span></p>
<p>public class PoorChinese {</p>
<p>} </p>
<p><span style="font-family: 宋体">执行</span> java PoorChinese <span style="font-family: 宋体">后，我们会得到</span>:</p>
<p><span style="font-family: 宋体">系统变量</span> file.encoding <span style="font-family: 宋体">的值为</span> GBK <span style="font-family: 宋体">，</span>user.language <span style="font-family: 宋体">的值为</span> zh <span style="font-family: 宋体">，</span> user.region <span style="font-family: 宋体">的值为</span> CN <span style="font-family: 宋体">，这些系统变量的值决定了系统默认的编码方式是</span> GBK <span style="font-family: 宋体">。</span></p>
<p><span style="font-family: 宋体">在上述系统中，下面的代码将</span> GB2312 <span style="font-family: 宋体">文件转换成</span> Big5 <span style="font-family: 宋体">文件，它们能够帮助我们理解</span> Java <span style="font-family: 宋体">中汉字编码的转化</span>:</p>
<p>?</p>
<p>import java.io.*;</p>
<p>import java.util.*;</p>
<p>?</p>
<p>public class gb2big5 {</p>
<p>?</p>
<p>static int iCharNum=0;</p>
<p>?</p>
<p>public static void main(String[] args) {</p>
<p>System.out.println("Input GB2312 file, output Big5 file.");</p>
<p>if (args.length!=2) {</p>
<p>System.err.println("Usage: jview gb2big5 gbfile big5file");</p>
<p>System.exit(1);</p>
<p>String inputString = readInput(args[0]);</p>
<p>writeOutput(inputString,args[1]);</p>
<p>System.out.println("Number of Characters in file: "+iCharNum+".");</p>
<p>}</p>
<p>?</p>
<p>static void writeOutput(String str, String strOutFile) {</p>
<p>try {</p>
<p>FileOutputStream fos = new FileOutputStream(strOutFile);</p>
<p>Writer out = new OutputStreamWriter(fos, "Big5");</p>
<p>out.write(str);</p>
<p>out.close();</p>
<p>}</p>
<p>catch (IOException e) {</p>
<p>e.printStackTrace();</p>
<p>e.printStackTrace();</p>
<p>}</p>
<p>}</p>
<p>?</p>
<p>static String readInput(String strInFile) {</p>
<p>StringBuffer buffer = new StringBuffer();</p>
<p>try {</p>
<p>FileInputStream fis = new FileInputStream(strInFile);</p>
<p>InputStreamReader isr = new InputStreamReader(fis, "GB2312");</p>
<p>Reader in = new BufferedReader(isr);</p>
<p>int ch;</p>
<p>while ((ch = in.read()) &gt; -1) {</p>
<p>iCharNum += 1;</p>
<p>buffer.append((char)ch);</p>
<p>}</p>
<p>in.close();</p>
<p>return buffer.toString();</p>
<p>}</p>
<p>catch (IOException e) {</p>
<p>e.printStackTrace();</p>
<p>return null;</p>
<p>}</p>
<p>}</p>
<p>}</p>
<p>?</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;</p>
<p><span style="font-family: 宋体">编码转化的过程如下：</span></p>
<p>GB2312------------------&gt;Unicode-------------&gt;Big5</p>
<p><span style="font-family: 宋体">执行</span> java gb2big5 gb.txt big5.txt <span style="font-family: 宋体">，如果</span> gb.txt <span style="font-family: 宋体">的内容是&#8220;今天星期三&#8221;，则得到的文件</span> big5.txt <span style="font-family: 宋体">中的字符能够正确显示；而如果</span> gb.txt <span style="font-family: 宋体">的内容是&#8220;情人节快乐&#8221;，则得到的文件</span> big5.txt <span style="font-family: 宋体">中对应于&#8220;节&#8221;和&#8220;乐&#8221;的字符都是符号&#8220;？&#8221;（</span>0x3F<span style="font-family: 宋体">），可见</span> sun.io.ByteToCharGB2312 <span style="font-family: 宋体">和</span> sun.io.CharToByteBig5 <span style="font-family: 宋体">这两个基本类并没有编好。</span></p>
<p><span style="font-family: 宋体">正如上例一样，</span> Java <span style="font-family: 宋体">的基本类也可能存在问题。由于国际化的工作并不是在国内完成的，所以在这些基本类发布之前，没有经过严格的测试，所以对中文字符的支持并不像</span> Java Soft <span style="font-family: 宋体">所声称的那样完美。前不久，我的一位技术上的朋友发信给我说，他终于找到了</span> Java Servlet <span style="font-family: 宋体">中文问题的根源。两周以来，他一直为</span> Java Servlet <span style="font-family: 宋体">的中文问题所困扰，因为每面对一个含有中文字符的字符串都必须进行强制转换才能够得到正确的结果（这好象是大家公认的唯一的解决办法）。后来，他确实不想如此继续安分下去了，因为这样的事情确实不应该是高级程序员所要做的工作，他就找出</span> Servlet <span style="font-family: 宋体">解码的源代码进行分析，因为他怀疑问题就出在解码这部分。经过四个小时的奋斗，他终于找到了问题的根源所在。原来他的怀疑是正确的，</span> Servlet <span style="font-family: 宋体">的解码部分完全没有考虑双字节，直接把</span> %XX <span style="font-family: 宋体">当作一个字符。（原来</span> Java Soft <span style="font-family: 宋体">也会犯这幺低级的错误！）</span></p>
<p><span style="font-family: 宋体">如果你对这个问题有兴趣或者遇到了同样的烦恼的话，你可以按照他的步骤</span> <span style="font-family: 宋体">对</span>Servlet.jar <span style="font-family: 宋体">进行修改：</span></p>
<p><span style="font-family: 宋体">找到源代码</span> HttpUtils <span style="font-family: 宋体">中的</span> static private String parseName <span style="font-family: 宋体">，在返回前将</span> sb<span style="font-family: 宋体">（</span>StringBuffer<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">复制成</span> byte bs[] <span style="font-family: 宋体">，然后</span> return new String(bs,<span style="font-family: 宋体">&#8221;</span>GB2312<span style="font-family: 宋体">&#8221;</span>)<span style="font-family: 宋体">。作上述修改后就需要自己解码了：</span></p>
<p>HashTable form=HttpUtils .parseQueryString(request.getQueryString())<span style="font-family: 宋体">或者</span></p>
<p>form=HttpUtils.parsePostData(&#8230;&#8230;)</p>
<p><span style="font-family: 宋体">千万别忘了编译后放到</span> Servlet.jar <span style="font-family: 宋体">里面。</span></p>
<p><strong><span style="font-family: 宋体">关于</span> Java </strong><strong><span style="font-family: 宋体">中文问题的总结</span></strong></p>
<p>Java <span style="font-family: 宋体">编程语言成长于网络世界，这就要求</span> Java <span style="font-family: 宋体">对多国字符有很好的支持。</span> Java <span style="font-family: 宋体">编程语言适应了计算的网络化的需求，为它能够在网络世界迅速成长奠定了坚实的基础。</span> Java <span style="font-family: 宋体">的缔造者</span> <span style="font-family: 宋体">（</span>Java Soft<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">已经考虑到</span> Java <span style="font-family: 宋体">编程语言对多国字符的支持，只是现在的解决方案有很多缺陷在里面，需要我们付诸一些补偿性的措施。而世界标准化组织也在努力把人类所有的文字统一在一种编码之中，其中一种方案是</span> ISO10646 <span style="font-family: 宋体">，它用四个字节来表示一个字符。当然，在这种方案未被采用之前，还是希望</span> Java Soft <span style="font-family: 宋体">能够严格地测试它的产品，为用户带来更多的方便。</span></p>
<p><span style="font-family: 宋体">附一个用于从数据库和网络中取出</span> <span style="font-family: 宋体">中文乱码的处理函数，入参是有问题的字符串，出参是问题已经解决了的字符串。</span></p>
<p><span style="font-family: 宋体">技术应用者提供解决方案</span></p>
<p><span style="font-family: 宋体">关于作者</span></p>
<p>&nbsp;<span style="font-family: 宋体">段明辉</span> has co-authored this article</p>
<p style="text-align: left" align="left"><span style="font-size: 8.5pt; color: blue; font-family: 宋体">编译代码文件</span><span style="font-size: 8.5pt; color: blue; font-family: Verdana">,</span><span style="font-size: 8.5pt; color: blue; font-family: 宋体">要用</span></p>
<p style="text-align: left" align="left"><span style="font-size: 8.5pt; color: blue; font-family: Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; javac -encoding GBK&nbsp;&nbsp; xxxxxx.java </span></p>
<p style="text-align: left" align="left"><span style="font-size: 8.5pt; color: blue; font-family: Verdana">&nbsp; &nbsp;</span><span style="font-size: 8.5pt; color: blue; font-family: 宋体">如果是用</span><span style="font-size: 8.5pt; color: blue; font-family: Verdana">ant</span><span style="font-size: 8.5pt; color: blue; font-family: 宋体">工具</span><span style="font-size: 8.5pt; color: blue; font-family: Verdana">,</span></p>
<p style="text-align: left" align="left"><span style="font-size: 8.5pt; color: blue; font-family: Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;target name="compile" depends="prepare" description="complie All Java source"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&lt;copy todir="${build.dir}"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&lt;fileset dir="${src.dir}" includes="**/*.properties" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/copy&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;javac srcdir="${src.dir}" destdir="${build.dir}" encoding="<strong><span style="background: yellow">GBK</span></strong>"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&lt;classpath refid="project.classpath" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&lt;/javac&gt;</span></p>
<p style="text-align: left" align="left"><span style="font-size: 8.5pt; color: blue; font-family: Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/target&gt;</span></p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/142342.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-09-03 15:49 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142342.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>制作Java安装程序</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142341.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Mon, 03 Sep 2007 07:48:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142341.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/142341.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142341.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/142341.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/142341.html</trackback:ping><description><![CDATA[&nbsp;
<p style="text-align: center" align="center"><strong><span style="font-family: 宋体">制作</span>Java</strong><strong><span style="font-family: 宋体">安装程序</span></strong></p>
<p><a href="http://zeroliu.blogdriver.com/zeroliu/1183916.html">http://zeroliu.blogdriver.com/zeroliu/1183916.html</a></p>
<p><span style="font-family: 宋体">这个工具利用</span> ANT <span style="font-family: 宋体">来制作在</span> Windows, MacOS X, Unix <span style="font-family: 宋体">平台上可执行的文件，比如</span> exe<span style="font-family: 宋体">，</span>zip<span style="font-family: 宋体">，</span>jar<span style="font-family: 宋体">。</span>ROXES ANT Tasks <span style="font-family: 宋体">基于</span> GPL <span style="font-family: 宋体">发布。</span>&nbsp;</p>
<p>&nbsp;http://www.roxes.com/produkte/rat.html </p>
<p>&nbsp;<span style="font-family: 宋体">企业开源参考架构</span></p>
<p>Java Web<span style="font-family: 宋体">应用产品安装程序制作方案</span></p>
<p><span style="font-family: 宋体">目录：</span></p>
<p><span style="font-family: 宋体">一．背景</span></p>
<p><span style="font-family: 宋体">二．开源工具</span></p>
<p><span style="font-family: 宋体">三．环境准备</span></p>
<p><span style="font-family: 宋体">四．技术准备</span></p>
<p>4.1. Jsmooth</p>
<p>4.1.1. Jsmooth<span style="font-family: 宋体">简介</span></p>
<p>4.1.2.<span style="font-family: 宋体">工作原理</span></p>
<p>4.2. IzPack</p>
<p>4.2.1.IzPack<span style="font-family: 宋体">简介</span></p>
<p>4.2.2.<span style="font-family: 宋体">工作原理</span></p>
<p><span style="font-family: 宋体">五．方案实例</span></p>
<p><span style="font-family: 宋体">六．结束</span></p>
<p><span style="font-family: 宋体">一．</span> <span style="font-family: 宋体">背景：</span></p>
<p><span style="font-family: 宋体">随着</span>Java<span style="font-family: 宋体">在应用产品开发中的广泛应用，基于</span>Java<span style="font-family: 宋体">的应用产品也就越来越多，那么如何为基于</span>Java<span style="font-family: 宋体">的应用产品制作安装程序的需求就产生了。以前人们一般都是使用</span>InstallShield<span style="font-family: 宋体">与</span>InstallAnyWhere<span style="font-family: 宋体">进行产品安装程序的制作，这是两个功能非常强大、易用的安装盘制作工具，尤其是</span>InstallAnyWhere<span style="font-family: 宋体">，它还支持</span>Java<span style="font-family: 宋体">应用产品安装制作，例如：大名鼎鼎的</span>Jbuilder<span style="font-family: 宋体">安装程序就是由它制作的。</span></p>
<p><span style="font-family: 宋体">本文并不准备对这些商业的安装制作工具进行讨论，本文将就如何利用开源的安装制作工具来进行</span>Java Web<span style="font-family: 宋体">应用产品程序制作进行一些探讨。</span></p>
<p><span style="font-family: 宋体">二．</span> <span style="font-family: 宋体">开源工具：</span></p>
<p><span style="font-family: 宋体">目前用于支持</span>Java<span style="font-family: 宋体">应用安装程序制作的开源工具非常丰富，本人将要本人在研究过程中所遇到的罗列一二以供参考：</span></p>
<p>Packlet</p>
<p>Packlet<span style="font-family: 宋体">是一个简单的</span>Java<span style="font-family: 宋体">安装制作工具。它将</span>Java Application<span style="font-family: 宋体">打包成一个可以发布的类似于</span>zip<span style="font-family: 宋体">或</span>tgz<span style="font-family: 宋体">的压缩文件中。这个压缩文件被简为</span>packlet<span style="font-family: 宋体">，它可以在安装有</span>Java 2 Runtime Environment<span style="font-family: 宋体">的操作系统上执行</span>. <span style="font-family: 宋体">通过执行</span>packlet<span style="font-family: 宋体">将会给用户提供一个图形化的安装配置界面并解压应用。</span></p>
<p>Go To Packlet </p>
<p>IzPack</p>
<p>IzPack<span style="font-family: 宋体">是一个用于</span>Java<span style="font-family: 宋体">平台的安装程序生成器。它用于产生一个轻量级、能运行于所有安装了</span>JVM<span style="font-family: 宋体">的任何的操作系统的安装程序。生成的安装程序可以通过双击或在</span>Command Line<span style="font-family: 宋体">通过</span>java <span style="font-family: 宋体">&#8211;</span>jar install.jar<span style="font-family: 宋体">命令进行启动，安装程序运行的方式具体将看操作系统的支持方式。</span>IzPack<span style="font-family: 宋体">的主要好处就是能够生成运行于任意操作系统的安装程序。</span></p>
<p>Go To IzPack </p>
<p>JSmooth</p>
<p>Jsmooth<span style="font-family: 宋体">可以将</span>Java<span style="font-family: 宋体">可执行应用</span>Wrapper<span style="font-family: 宋体">成</span>window<span style="font-family: 宋体">可执行</span>Exe<span style="font-family: 宋体">程序。通过</span>Jsmooth<span style="font-family: 宋体">生成的</span>Exe<span style="font-family: 宋体">程序会自动按制作时定义的顺序寻找合适的</span>JVM<span style="font-family: 宋体">，如果能不查找到</span>JVM<span style="font-family: 宋体">，安装程序会提示用户并能根据定义好的</span>URL<span style="font-family: 宋体">启动</span>Web Browser<span style="font-family: 宋体">让用户下载</span>JVM. <span style="font-family: 宋体">注意：</span>Jsmooth<span style="font-family: 宋体">并不是纯</span>Java<span style="font-family: 宋体">应用。</span></p>
<p>Go To JSmooth </p>
<p>VAInstall</p>
<p>VAInsall<span style="font-family: 宋体">是一个用</span>Java<span style="font-family: 宋体">写的多平台安装程序工具。它是基于</span>GNU GPL2.0<span style="font-family: 宋体">许可。通过一个简单的配置文件，它允许安装程序打包工具由不同的目录下收集程序包，这与一般情况下安装程序制作工具只能由一个根目录开始相比更为灵活。由</span>VAInstall<span style="font-family: 宋体">生成的安装程序允许先择不同的安装模式</span>(graphic,text<span style="font-family: 宋体">或</span>ansi)<span style="font-family: 宋体">。</span></p>
<p>Go To VAInstall </p>
<p>Java Service Wrapper</p>
<p><span style="font-family: 宋体">用于将</span>Java Application<span style="font-family: 宋体">安装成为</span>Window NT Service.<span style="font-family: 宋体">同时与之附带的</span>scripts<span style="font-family: 宋体">能够很容易将</span>Java Application<span style="font-family: 宋体">安装成为</span>UNIX<span style="font-family: 宋体">的后台进程。</span></p>
<p>Go To Java Service Wrapper </p>
<p>Lift Off Java Installer</p>
<p>Lift Off Java Installer<span style="font-family: 宋体">的最大特色就是：自解压</span>class <span style="font-family: 宋体">文件，对目标系统要求低以及跨平台性。</span></p>
<p>Go To Lift Off Java Installer </p>
<p>Toolshed</p>
<p><span style="font-family: 宋体">一个小巧、简单、纯</span>Java<span style="font-family: 宋体">实现的安装程序制作工作。</span></p>
<p>Go To Toolshed </p>
<p>Launch4J</p>
<p>Lauch4J<span style="font-family: 宋体">也是一个</span>Java<span style="font-family: 宋体">应用</span>Window Exe<span style="font-family: 宋体">封装工具。通过</span>Lauch4J<span style="font-family: 宋体">，可以提供</span>splash screen, <span style="font-family: 宋体">图标，自动查询</span>JRE<span style="font-family: 宋体">或内置</span>JRE<span style="font-family: 宋体">等功能，同时还支持启动失败反馈以及命令行参数。</span></p>
<p>Go To Launch4J </p>
<p>AntInstaller</p>
<p>AntInstaller<span style="font-family: 宋体">是一个安装程序框架，它利用一个简单的</span>XML<span style="font-family: 宋体">定义安装界面，并以</span>Ant<span style="font-family: 宋体">执行安装过程。基于</span>AntInstaller<span style="font-family: 宋体">的安装程序可以打包成自解压</span>jar<span style="font-family: 宋体">通过</span>command line<span style="font-family: 宋体">执行可</span>Swing GUI<span style="font-family: 宋体">来执行。</span></p>
<p>Go To AntInstaller </p>
<p>Antigen</p>
<p>Antigen----<span style="font-family: 宋体">即</span>Ant Installer Generator<span style="font-family: 宋体">。它主要的目的就是根据</span>Ant<span style="font-family: 宋体">脚本创建图形化安装程序。</span></p>
<p>Go To Antigen </p>
<p>FreeInstaller</p>
<p>FreeInstaller<span style="font-family: 宋体">是一个开源项目，完全用</span>Java<span style="font-family: 宋体">编写。它将应用程序打包成一个自解压的</span>Java<span style="font-family: 宋体">应用。通过</span>FreeInstaller<span style="font-family: 宋体">可以将</span>Java<span style="font-family: 宋体">或非</span>Java<span style="font-family: 宋体">的应用安装到</span>UNIX,LINUX<span style="font-family: 宋体">以及</span>window NT<span style="font-family: 宋体">系统中。</span></p>
<p>Go To FreeInstaller </p>
<p>Mini Installer</p>
<p><span style="font-family: 宋体">一个简单的</span>Java<span style="font-family: 宋体">安装程序制作工具。整个制作过程是通过脚本完成的，最终生成一个可以通过双击方式执行的</span>jar<span style="font-family: 宋体">文件。</span></p>
<p>Go To Mini Installer </p>
<p><span style="font-family: 宋体">通过对如上各产品的初步探索，本人最终选择了利用</span>izpack + jsmooth<span style="font-family: 宋体">作为</span>Java Web<span style="font-family: 宋体">应用产品的安装程序制作方案。选择这两种工具并不代表其它开源工具不好，只是本人自已结合自已项目的需求</span>(<span style="font-family: 宋体">本人负责公司一企业应用开发平台的研发工作</span>)<span style="font-family: 宋体">及本人的偏好作出的选择。</span></p>
<p><span style="font-family: 宋体">由于本人所在公司为商业公司，所以本文描述的方案并不是企业应用开发系统平台的实现模式，本文只是提供一个解决办法，关于如何与自已的框架或平台进行有效的整合，请读者自行考虑。</span></p>
<p><span style="font-family: 宋体">三．</span> <span style="font-family: 宋体">环境准备：</span></p>
<p><span style="font-family: 宋体">你需要安装</span>J2SDK1.4.1+<span style="font-family: 宋体">版本；关于</span>J2SDK<span style="font-family: 宋体">请由</span>Sun<span style="font-family: 宋体">公司下载；</span></p>
<p><span style="font-family: 宋体">你需要安装</span>Ant1.6.2<span style="font-family: 宋体">版本，理论上其它版本也行，只是本人用的是</span>1.6.2<span style="font-family: 宋体">；</span></p>
<p><span style="font-family: 宋体">请下载并安装</span>izpack<span style="font-family: 宋体">；设定定装到</span>IZPACK_HOME</p>
<p><span style="font-family: 宋体">请下载并安装</span>jsmooth<span style="font-family: 宋体">；设定安装到</span>JSMOOTH_HOME</p>
<p><span style="font-family: 宋体">四．</span> <span style="font-family: 宋体">技术准备：</span></p>
<p><span style="font-family: 宋体">为了便于理解，你需要对</span>Java<span style="font-family: 宋体">进行应用的开发有一定的基础，本例将以</span>Web<span style="font-family: 宋体">应用的安装程序制作为背景进行相关介绍，所以需要你对</span>Web <span style="font-family: 宋体">应用开发以及其发布方式有一定的基础；另外，本方案将会以</span>Ant<span style="font-family: 宋体">作为应用</span>build<span style="font-family: 宋体">的工具，所以你需要有一定的</span>Ant<span style="font-family: 宋体">技术；对于如上相关知识本部分不准备介绍。下面本部分将主要对</span>izpack<span style="font-family: 宋体">及</span>jsmooth<span style="font-family: 宋体">进行简单的介绍。</span></p>
<p>4.1. jsmooth<span style="font-family: 宋体">：</span></p>
<p>4.1.1 Jsmooth <span style="font-family: 宋体">简介：</span></p>
<p>Jsmooth<span style="font-family: 宋体">，一个</span>Java<span style="font-family: 宋体">可执行应用封装器</span>(Wrapper)<span style="font-family: 宋体">，即将</span>Java<span style="font-family: 宋体">可执行应用程序</span>(<span style="font-family: 宋体">即可执行</span>jar)<span style="font-family: 宋体">封装为</span>Window<span style="font-family: 宋体">可执行文件</span>------exe<span style="font-family: 宋体">文件的工具。</span></p>
<p><span style="font-family: 宋体">通过</span>Jsmooth<span style="font-family: 宋体">将可执行</span>jar<span style="font-family: 宋体">封装为</span>Exe<span style="font-family: 宋体">文件，使得用户执行</span>Java<span style="font-family: 宋体">应用就如同执行一般的</span>Window<span style="font-family: 宋体">应用程序一样，重用用户经验。</span></p>
<p>Jsmooth<span style="font-family: 宋体">对</span>jar<span style="font-family: 宋体">进行封装时可以设定</span>classpath<span style="font-family: 宋体">，</span>JVM<span style="font-family: 宋体">参数，命令行参数，</span>JVM<span style="font-family: 宋体">版本及位置，这样用户在执行</span>exe<span style="font-family: 宋体">时不用关心</span>JVM,Classpath<span style="font-family: 宋体">等问题，这样就简化了</span>Java<span style="font-family: 宋体">应用执行。</span></p>
<p>4.1.2 <span style="font-family: 宋体">工作原理：</span></p>
<p><span style="font-family: 宋体">通过</span>Jsmooth<span style="font-family: 宋体">生成的</span>Window Exe<span style="font-family: 宋体">文件通常定义为&#8220;</span>Jsmooth Application<span style="font-family: 宋体">&#8221;；</span></p>
<p><span style="font-family: 宋体">要想生成</span>Jsmooth Application<span style="font-family: 宋体">，我们需要一个</span>JsmoothGen <span style="font-family: 宋体">项目文件</span>-----.jsmooth<span style="font-family: 宋体">文件，后面我们将其称为&#8220;</span>.jsmooth<span style="font-family: 宋体">文件&#8221;；</span>.jsmooth<span style="font-family: 宋体">文件实际上是一个</span>xml<span style="font-family: 宋体">文件，用于描述</span>/<span style="font-family: 宋体">定义</span>Jsmooth Application<span style="font-family: 宋体">的相关属性，例如：</span>classpath, JVM<span style="font-family: 宋体">，</span>Java main<span style="font-family: 宋体">方法类，以及其它与</span>Java<span style="font-family: 宋体">应用运行相关的各种设定等；通常你可以通过</span>Jsmooth<span style="font-family: 宋体">提供的</span>JsmoothGen.exe--------Windows Project Editor<span style="font-family: 宋体">来创建和编辑这个文件，这个</span>Editor<span style="font-family: 宋体">如下图所示：</span></p>
<p>(<span style="font-family: 宋体">图</span>-1)Widnow Project Editor</p>
<p>(<span style="font-family: 宋体">图</span>-2)Widnow Project Editor</p>
<p>(<span style="font-family: 宋体">图</span>-3)Widnow Project Editor</p>
<p><span style="font-family: 宋体">在</span>.jsmooth<span style="font-family: 宋体">文件生成之后，就可以通过如下方式生成目标</span>Jsmooth Application<span style="font-family: 宋体">，即</span>Exe<span style="font-family: 宋体">文件：</span></p>
<p>(1)<span style="font-family: 宋体">。</span>Window Project Editor<span style="font-family: 宋体">：</span></p>
<p><span style="font-family: 宋体">你可以直接在如上图所示的编辑器通过工具条来生成：</span>Project<span style="font-family: 宋体">&#224;</span>Create Exe<span style="font-family: 宋体">。</span></p>
<p>(2)<span style="font-family: 宋体">。</span>Command Line<span style="font-family: 宋体">：</span></p>
<p><span style="font-family: 宋体">你也可以进入。</span>jsmooth<span style="font-family: 宋体">文件所以目录，通过如下命令来生成目标</span>Exe<span style="font-family: 宋体">文件：</span></p>
<p><span style="font-family: 宋体">&#8230;&#8230;&#8230;</span>&gt; %jsmooth_home%"jsmoothcmd.exe yourproject.jsmooth</p>
<p>(3)<span style="font-family: 宋体">。通过</span>Ant<span style="font-family: 宋体">任务调用生成目标</span>Exe<span style="font-family: 宋体">：</span></p>
<p><span style="font-family: 宋体">首先你需要在你的</span>build<span style="font-family: 宋体">文件中加入</span>jsmooth Ant <span style="font-family: 宋体">任务定义：</span></p>
<p>&lt;&gt;&nbsp;</p>
<p>classname="net.charabia.jsmoothgen.ant.JSmoothGen" </p>
<p>classpath="${jsmooth_home}/lib/jsmoothgen-ant.jar"/&gt;</p>
<p><span style="font-family: 宋体">然后，通过</span>jsmoothgen<span style="font-family: 宋体">任务来执行生成</span>Exe<span style="font-family: 宋体">的工作：</span></p>
<p>skeletonroot=&#8221;${jsmooth_home}/skeletons&#8221;/&gt;</p>
<p><span style="font-family: 宋体">所以通过</span>Jsmooth<span style="font-family: 宋体">我们可以很容易将</span>Java Application<span style="font-family: 宋体">制作</span>Windows Exe<span style="font-family: 宋体">应用。</span></p>
<p><span style="font-family: 宋体">关于</span>Jsmooth<span style="font-family: 宋体">的详细介绍请参考</span>http://jsmooth.sourceforge.net</p>
<p>4.2. izpack<span style="font-family: 宋体">：</span></p>
<p>4.2.1. izpack<span style="font-family: 宋体">简介：</span></p>
<p>izpack<span style="font-family: 宋体">是基于</span>Apache Software License 2.0<span style="font-family: 宋体">许可的开源项目；</span></p>
<p>izpack<span style="font-family: 宋体">是纯</span>Java<span style="font-family: 宋体">，对部分特性有针对不同平台版本的</span>Library<span style="font-family: 宋体">。例如：快捷键的创建。</span></p>
<p>izpack<span style="font-family: 宋体">是一个用于解决安装程序制作的</span>Builder<span style="font-family: 宋体">工具；</span></p>
<p><span style="font-family: 宋体">通过</span>izpack<span style="font-family: 宋体">制作的安装程序可以运行于不同的操作系统，</span>Windows, Linux, Unix<span style="font-family: 宋体">等，只要安装了</span>JDK1.4<span style="font-family: 宋体">以及其后版本即可；</span></p>
<p>izpack<span style="font-family: 宋体">优秀的模块化设计可以允许你定制安装程序外观、安装过程等；同时允许你通过其提供</span>API<span style="font-family: 宋体">调整</span>izpack<span style="font-family: 宋体">安装过程。</span></p>
<p>izpack<span style="font-family: 宋体">的主要功能包括</span>(<span style="font-family: 宋体">但不限于</span>)<span style="font-family: 宋体">：</span></p>
<p><span style="font-family: 宋体">&#183;</span> XML based installation files </p>
<p><span style="font-family: 宋体">&#183;</span> easy internationalization using XML files (10 translations are already available) </p>
<p><span style="font-family: 宋体">&#183;</span> Ant integration, command-line compiler </p>
<p><span style="font-family: 宋体">&#183;</span> easy customization with the panels and a rich API (even an XML parser is included !) </p>
<p><span style="font-family: 宋体">&#183;</span> powerful variable substitution system that you can use to customize scripts and more generally any text-based file </p>
<p><span style="font-family: 宋体">&#183;</span> different kinds of installers (standard, web-based, ...) </p>
<p><span style="font-family: 宋体">&#183;</span> launching of external executables during the installation process and Unix executable flag support (useful for the scripts for instance) </p>
<p><span style="font-family: 宋体">&#183;</span> layout of the installation files in packs (some can be optional) </p>
<p><span style="font-family: 宋体">&#183;</span> native code integration facilities </p>
<p><span style="font-family: 宋体">&#183;</span> jar files nesting support </p>
<p><span style="font-family: 宋体">&#183;</span> ... more things to discover and create !. </p>
<p>(<span style="font-family: 宋体">图</span>-4)IzPack<span style="font-family: 宋体">制作的安装界面示例－选择安装的</span>Pack.</p>
<p>4.2.2. <span style="font-family: 宋体">原理及过程</span></p>
<p><span style="font-family: 宋体">利用</span>izpack<span style="font-family: 宋体">制作安装程序的主要有两步：</span></p>
<p><span style="font-family: 宋体">第一步：创建并描述安装定义文件；</span></p>
<p><span style="font-family: 宋体">第二步：通过</span>izpack<span style="font-family: 宋体">提供</span>CommandLine<span style="font-family: 宋体">工具或</span>Ant Task<span style="font-family: 宋体">对安装定义文件进行编译，编译的结果即是生成一个可执行的</span>jar<span style="font-family: 宋体">文件，其中包括了整个安装过程的实现以及安装数据；</span></p>
<p><span style="font-family: 宋体">安装定义文件：</span></p>
<p><span style="font-family: 宋体">安装过程定义文件是一个</span>XML<span style="font-family: 宋体">文件，</span>installation<span style="font-family: 宋体">是根元素，表示定义的开始。定义主要由如下几部分组成：</span></p>
<p>1<span style="font-family: 宋体">．&#8230;</span>.</p>
<p><span style="font-family: 宋体">用于定义安装程序的基本信息；</span></p>
<p><span style="font-family: 宋体">产品中文名称</span></p>
<p><span style="font-family: 宋体">产品版本号，例如：</span>1.0-062312</p>
<p><span style="font-family: 宋体">公司网址</span></p>
<p>JDK<span style="font-family: 宋体">版本号：</span>1.4.2 </p>
<p>2<span style="font-family: 宋体">．&#8230;&#8230;</span></p>
<p><span style="font-family: 宋体">用于定义安装程序界面信息，例如：</span></p>
<p>3.&#8230;&#8230;..</p>
<p><span style="font-family: 宋体">定义变量或配置信息，变量在整个安装制作的过程中非常重要，变量两种用途：其一：作为配置用，例如可以通过按照一定的命名称规则为某个变量设定一个值，</span>izpack<span style="font-family: 宋体">在执行安装过程中将会读取某个变量的值来决定某个安装向导窗口是否可见等；例如：我们可以通过定义</span>compareToVariable.<span style="font-family: 宋体">、</span>compareToOperator.<span style="font-family: 宋体">与</span>compareToValue.<span style="font-family: 宋体">的组合决定第个用户自定义的向导窗口在安装时是否可见，这样就可以通过上个窗口用户选择来决定下个窗口是否可见；其二：作为替换变量用，通常安装过程中收集的信息存放在变量中，然后，在安装程序进行到最后，利用变量的值来替换安装目标文件中的内容。</span></p>
<p>4. &#8230;.</p>
<p><span style="font-family: 宋体">决定，安装程序界面所支持的语言。</span></p>
<p>5. &#8230;&#8230;..</p>
<p><span style="font-family: 宋体">用于为安装界面指定图片或图标</span></p>
<p><span style="font-family: 宋体">用于指定用户自定义安装向导窗口定义</span>XML<span style="font-family: 宋体">文件的位置</span></p>
<p><span style="font-family: 宋体">用于指定安装向导窗口中国际化资源</span>XML<span style="font-family: 宋体">文件的位置</span></p>
<p><span style="font-family: 宋体">等等，例如：</span></p>
<p>&lt;resources&gt;</p>
<p>&lt;res src="langsel.jpg" id="installer.langsel.img" /&gt;</p>
<p>&lt;res src="readme.html" id="HTMLInfoPanel.info" parse="yes" type="plain" encoding="GB2312" /&gt;</p>
<p>&lt;res src="readme_chn.html" id="HTMLInfoPanel.info_chn" parse="yes" type="plain" encoding="GB2312" /&gt;</p>
<p>&lt;res src="license.html" id="HTMLLicencePanel.licence" parse="yes" type="plain" encoding="GB2312" /&gt;</p>
<p>&lt;res src="license_chn.html" id="HTMLLicencePanel.licence_chn" parse="yes" type="plain" encoding="GB2312" /&gt;</p>
<p>&lt;res src="shortcutSpec.xml" id="shortcutSpec.xml" parse="yes" type="xml" encoding="GB2312" /&gt;</p>
<p>&lt;res src="Unix_shortcutSpec.xml" id="Unix_shortcutSpec.xml" parse="yes" type="xml" encoding="GB2312" /&gt;</p>
<p>&lt;res src="packsLang.xml" id="packsLang.xml" /&gt;</p>
<p>&lt;res src="packsLang_chn.xml" id="packsLang.xml_chn" /&gt;</p>
<p>&lt;res src="UserInputSpec.xml" id="userInputSpec.xml" /&gt;</p>
<p>&lt;res src="UserInputLang.xml" id="userInputLang.xml" /&gt;</p>
<p>&lt;res src="UserInputLang_chn.xml" id="userInputLang.xml_chn" /&gt;</p>
<p>resources&gt; </p>
<p>6. &#8230;&#8230;. </p>
<p><span style="font-family: 宋体">本部分用于定义整个安装过程，每个</span>panel<span style="font-family: 宋体">即是一个安装向导窗口，</span>panel<span style="font-family: 宋体">是按顺序由</span>IzPack<span style="font-family: 宋体">调用的。</span>IzPack<span style="font-family: 宋体">内置了很多的</span>Panel<span style="font-family: 宋体">，另外它还支持用户自定义的功能，主要是通过</span>UserInputPanel<span style="font-family: 宋体">来实现的，你可以通过在&#8230;&#8230;中定义的</span>ID<span style="font-family: 宋体">为</span>UserInputSpec.xml<span style="font-family: 宋体">的资源</span>(XML)<span style="font-family: 宋体">中定义</span>UserInputPanel<span style="font-family: 宋体">窗口中用户录入项目及相关存放的变量。另外，</span>Izpack<span style="font-family: 宋体">支持条件用户自定义</span>Panel,<span style="font-family: 宋体">即</span>ConditionalUserInputPanel<span style="font-family: 宋体">，你可以在&#8230;</span>.<span style="font-family: 宋体">中通过变量来控制这样的向导窗口的可见性。当安装过程执行到</span>InstallPanel<span style="font-family: 宋体">时</span>IzPack<span style="font-family: 宋体">开始解压安装包到硬盘中，所以，一般来说所有的配置信息</span>(<span style="font-family: 宋体">例如，安装目录，安装包的选择等</span>)<span style="font-family: 宋体">都应在</span>InstallPanel<span style="font-family: 宋体">之前完成。在</span>InstallPanel<span style="font-family: 宋体">之后可以通过</span>ShortcutPanel<span style="font-family: 宋体">来显示快捷方式创建窗口，另外还可以通过</span>ProcessPanel<span style="font-family: 宋体">来执行一些后续操作。</span></p>
<p>&lt;panels&gt;</p>
<p>&lt;panel classname="HTMLLicencePanel" /&gt;</p>
<p>&lt;panel classname="HTMLInfoPanel" /&gt;</p>
<p>&lt;panel classname="TargetPanel" /&gt;</p>
<p>&lt;panel classname="PacksPanel" /&gt;</p>
<p>&lt;panel classname="UserInputPanel" /&gt;</p>
<p>&lt;panel classname="SummaryPanel" /&gt;</p>
<p>&lt;panel classname="InstallPanel" /&gt;</p>
<p>&lt;panel classname="ShortcutPanel" /&gt;</p>
<p>&lt;panel classname="SimpleFinishPanel" /&gt;</p>
<p>panels&gt; </p>
<p>7. &#8230;&#8230;. </p>
<p><span style="font-family: 宋体">本部分主要用于定义安装包，即将哪些文件进行打包，以及将来安装时如何进行安装。通过可以将应用程序文件分解成不同的安装包，可以指定哪些</span>pack<span style="font-family: 宋体">是必须安装的，哪些是可选的。</span></p>
<p><span style="font-family: 宋体">前边我们讲过，我们可以在中加入自定义向导窗口来允许用户指定一些配置，这些配置信息被存放到变量中，我们可以利用用户指定的值来替换应用程序中部分文件中的内容。那么在定义</span>pack<span style="font-family: 宋体">时，就可以指定哪些文件在安装时需要进行解析</span>(parseable)<span style="font-family: 宋体">。需要注意的，你需要指定需要解析的方式</span>(xml, javaprop, plain,shell)<span style="font-family: 宋体">，如查将</span>javaprop<span style="font-family: 宋体">类型的文件解析类型设定为</span>plain<span style="font-family: 宋体">的话，可以就有问题，例如：如果变量的值为路径，那么在可能就会有问题。</span></p>
<p><span style="font-family: 宋体">另，对于每一个</span>Pack<span style="font-family: 宋体">在它安装</span>(copy<span style="font-family: 宋体">文件</span>)<span style="font-family: 宋体">之后，可以定义它执行一个程序，例如脚本程序。你可以利用这种功能来做一些工作，例如：你可执行脚本程序来导入数据库数据等。</span></p>
<p><span style="font-family: 宋体">下面是一个示例：</span></p>
<p>&lt;packs&gt;</p>
<p>&lt;pack id="ToolKit" name="ToolKit" required="yes"&gt;</p>
<p><span style="font-family: 宋体">&#8230;&#8230;&#8230;&#8230;</span></p>
<p>pack&gt;</p>
<p>&lt;pack id="Core" name="Core" required="yes"&gt;</p>
<p>&lt;description&gt;<span style="font-family: 宋体">在</span>packsLang.xml<span style="font-family: 宋体">和</span>packsLang.xml_chn<span style="font-family: 宋体">中描述了</span>.description&gt;</p>
<p>&lt;fileset dir="app" targetdir="$INSTALL_PATH"app"&gt;</p>
<p>&lt;include name="*" /&gt;</p>
<p>&lt;include name="**" /&gt;</p>
<p>fileset&gt;</p>
<p>&lt;fileset dir="native" targetdir="$INSTALL_PATH"native"&gt;</p>
<p>&lt;include name="*" /&gt;</p>
<p>&lt;include name="**" /&gt;</p>
<p>fileset&gt;</p>
<p>&lt;file src="clear.db.splash.gif" targetdir="$INSTALL_PATH" /&gt;</p>
<p>&lt;file src="init.db.splash.gif" targetdir="$INSTALL_PATH" /&gt;</p>
<p>&lt;file src="installer.properties" targetdir="$INSTALL_PATH" /&gt;</p>
<p>&lt;file src="installer.xml" targetdir="$INSTALL_PATH" /&gt;</p>
<p>&lt;file src="installer.bat" targetdir="$INSTALL_PATH" /&gt;</p>
<p>&lt;file src="uninstaller.bat" targetdir="$INSTALL_PATH" /&gt;</p>
<p>&lt;parsable targetfile="$INSTALL_PATH/installer.properties" </p>
<p>type="javaprop" /&gt;</p>
<p>&amp; </p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/142341.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-09-03 15:48 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142341.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java中调用其它的程序</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142335.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Mon, 03 Sep 2007 07:44:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142335.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/142335.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142335.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/142335.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/142335.html</trackback:ping><description><![CDATA[&nbsp;
<p style="text-align: center" align="center">Java<span style="font-family: 宋体">中调用其它的程序</span></p>
<p>1<span style="font-family: 宋体">、运行外部程序：</span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Runtime.getRuntime().exec("notepad");</p>
<p>2<span style="font-family: 宋体">、运行系统内部命令：</span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Runtime.getRuntime().exec("command.com /c dir");</p>
<p>Runtime.getRuntime().exec("cmd xxx");</p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/142335.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-09-03 15:44 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142335.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SVN Beginning-2</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142332.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Mon, 03 Sep 2007 07:40:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142332.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/142332.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142332.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/142332.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/142332.html</trackback:ping><description><![CDATA[&nbsp;
<p style="text-align: center" align="center">SVN Beginning-2</p>
<p><strong><span style="background: yellow">SVN</span></strong><strong><span style="background: yellow; font-family: 宋体">版本问题解决方案：</span></strong></p>
<p><span style="color: red; font-family: Arial">1</span><span style="color: red; font-family: 宋体">、</span><span style="color: red; font-family: Arial">svn: Expected version '3' of repository; found version '5' /</span><span style="font-size: 10pt; color: red; font-family: Arial"> svn: Expected format '3' of repository; found format '5'</span></p>
<p><span style="color: red; font-family: 宋体">把</span><span style="color: red; font-family: Arial">home/svnroot/repository/test/format</span><span style="color: red; font-family: 宋体">文件中的</span><span style="color: red; font-family: Arial">5</span><span style="color: red; font-family: 宋体">改成</span><span style="color: red; font-family: Arial">3</span><span style="color: red; font-family: 宋体">就可以了</span><span style="color: red; font-family: Arial">. </span></p>
<p><span style="color: red; font-family: Arial">2</span><span style="color: red; font-family: 宋体">、</span><span style="color: red; font-family: Arial">svn: Expected FS format '1'; found format '2'</span></p>
<p><span style="color: red; font-family: 宋体">把</span><span style="color: red; font-family: Arial">home/svnroot/repository/test/db/format</span><span style="color: red; font-family: 宋体">文件中的</span><span style="color: red; font-family: Arial">2</span><span style="color: red; font-family: 宋体">改成</span><span style="color: red; font-family: Arial">1</span><span style="color: red; font-family: 宋体">就可以了</span><span style="color: red; font-family: Arial">.</span></p>
<p>Linux<span style="font-family: 宋体">环境下</span>Subversion,apache2,ssl<span style="font-family: 宋体">配置安装（</span>FC4<span style="font-family: 宋体">系统）</span></p>
<p>/////////////////////////////////////////////////////////// </p>
<p><span style="font-family: 宋体">工具包</span></p>
<p>httpd-2.2.4 </p>
<p><span style="font-family: 宋体">下载地址</span></p>
<p>[url=http://apache.justdn.org/httpd/]http://apache.justdn.org/httpd/[/url] </p>
<p>apr-1.2.8 </p>
<p>apr-util-1.2.8 </p>
<p><span style="font-family: 宋体">下载地址</span></p>
<p>[url=http://apache.justdn.org/apr/]http://apache.justdn.org/apr/[/url] </p>
<p>openssl </p>
<p>openssl-0.9.7d.tar.gz </p>
<p><span style="font-family: 宋体">下载地址</span></p>
<p>http://www.openssl.org/source/ </p>
<p><span style="font-family: 宋体">证书软件</span></p>
<p>ssl.ca-0.1.tar.gz </p>
<p><span style="font-family: 宋体">下载地址</span></p>
<p>http://www.openssl.org/contrib/ssl.ca-0.1.tar.gz </p>
<p>SVN </p>
<p><span style="font-family: 宋体">下载地址</span></p>
<p>[url=http://www.iusesvn.com/bbs/download/subversion-1.4.0.tar.gz]http://www.iusesvn.com/bbs/download/subversion-1.4.0.tar.gz[/url] </p>
<p>////////////////////////////////////////////////////////////////////// </p>
<p><span style="font-family: 宋体">开始安装</span></p>
<p><span style="font-family: 宋体">安装</span>apr,apr-util </p>
<p>tar zxvf apr-1.2.8.tar.gz </p>
<p>cd apr-1.2.8 </p>
<p>./configure --prefix=/usr/local/apr </p>
<p>make </p>
<p>make install </p>
<p>tar zxvf apr-util-1.2.8.tar.gz </p>
<p>cd apr-util-1.2.8 </p>
<p>./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr make </p>
<p>make install </p>
<p># tar zxvf openssl-0.9.8d.tar.gz </p>
<p># cd openssl-0.9.8d </p>
<p># ./config --prefix=/usr/local/openssl </p>
<p># make </p>
<p># make install </p>
<p><span style="font-family: 宋体">安装</span>apache </p>
<p>tar zxvf httpd-2.2.3.tar.gz </p>
<p>cd httpd-2.2.3 </p>
<p>./configure --prefix=/usr/local/apache2 --enable-so --enable-rewrite=share --enable-proxy=share --enable-proxy-ajp=share --enable-dav=share --enable-dav-fs --with-apr=/usr/local/apr/ --with-apr-util=/usr/local/apr-util/ --enable-ssl=static --with-ssl=/usr/local/ssl --enable-mods-shared=all //<span style="font-family: 宋体">此语句意思是把所有模块都添加上，在这里可以不写</span></p>
<p>make </p>
<p>make install </p>
<p><span style="font-family: 宋体">其中</span>/usr/local/ssl<span style="font-family: 宋体">目录自己建</span></p>
<p><span style="font-family: 宋体">安装</span>SVN </p>
<p>tar zxvf subversion-1.4.2.tar.gz </p>
<p>cd subversion-1.4.2 </p>
<p>./configure --with-apxs=/usr/local/apache2/bin/apxs --prefix=/usr/local/subversion --with-apr=/usr/local/apr --with-apr-util=/usr/local/apr-util --with-ssl --with-zlib --enable-maintainer-mode </p>
<p>make </p>
<p>make install </p>
<p>/////////////////////////////////////////////////////////// </p>
<p><span style="font-family: 宋体">配置</span></p>
<p>1.//<span style="font-family: 宋体">创建库文件</span></p>
<p># mkdir /home/svnroot/repository //<span style="font-family: 宋体">进入</span>subversion<span style="font-family: 宋体">的</span>bin<span style="font-family: 宋体">目录</span></p>
<p># cd /usr/local/subversion/bin </p>
<p># ./svnadmin create /home/svnroot/repository/test //<span style="font-family: 宋体">创建仓库</span>"test" </p>
<p># ls <span style="font-family: 宋体">&#8211;</span>l /home/svnroot/repository/test //<span style="font-family: 宋体">看看是不是多了些文件，如果是则说明</span>Subversion<span style="font-family: 宋体">安装成功了</span></p>
<p># cd /usr/local/subverion/bin </p>
<p># ./svn import /home/user/import file:///home/svnroot/repository/test <span style="font-family: 宋体">&#8211;</span>m "init" //<span style="font-family: 宋体">这条语句将把路径</span>/home/user/import<span style="font-family: 宋体">下找到的文件导入到你创建的</span>Subversion <span style="font-family: 宋体">仓库中去，其中</span>/user/import/<span style="font-family: 宋体">下有自己的项目</span>.<span style="font-family: 宋体">提交后的修订版为</span>1<span style="font-family: 宋体">。</span></p>
<p>apache<span style="font-family: 宋体">进程的权限：因为所有跟仓库传输的操作都是通过</span>apache<span style="font-family: 宋体">进程进行的，所以即使你给</span>svn<span style="font-family: 宋体">用户设置了很大的权限，但是</span>apache<span style="font-family: 宋体">进程没有访问仓库或者相关文件的权限也没有用，</span>apache<span style="font-family: 宋体">进程的权限设置在</span> /usr/local/apache2/conf/httpd.conf <span style="font-family: 宋体">文件中配置，找到文件中的这两行：</span></p>
<p>User daemon # <span style="font-family: 宋体">将</span>daemon<span style="font-family: 宋体">改为</span>svnroot<span style="font-family: 宋体">，</span></p>
<p>Group daemon </p>
<p>2.<span style="font-family: 宋体">修改</span>Apache<span style="font-family: 宋体">配置文件</span></p>
<p># cd /usr/local/apache2/bin </p>
<p># ./apachect1 start //<span style="font-family: 宋体">启动</span>Apache </p>
<p># vi /opt/apache2/conf/httpd.conf //<span style="font-family: 宋体">在最下面添加</span></p>
<p>#LoadModule dav_svn_module modules/mod_dav_svn.so </p>
<p>#LoadModule authz_svn_module modules/mod_authz_svn.so //<span style="font-family: 宋体">如果有可不写</span></p>
<p>&lt;Location /svn&gt; </p>
<p>DAV svn </p>
<p>SVNParentPath /home/svnroot/repository/ //svn<span style="font-family: 宋体">父目录</span></p>
<p>AuthzSVNAccessFile /home/svnroot/repository/authz.conf //<span style="font-family: 宋体">权限配置文件</span></p>
<p>AuthType Basic //<span style="font-family: 宋体">连接类型设置</span></p>
<p>AuthName "Subversion.zoneyump" //<span style="font-family: 宋体">连接框提示</span></p>
<p>AuthUserFile /home/svnroot/repository/authfile //<span style="font-family: 宋体">用户配置文件</span></p>
<p>Require valid-user //<span style="font-family: 宋体">采用何种认证</span></p>
<p>&lt;/Location&gt; </p>
<p>#"Require valid-user"<span style="font-family: 宋体">告诉</span>apache<span style="font-family: 宋体">在</span>authfile<span style="font-family: 宋体">中所有的用户都可以访问。如果没有它，则只能第一个用户可以访问新建库</span></p>
<p>3.<span style="font-family: 宋体">创建用户配置文件</span></p>
<p>#cd /usr/local/apache2/bin </p>
<p>#htpasswd -c /home/svnroot/repository/authfile wooin //<span style="font-family: 宋体">其中</span>authfile<span style="font-family: 宋体">是通过来创建的</span></p>
<p>4.<span style="font-family: 宋体">配置用户访问权限</span>: </p>
<p>vi /home/svnroot/repository/authz.conf //<span style="font-family: 宋体">示例</span></p>
<p>[groups] </p>
<p>admin = mangosoft </p>
<p>[/] </p>
<p>@admin = rw </p>
<p>[test:/] </p>
<p>@admin = rw </p>
<p>wooin = rw </p>
<p><span style="font-family: 宋体">为了简化配置，</span>3<span style="font-family: 宋体">个版本库共用</span>1<span style="font-family: 宋体">个权限配置文件</span>/home/svnroot/repository/pwd.conf<span style="font-family: 宋体">。如有必要，也可以分开。文件中定义用户组和版本库目录权限。</span></p>
<p><span style="font-family: 宋体">注意：</span></p>
<p>* <span style="font-family: 宋体">权限配置文件中出现的用户名必须已在用户配置文件中定义。</span></p>
<p>* <span style="font-family: 宋体">对权限配置文件的修改立即生效，不必重启</span>svn<span style="font-family: 宋体">。</span></p>
<p><span style="font-family: 宋体">用户组格式：</span></p>
<p>[groups] </p>
<p>&lt;<span style="font-family: 宋体">用户组名</span>&gt; = &lt;<span style="font-family: 宋体">用户</span>1&gt;,&lt;<span style="font-family: 宋体">用户</span>2&gt; </p>
<p><span style="font-family: 宋体">其中，</span>1<span style="font-family: 宋体">个用户组可以包含</span>1<span style="font-family: 宋体">个或多个用户，用户间以逗号分隔。</span></p>
<p><span style="font-family: 宋体">版本库目录格式：</span></p>
<p>[&lt;<span style="font-family: 宋体">版本库</span>&gt;:/<span style="font-family: 宋体">项目</span>/<span style="font-family: 宋体">目录</span>] </p>
<p>@&lt;<span style="font-family: 宋体">用户组名</span>&gt; = &lt;<span style="font-family: 宋体">权限</span>&gt; </p>
<p>&lt;<span style="font-family: 宋体">用户名</span>&gt; = &lt;<span style="font-family: 宋体">权限</span>&gt; </p>
<p><span style="font-family: 宋体">其中，方框号内部分可以有多种写法</span>: </p>
<p>/,<span style="font-family: 宋体">表示根目录及以下。根目录是</span>svnserve<span style="font-family: 宋体">启动时指定的，我们指定为</span>/home/svnroot/repository<span style="font-family: 宋体">。这样，</span>/<span style="font-family: 宋体">就是表示对全部版本库设置权限。</span></p>
<p>test:/,<span style="font-family: 宋体">表示对版本库</span>test<span style="font-family: 宋体">设置权限</span></p>
<p><span style="font-family: 宋体">权限主体可以是用户组、用户或</span>*<span style="font-family: 宋体">，用户组在前面加</span>@<span style="font-family: 宋体">，</span>*<span style="font-family: 宋体">表示全部用户。权限可以是</span>w<span style="font-family: 宋体">、</span>r<span style="font-family: 宋体">、</span>wr<span style="font-family: 宋体">和空，空表示没有任何权限。</span></p>
<p>5. <span style="font-family: 宋体">不让其他人有该目录的权限</span></p>
<p># chown -R svnroot:daemon /home/svnroot/repository //<span style="font-family: 宋体">，这里的用户名可以自己定</span></p>
<p>6.<span style="font-family: 宋体">检验是否成功</span></p>
<p><span style="font-family: 宋体">重启</span>apache </p>
<p>cd /usr/local/apache2/bin/ </p>
<p>./apachectl restart </p>
<p>//<span style="font-family: 宋体">打开浏览器访问</span>[url=http://localhost/svn/test/] </p>
<p>http://localhost/svn/test/ //<span style="font-family: 宋体">如果有东西显示就说明成功。</span></p>
<p><span style="font-family: 宋体">注意：如果没成功在</span>/usr/local/apache2/htdocs/<span style="font-family: 宋体">下建一个</span>favicon.ico<span style="font-family: 宋体">文件</span>. </p>
<p>//////////////////////////////////////////////////////// </p>
<p><span style="font-family: 宋体">基本应用</span></p>
<p>1. <span style="font-family: 宋体">权限管理</span></p>
<p>1)<span style="font-family: 宋体">增加用户</span></p>
<p># htpasswd [-c] /home/svnroot/repository/authfile wooin //<span style="font-family: 宋体">第一次设置用户时使用</span>-c<span style="font-family: 宋体">表示新建一个用户文件。回车后输入用户密码，</span></p>
<p># htpasswd authfile <span style="font-family: 宋体">用户名</span>(<span style="font-family: 宋体">加入新的用户</span>) //<span style="font-family: 宋体">完成对用户</span> <span style="font-family: 宋体">的增加</span></p>
<p>2)<span style="font-family: 宋体">权限分配</span></p>
<p># vi /home/svnroot/repository/authz.conf </p>
<p>[test:/] //<span style="font-family: 宋体">这表示，仓库</span>test<span style="font-family: 宋体">的根目录下的访问权限</span></p>
<p>wooin = rw //test<span style="font-family: 宋体">仓库</span>wooin<span style="font-family: 宋体">用户具有读和写权限</span></p>
<p>bao = r //test<span style="font-family: 宋体">仓库</span>bao<span style="font-family: 宋体">用户具有读权限</span></p>
<p>[test2:/] //test2<span style="font-family: 宋体">仓库根目录下的访问权限</span></p>
<p>wooin = r //wooin<span style="font-family: 宋体">用户在</span>test2<span style="font-family: 宋体">仓库根目录下只有读权限</span></p>
<p>bao = //bao<span style="font-family: 宋体">用户在</span> test2<span style="font-family: 宋体">仓库根目录下无任何权限</span></p>
<p>[/] //<span style="font-family: 宋体">这个表示在所有仓库的根目录下</span></p>
<p>* = r //<span style="font-family: 宋体">这个表示对所有的用户都具有读权限</span></p>
<p>#[groups] //<span style="font-family: 宋体">这个表示群组设置</span></p>
<p>#svn1-developers = wooin, bao //<span style="font-family: 宋体">这个表示某群</span> <span style="font-family: 宋体">组里的成员</span></p>
<p>#svn2-developers = wooin </p>
<p>#[svn1:/] </p>
<p>#@svn1-developers = rw //<span style="font-family: 宋体">如果在前面加上</span>@<span style="font-family: 宋体">符号，则表</span> <span style="font-family: 宋体">示这是个群组权限设置</span></p>
<p><span style="font-family: 宋体">将这个设置完成后。重启</span>Apache<span style="font-family: 宋体">，就可以通过</span></p>
<p>http://localhost/svn/test </p>
<p><span style="font-family: 宋体">这个</span>URL<span style="font-family: 宋体">来访问仓库了，当然，受权限的限制，必须是合法用户才能访问且具有相应的权限</span></p>
<p>2. <span style="font-family: 宋体">在</span>/etc/profile<span style="font-family: 宋体">的结尾设置一些</span>svn<span style="font-family: 宋体">启动时要做的工作</span></p>
<p># start apache server for svn </p>
<p>/usr/sbin/apachectl start </p>
<p>export SVN_EDITOR=vi </p>
<p>3. <span style="font-family: 宋体">如果</span>linux<span style="font-family: 宋体">的登录用户名密码都和</span>svn<span style="font-family: 宋体">的其中一个用户名密码相同时，在</span>checkout<span style="font-family: 宋体">的时候不会要求输入用户名密码直接就可以</span>checkout<span style="font-family: 宋体">出来。比如：</span>linux<span style="font-family: 宋体">有个用户</span>wooin<span style="font-family: 宋体">，</span>svn<span style="font-family: 宋体">也有一个用户</span>wooin<span style="font-family: 宋体">，并且密码都是一样的，当用</span>wooin<span style="font-family: 宋体">登录</span>linux<span style="font-family: 宋体">后，执行</span>checkout<span style="font-family: 宋体">，可以直接提取出源码文件，不用输入现ば畔ⅰ</span>?</p>
<p>4. <span style="font-family: 宋体">在</span>svn<span style="font-family: 宋体">使用过程中牵扯到几种权限：文件系统的权限，</span>linux<span style="font-family: 宋体">系统权限，</span>svn<span style="font-family: 宋体">用户的权限，</span>apache<span style="font-family: 宋体">进程的权限。</span></p>
<p><span style="font-family: 宋体">文件系统的权限，</span>linux<span style="font-family: 宋体">系统权限：这里相同的意思，就是平时大家使用</span>linux<span style="font-family: 宋体">时文件夹和文件的访问权限。在</span> svn<span style="font-family: 宋体">建立仓库，文件夹，配置文件的时候用</span>svnroot<span style="font-family: 宋体">用户，并将仓库权限设置为</span>700<span style="font-family: 宋体">，不允许其他用户直接通过文件系统查看，只能由</span>svnroot<span style="font-family: 宋体">进行管理。</span></p>
<p>apache<span style="font-family: 宋体">进程的权限：因为所有跟仓库传输的操作都是通过</span>apache<span style="font-family: 宋体">进程进行的，所以即使你给</span>svn<span style="font-family: 宋体">用户设置了很大的权限，但是</span>apache<span style="font-family: 宋体">进程没有访问仓库或者相关文件的权限也没有用，</span>apache<span style="font-family: 宋体">进程的权限设置在</span> /usr/local/apache2/conf/httpd.conf <span style="font-family: 宋体">文件中配置，找到文件中的这两行：</span></p>
<p>User daemon # <span style="font-family: 宋体">将</span>daemon<span style="font-family: 宋体">改为</span>svnroot<span style="font-family: 宋体">，让</span>apache<span style="font-family: 宋体">进程以</span>svnroot<span style="font-family: 宋体">的身份运行</span></p>
<p>Group daemon </p>
<p>svn<span style="font-family: 宋体">用户的权限：就是在</span>authz.conf<span style="font-family: 宋体">文件中设置的权限信息，是</span>svn<span style="font-family: 宋体">用来管理仓库访问权限的。</span></p>
<p>5. <span style="font-family: 宋体">重新部署</span>SVN<span style="font-family: 宋体">仓库</span></p>
<p><span style="font-family: 宋体">需要将目前的某个仓库导出，并导入到另一个仓库（可以导入到该仓库的指定目录下），</span> </p>
<p><span style="font-family: 宋体">要用到以下的命令：</span></p>
<p># svnadmin dump /home/svnroot/sonatina/ &gt; stn.dump // <span style="font-family: 宋体">导出所有版本到</span>stn.dump<span style="font-family: 宋体">文件中</span></p>
<p># svnadmin dump /home/svnroot/sonatina/ --revision 10 &gt; stn.r10.dump // <span style="font-family: 宋体">或者也可以只导出其中一个版本</span></p>
<p># svnadmin dump /home/svnroot/sonatina/ --revision 0:10 &gt; stn.r0-10.dump // <span style="font-family: 宋体">或者也可以导出多个版本，比如</span>0-10<span style="font-family: 宋体">版本</span></p>
<p># svnadmin load /home/svnroot/sonatinab/ --parent-dir trunk &lt; stn.r0-10.dump // <span style="font-family: 宋体">导入到</span>sonatinab/trunk<span style="font-family: 宋体">目录下，如果不指定</span>--parent-dir<span style="font-family: 宋体">，则会导入到根目录</span>sonatinab/<span style="font-family: 宋体">下</span></p>
<p>////////////////////////////////////////////////////////// </p>
<p><span style="font-family: 宋体">使用</span>ssh<span style="font-family: 宋体">方式验证</span>: </p>
<p>cd /home/usr/local/subversion/bin </p>
<p>./svn list svn+ssh://ip<span style="font-family: 宋体">地址</span>/home/svnroot/repository/test </p>
<p><span style="font-family: 宋体">如果出现这个问题</span>: </p>
<p>subversion/libsvn_repos/repos.c:1004: (apr_err=165005) </p>
<p>svn: Expected version '3' of repository; found version '5' </p>
<p><span style="font-family: 宋体">把</span>home/svnroot/repository/test/format<span style="font-family: 宋体">文件中的</span>5<span style="font-family: 宋体">改成</span>3<span style="font-family: 宋体">就可以了</span>. </p>
<p>/////////////////////////////////////////////////////// </p>
<p><span style="font-family: 宋体">使用</span>https<span style="font-family: 宋体">方式验证</span></p>
<p>vi /usr/local/apache/conf/http.conf </p>
<p># Secure (SSL/TLS) connections </p>
<p>Include conf/extra/httpd-ssl.conf //<span style="font-family: 宋体">把此处的</span>#<span style="font-family: 宋体">去掉</span></p>
<p># </p>
<p># Note: The following must must be present to support </p>
<p># starting without SSL on platforms with no /dev/random equivalent </p>
<p># but a statically compiled-in mod_ssl. </p>
<p># </p>
<p># cd /usr/local/apache2 </p>
<p># ./bin/apachectl start </p>
<p>Syntax error on line 108 of /usr/local/apache2/conf/ssl.conf: </p>
<p>SSLCertificateFile: file '/usr/local/apache2/conf/server.key' does not exist or is empty </p>
<p><span style="font-family: 宋体">这又是什么原因呢？因为我们没有配置</span>ssl<span style="font-family: 宋体">，需要生成</span>ssl<span style="font-family: 宋体">需要的证书。</span></p>
<p><span style="font-family: 宋体">以前使用</span>apache1+mod_ssl<span style="font-family: 宋体">的时候，</span>make<span style="font-family: 宋体">之后有一个这样的步骤</span></p>
<p>$ make certificate </p>
<p><span style="font-family: 宋体">可以用来生成</span>ssl<span style="font-family: 宋体">所用到的证书。</span></p>
<p><span style="font-family: 宋体">现在没有这个工具了，只能自己动手生成了，对证书不熟悉的人，有一个工具可以使用：</span>http://www.openssl.org/contrib/ssl.ca-0.1.tar.gz </p>
<p># cd /usr/local/apache2/conf </p>
<p># tar zxvf ssl.ca-0.1.tar.gz </p>
<p># cd ssl.ca-0.1 </p>
<p># ./new-root-ca.sh (<span style="font-family: 宋体">生成根证书</span>) </p>
<p>No Root CA key round. Generating one </p>
<p>Generating RSA private key, 1024 bit long modulus </p>
<p>...........................++++++ </p>
<p>....++++++ </p>
<p>e is 65537 (0x10001) </p>
<p>Enter pass phrase for ca.key: (<span style="font-family: 宋体">输入一个密码</span>) </p>
<p>Verifying - Enter pass phrase for ca.key: (<span style="font-family: 宋体">再输入一次密码</span>) </p>
<p>...... </p>
<p>Self-sign the root CA... (<span style="font-family: 宋体">签署根证书</span>) </p>
<p>Enter pass phrase for ca.key: (<span style="font-family: 宋体">输入刚刚设置的密码</span>) </p>
<p>........ </p>
<p>........ (<span style="font-family: 宋体">下面开始签署</span>) </p>
<p>Country Name (2 letter code) [MY]: CN </p>
<p>State or Province Name (full name) [Perak]: liaoning </p>
<p>Locality Name (eg, city) [Sitiawan]: dalian </p>
<p>Organization Name (eg, company) [My Directory Sdn Bhd]: jishikeyan </p>
<p>Organizational Unit Name (eg, section) [Certification Services Division]: ACSTAR </p>
<p>Common Name (eg, MD Root CA) []: yong </p>
<p>Email Address []: yong@yong.com.cn </p>
<p><span style="font-family: 宋体">这样就生成了</span>ca.key<span style="font-family: 宋体">和</span>ca.crt<span style="font-family: 宋体">两个文件，下面还要为我们的服务器生成一个证书：</span></p>
<p># ./new-server-cert.sh server (<span style="font-family: 宋体">这个证书的名字是</span>server) </p>
<p>...... </p>
<p>...... </p>
<p>Country Name (2 letter code) [MY]: CN </p>
<p>State or Province Name (full name) [Perak]: liaoning </p>
<p>Locality Name (eg, city) [Sitiawan]: dalian </p>
<p>Organization Name (eg, company) [My Directory Sdn Bhd]: jishikeyan </p>
<p>Organizational Unit Name (eg, section) [Secure Web Server]: ACSTAR </p>
<p>Common Name (eg, www.domain.com) []: localhost </p>
<p>Email Address []: yong@yong.com.cn </p>
<p><span style="font-family: 宋体">这样就生成了</span>server.csr<span style="font-family: 宋体">和</span>server.key<span style="font-family: 宋体">这两个文件。</span></p>
<p><span style="font-family: 宋体">还需要签署一下才能使用的：</span></p>
<p># ./sign-server-cert.sh server </p>
<p>CA signing: server.csr -&gt; server.crt: </p>
<p>Using configuration from ca.config </p>
<p>Enter pass phrase for ./ca.key: (<span style="font-family: 宋体">输入上面设置的根证书密码</span>) </p>
<p>Check that the request matches the signature </p>
<p>Signature ok </p>
<p>The Subject's Distinguished Name is as follows </p>
<p>countryName :PRINTABLE:'CN' </p>
<p>stateOrProvinceName :PRINTABLE:'liaoning' </p>
<p>localityName :PRINTABLE:'liaoning' </p>
<p>organizationName :PRINTABLE:'jishikeyan' </p>
<p>organizationalUnitName:PRINTABLE:'ACSTAR' </p>
<p>commonName :PRINTABLE:'localhost' </p>
<p>emailAddress :IA5STRING:'yongl@yong.com.cn' </p>
<p>Certificate is to be certified until Jul 16 12:55:34 2005 GMT (365 days) </p>
<p>Sign the certificate? [y/n]: y </p>
<p>1 out of 1 certificate requests certified, commit? [y/n] y </p>
<p>Write out database with 1 new entries </p>
<p>Data Base Updated </p>
<p>CA verifying: server.crt &lt;-&gt; CA cert </p>
<p>server.crt: OK </p>
<p><span style="font-family: 宋体">下面要按照</span>ssl.conf<span style="font-family: 宋体">里面的设置，将证书放在适当的位置。</span></p>
<p># chmod 400 server.key </p>
<p># cd .. </p>
<p># mv ssl.ca-0.1/server.key server.key </p>
<p># mv ssl.ca-0.1/server.crt server.crt </p>
<p><span style="font-family: 宋体">然后就可以启动啦！</span></p>
<p># cd /usr/local/apache2 </p>
<p># ./bin/apachectl start </p>
<p><span style="font-family: 宋体">在浏览器中</span>https://127.0.0.1/svn/test<span style="font-family: 宋体">就可以进行</span>https<span style="font-family: 宋体">用户验证啦</span>! </p>
<p>subversion<span style="font-family: 宋体">验证</span></p>
<p>./svn list https://localhost/svn/test </p>
<p><span style="font-family: 宋体">验证&#8220;</span>https://localhost:443<span style="font-family: 宋体">&#8221;的服务器凭证时发生错误：</span></p>
<p>- <span style="font-family: 宋体">本凭证并不是由受信任的权威机权所核发。请手动利用指纹以验证</span></p>
<p><span style="font-family: 宋体">凭证的有效性！</span></p>
<p>- <span style="font-family: 宋体">本凭证的主机名称不符。</span></p>
<p><span style="font-family: 宋体">凭证信息：</span></p>
<p>- <span style="font-family: 宋体">主机名称：</span>www.yong.com </p>
<p>- <span style="font-family: 宋体">有效期间：自</span> Jan 25 07:55:48 2007 GMT <span style="font-family: 宋体">至</span> Jan 25 07:55:48 2008 GMT - <span style="font-family: 宋体">发行者：</span>yong, jishi, dalian, liaoning, CN </p>
<p>- <span style="font-family: 宋体">指纹：</span>49:c4:12:38:5e:03:df:52:64:eb:f4:02:b8:a4:f3:b0:2c:f7:8d:2a(R)<span style="font-family: 宋体">拒绝，</span>(t)<span style="font-family: 宋体">暂时接受</span> <span style="font-family: 宋体">或</span> (p)<span style="font-family: 宋体">永远接受？</span>t </p>
<p><span style="font-family: 宋体">填写证书密码</span></p>
<p><span style="font-family: 宋体">用户名</span></p>
<p><span style="font-family: 宋体">密码</span></p>
<p><span style="font-family: 宋体">登录成功</span>!!!!! </p>
<p>////////////////////////////////////////////////////// </p>
<p>subversion<span style="font-family: 宋体">基本操作</span></p>
<p>1.<span style="font-family: 宋体">从服务器中拷贝库文件</span></p>
<p>#cd /usr/local/subversion/bin </p>
<p>#./svn checkout http://ip<span style="font-family: 宋体">地址</span>/svn/test </p>
<p>[root@localhost bin]# ./svn checkout http://192.168.9.5/svn/test </p>
<p><span style="font-family: 宋体">认证领域：</span>&lt;http://192.168.9.5:80&gt; Subversion.zoneyump </p>
<p><span style="font-family: 宋体">&#8220;</span>root<span style="font-family: 宋体">&#8221;的密码：</span></p>
<p><span style="font-family: 宋体">认证领域：</span>&lt;http://192.168.9.5:80&gt; Subversion.zoneyump </p>
<p><span style="font-family: 宋体">用户登录名：</span>gy </p>
<p><span style="font-family: 宋体">&#8220;</span>gy<span style="font-family: 宋体">&#8221;的密码：</span></p>
<p>A test/index.html </p>
<p>A test/dianhuaben </p>
<p>A test/dianhuaben/chaxun.jsp </p>
<p>A test/dianhuaben/modify.jsp </p>
<p>A test/dianhuaben/work </p>
<p>A test/dianhuaben/work/tldCache.ser </p>
<p>A test/dianhuaben/work/org </p>
<p>A test/dianhuaben/work/org/apache </p>
<p>A test/dianhuaben/work/org/apache/jsp </p>
<p>A test/dianhuaben/work/org/apache/jsp/addtel_jsp.java </p>
<p>A test/dianhuaben/work/org/apache/jsp/selectAllTel_jsp.java </p>
<p>A test/dianhuaben/work/org/apache/jsp/addtel_jsp.class </p>
<p>A test/dianhuaben/work/org/apache/jsp/selectAllTel_jsp.class </p>
<p>A test/dianhuaben/work/SESSIONS.ser </p>
<p>A test/dianhuaben/.tomcatplugin </p>
<p>A test/dianhuaben/.project </p>
<p>A test/dianhuaben/modifytel.jsp </p>
<p>A test/dianhuaben/WEB-INF </p>
<p>A test/dianhuaben/WEB-INF/_desktop.ini </p>
<p>A test/dianhuaben/WEB-INF/lib </p>
<p>A test/dianhuaben/WEB-INF/src </p>
<p>A test/dianhuaben/WEB-INF/web.xml </p>
<p>A test/dianhuaben/WEB-INF/.cvsignore </p>
<p>A test/dianhuaben/WEB-INF/classes </p>
<p>A test/dianhuaben/WEB-INF/classes/com </p>
<p>A test/dianhuaben/WEB-INF/classes/com/Telbook.java </p>
<p>A test/dianhuaben/WEB-INF/classes/com/Telbook.class </p>
<p>A test/dianhuaben/WEB-INF/classes/com/DataBaseConnection.java </p>
<p>A test/dianhuaben/WEB-INF/classes/com/DataBaseConnection.class </p>
<p>A test/dianhuaben/WEB-INF/classes/com/TelBean.java </p>
<p>A test/dianhuaben/WEB-INF/classes/com/TelBean.class </p>
<p>A test/dianhuaben/modifydel1.jsp </p>
<p>A test/dianhuaben/addtel.jsp </p>
<p>A test/dianhuaben/modify.html </p>
<p>A test/dianhuaben/chanxun.jsp </p>
<p>A test/dianhuaben/addtel.html </p>
<p>A test/dianhuaben/.classpath </p>
<p>A test/dianhuaben/deletetel.jsp </p>
<p>A test/dianhuaben/deltel.jsp </p>
<p>A test/dianhuaben/selectAllTel.jsp </p>
<p>A test/dianhuaben/index.html </p>
<p>A test/dianhuaben/.cvsignore </p>
<p><span style="font-family: 宋体">取出修订版</span> 1<span style="font-family: 宋体">。</span></p>
<p>2. <span style="font-family: 宋体">发布你的修改给别人，你可以使用</span>Subversion<span style="font-family: 宋体">的提交（</span>commit<span style="font-family: 宋体">）命令</span></p>
<p>#./svn commit <span style="font-family: 宋体">项目名或文件名</span></p>
<p>[root@localhost bin]# ./svn commit test/index.html </p>
<p><span style="font-family: 宋体">日志信息未改变，或是未指定</span></p>
<p>a)<span style="font-family: 宋体">中断，</span>c)<span style="font-family: 宋体">继续，</span>e)<span style="font-family: 宋体">编辑</span></p>
<p>c </p>
<p><span style="font-family: 宋体">正在发送</span> test/index.html </p>
<p><span style="font-family: 宋体">传输文件数据</span>. </p>
<p><span style="font-family: 宋体">提交后的修订版为</span> 3<span style="font-family: 宋体">。</span></p>
<p>3.<span style="font-family: 宋体">状态查询（</span>status<span style="font-family: 宋体">）</span></p>
<p>#./svn status <span style="font-family: 宋体">路径</span>/<span style="font-family: 宋体">项目名</span></p>
<p>L some_dir # svn<span style="font-family: 宋体">已经在</span>.svn<span style="font-family: 宋体">目录锁定了</span>some_dir </p>
<p>M bar.c # bar.c<span style="font-family: 宋体">的内容已经在本地修改过了</span></p>
<p>M baz.c # baz.c<span style="font-family: 宋体">属性有修改，但没有内容修改</span></p>
<p>X 3rd_party # <span style="font-family: 宋体">这个目录是外部定义的一部分</span></p>
<p>? foo.o # svn<span style="font-family: 宋体">并没有管理</span>foo.o </p>
<p>! some_dir # svn<span style="font-family: 宋体">管理这个，但它可能丢失或者不完</span></p>
<p>~ qux # <span style="font-family: 宋体">作为</span>file/dir/link<span style="font-family: 宋体">进行了版本控制，但类型已经改变</span></p>
<p>I .screenrc # svn<span style="font-family: 宋体">不管理这个，配置确定要忽略它</span></p>
<p>A + moved_dir # <span style="font-family: 宋体">包含历史的添加，历史记录了它的来历</span></p>
<p>M + moved_dir/README # <span style="font-family: 宋体">包含历史的添加，并有了本地修改</span></p>
<p>D stuff/fish.c # <span style="font-family: 宋体">这个文件预定要删除</span></p>
<p>A stuff/loot/bloo.h # <span style="font-family: 宋体">这个文件预定要添加</span></p>
<p>C stuff/loot/lump.c # <span style="font-family: 宋体">这个文件在更新时发生冲突</span></p>
<p>C stuff/loot/glub.c # <span style="font-family: 宋体">文件在更新时发生属性冲突</span></p>
<p>R xyz.c # <span style="font-family: 宋体">这个文件预定要被替换</span></p>
<p>S stuff/squawk # <span style="font-family: 宋体">这个文件已经跳转到了分支</span></p>
<p>K dog.jpg # <span style="font-family: 宋体">文件在本地锁定；有锁定令牌</span></p>
<p>O cat.jpg # <span style="font-family: 宋体">文件在版本库被其他用户锁定</span></p>
<p>B bird.jpg # <span style="font-family: 宋体">文件本地锁定，但锁定发生错误</span></p>
<p>T fish.jpg # <span style="font-family: 宋体">文件本地锁定，但锁定丢失</span></p>
<p>4.<span style="font-family: 宋体">检查修改的方式是</span>svn diff<span style="font-family: 宋体">命令，你可以通过不带参数的</span>svn diff<span style="font-family: 宋体">精确的找出你所做的修改</span></p>
<p>#./svn diff <span style="font-family: 宋体">项目名</span></p>
<p>root@localhost bin]# ./svn diff test </p>
<p>Index: test/index.html </p>
<p>=================================================================== </p>
<p>--- test/index.html <span style="font-family: 宋体">（修订版</span> 2<span style="font-family: 宋体">）</span></p>
<p>+++ test/index.html <span style="font-family: 宋体">（工作拷贝）</span></p>
<p>@@ -1,6 +1,6 @@ </p>
<p>&lt;html&gt; </p>
<p>&lt;head&gt; </p>
<p>- &lt;title&gt;<span style="font-family: 宋体">人才库</span>&lt;/html&gt; </p>
<p>+ &lt;title&gt;<span style="font-family: 宋体">人才库资料</span>&lt;/html&gt; </p>
<p>&lt;meta context="text/html;charset=UTF-8"&gt; </p>
<p>&lt;/head&gt; </p>
<p>&lt;body&gt; </p>
<p><span style="font-family: 宋体">输出的格式为统一区别格式（</span>unified diff format<span style="font-family: 宋体">），删除的行前面加一个</span>-<span style="font-family: 宋体">，添加的行前面有一个</span>+ </p>
<p>svn diff<span style="font-family: 宋体">命令也打印文件名和打补丁需要的信息，所以你可以通过重定向一个区别文件来生成&#8220;补丁&#8221;</span></p>
<p>#./svn diff <span style="font-family: 宋体">项目名</span> &gt; <span style="font-family: 宋体">文件名</span></p>
<p>[root@localhost bin]# ./svn diff test &gt; haha </p>
<p>[root@localhost bin]# ls </p>
<p>haha svn svndumpfilter svnserve svnversion </p>
<p>stn.dump svnadmin svnlook svnsync test </p>
<p><span style="font-family: 宋体">生成一个</span>haha<span style="font-family: 宋体">文件</span></p>
<p>5.<span style="font-family: 宋体">添加文件或目录（</span>add<span style="font-family: 宋体">）</span></p>
<p>#./svn add <span style="font-family: 宋体">项目名</span>/<span style="font-family: 宋体">新建文件或目录</span></p>
<p>6.<span style="font-family: 宋体">删除文件或目录（</span>delete<span style="font-family: 宋体">）</span></p>
<p>#./svn delete <span style="font-family: 宋体">项目名</span>/<span style="font-family: 宋体">删除的文件或目录</span></p>
<p>svn delete http://ip<span style="font-family: 宋体">地址</span>/svn_dir/repository/project_dir <span style="font-family: 宋体">这条命令刚好可以用来删除</span></p>
<p>7.<span style="font-family: 宋体">列出仓库中的项目（</span>list<span style="font-family: 宋体">）</span></p>
<p>svn list --verbose </p>
<p>#./svn list --verbose file:///home/svnroot/repository/test/ </p>
<p>[root@localhost bin]# ./svn list --verbose file:///home/svnroot/repository/test/ </p>
<p>1 root 529 1<span style="font-family: 宋体">月</span> 25 14:16 .classpath </p>
<p>1 root 4 1<span style="font-family: 宋体">月</span> 25 14:16 .cvsignore </p>
<p>1 root 12288 1<span style="font-family: 宋体">月</span> 25 14:16 .genggai1.jsp.swp </p>
<p>1 root 425 1<span style="font-family: 宋体">月</span> 25 14:16 .project </p>
<p>1 root 358 1<span style="font-family: 宋体">月</span> 25 14:16 .tomcatplugin </p>
<p>1 root 1<span style="font-family: 宋体">月</span> 25 14:16 WEB-INF/ </p>
<p>1 root 10 1<span style="font-family: 宋体">月</span> 25 14:16 _desktop.ini </p>
<p>1 root 29269 1<span style="font-family: 宋体">月</span> 25 14:16 a.gif </p>
<p>1 root 1172 1<span style="font-family: 宋体">月</span> 25 14:16 chaxun.jsp </p>
<p>1 root 1245 1<span style="font-family: 宋体">月</span> 25 14:16 genggai.jsp </p>
<p>1 root 1787 1<span style="font-family: 宋体">月</span> 25 14:16 genggai1.jsp </p>
<p>1 root 707 1<span style="font-family: 宋体">月</span> 25 14:16 genggai2.jsp </p>
<p>6 wooin 1<span style="font-family: 宋体">月</span> 26 12:10 hehe/ </p>
<p>4 wooin 1047 1<span style="font-family: 宋体">月</span> 26 11:48 index.html </p>
<p>1 root 3719546 1<span style="font-family: 宋体">月</span> 25 14:16 love.mp3 </p>
<p>1 root 3073 1<span style="font-family: 宋体">月</span> 25 14:16 rencaiku.txt </p>
<p>1 root 1243 1<span style="font-family: 宋体">月</span> 25 14:16 shanchu.jsp </p>
<p>1 root 409 1<span style="font-family: 宋体">月</span> 25 14:16 shanchu1.jsp </p>
<p>1 root 1073 1<span style="font-family: 宋体">月</span> 25 14:16 tianjia.html </p>
<p>1 root 813 1<span style="font-family: 宋体">月</span> 25 14:16 tianjia.jsp </p>
<p>1 root 1<span style="font-family: 宋体">月</span> 25 14:16 work/ </p>
<p>//////////////////////////////////////////////////////////////////////// </p>
<p>subversion<span style="font-family: 宋体">的分支与合并</span></p>
<p>1.<span style="font-family: 宋体">建立分支</span></p>
<p>#cd /usr/local/subversion/bin </p>
<p>#./svn copy http://192.168.9.53/svn/test http://192.168.9.53/svn/test/mycopy -m "copy a branch" </p>
<p>2.<span style="font-family: 宋体">在分支上工作</span>(<span style="font-family: 宋体">导出分支到本地</span>) </p>
<p>#./svn checkout http://192.168.9.53/svn/test/mycopy mycopy1 </p>
<p>3.<span style="font-family: 宋体">合并</span></p>
<p>#./svn merge -r 15:16 http://192.168.9.53/svn/test/mycopy test</p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/142332.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-09-03 15:40 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142332.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SVN Beginning</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142330.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Mon, 03 Sep 2007 07:40:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142330.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/142330.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142330.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/142330.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/142330.html</trackback:ping><description><![CDATA[&nbsp;
<p style="text-align: center" align="center">SVN Beginning</p>
<p><a href="http://blog.doesite.net/read.php?save_215">http://blog.doesite.net/read.php?save_215</a></p>
<p>1.<span style="font-family: 宋体">安装</span> subversion</p>
<p># apt-get install subversion subversion-tools</p>
<p><span style="font-family: 宋体">创建一个新的储存库：</span></p>
<p>#svnadmin create /svn/repository</p>
<p><span style="font-family: 宋体">在</span>/svn<span style="font-family: 宋体">目录创建一个新的空储存库，数据储存方式默认采用</span>Berkeley DB<span style="font-family: 宋体">。</span></p>
<p><span style="font-family: 宋体">导入你的源码：</span></p>
<p># svn import /svn/repository file:///data/svn/ldap</p>
<p><span style="font-family: 宋体">把</span>/data/ldap<span style="font-family: 宋体">整个目录导入到储存库中的</span>repository<span style="font-family: 宋体">目录中，储存库的</span>repository<span style="font-family: 宋体">目录会自动创建。</span></p>
<p><span style="font-family: 宋体">显示储存库内容：</span></p>
<p>mt@mtmt:~$ svn list file:///svn/repository</p>
<p>.cache/</p>
<p>.project</p>
<p>.projectOptions</p>
<p>.settings/</p>
<p>bbscnmo/</p>
<p>newcnmo/</p>
<p><span style="font-family: 宋体">显示目录内容，成功导入。</span></p>
<p><span style="font-family: 宋体">上面使用了</span>file:///<span style="font-family: 宋体">形式的</span>URL<span style="font-family: 宋体">来访问</span>Subversion<span style="font-family: 宋体">库，这表示在本地通过文件系统访问。但我们的</span>Subversion<span style="font-family: 宋体">库可能需要通过网络被其它用户访问，这就需要用到其它的协议，下表是</span>Subversion<span style="font-family: 宋体">支持的各种访问协议：</span></p>
<p><span style="font-family: 宋体">访问协议</span></p>
<p><span style="font-family: 宋体">协议</span> <span style="font-family: 宋体">访问方法</span></p>
<p>file:/// <span style="font-family: 宋体">通过本地磁盘访问。</span></p>
<p>http:// <span style="font-family: 宋体">与</span>Apache<span style="font-family: 宋体">组合，通过</span>WebDAV<span style="font-family: 宋体">协议访问。</span></p>
<p>https:// <span style="font-family: 宋体">同上，但支持</span>SSL<span style="font-family: 宋体">协议加密连接。</span></p>
<p>svn:// <span style="font-family: 宋体">通过</span>svnserve<span style="font-family: 宋体">服务自定义的协议访问。</span></p>
<p>svn+ssh:// <span style="font-family: 宋体">同上，但通过</span>SSH<span style="font-family: 宋体">协议加密连接。</span></p>
<p>2.<span style="font-family: 宋体">配置</span> subversion <span style="font-family: 宋体">与</span>Apache<span style="font-family: 宋体">组合通过</span>WebDAV<span style="font-family: 宋体">方式访问</span>Subversion<span style="font-family: 宋体">库</span></p>
<p># apt-get install apache2 libapache2-svn</p>
<p><span style="font-family: 宋体">配置文件位于</span>/etc/apache2/mods-enabled/<span style="font-family: 宋体">目录下，配置文件共有两个，分别是</span>dav_svn.conf<span style="font-family: 宋体">和</span>dav_svn.load<span style="font-family: 宋体">，</span>dav_svn.load<span style="font-family: 宋体">文件负责装载必要的模块，内容如下：</span></p>
<p># Load mod_dav_svn when apache starts</p>
<p>LoadModule dav_svn_module /usr/lib/apache2/modules/mod_dav_svn.so</p>
<p>LoadModule authz_svn_module /usr/lib/apache2/modules/mod_authz_svn.so</p>
<p><span style="font-family: 宋体">在装载</span>mod_dav_svn.so<span style="font-family: 宋体">前，必须先装载</span>mod_dav.so<span style="font-family: 宋体">模块。它由</span>dav.load<span style="font-family: 宋体">文件控制，内容如下：</span></p>
<p>LoadModule dav_module /usr/lib/apache2/modules/mod_dav.so</p>
<p>dav_svn.conf<span style="font-family: 宋体">是</span>mod_dav_svn.so<span style="font-family: 宋体">模块的配置文件，内容如下：</span></p>
<p># dav_svn.conf - Example Subversion/Apache configuration</p>
<p>#</p>
<p># For details and further options see the Apache user manual and</p>
<p># the Subversion book.</p>
<p># &#8230;</p>
<p># URL controls how the repository appears to the outside world.</p>
<p># In this example clients access the repository as http://hostname/svn/</p>
<p>#<span style="font-family: 宋体">设置访问路径</span></p>
<p># Uncomment this to enable the repository,</p>
<p>DAV svn #<span style="font-family: 宋体">启用</span>by siko</p>
<p># Set this to the path to your repository</p>
<p>SVNPath /data/subversion #<span style="font-family: 宋体">设置储存库路径，仅支持单个储存库，该路径要可被</span>Apache<span style="font-family: 宋体">进程访问。</span></p>
<p>#SVNParentPath /data/subversion #<span style="font-family: 宋体">如果</span>subversion<span style="font-family: 宋体">下有多个储存库，则用</span>SVNParentPath</p>
<p># The following allows for basic http authentication. Basic authentication</p>
<p># should not be considered secure for any particularly rigorous definition of</p>
<p># secure.</p>
<p># to create a passwd file #<span style="font-family: 宋体">按下面的步骤创建</span>Apache<span style="font-family: 宋体">用户验证文件</span></p>
<p># # rm -f /etc/apache2/dav_svn.passwd</p>
<p># # htpasswd2 -c /etc/apache2/dav_svn.passwd dwhedon</p>
<p># New password:</p>
<p># Re-type new password:</p>
<p># Adding password for user dwhedon</p>
<p># #</p>
<p># Uncomment the following 3 lines to enable Basic Authentication</p>
<p>AuthType Basic #<span style="font-family: 宋体">启用</span>Apache<span style="font-family: 宋体">基础验证</span></p>
<p>AuthName <span style="font-family: 宋体">&#8220;</span>Subversion Repository<span style="font-family: 宋体">&#8221;</span> #<span style="font-family: 宋体">设置验证框标题</span></p>
<p>AuthUserFile /etc/apache2/dav_svn.passwd #<span style="font-family: 宋体">指定验证用户文件名</span></p>
<p># Uncomment the following line to enable Authz Authentication</p>
<p>AuthzSVNAccessFile /etc/apache2/dav_svn.authz #<span style="font-family: 宋体">启用目录级别授权，</span>dav_svn.authz<span style="font-family: 宋体">是授权配置文档</span></p>
<p># The following three lines allow anonymous read, but make</p>
<p># committers authenticate themselves.</p>
<p>#</p>
<p>#<span style="font-family: 宋体">允许匿名访问，不允许</span>Commit<span style="font-family: 宋体">，不能与</span>AuthzSVNAccessFile<span style="font-family: 宋体">同时使用</span></p>
<p>Require valid-user</p>
<p>#</p>
<p><span style="font-family: 宋体">修改</span>/data/subversion<span style="font-family: 宋体">目录访问权限使它可被</span>Apache<span style="font-family: 宋体">进程访问，我的</span>Apache<span style="font-family: 宋体">是用</span>www-data<span style="font-family: 宋体">启动的，所以设置方法如下：</span></p>
<p># chown -R www-data.www-data /data/subversion</p>
<p><span style="font-family: 宋体">通</span> <span style="font-family: 宋体">过</span>Apache<span style="font-family: 宋体">的用户验证功能可以区别匿名用户和验证用户，从而赋予匿名用户读权限和验证用户读</span>/<span style="font-family: 宋体">写的权限。这些权限只能在全局范围内设置，不能设置具体</span> <span style="font-family: 宋体">的某个目录是否能被某个用户操作。要实现目录级别的授权，就要使用</span>mod_authz_svn.so<span style="font-family: 宋体">模块提供的</span> AuthzSVNAccessFile<span style="font-family: 宋体">指令。它会指定一个授权文档，该授权文档设置具体的目录权限。根据上面的配置，授权文档名叫</span> dav_svn.authz<span style="font-family: 宋体">，它的内容如下：</span></p>
<p>[groups] #<span style="font-family: 宋体">定义组</span></p>
<p>admin=jims,ringkee</p>
<p>tests=tester1,tester2</p>
<p>[erp:/] #<span style="font-family: 宋体">定义</span>erp<span style="font-family: 宋体">储存库根目录的访问权限</span></p>
<p>@admin=rw #admin<span style="font-family: 宋体">组有读写权限</span></p>
<p>tests=r #test<span style="font-family: 宋体">用户只有读权限</span></p>
<p>[oa:/test] #<span style="font-family: 宋体">定义</span>oa<span style="font-family: 宋体">储存库下</span>test<span style="font-family: 宋体">目录的访问权限</span></p>
<p>*= #<span style="font-family: 宋体">禁止所有用户访问，星号代表所有用户，权限为空代表没有任何权限</span></p>
<p>ringkee=rw #<span style="font-family: 宋体">打开</span>ringkee<span style="font-family: 宋体">用户的读写权限</span></p>
<p><span style="font-family: 宋体">在该文件中使用的用户需在</span>apache2<span style="font-family: 宋体">的用户文件</span>/etc/apache2/dav_svn.passwd<span style="font-family: 宋体">中预先设置好。</span></p>
<p>3.<span style="font-family: 宋体">安装</span>trac #sudo apt-get install trac <span style="font-family: 宋体">配置</span>TRAC</p>
<p>#cd /trac/</p>
<p>#trac-admin repository initenv</p>
<p><span style="font-family: 宋体">在运行</span>trac-admin<span style="font-family: 宋体">时有一步设置需要注意，就是&#8221;</span>Path to repository<span style="font-family: 宋体">&#8221;，要指向上面的</span>/svn/repository</p>
<p>chown -R www-data.www-data /trac/repository</p>
<p><span style="font-family: 宋体">以</span>CGI<span style="font-family: 宋体">方式运行</span>TRAC,<span style="font-family: 宋体">有一些设置要做</span></p>
<p><span style="font-family: 宋体">建立密码文件</span>:</p>
<p>htpasswd -c /somewhere/trac.htpasswd username</p>
<p><span style="font-family: 宋体">编辑</span>apache<span style="font-family: 宋体">的</span>apache2.conf</p>
<p>#edit by siko@ 2006.11.24</p>
<p>ScriptAlias /trac /usr/share/trac/cgi-bin/trac.cgi</p>
<p>SetEnv TRAC_ENV &#8220;/trac/repository&#8221;</p>
<p>Alias /tracdoc &#8220;/usr/share/trac/htdocs/&#8221;</p>
<p>Options -Indexes -MultiViews</p>
<p>AllowOverride None</p>
<p>Order allow,deny</p>
<p>Allow from all</p>
<p>AuthType Basic</p>
<p>AuthName &#8220;Trac&#8221;</p>
<p>AuthUserFile /home/mt/trac.htpasswd</p>
<p>Require valid-user</p>
<p><span style="font-family: 宋体">重启</span>apache<span style="font-family: 宋体">使其生效</span></p>
<p>4. svn<span style="font-family: 宋体">的</span>eclipse<span style="font-family: 宋体">插件</span> <span style="font-family: 宋体">安装配置：</span></p>
<p>1.<span style="font-family: 宋体">更新安装</span>http://subclipse.tigris.org/update<span style="font-family: 宋体">的</span>subclipse<span style="font-family: 宋体">插件</span></p>
<p>2.<span style="font-family: 宋体">安装完成后</span>eclipse<span style="font-family: 宋体">会自动重启后，在</span>svn<span style="font-family: 宋体">的透视图中可以看到</span>svn<span style="font-family: 宋体">的相关菜单</span></p>
<p>3.<span style="font-family: 宋体">将新的</span> SVN <span style="font-family: 宋体">资源库添加至&#8220;</span>SVN <span style="font-family: 宋体">资源库。</span>url<span style="font-family: 宋体">为</span>http://your_ip/svn</p>
<p>4.<span style="font-family: 宋体">引用项目成功后，便可以用前面的用户名和密码来更新和提交工程内文件了。</span></p>
<p>5.subclipse<span style="font-family: 宋体">的较新版本都是中文的，详细操作略。</span>svn<span style="font-family: 宋体">有很多的客户端，在此只通过命令行来操作，结合</span>eclipse<span style="font-family: 宋体">的插件来控制版本并不涉及任何客户端程序。</span></p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/142330.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-09-03 15:40 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142330.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java如何处理大文件(在内存中)</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142329.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Mon, 03 Sep 2007 07:39:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142329.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/142329.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142329.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/142329.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/142329.html</trackback:ping><description><![CDATA[&nbsp;
<p style="text-align: center" align="center"><span style="font-size: 9pt; color: black; font-family: Verdana">java</span><span style="font-size: 9pt; color: black; font-family: 宋体">如何处理大文件</span><span style="font-size: 9pt; color: black; font-family: Verdana">(</span><span style="font-size: 9pt; color: black; font-family: 宋体">在内存中</span><span style="font-size: 9pt; color: black; font-family: Verdana">)</span></p>
<p><span style="font-size: 10pt; color: black; font-family: Verdana">java -Xms256m -Xmx512m Diff /hbbi/bossjf/A0500220040628WH005.avl /hbbi/bossjf/A0500220040628WH005.avl</span></p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/142329.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-09-03 15:39 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142329.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDK5 to JDK1.4 Tools</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142319.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Mon, 03 Sep 2007 07:31:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142319.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/142319.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142319.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/142319.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/142319.html</trackback:ping><description><![CDATA[&nbsp;
<p style="text-align: center" align="center">JDK5 to JDK1.4 Tools</p>
<p><span style="font-family: 宋体">许多工具可以将</span>JDK5<span style="font-family: 宋体">的代码，编译成</span>JDK1.4<span style="font-family: 宋体">可以运行的代码，其中最好的有两个</span>:</p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://retrotranslator.sourceforge.net/">http://retrotranslator.sourceforge.net/</a></p>
<p>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://retroweaver.sourceforge.net/">http://retroweaver.sourceforge.net/</a></p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/142319.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-09-03 15:31 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142319.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>POAD Beginning -2</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142318.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Mon, 03 Sep 2007 07:29:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142318.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/142318.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142318.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/142318.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/142318.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;POAD Beginning -2Simulation of Waiting QueuesSimulation is a software engineering technique that is commonly used prior to actual implementation for several purposes, including verificatio...&nbsp;&nbsp;<a href='http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142318.html'>阅读全文</a><img src ="http://www.blogjava.net/hengheng123456789/aggbug/142318.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-09-03 15:29 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142318.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Concurrency</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142316.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Mon, 03 Sep 2007 07:20:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142316.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/142316.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142316.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/142316.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/142316.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;ConcurrencyComputer users take it for granted that their systems can do more than one thing at a time. They assume that they can continue to work in a word processor, while other application...&nbsp;&nbsp;<a href='http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142316.html'>阅读全文</a><img src ="http://www.blogjava.net/hengheng123456789/aggbug/142316.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-09-03 15:20 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/09/03/142316.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Reactor pattern Beginning</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126896.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Thu, 28 Jun 2007 10:18:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126896.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/126896.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126896.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/126896.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/126896.html</trackback:ping><description><![CDATA[<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><span lang=EN-US>Reactor pattern Beginning</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US><o:p>&nbsp;</o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US><o:p>&nbsp;</o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">The <em>Reactor</em> pattern has been introduced in &nbsp;[<em><a href="http://www.cs.vu.nl/~eliens/online/oo/I/2/@ref-Schmidt95.html"><span style="COLOR: black"><u>Schmidt95</u></span></a></em>] as a general architecture for event-driven systems. It explains how to register handlers for particular event types, and how to activate handlers when events occur, even when events come from multiple sources, in a single-threaded environment. In other words, the <em>reactor</em> allows for the combination of multiple event-loops, without introducing additional threads. <o:p></o:p></span></p>
<div class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align=center><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">
<hr align=center width="100%" SIZE=2>
</span></div>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-outline-level: 4; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><a name=reactor><strong><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">The Reactor pattern<o:p></o:p></span></strong></a></p>
<ul type=disc>
    <li class=MsoNormal style="MARGIN: 0cm 0cm 0pt; COLOR: black; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-list: l0 level1 lfo1; tab-stops: list 36.0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"><span style="mso-bookmark: reactor"><span lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">activate handlers when events occur <o:p></o:p></span></span></li>
    <li class=MsoNormal style="MARGIN: 0cm 0cm 0pt; COLOR: black; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-list: l0 level1 lfo1; tab-stops: list 36.0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"><span style="mso-bookmark: reactor"><span lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">allow events from multiple sources <o:p></o:p></span></span></li>
    <li class=MsoNormal style="MARGIN: 0cm 0cm 0pt; COLOR: black; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-list: l0 level1 lfo1; tab-stops: list 36.0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"><span style="mso-bookmark: reactor"><span lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">in single threaded process <o:p></o:p></span></span></li>
</ul>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span style="mso-bookmark: reactor"><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: blue; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">See D.C. Schmidt, Using Design Patterns to Develop Reusable Object-oriented Communication Software, CACM October '95, 38(10): 65-74 </span></span><span style="mso-bookmark: reactor"><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体"><o:p></o:p></span></span></p>
<div class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align=center><span style="mso-bookmark: reactor"><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">
<hr align=center width="100%" SIZE=2>
</span></span></div>
<span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><span style="mso-bookmark: reactor"></span></span>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align=center><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体"><a href="http://www.cs.vu.nl/~eliens/online/oo/I/2/contents.html"><u><em><span style="COLOR: black">slide</span></em><span style="COLOR: black">: </span></u></a><a href="http://www.cs.vu.nl/~eliens/online/oo/I/2/@slide-reactor.html"><span style="COLOR: black"><u>The Reactor pattern</u></span></a><o:p></o:p></span></p>
<div class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align=center><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体"><u>
<hr align=center width="100%" SIZE=2>
</u></span></div>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">The abstract layout of the software architecture needed to realize the pattern is depicted in slide <a href="http://www.cs.vu.nl/~eliens/online/oo/I/2/reactor.html#reactor-structure#reactor-structure"><span style="COLOR: black"><u>reactor-structure</u></span></a>. The <em>reactor</em> environment must allow for binding <em>handlers</em> to particular types of <em>events</em>. In addition, it must be able to receive events, and select a handler to which the event can be dispatched. <o:p></o:p></span></p>
<div class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align=center><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">
<hr align=center width="100%" SIZE=2>
</span></div>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align=center><a name=reactor-structure><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">
<script language=JavaScript>
document.write("<img src=../../../@share/figures/patterns/f-reactor.gif  width=" + imgw(450) + " height=" + imgh(275) + ">");
</script>
<v:shapetype id=_x0000_t75 stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype><v:shape id=_x0000_i1035 style="WIDTH: 337.5pt; HEIGHT: 206.25pt" alt="" type="#_x0000_t75"><v:imagedata o:href="http://www.cs.vu.nl/~eliens/online/@share/figures/patterns/f-reactor.gif" src="file:///C:\DOCUME~1\ZHANGH~1\LOCALS~1\Temp\msohtml1\11\clip_image001.png"></v:imagedata></v:shape><o:p></o:p></span></a></p>
<div class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align=center><span style="mso-bookmark: reactor-structure"><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">
<hr align=center width="100%" SIZE=2>
</span></span></div>
<span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><span style="mso-bookmark: reactor-structure"></span></span>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align=center><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体"><a href="http://www.cs.vu.nl/~eliens/online/oo/I/2/contents.html"><u><em><span style="COLOR: black">slide</span></em><span style="COLOR: black">: </span></u></a><a href="http://www.cs.vu.nl/~eliens/online/oo/I/2/@slide-reactor-structure.html"><span style="COLOR: black"><u>The Reactor pattern -- structure</u></span></a><o:p></o:p></span></p>
<div class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align=center><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体"><u>
<hr align=center width="100%" SIZE=2>
</u></span></div>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">Events may be organized in a hierarchy. There are two possible choices here. Either the topmost event class has a fat interface, containing all the methods that an event may ever need to support, or the topmost event class can be lean, so that additional methods need to be added by the subclasses of event. The first solution is chosen for <em>hush</em>, because in C++ it is not possible to load new classes dynamically. The latter solution is the way Java does it. In Java new event types can be added at the <em>reactor</em> level without recompiling the system. In the Java AWT and Swing libraries, handlers are called <em>Listeners</em>. <o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">Concrete handlers, derived from an abstract handler, must provide a method, such as operate(Event) that can be called by the <em>reactor</em> when the handler is selected after receiving an event. <o:p></o:p></span></p>
<div class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align=center><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">
<hr align=center width="100%" SIZE=2>
</span></div>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align=center><a name=reactor-interactio><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">
<script language=JavaScript>
document.write("<img src=../../../@share/figures/patterns/interact.gif  width=" + imgw(450) + " height=" + imgh(275) + ">");
</script>
<v:shape id=_x0000_i1037 style="WIDTH: 337.5pt; HEIGHT: 206.25pt" alt="" type="#_x0000_t75"><v:imagedata o:href="http://www.cs.vu.nl/~eliens/online/@share/figures/patterns/interact.gif" src="file:///C:\DOCUME~1\ZHANGH~1\LOCALS~1\Temp\msohtml1\11\clip_image003.png"></v:imagedata></v:shape><o:p></o:p></span></a></p>
<div class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align=center><span style="mso-bookmark: reactor-interactio"><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">
<hr align=center width="100%" SIZE=2>
</span></span></div>
<span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><span style="mso-bookmark: reactor-interactio"></span></span>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align=center><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体"><a href="http://www.cs.vu.nl/~eliens/online/oo/I/2/contents.html"><u><em><span style="COLOR: black">slide</span></em><span style="COLOR: black">: </span></u></a><a href="http://www.cs.vu.nl/~eliens/online/oo/I/2/@slide-reactor-interactio.html"><span style="COLOR: black"><u>The Reactor Pattern - interaction</u></span></a><o:p></o:p></span></p>
<div class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center; mso-pagination: widow-orphan" align=center><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体"><u>
<hr align=center width="100%" SIZE=2>
</u></span></div>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">The interaction between the application, its handlers, the <em>reactor</em> and the environment from which the events originate is depicted in slide <a href="http://www.cs.vu.nl/~eliens/online/oo/I/2/reactor.html#reactor-interaction#reactor-interaction"><span style="COLOR: black"><u>reactor-interaction</u></span></a>. First, the <em>reactor</em> must be initialized, then one or more handlers can be registered, providing a binding for particular types of events. The <em>reactor</em> must then start to execute its eventloop. When it receives an event from the environment, it selects a handler and dispatches the event to that handler, by calling operate(Event). <o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-outline-level: 4; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><strong><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">Consequences<o:p></o:p></span></strong></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">Modularity is one of the advantages of an event-driven software architecture. Handlers can be composed easily, since their invocation is controlled by the <em>reactor</em>. Another advantage is the decoupling of application-independent mechanisms from application-specific policies. In other words, handler objects need not be aware of how events are dispatched. This is the responsibility of the system or framework. <o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">The fact that control is handed over to the environment has, however, also some disadvantages. First of all, as experience with student assignments shows, it is difficult to learn in the beginning. But even when mastered, applications may be hard to debug, since it is not always clear why a particular handler was invoked, and because it may be difficult to repeat the computation preceding the fault. <o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-outline-level: 4; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><strong><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">Applicability<o:p></o:p></span></strong></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体; mso-font-kerning: 0pt; mso-bidi-font-family: 宋体">Some variant of the <em>reactor</em> pattern is used in Unix (X) Windows, (MS) Windows, and also GUI libraries such as Interviews, ET++ and <em>hush</em>. Another example is the Orbacus object request broker, that supports a <em>reactor</em> mode for server objects, which allows for receiving messages from multiple sources in a single thread. The Orbacus broker, however, also allows for multi-threaded servers.</span></p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/126896.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-06-28 18:18 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126896.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>POAD Beginning</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126895.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Thu, 28 Jun 2007 10:17:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126895.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/126895.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126895.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/126895.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/126895.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: POAD Beginning&nbsp;Design patterns are immensely powerful, but to build large-scale robust systems, you need more. Pattern-Oriented Analysis and Design introduces a methodology for "composing" pr...&nbsp;&nbsp;<a href='http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126895.html'>阅读全文</a><img src ="http://www.blogjava.net/hengheng123456789/aggbug/126895.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-06-28 18:17 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126895.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Observer Pattern Beginning</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126894.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Thu, 28 Jun 2007 10:16:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126894.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/126894.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126894.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/126894.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/126894.html</trackback:ping><description><![CDATA[&nbsp;
<p align=center><strong><span>Observer Pattern Beginning</span></strong></p>
<p>&nbsp;</p>
<p><span><a href="http://www.levilee.cn/Jeans/304/Play_9426_1/">http://www.levilee.cn/Jeans/304/Play_9426_1/</a></span></p>
<p>&nbsp;</p>
<p><strong><span><span>1.<span>&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span></strong><strong><span>使用观察者</span></strong><strong><span>(Observer)</span></strong><strong><span>实现对象监听</span></strong><strong></strong></p>
<p><span>观察者</span><span>(Observer)</span><span>是一种模式，也是</span><span>Java</span><span>中的一个</span><span>API</span><span>，它让一个值对象</span><span>(Value Object)</span><span>具备自省的功能，当他发现自己的状态改变了，就向相关的对象发送消息，这样的监听方式当然比轮询好。我感冒了自己会去医院，用不着医生每个月来问一次。</span></p>
<p><span>Java</span><span>的</span><span>Observer API</span><span>是对观察者模式的一个实现。假设我们有一个对象容器，其中存放用户消息，我希望这个容器自省，当有新的消息进来就自动触发观察者作出响应。首先定义消息对象，是个很简单的值对象：</span></p>
<p><span>package com.gwnet.smsMessenger.mm.bromon; </span></p>
<p><span>public class Message </span></p>
<p><span>{ </span></p>
<p><span>private int id; </span></p>
<p><span>private String sender; </span></p>
<p><span>private String receiver; </span></p>
<p><span>private String content; </span></p>
<p><span>private String time; </span></p>
<p><span>//</span><span>请自己实现</span><span>set/get</span><span>方法，比如</span><span>: </span></p>
<p><span>public int getId() </span></p>
<p><span>{ </span></p>
<p><span>return id; </span></p>
<p><span>} </span></p>
<p><span>public void setId(int id) </span></p>
<p><span>{ </span></p>
<p><span>this.id=id; </span></p>
<p><span>} </span></p>
<p><span>} </span></p>
<p><span>然后写一个存放</span><span>Message</span><span>的容器，容器使用</span><span>ArrayList</span><span>来存放对象是个很好的选择，也很简单：</span></p>
<p><strong><span>package</span></strong><span> com.gwnet.smsMessenger.mm.bromon; </span></p>
<p><strong><span>import</span></strong><span> java.util.*; </span></p>
<p><span>public class MessageList extends Observable </span></p>
<p><span>{ </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;private List m=new ArrayList(); </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;private static MessageList ml=null; </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp; </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;public MessageList() </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;{ </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;} </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp; </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;public static MessageList getInstance() </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;{ </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(ml==null) </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ml=new MessageList(); </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return ml; </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;} </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp; </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;public void add(Message msg) </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;{ </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m.add(msg); </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super.setChanged(); </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super.notifyObservers(m); </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;} </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp; </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;public void <st1:place w:st="on"><st1:state w:st="on">del</st1:state></st1:place>(Message msg) </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;{ </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m.remove(msg); </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;} </span></p>
<p><span>} </span></p>
<p><span>这个类继承了</span><span>Observable</span><span>类，并且对其中的</span><span>add</span><span>方法做了手脚，很明显，</span><span>add</span><span>方法的作用是向</span><span>ArrayList</span><span>容器中放入一个对象，这正是我们想监听的操作，所以有了</span><span>:</span></p>
<p><span>uper.setChanged(); </span></p>
<p><span>super.notifyObservers(m); </span></p>
<p><span>这意思是一旦调用</span><span>add</span><span>方法，这个类自己就会向所有注册过的观察者发送消息，消息内容是什么呢？内容就是</span><span>m</span><span>，是存放消息的容器，观察者可以收到这个改变了状态的容器，然后对它进行操作，从而实现了对容器的监听，当然，我们只实现了对</span><span>add</span><span>方法的监听，你也可以试试其他的。</span><span> </span></p>
<p><span>需要特别注意的是这是一个不完整的单例类，写成单例是为了要保证整个</span><span>jvm</span><span>中只有这一个存放消息的容器，而不写成完整的单例，原因是将来可能要提供另外的实例化方法。所以理解起来可能稍微难一点，大家可以参考一下设计模式中的单例模式。</span></p>
<p><span>下面就是编写观察者并且注册它：</span></p>
<p><span>package com.gwnet.smsMessenger.bromon; </span></p>
<p><span>import java.util.*; </span></p>
<p><span>public class MessageObserver implements Observer </span></p>
<p><span>{ </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;public void update(Observable arg0, Object arg1) </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;{ </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List l=(List)arg1; </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Message m=(Message)l.get(l.size()-1); </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String receiver=m.getReceiver(); </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("</span><span>给</span><span>"+m.getReceiver()+&#8221;</span><span>的新消息</span><span>:&#8221;+m.getContent()); </span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;} </span></p>
<p><span>} </span></p>
<p><span>这个类继承</span><span>Oberver</span><span>接口，</span><span>update(Observable,Object)</span><span>是必须提供的方法，在这个方法中我们接收被观察类传过来的数据（含有消息的容器），然后取出其中最后一个，读取它的内容。</span><span> </span></p>
<p><span>Java</span><span>里的观察者使用起来是非常简单的。我们的例子好处是所有的操作都在内存中进行，而且不需要轮询，效率非常高，缺点是一旦当机内存中的数据就丢失了，所以如果有一套比较完善的对象缓冲机制，就可以应付复杂的应用，写出高效简洁的多线程服务器。</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span><a href="http://www.cnblogs.com/goodcandle/archive/2006/04/05/observerext.html">http://www.cnblogs.com/goodcandle/archive/2006/04/05/observerext.html</a></span></p>
<p>&nbsp;</p>
<p><span><span>2.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>Observer</span></strong><strong><span>模式为何要区分推拉模式</span></strong></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>先来比较两张</span><span>UML</span><span>图：</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></p>
<p align=center><span>推模式</span></p>
<p align=center></p>
<p align=center><span>拉模式</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>两者的区别我再罗嗦一下，推模式是当通知消息来之时，把所有相关信息都通过参数的形式</span><span>&#8220;</span><span>推给</span><span>&#8221;</span><span>观察者。而拉模式是当通知消息来之时，通知的函数不带任何相关的信息，而是要观察者主动去</span><span>&#8220;</span><span>拉</span><span>&#8221;</span><span>信息。</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span>推模式的优点</span></strong><span>：</span></p>
<p align=left><span>是当消息来临时，观察者很直接地都到信息，然后进行相关地处理，与被观察者没有一点联系，两者几乎没有耦合。</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span>推模式的缺点：</span></strong><strong></strong></p>
<p align=left><span>是当消息来临时，所有的信息都强迫观察者，不管有用与否。还有一个致命的缺点是，如果想在通知消息中添加一个参数，那么所有的观察者都需要修改了，这一点往往被忽视。</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>看来事物都有其两面性一点都不假，信息太全也不是一件好事。</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&#8220;</span><span>存在即有理由</span><span>&#8221;</span><span>，为了弥补推模式的不足，拉模式就诞生了。</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>就接着上面的例子，如果</span><span>CPerson2</span><span>想要都到秒的信息，按推模式来说，</span><span>CPerson1</span><span>也就需要修改了，然而用拉模式，各个观测者之间就没有什么联系了，因为具体的信息还要观测者主动去</span><span>&#8220;</span><span>拉</span><span>&#8221;</span><span>，而一旦有了主动权，各个观察者想拉什么信息就取决于具体的观察者了，这样</span><span>CPerson1</span><span>就无需修改了，只要在</span><span>CNotifyBase</span><span>中再添加一个接口函数就行了（</span><span>GetSecond</span><span>）。</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Q</span><span>：<span>那</span></span><span>CClockDevice</span><span>不是还要修改吗？</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>A</span><span>：<span>修改是难免的，使用设计模式的目的不是不允许修改，而是让软件更易扩展，更易扩展体现在哪里呢？那就是让修改处尽可能的减少。看到</span></span><span>UML</span><span>图中那</span><span>1</span><span>和</span><span>*</span><span>了吗？你现在应该明白了吧？被观察者只要一个，而且不太会更改，而观察者确有很多。让你选择，你会选择修改什么呢？</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>当然<strong>拉模式的缺点</strong>也是存在的，那就是：</span></p>
<p align=left><span>和被观察者有一定的耦合，但我们可以通过接口，把耦合降到最低。</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>下面是观察者模式其它一些优缺点</span><span>:</span></p>
<p align=left><span>1 ) </span><span>目标和观察者间的抽象耦合一个目标所知道的仅仅是它有一系列观察者</span><span>, </span><span>每个都符合抽象的</span><span>O b s e r v e r</span><span>类的简单接口。目标不知道任何一个观察者属于哪一个具体的类。这样目标和观察者之间的耦合是抽象的和最小的。</span></p>
<p align=left><span>因为目标和观察者不是紧密耦合的</span><span>, </span><span>它们可以属于一个系统中的不同抽象层次。一个处于较低层次的目标对象可与一个处于较高层次的观察者通信并通知它</span><span>, </span><span>这样就保持了系统层次的完整。如果目标和观察者混在一块</span><span>, </span><span>那么得到的对象要么横贯两个层次</span><span>(</span><span>违反了层次性</span><span>), </span><span>要么必须放在这两层的某一层中</span><span>(</span><span>这可能会损害层次抽象</span><span>)</span><span>。</span></p>
<p align=left><span>2) </span><span>支持广播通信不像通常的请求</span><span>, </span><span>目标发送的通知不需指定它的接收者。通知被自动广播给所有已向该目标对象登记的有关对象。目标对象并不关心到底有多少对象对自己感兴趣</span><span>;</span><span>它唯一的责任就是通知它的各观察者。这给了你在任何时刻增加和删除观察者的自由。处理还是忽略一个通知取决于观察者。</span></p>
<p align=left><span>3) </span><span>意外的更新因为一个观察者并不知道其它观察者的存在</span><span>, </span><span>它可能对改变目标的最终代价一无所知。在目标上一个看似无害的操作可能会引起一系列对观察者以及依赖于这些观察者的那些对象的更新。此外</span><span>, </span><span>如果依赖准则的定义或维护不当，常常会引起错误的更新</span><span>, </span><span>这种错误通常很难捕捉。</span></p>
<p align=left><span>简单的更新协议不提供具体细节说明目标中什么被改变了</span><span>, </span><span>这就使得上述问题更加严重。</span></p>
<p align=left><span>如果没有其他协议帮助观察者发现什么发生了改变，它们可能会被迫尽力减少改变。</span></p>
<p align=left>&nbsp;</p>
<p align=left>&nbsp;</p>
<p align=left>&nbsp;</p>
<p align=left>&nbsp;</p>
<p align=left><span>这一节讨论一些与实现依赖机制相关的问题。</span></p>
<p align=left><span>1) </span><span>创建目标到其观察者之间的映射一个目标对象跟踪它应通知的观察者的最简单的方法是显式地在目标中保存对它们的引用。然而</span><span>, </span><span>当目标很多而观察者较少时</span><span>, </span><span>这样存储可能代价太高。一个解决办法是用时间换空间</span><span>, </span><span>用一个关联查找机制</span><span>(</span><span>例如一个</span><span>h a s h</span><span>表</span><span>)</span><span>来维护目标到观察者的映射。这样一个没有观察者的目标就不产生存储开销。但另一方面</span><span>, </span><span>这一方法增加了访问观察者的开销。</span></p>
<p align=left><span>2) </span><span>观察多个目标在某些情况下</span><span>, </span><span>一个观察者依赖于多个目标可能是有意义的。例如</span><span>, </span><span>一个表格对象可能依赖于多个数据源。在这种情况下</span><span>, </span><span>必须扩展</span><span>U p d a t e</span><span>接口以使观察者知道是哪一个目标送来的通知。目标对象可以简单地将自己作为</span><span>U p d a t e</span><span>操作的一个参数</span><span>, </span><span>让观察者知道应去检查哪一个目标。</span></p>
<p align=left><span>3) </span><span>谁触发更新目标和它的观察者依赖于通知机制来保持一致。但到底哪一个对象调用</span><span>N o t i f y</span><span>来触发更新</span><span>? </span><span>此时有两个选择</span><span>:</span></p>
<p align=left><span>a) </span><span>由目标对象的状态设定操作在改变目标对象的状态后自动调用</span><span>N o t i f y</span><span>。这种方法的优点是客户不需要记住要在目标对象上调用</span><span>N o t i f y</span><span>，缺点是多个连续的操作会产生多次连续的更新</span><span>, </span><span>可能效率较低。</span></p>
<p align=left><span>b) </span><span>让客户负责在适当的时候调用</span><span>N o t i f y</span><span>。这样做的优点是客户可以在一系列的状态改变完成后再一次性地触发更新</span><span>,</span><span>避免了不必要的中间更新。缺点是给客户增加了触发更新的责任。由于客户可能会忘记调用</span><span>N o t i f y</span><span>，这种方式较易出错。</span></p>
<p align=left><span>4) </span><span>对已删除目标的悬挂引用删除一个目标时应注意不要在其观察者中遗留对该目标的悬挂引用。一种避免悬挂引用的方法是</span><span>, </span><span>当一个目标被删除时，让它通知它的观察者将对该目标的引用复位。一般来说</span><span>, </span><span>不能简单地删除观察者</span><span>, </span><span>因为其他的对象可能会引用它们</span><span>, </span><span>或者也可能它们还在观察其他的目标。</span></p>
<p align=left><span>5) </span><span>在发出通知前确保目标的状态自身是一致的在发出通知前确保状态自身一致这一点很重要</span><span>, </span><span>因为观察者在更新其状态的过程中需要查询目标的当前状态。当</span><span>S u b j e c t</span><span>的子类调用继承的该项操作时</span><span>, </span><span>很容易无意中违反这条自身一致的准则。你可以用抽象的</span><span>S u b j e c t</span><span>类中的模板方法</span><span>( Template Method(5.10))</span><span>发送通知来避免这种错误。定义那些子类可以重定义的原语操作</span><span>, </span><span>并将</span><span>N o t i f y</span><span>作为模板方法中的最后一个操作</span><span>, </span><span>这样当子类重定义了</span><span>S u b j e c t</span><span>的操作时，还可以保证该对象的状态是自身一致的。</span></p>
<p align=left><span>6) </span><span>避免特定于观察者的更新协议</span><span>-</span><span>推</span><span>/</span><span>拉模型观察者模式的实现经常需要让目标广播关于其改变的其他一些信息。目标将这些信息作为</span><span>U p d a t e</span><span>操作一个参数传递出去。这些信息的量可能很小，也可能很大。一个极端情况是，目标向观察者发送关于改变的详细信息</span><span>, </span><span>而不管它们需要与否。我们称之为推模型</span><span>(push model)</span><span>。另一个极端是拉模型</span><span>(pull model); </span><span>目标除最小通知外什么也不送出</span><span>,</span><span>而在此之后由观察者显式地向目标询问细节。</span></p>
<p align=left><span>拉模型强调的是目标不知道它的观察者</span><span>, </span><span>而推模型假定目标知道一些观察者的需要的信息。</span></p>
<p align=left><span>推模型可能使得观察者相对难以复用，因为目标对观察者的假定可能并不总是正确的。</span></p>
<p align=left><span>另一方面。拉模型可能效率较差</span><span>, </span><span>因为观察者对象需在没有目标对象帮助的情况下确定什么改变了。</span></p>
<p align=left><span>7) </span><span>显式地指定感兴趣的改变你可以扩展目标的注册接口</span><span>,</span><span>让各观察者注册为仅对特定事件感兴趣，以提高更新的效率。当一个事件发生时</span><span>, </span><span>目标仅通知那些已注册为对该事件感兴趣的观察者。支持这种做法一种途径是，对使用目标对象的方面（</span><span>a s p e c t s</span><span>）的概念。可用如下代码将观察者对象注册为对目标对象的某特定事件感兴趣：</span></p>
<p align=left><span>void Subject::Attach(Observer*, Aspect&amp; interest);</span></p>
<p align=left><span>此处</span><span>i n t e r e s t</span><span>指定感兴趣的事件。在通知的时刻</span><span>, </span><span>目标将这方面的改变作为</span><span>U p d a t e</span><span>操作的一个参数提供给它的观察者，例如</span><span>:</span></p>
<p align=left><span>void Observer::Update(Subject*, Aspect&amp; interest);</span></p>
<p align=left><span>8) </span><span>封装复杂的更新语义当目标和观察者间的依赖关系特别复杂时</span><span>, </span><span>可能需要一个维护这些关系的对象。我们称这样的对象为更改管理器（</span><span>C h a n g e M a n a g e r</span><span>）。它的目的是尽量减少观察者反映其目标的状态变化所需的工作量。例如</span><span>, </span><span>如果一个操作涉及到对几个相互依赖的目标进行改动</span><span>, </span><span>就必须保证仅在所有的目标都已更改完毕后，才一次性地通知它们的观察者</span><span>,</span><span>而不是每个目标都通知观察者。</span></p>
<p align=left><span>C h a n g e M a n a g e r</span><span>有三个责任</span><span>:</span></p>
<p align=left><span>a) </span><span>它将一个目标映射到它的观察者并提供一个接口来维护这个映射。这就不需要由目标来维护对其观察者的引用</span><span>, </span><span>反之亦然。</span></p>
<p align=left><span>b) </span><span>它定义一个特定的更新策略。</span></p>
<p align=left><span>c) </span><span>根据一个目标的请求</span><span>, </span><span>它更新所有依赖于这个目标的观察者。</span></p>
<p align=left><span>有两种特殊的</span><span>C h a n g e M a n a g e r</span><span>。</span><span>S i m p l e C h a n g e M a n a g e r</span><span>总是更新每一个目标的所有观察者</span><span>, </span><span>比较简单。相反</span><span>,D A G C h a n g e M a n a g e r</span><span>处理目标及其观察者之间依赖关系构成的无环有向图。当一个观察者观察多个目标时</span><span>, DAGChangeManager</span><span>要比</span><span>S i m p l e C h a n g e M a n a g e r</span><span>更好一些。在这种情况下</span><span>, </span><span>两个或更多个目标中产生的改变可能会产生冗余的更新。</span><span>D A G C h a n g e M a n a g e r</span><span>保证观察者仅接收一个更新。当然，当不存在多重更新的问题时</span><span>, SimpleChangeManager</span><span>更好一些。</span></p>
<p align=left><span>C h a n g e M a n a g e r</span><span>是一个</span><span>M e d i a t o r ( 5 . 5 )</span><span>模式的实例。通常只有一个</span><span>C h a n g e M a n a g e r, </span><span>并且它是全局可见的。这里</span><span>S i n g l e t o n ( 3 . 5 )</span><span>模式可能有用。</span></p>
<p align=left><span>9) </span><span>结合目标类和观察者类用不支持多重继承的语言</span><span>(</span><span>如</span><span>S m a l l t a l k )</span><span>书写的类库通常不单独定义</span><span>S u b j e c t</span><span>和</span><span>O b s e r v e r</span><span>类</span><span>, </span><span>而是将它们的接口结合到一个类中。这就允许你定义一个既是一个目标又是一个观察者的对象，而不需要多重继承。例如在</span><span>S m a l l t a l k</span><span>中</span><span>, Subject</span><span>和</span><span>O b s e r v e r</span><span>接口</span></p>
<p align=left>&nbsp;</p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/126894.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-06-28 18:16 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126894.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>类图与java代码</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126893.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Thu, 28 Jun 2007 10:15:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126893.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/126893.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126893.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/126893.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/126893.html</trackback:ping><description><![CDATA[&nbsp;
<p align=center><span>类图与</span><span>java</span><span>代码</span></p>
<p>&nbsp;</p>
<p><span><a href="http://www.javaeye.com/topic/37302">http://www.javaeye.com/topic/37302</a></span></p>
<p>&nbsp;</p>
<p align=left><strong><span>1.</span></strong><strong><span>泛化</span></strong><strong><span>(Generalization)</span></strong><strong><span><br></span></strong><strong><span>[</span></strong><strong><span>泛化</span></strong><strong><span>]</span></strong><strong><span><br></span></strong><span>表示类与类之间的继承关系，接口与接口之间的继承关系，或类对接口的实现关系。一般化的关系是从子类指向父类的，与继承或实现的方法相反。</span><span><br><strong><span>[</span></strong></span><strong><span>具体表现</span></strong><strong><span>]<br></span></strong><span>父类</span><span> </span><span>父类实例＝</span><span>new </span><span>子类</span><span>()<br><strong><span>[UML</span></strong></span><strong><span>图</span></strong><strong><span>](</span></strong><strong><span>图</span></strong><strong><span>1.1)<br></span></strong><strong><span><br></span></strong><strong><span>图</span></strong><strong><span>1.1</span></strong><span> <strong>Animal</strong></span><strong><span>类与</span></strong><strong><span>Tiger</span></strong><strong><span>类</span></strong><strong><span>,Dog</span></strong><strong><span>类的泛化关系</span></strong><strong><span><br></span></strong><span><br><strong><span>[</span></strong></span><strong><span>代码表现</span></strong><strong><span>]</span></strong></p>
<ol type=1>
    <li><span>class<span>&nbsp;Animal{} &nbsp;&nbsp; </span></span></li>
    <li><span>class<span>&nbsp;Tiger&nbsp;extends&nbsp;Animal{} &nbsp;&nbsp; </span></span></li>
    <li><span>public<span>&nbsp;class&nbsp;Test &nbsp;&nbsp; </span></span></li>
    <li><span>{ &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;test() &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Animal&nbsp;a=new&nbsp;Tiger(); &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp; </span></li>
    <li><span>}&nbsp;&nbsp; </span></li>
</ol>
<p align=left><span><br></span><strong><span>2.</span></strong><strong><span>依赖</span></strong><strong><span>(Dependency)</span></strong><strong><span><br><span>[</span></span></strong><strong><span>依赖</span></strong><strong><span>]<br></span></strong><span>对于两个相对独立的对象，当一个对象负责构造另一个对象的实例，或者依赖另一个对象的服务时，这两个对象之间主要体现为依赖关系。</span><span><br><strong><span>[</span></strong></span><strong><span>具体表现</span></strong><strong><span>]<br></span></strong><span>依赖关系表现在<span>局部变量</span>，<span>方法的参数</span>，以及对<span>静态方法的调用</span></span><span><br><strong><span>[</span></strong></span><strong><span>现实例子</span></strong><strong><span>]<br></span></strong><span>比如说你要去拧螺丝，你是不是要借助</span><span>(</span><span>也就是依赖</span><span>)</span><span>螺丝刀</span><span>(Screwdriver)</span><span>来帮助你完成拧螺丝</span><span>(screw)</span><span>的工作</span><span><br><strong><span>[UML</span></strong></span><strong><span>表现</span></strong><strong><span>](</span></strong><strong><span>图</span></strong><strong><span>1.2)</span></strong></p>
<p align=left><strong></strong></p>
<p align=left><span><br></span><strong><span>图</span></strong><strong><span>1.2 </span></strong><strong><span>Person</span></strong><strong><span>类与</span></strong><strong><span>Screwdriver</span></strong><strong><span>类的依赖关系</span></strong><span><br><strong><span><br>[</span></strong></span><strong><span>代码表现</span></strong><strong><span>] </span></strong></p>
<ol type=1>
    <li><span>public<span>&nbsp;class&nbsp;Person{ &nbsp;&nbsp; </span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;/**&nbsp;</span><span>拧螺丝</span><span>&nbsp;*/&nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;screw(Screwdriver&nbsp;screwdriver){ &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;screwdriver.screw(); &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp; </span></li>
    <li><span>}&nbsp;&nbsp; </span></li>
</ol>
<p align=left><span><br></span><strong><span>3.</span></strong><strong><span>关联</span></strong><strong><span>(Association)</span></strong><strong><span><br><span>[</span></span></strong><strong><span>关联</span></strong><strong><span>]<br></span></strong><span>对于两个相对独立的对象，当一个对象的实例与另一个对象的一些特定实例存在固定的对应关系时，这两个对象之间为关联关系。</span><span><br><strong><span>[</span></strong></span><strong><span>具体表现</span></strong><strong><span>]<br></span></strong><span>关联关系是使用<span>实例变量</span>来实现</span><span><br><strong><span>[</span></strong></span><strong><span>现实例子</span></strong><strong><span>]<br></span></strong><span>比如客户和订单，每个订单对应特定的客户，每个客户对应一些特定的订单；再例如公司和员工，每个公司对应一些特定的员工，每个员工对应一特定的公司</span><span><br><strong><span>[UML</span></strong></span><strong><span>图</span></strong><strong><span>] (</span></strong><strong><span>图</span></strong><strong><span>1.3)<br></span></strong><strong><span><br></span></strong><strong><span>图</span></strong><strong><span>1.3 </span></strong><strong><span>公司和员工的关联关系</span></strong><span><br><strong><br><span>[</span></strong></span><strong><span>代码表现</span></strong><strong><span>]</span></strong><span> </span></p>
<ol type=1>
    <li><span>public<span>&nbsp;class&nbsp;Company{ &nbsp;&nbsp; </span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Employee&nbsp;employee; &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;Employee&nbsp;getEmployee(){ &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;employee; &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;setEmployee(Employee&nbsp;employee){ &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.employee=employee; &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;//</span><span>公司运作</span><span> &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;run(){ &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;employee.startWorking(); &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp; </span></li>
    <li><span>}&nbsp;&nbsp; </span></li>
</ol>
<p align=left><strong><span>(4)</span></strong><strong><span>聚合（</span></strong><strong><span>Aggregation</span></strong><strong><span>）</span></strong><strong><span><br><span>[</span></span></strong><strong><span>聚合</span></strong><strong><span>]<br></span></strong><span>当对象</span><span>A</span><span>被加入到对象</span><span>B</span><span>中，成为对象</span><span>B</span><span>的组成部分时，对象</span><span>B</span><span>和对象</span><span>A</span><span>之间为聚集关系。聚合是关联关系的一种，是较强的关联关系，强调的是<span>整体</span>与<span>部分</span>之间的关系。</span><span><br><strong><span>[</span></strong></span><strong><span>具体表现</span></strong><strong><span>]<br></span></strong><span>与关联关系一样，聚合关系也是通过<span>实例变量</span>来实现这样关系的。关联关系和聚合关系来语法上是没办法区分的，从<span>语义</span>上才能<span>更好的区分</span>两者的区别。</span><span><br><strong><span>[</span></strong></span><strong><span>关联与聚合的区别</span></strong><strong><span>]</span></strong><span><br>(1)</span><span>关联关系所涉及的两个对象是处在同一个层次上的。比如人和自行车就是一种关联关系，而不是聚合关系，因为人不是由自行车组成的。</span><span><br></span><span>聚合关系涉及的两个对象处于不平等的层次上，一个代表整体，一个代表部分。比如电脑和它的显示器、键盘、主板以及内存就是聚集关系，因为主板是电脑的组成部分。</span><span><br>(2)</span><span>对于具有聚集关系（尤其是强聚集关系）的两个对象，整体对象会制约它的组成对象的生命周期。部分类的对象不能单独存在，它的生命周期依赖于整体类的对象的生命周期，当整体消失，部分也就随之消失。比如张三的电脑被偷了，那么电脑的所有组件也不存在了，除非张三事先把一些电脑的组件（比如硬盘和内存）拆了下来。</span><span><br><strong><span>[UML</span></strong></span><strong><span>图</span></strong><strong><span>](</span></strong><strong><span>图</span></strong><strong><span>1.4)</span></strong><span><br><strong><br></strong></span><strong><span>图</span></strong><strong><span>1.3 </span></strong><strong><span>电脑和组件的聚合关系</span></strong><strong><span><br><br><span>[</span></span></strong><strong><span>代码表现</span></strong><strong><span>]</span></strong><span> </span></p>
<ol type=1>
    <li><span>public<span>&nbsp;class&nbsp;Computer{ &nbsp;&nbsp; </span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;CPU&nbsp;cpu; &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;CPU&nbsp;getCPU(){ &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;cpu; &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;setCPU(CPU&nbsp;cpu){ &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.cpu=cpu; &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;//</span><span>开启电脑</span><span> &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;start(){ &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//cpu</span><span>运作</span><span> &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cpu.run(); &nbsp;&nbsp; </span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp; </span></li>
    <li><span>}&nbsp;&nbsp; </span></li>
</ol>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/126893.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-06-28 18:15 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126893.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JProfile Beginning</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126891.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Thu, 28 Jun 2007 10:14:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126891.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/126891.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126891.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/126891.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/126891.html</trackback:ping><description><![CDATA[&nbsp;
<p align=center><span>JProfile Beginning</span></p>
<p>&nbsp;</p>
<p><span>JProfiler </span><span>是一个著名的用于</span><span> java </span><span>系统监控分析的软件，功能很强大，可以监控普通的</span><span> java application, applet, java web start, application server </span><span>等等。除了可以监控本地的程序，还可以对远程服务器上跑的应用进行监控。</span></p>
<p>&nbsp;</p>
<p><span><a href="http://resources.ej-technologies.com/jprofiler/help/doc/indexRedirect.html?http&amp;&amp;&amp;resources.ej-technologies.com/jprofiler/help/doc/ide/eclipse3.html">http://resources.ej-technologies.com/jprofiler/help/doc/indexRedirect.html?http&amp;&amp;&amp;resources.ej-technologies.com/jprofiler/help/doc/ide/eclipse3.html</a></span></p>
<p>&nbsp;</p>
<h2><span><span>一、<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>JProfiler as an Eclipse 3.x Plugin</span></h2>
<p>&nbsp;<span><span> </span></span><span>When JProfiler is integrated into the <a href="http://www.eclipse.org/" target=_blank>eclipse 3.x IDE</a>, JProfiler can be invoked from within the IDE without any further need for session configuration. </span></p>
<p><strong><span>Requirements: </span></strong><span>The eclipse 3.x plugins work with <strong>the full SDKs for</strong> eclipse 3.0 and eclipse 3.1. The JProfiler integration does not work with partial installations of the eclipse framework. For eclipse 2.x, a <a href="http://resources.ej-technologies.com/jprofiler/help/doc/ide/eclipse.html">different plugin</a> is available. </span></p>
<p>&nbsp;</p>
<p>&nbsp;<span><span> </span></span><span>The installation of the eclipse plugin is started by selecting "eclipse 3.0" or "eclipse 3.1" on the </span></p>
<ul type=disc>
    <li><span>IDE integration tab of JProfiler's <a href="http://resources.ej-technologies.com/jprofiler/help/doc/setup/setup.html">setup wizard</a> </span></li>
    <li><span><a href="http://resources.ej-technologies.com/jprofiler/help/doc/generalSettings/misc.html">miscellaneous options tab</a> of JProfiler's <a href="http://resources.ej-technologies.com/jprofiler/help/doc/generalSettings/generalSettings.html">general settings</a> (use <em>Session-&gt;IDE integrations</em> in JProfiler's main menu as a shortcut). </span></li>
</ul>
<p><span>and clicking on <strong>[Integrate]</strong> </span></p>
<p><strong><span>Reminder:</span></strong><span> Please close eclipse while performing the plugin installation. If you are performing the installation from JProfiler's <a href="http://resources.ej-technologies.com/jprofiler/help/doc/setup/setup.html">setup wizard</a>, please complete the entire setup first before starting eclipse. </span></p>
<p><span>A file selector will then prompt you to locate the <strong>installation directory</strong> of eclipse. </span></p>
<p><span>After acknowledging the completion message, you can start eclipse and check whether the installation was successful. If the menu item <em>Run-&gt;Profile ...</em> does not exist in the <strong>Java perspective</strong>, please enable the "Profile" actions for this perspective under <em>Window-&gt;Customize perspective</em> by bringing the <strong>Command</strong> tab to front and selecting the "Profile" checkbox. </span></p>
<p><span>eclipse provides shared infrastructure for profiling plugins that allows only one active profiler at a time. If another profiler has registered itself in eclipse, JProfiler will show a collision message dialog at startup. Please go to the </span><tt><em><span>plugin</span></em></tt><span> directory in your eclipse installation and delete the plugins that are specified in the warning message in order to guarantee that JProfiler will be used when you click on one of the profiling actions. </span></p>
<p><span>If you are upgrading the integration from JProfiler &lt;=3.2, please delete your Eclipse "configuration" directory except the config.ini file before restarting Eclipse. This is to avoid a common Eclipse 3.x plugin cache bug. </span></p>
<p>&nbsp;</p>
<p>&nbsp;<span><span> </span></span><span>To profile your application from eclipse, choose one of the profiling commands in the <em>Run</em> menu or click on the corresponding toolbar button. The profile commands are equivalent to the debug and run commands in eclipse and are part of eclipse's infrastructure. </span></p>
<p align=center><span><br></span><span>Main eclipse toolbar with "Profile" button</span><span> <br>&nbsp;</span></p>
<p align=center><span><br></span><span>eclipse "Run" menu with "Profile" actions</span><span> <br>&nbsp;</span></p>
<p><span>The profiled application is then started just as with the usual "Run" commands. If no instance of JProfiler is currently running, JProfiler is also started, otherwise the running instance of JProfiler will be used for presenting profiling data. </span></p>
<p><span>Every time a run configuration is profiled, a dialog box is brought up that asks you whether a new window should be opened in JProfiler. To get rid of this dialog, you can select the "Don't ask me again" checkbox. The window policy can subsequently be configured in the JProfiler settings in eclipse (see below). </span></p>
<p><span>All profiling settings and view settings changes are persistent across session restarts. </span></p>
<p><span>When JProfiler is used with the eclipse integration, the "Show source" action for a class or a method in one of JProfiler's view will show the source element in eclipse and not in JProfiler's integrated source code viewer. </span></p>
<p>&nbsp;</p>
<p>&nbsp;<span><span> </span></span><span>Several JProfiler-related settings can be adjusted in eclipse under <em>Window-&gt;Preferences-&gt;JProfiler</em>: </span></p>
<ul type=disc>
    <li><span>The used <strong>JProfiler installation</strong> can be changed by repeating the integration from JProfiler or by adjusting the JProfiler executable in the corresponding text field. When you upgrade to a newer version of JProfiler, make sure to repeat the integration, since the plugin has to be updated, too. </span></li>
    <li><span>The <strong>window policy</strong> can be configured as </span></li>
    <ul type=circle>
        <li><strong><span>Ask each time</span></strong><span> <br>Every time you profile a run configuration, a dialog box will ask you whether a new window should be opened in JProfiler. This is the default setting. </span></li>
        <li><strong><span>Always new window</span></strong><span> <br>Every time you profile a run configuration, a new window will be opened in JProfiler. </span></li>
        <li><strong><span>Reuse last window</span></strong><span> <br>Every time you profile a run configuration, the last window will be reused in JProfiler. </span></li>
    </ul>
    <li><span>You can manually repeat the <strong>collision detection</strong> that is performed at startup. With the corresponding checkbox, you can also switch off collision detection at startup. </span></li>
</ul>
<p align=left><span><span>&#183;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>You can ask JProfiler to always use <strong>interpreted mode</strong> for profiling. A separate checkbox tells JProfiler to use the <strong>deprecated JVMPI interface</strong> when profiling with a 1.5 JRE. Both these settings are trouble-shooting options and should normally not be selected. </span></p>
<p>&nbsp;</p>
<p align=left>&nbsp;<span><span> </span></span><span>For eclipse 3.2 and higher, profiling <strong>WTP run configurations</strong> is supported. </span></p>
<h2><span><span>二、<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>Overview of Features</span></h2>
<p>&nbsp;<span><span> </span></span><span>JProfiler's features are ordered into view sections. A view section can be made visible by selecting in JProfiler's sidebar. JProfiler offers the following view sections: </span></p>
<ul type=disc>
    <li><span><a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/memory/memory.html">Memory profiling</a> <br>Keep track of your objects and find out where the problem spots are. </span></li>
    <li><span><a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/heapwalker/heapwalker.html">The heap walker</a> <br>Use the drill down capabilities of JProfiler's unique heap walker to find memory leaks. </span></li>
    <li><span><a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/cpu/cpu.html">CPU profiling</a> <br>Find out where your CPU time is going and zero in on performance bottlenecks. </span></li>
    <li><span><a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/threads/threads.html">Thread profiling</a> <br>Check the activity of your threads, resolve deadlocks and get detailed information on your application's monitor usage. </span></li>
</ul>
<p align=left><span><span>&#183;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span><a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/telemetry/telemetry.html">VM telemetry information</a> <br>Unfold the statistical history of your application with JProfiler's virtual machine telemetry monitors. </span></p>
<p>&nbsp;</p>
<p>&nbsp;<span><span> </span></span><span>In order to help you find JProfiler's features which are most important to you, we present a situational overview. There are two types of uses for a profiler which arise from different motivations: </span></p>
<ul type=disc>
    <li><strong><span>Problem solving</span></strong><span> <br>If you turn to a profiler with a problem in your application, it most likely falls into one of the following three categories: </span></li>
    <ul type=circle>
        <li><strong><span>Performance problem</span></strong><span> <br>To find performance related problem spots in your application, turn to JProfiler's <a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/cpu/cpu.html">CPU section</a>. Often, performance problems are caused by excessive creation of temporary objects. For that case, the <a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/memory/recordedObjects.html">recorded objects views</a> with its view mode set to "garbage collected objects" will show you where efforts to reduce allocations make sense. </span></li>
        <li><strong><span>Excessive memory consumption</span></strong><span> <br>If your application consumes too much memory, the <a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/memory/memory.html">memory views</a> will show you where the memory consumption comes from. With the <a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/heapwalker/references.html">reference views</a> in the <a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/heapwalker/heapwalker.html">heap walker</a> you can find out which objects are unnecessarily kept alive in the heap. </span></li>
        <li><strong><span>Memory leak</span></strong><span> <br>If your application's memory consumption goes up linearly with time, you likely have a memory leak which is show stopper especially for application servers. The "mark current values and show differences" feature in the <a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/memory/memory.html">memory section</a> and the <a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/heapwalker/heapwalker.html">heap walker</a> will help you to find the cause. </span></li>
        <li><strong><span>Deadlock</span></strong><span> <br>If you experience a deadlock, JProfiler's <a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/threads/deadlock.html">deadlock detection graph</a> will help you to find the cause even for complex locking situations. </span></li>
        <li><strong><span>Hard to find bug</span></strong><span> <br>A often overlooked but highly profitable use of a profiler is that of debugging. Many kinds of bugs are exceptionally hard to find by hand or by using a traditional debugger. Some bugs revolve around complex call stack scenarios (have a look at the <a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/cpu/cpu.html">CPU section</a>), others around entangled object reference graphs (have a look at the <a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/heapwalker/heapwalker.html">heap walker section</a>), both of which are not easy to keep track of. <br>Particularly JProfiler's <a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/threads/threads.html">thread views</a> are of great help in multi-threaded situations, where race-conditions and deadlocks are hard to track down. </span></li>
    </ul>
</ul>
<p align=left><span><span>&#183;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>Quality assurance</span></strong><span> <br>During a development process, it's a good idea to regularly run a profiler on your application to assess potential problem spots. Even though an application may prove to be "good enough" in test cases, an awareness for performance and memory bottlenecks enables you adapt your design decisions as the project evolves. In this way you avoid costly re-engineering when real-world needs are not met. Use the information presented in JProfiler's <a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/telemetry/telemetry.html">telemetry section</a> to keep an eye on the evolution of your application. The ability to <a href="http://resources.ej-technologies.com/jprofiler/help/doc/sessions/saving.html">save profiling snapshots</a> enables you to keep track of your project's evolution. The <a href="http://resources.ej-technologies.com/jprofiler/help/doc/offline/offline.html">offline profiling</a> capability allows you to perform automated profiling runs on your application. </span></p>
<p>&nbsp;</p>
<h2><span><span>三、<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>Finding a Memory Leak</span></h2>
<h3><span>1. Introduction</span></h3>
<p><span>Unlike C/C++, Java has a garbage collector that eventually frees all unreferenced instances. This means that there are no classic memory leaks in Java where you forget to delete an object or a memory region. However, in Java you can forget something else: to remove all references to an instance so that the object can be garbage collected. If an object is only ever held in a single location, this may seem simple, but in many complex systems objects are passed around through many layers, each of which can add a permanent reference to the object. </span></p>
<p><span>Sometimes it appears to be clear that an object should be garbage collected when looking at the local environment of where the object is created and discarded. However, any call to a different part of a system that passes the object as a parameter can cause the object to "escape" if the receiver intentionally or by mistake continues to hold a reference to the object after the call has completed. Often, over-eager caching with the intention to improve performance or design mistakes where parallel access structures are built are the reason for memory leaks. </span></p>
<h3><span>2. Recognizing a memory leak</span></h3>
<p><span>The first step when suspecting a memory leak is to look at the heap and object telemetry views. When you have a memory leak in your application, these graphs must show a linear positive trend with possible oscillations on top. </span></p>
<p><span>If there's no such linear trend, your application probably simply consumes a lot of memory. This is not a memory leak and the strategy for that case is straightforward: Find out which classes or arrays use a lot of memory and try to reduce their size or number or instances. </span></p>
<h3><span>3. Using differencing to narrow down a memory leak</span></h3>
<p><span>The first stop when looking for the origin of a memory leak is the <a href="http://resources.ej-technologies.com/jprofiler/help/doc/helptopics/memory/diff.html">differencing action</a> of the all objects view and the recorded objects view. Simple memory leaks can sometimes be tracked down with the differencing function alone. </span></p>
<p><span>First, you observe the differences in the all objects view or the recorded objects view and find out which class is causing the problems. Then you switch to the allocation hotspots view, select the problematic class and observe in the difference column in which method the problematic instances are allocated. Now you know the method in which these instances were created. </span></p>
<p><span>An analysis of the code for this method and the methods to which these instances are passed may already yield the solution to the memory leak. If not, you have to continue with the heap walker. </span></p>
<p><span>Another tool to observe instance counts that also presents a history of values is the class tracker. The class tracker shows graphs of instance counts versus time for selected classes and packages. When the difference columns in the "all objects" or "recorded objects" views identify suspicious classes, the class tracker can often generate further insight into the evolution of these instance counts since you can correlate jumps or increases in the allocation rate with other telemetry views or bookmarks. </span></p>
<h3><span>4. The heap walker and memory leaks</span></h3>
<p><span>When you take a heap snapshot, you first have to create an object set with those object instances or arrays that should be freed by the garbage collector but are still referenced somewhere. If you've already narrowed down the origin of the memory leak in the dynamic memory views, you can use the "Take heap snapshot for selection" action to save you some work and to start in the heap walker right at the point where you left off in the dynamic memory views. </span></p>
<p><span>By default, the heap walker cleans a heap snapshot from objects that are unreferenced but are still not collected by the garbage collector. This behavior can be controlled by the "Remove unreferenced and weakly referenced objects" option in the heap walker options dialog. When searching for a memory leak, this "full garbage collection" is desirable, since unreferenced objects are a temporary phenomenon without any connection to a memory leak. </span></p>
<p><span>If necessary, you can now further narrow down the memory leak by adding additional selection steps. For example, you can go to the data view and look at the instance data to find out a number of instances that definitely should have been freed. By flagging these instances and creating a new set of objects you can reduce the number of objects that are in your focus. </span></p>
<h3><span>5. Using the reference graph to find the reason for a memory leak</span></h3>
<p><span>The core instrument for finding memory leaks is <span>the reference graph</span> in the heap walker. Here you can find out how single objects are referenced and why they're not garbage collected. By successively opening incoming references you may spot a "wrong" reference immediately. In complex systems this is often not possible. In that case you have to find one or multiple "<span>garbage collector roots</span>". Garbage collector roots are points in the JVM that are not subject to garbage collection. These roots emanate strong references, any object that is linked by a chain of references to such a root cannot be garbage collected. </span></p>
<p><span>When you right-click on an object in the reference view, the context menu offers the option to search for paths to the garbage collector roots: </span></p>
<p>&#160;</p>
<p><span>Potentially there are very many garbage collector roots and displaying them all can lead to the situation that a sizable fraction of the entire heap has to be shown in the reference graph. Also, looking for garbage collector roots is computationally quite expensive, and if thousands of roots can be found, the computation can take very long and use a lot of memory. In order to prevent this, it is recommend to start with a single garbage collector root and search for more roots if required. An option dialog is displayed after you trigger the search: </span></p>
<p>&#160;</p>
<p><span>As you can see in this example, the chain to a garbage collector root can be quite long: </span></p>
<p>&#160;</p>
<p><span>The reason for a memory leak can be anywhere along this chain. It is of a semantic nature and cannot be found out by JProfiler, but only by the programmer. Once you have found the faulty reference, you can work on your code to remove it. Unless there are other references, the memory leak will be gone. </span></p>
<h3><span>6. Using the cumulated references views to find the reason for a memory leak</span></h3>
<p><span>In some cases, you might not succeed in narrowing down the object set to a reasonable size. You object set might still contain a large number of instances that are OK and using the reference graph might not provide any insight in this situation. </span></p>
<p><span>If such a situation arises, the cumulated reference tables available in the reference view of the heap walker can be of help. The cumulated incoming reference table shows all possible <strong>reference types</strong> into the current object set: </span></p>
<p>&#160;</p>
<p><span>From the reference type, you may be able to narrow down the object set. For example, you may know that one type of reference is OK, but another is not. As a hypothetical example, the reference from </span><code><span>HashMap$Entry</span></code><span> in the table above might be OK, but the reference from </span><code><span>java.util.jar.Manifest</span></code><span> might be suspicious. By selecting the 8 objects who are referenced in this way, you can discard the other 224 instances and use the reference graph to show the path to a garbage collector root. </span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h2><span><span>四、<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>JProfiler's Menu</span></h2>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>JProfiler's toolbar and menu contain actions applicable to all views as well as actions which are view-sensitive or appear for certain views only. The common menu and toolbar entries fall into six categories: </span></p>
<p>&nbsp;<span><span> </span></span><span>The <strong>session menu</strong> contains actions to create, open and close sessions and snapshots. </span></p>
<ul type=disc>
    <li><strong><span>Start center</span></strong><span> <br>(</span><code><span>CTRL-O</span></code><span>) Brings up JProfiler's <a href="http://resources.ej-technologies.com/jprofiler/help/doc/quickstart/startcenter.html">start center</a>. If there already is an open session in the current window, it will be discarded once a new session is opened. This action is also available from JProfiler's toolbar. </span></li>
    <li><strong><span>New window</span></strong><span> <br>(</span><code><span>CTRL-ALT-O</span></code><span>) Open in a new instance of JProfiler's main window and brings up JProfiler's <a href="http://resources.ej-technologies.com/jprofiler/help/doc/quickstart/startcenter.html">start center</a>. </span></li>
    <li><strong><span>New session</span></strong><span> <br>(</span><code><span>CTRL-N</span></code><span>) Creates a new session and brings up the <a href="http://resources.ej-technologies.com/jprofiler/help/doc/sessions/application/applicationSettings.html">application settings dialog</a>. The new session will be started after leaving the dialog with <strong>[OK]</strong>. If there is already an open session in the current window, it will be discarded. </span></li>
    <li><strong><span>Integration wizards</span></strong><span> <br>This submenu contains the starting points for the <a href="http://resources.ej-technologies.com/jprofiler/help/doc/quickstart/appservers.html">application server integration wizards</a>, just like the "New session" tab on the <a href="http://resources.ej-technologies.com/jprofiler/help/doc/quickstart/startcenter.html">start center</a>. </span></li>
    <li><strong><span>Conversion wizards</span></strong><span> <br>This submenu contains the starting points for the conversion wizards, just like the "Convert" tab on the <a href="http://resources.ej-technologies.com/jprofiler/help/doc/quickstart/startcenter.html">start center</a>. </span></li>
    <li><strong><span>Open session</span></strong><span> <br>Brings up the <a href="http://resources.ej-technologies.com/jprofiler/help/doc/sessions/open.html">open session dialog</a>. If there already is an open session in the current window, it will be discarded once a new session is opened. </span></li>
    <li><strong><span>Save snapshot</span></strong><span> <br>(</span><code><span>CTRL-S</span></code><span>) Brings up a file chooser to select a <a href="http://resources.ej-technologies.com/jprofiler/help/doc/sessions/saving.html">snapshot file</a> to be written. A dialog box informs about the successful completion of the operation. This action is also available from JProfiler's toolbar. </span></li>
    <li><strong><span>Open snapshot</span></strong><span> <br>Brings up a file chooser to select a <a href="http://resources.ej-technologies.com/jprofiler/help/doc/sessions/saving.html">snapshot file</a> to be opened. If there already is an open session in the current window, it will be discarded. </span></li>
    <li><strong><span>Session settings</span></strong><span> <br>Brings up the <a href="http://resources.ej-technologies.com/jprofiler/help/doc/sessions/sessions.html">session settings dialog</a>. Note that any changes here become effective only when the session is restarted. </span></li>
    <li><strong><span>General settings</span></strong><span> <br>Brings up the <a href="http://resources.ej-technologies.com/jprofiler/help/doc/generalSettings/generalSettings.html">general settings dialog</a>. </span></li>
    <li><strong><span>IDE integrations</span></strong><span> <br>Short cut to the IDE integrations tab of the <a href="http://resources.ej-technologies.com/jprofiler/help/doc/generalSettings/ide.html">general settings dialog</a> where you can integrate all supported IDEs. </span></li>
    <li><strong><span>Close window</span></strong><span> <br>(</span><code><span>CTRL-W</span></code><span>) Closes the current window. If there is an open session in the current window, you will be asked for confirmation. </span></li>
</ul>
<p align=left><span><span>&#183;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>Exit JProfiler</span></strong><span> <br>(</span><code><span>CTRL-ALT-X</span></code><span>) After confirmation, closes all open main windows and exits JProfiler. </span></p>
<p>&nbsp;</p>
<p>&nbsp;<span><span> </span></span><span>The <strong>view menu</strong> contains view-specific actions and gives access to the view settings dialog. View specific actions are described in the help page of the <a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/views.html">corresponding view</a>. </span></p>
<p align=left><span><span>&#183;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>View settings</span></strong><span> <br>(</span><code><span>CTRL-T</span></code><span>) Brings up the view settings dialog for the corresponding view. If disabled, the currently active view has no particular settings. This action is also available from JProfiler's toolbar. </span></p>
<p>&nbsp;</p>
<p>&nbsp;<span><span> </span></span><span>The <strong>profiling menu</strong> contains actions which change the window or session as a whole. </span></p>
<ul type=disc>
    <li><strong><span>Stop/Detach/Start/Attach session</span></strong><span> <br>(</span><code><span>F11</span></code><span>) This action is also available from JProfiler's toolbar. </span></li>
    <ul type=circle>
        <li><span>&nbsp;Stops the session (all <a href="http://resources.ej-technologies.com/jprofiler/help/doc/sessions/sessions.html">session types</a> except remote session), i.e. the process is destroyed. In a stopped session, the profiling views are <a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/views.html">not fully functional</a> (visible if currently started and not remote session). </span></li>
        <li><span>&nbsp;Detaches the current <a href="http://resources.ej-technologies.com/jprofiler/help/doc/sessions/sessions.html">remote session</a>. The profiled JVM will be detached from JProfiler's front end and continues to run undisturbed. In a detached session, the profiling views are <a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/views.html">not fully functional</a> (visible if currently attached and remote session). </span></li>
        <li><span>Starts the application configured in the current session if it is a <a href="http://resources.ej-technologies.com/jprofiler/help/doc/sessions/sessions.html">local session, applet session or Web Start session</a> (visible if currently detached and not remote session). </span></li>
        <li><span>Attaches the current <a href="http://resources.ej-technologies.com/jprofiler/help/doc/sessions/sessions.html">remote session</a> to a remote application or reconnects to it. (visible if currently detached and remote session). </span></li>
    </ul>
    <li><strong><span>Freeze/Unfreeze session</span></strong><span> <br>(</span><code><span>F12</span></code><span>) This action is also available from JProfiler's toolbar. </span></li>
    <ul type=circle>
        <li><span><a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/views.html">Freeze all views</a> for the current session (visible if currently not frozen). </span></li>
        <li><span><a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/views.html">Unfreeze all views</a> for the current session (visible if currently frozen). </span></li>
    </ul>
    <li><strong><span>Get current data</span></strong><span> <br>(</span><code><span>F5</span></code><span>) <a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/views.html">Update all views</a> with the current data. If the current session is frozen, this action reloads all views and is also available from JProfiler's toolbar. If the session is not frozen, only the current view is updated. This action only has an effect on dynamic views that get auto-updated, views where data is calculated on demand are not re-calculated with this action. </span></li>
    <li><strong><span>Record allocation data</span></strong><span> <br>This action is also available from JProfiler's toolbar. The <a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/memory/memory.html">memory views</a> and some <a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/telemetry/telemetry.html">telemetry views</a> rely on allocation data. </span></li>
    <ul type=circle>
        <li><span>Start recording allocation data. (visible if allocations are currently not recorded). Adds a bookmark with a solid line to all graph views with a time axis. </span></li>
        <li><span>Stop recording allocation data. (visible if allocations are currently recorded). Adds a bookmark with a dashed line to all graph views with a time axis. </span></li>
    </ul>
    <li><strong><span>Record CPU data</span></strong><span> <br>This action is also available from JProfiler's toolbar. The <a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/cpu/cpu.html">CPU views</a> rely on CPU data. </span></li>
    <ul type=circle>
        <li><span>Start recording CPU data. (visible if CPU data is currently not recorded). Adds a bookmark with a solid line to all graph views with a time axis. </span></li>
        <li><span>Stop recording CPU data. (visible if CPU data is currently recorded). Adds a bookmark with a dashed line to all graph views with a time axis. </span></li>
    </ul>
    <li><strong><span>Save HPROF snapshot</span></strong><span> <br>Brings up a dialog to select a path for an <a href="http://resources.ej-technologies.com/jprofiler/help/doc/sessions/saving.html">HPROF snapshot file </a>to be saved. A dialog box informs about the successful completion of the operation. </span></li>
    <li><strong><span>Run garbage collector</span></strong><span> <br>Run the garbage collector in the profiled JVM. This action is also available from JProfiler's toolbar. </span></li>
    <li><strong><span>Add bookmark</span></strong><span> <br>Add a bookmark in all graph views with a time axis. Bookmarks can be renamed or deleted by right-clicking them and choosing the appropriate action from the context menu. Bookmarks can also be set programmatically from the <a href="http://resources.ej-technologies.com/jprofiler/help/doc/offline/javadoc/com/jprofiler/agent/Controller.html">profiling API</a>. </span></li>
</ul>
<p align=left><span><span>&#183;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>Show global filters for method call recording</span></strong><span> <br>Show a dialog with a tree view of all <a href="http://resources.ej-technologies.com/jprofiler/help/doc/sessions/filters/view.html">exclusive or inclusive filters</a> that JProfiler uses when recording the method call tree. This action is also available at the bottom of several views that show call trees. </span></p>
<p>&nbsp;</p>
<p align=left>&nbsp;<span><span> </span></span><span>The <strong>go to menu</strong> provides one-click access to all of JProfiler's profiling views, grouped into the four &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/views.html">view sections</a>. </span></p>
<p>&nbsp;</p>
<p>&nbsp;<span><span> </span></span><span>The <strong>window menu</strong> allows you to keep track of all <a href="http://resources.ej-technologies.com/jprofiler/help/doc/views/windows.html">tops level windows created by JProfiler</a>. </span></p>
<ul type=disc>
    <li><strong><span>Undock/Dock view</span></strong><span> <br>(</span><code><span>CTRL-E</span></code><span>) This action is also available from the context menu when right clicking the view in the tab selector at the bottom of the window. </span></li>
    <ul type=circle>
        <li><span>&nbsp;Undocks the view and shows it in a separate top level window. (visible if the currently active view is docked into the main window) </span></li>
        <li><span>&nbsp;Docks the view and returns it to the main window. (visible if the currently active view is undocked) </span></li>
    </ul>
    <li><strong><span>Dock all floating views</span></strong><span> <br>Docks all currently undocked views into their main windows. </span></li>
    <li><strong><span>Cycle to previous window</span></strong><span> <br>(</span><code><span>CTRL-F2</span></code><span>) Activate the previous window in the window list and bring it to the front. </span></li>
    <li><strong><span>Cycle to next window</span></strong><span> <br>(</span><code><span>CTRL-F3</span></code><span>) Activate the next window in the window list and bring it to the front. </span></li>
    <li><strong><span>Tile all undocked views</span></strong><span> <br>Tile the desktop with all undocked views. </span></li>
    <li><strong><span>Stack all undocked views</span></strong><span> <br>Resize all undocked views to a standard size and stack them regularly on the desktop. </span></li>
    <li><strong><span>Close unused console windows</span></strong><span> <br>Close all console windows that do not have an active process associated with them. </span></li>
</ul>
<p><span>At the bottom of the window menu you can directly navigate to a window by selecting it from the list. </span></p>
<p>&nbsp;</p>
<p>&nbsp;<span><span> </span></span><span>The <strong>help menu</strong> gives access to help, web sites, and useful e-mail addresses for JProfiler. </span></p>
<ul type=disc>
    <li><strong><span>Help contents</span></strong><span> <br>(</span><code><span>F1</span></code><span>) Brings up context sensitive help. This action is also available from JProfiler's toolbar. </span></li>
    <li><strong><span>JProfiler on the web</span></strong><span> <br>Connects to JProfiler's web site in the web browser configured under <a href="http://resources.ej-technologies.com/jprofiler/help/doc/generalSettings/misc.html">general settings</a>. </span></li>
    <li><strong><span>Contact sales</span></strong><span> <br>Brings up a sales contact form in the web browser configured under <a href="http://resources.ej-technologies.com/jprofiler/help/doc/generalSettings/misc.html">general settings</a>. </span></li>
    <li><strong><span>Contact support</span></strong><span> <br>Brings up a support contact form in the web browser configured under <a href="http://resources.ej-technologies.com/jprofiler/help/doc/generalSettings/misc.html">general settings</a>. </span></li>
    <li><strong><span>Enter license key</span></strong><span> <br>Allows you to <a href="http://resources.ej-technologies.com/jprofiler/help/doc/setup/licenseKey.html">enter your license key</a>. </span></li>
</ul>
<p align=left><span><span>&#183;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><strong><span>About JProfiler</span></strong><span> <br>Shows general information about your copy of JProfiler and its license status. </span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span><span>1.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>下载软件</span><span>JProfile4.2.2(for windows</span><span>版本</span><span>)</span></p>
<p><span><span>2.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>安装</span><span>JProfile</span><span>，</span><span>License</span><span>使用如下信息</span><span> </span></p>
<p><span>Name: License for You </span></p>
<p><span>Lincese Code: A-G667#42616F-10kg1r134fq9m#2217</span></p>
<p>&nbsp;</p>
<p><span><a href="http://blog.csdn.net/samlei/archive/2007/03/16/1531510.aspx">http://blog.csdn.net/samlei/archive/2007/03/16/1531510.aspx</a></span></p>
<p>&nbsp;</p>
<p align=left><span>摘要：不当的<span>O/R-Mapping</span>框架使用，导致垃圾对象的生成。</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>最近用<span>JProfile</span>测试一个比较大的工程，希望能找到一些程序运行的瓶颈。过去使用<span>Hibernate</span>，很多人反映效率低。特别是懒加载关闭的时候，对象的持续生成最后会导致<span>JVM</span>直接<span>OutOfMemory</span>错误。目前使用<span>iBatis</span>，发现临时对象还是特别多，一开始百思不解。通过使用<span>JProfile</span>以后，终于找到了原因所在。</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>对象引用关系：<span>baseView -&gt;InstanceModel -&gt; City</span></span></p>
<p align=left><span>其中，<span>baseView </span>引用了<span>InstanceMode</span>，而<span>InstanceMode </span>引用了<span>City</span>对象，<span>City</span>对象是一个比较简单的对象，只有<span>id</span>、<span>name</span>、中文名称等属性。在工程实际使用环境中，<span>InstanceModel </span>是比较多的，可能会有数万经常被使用。通过对<span>JVM</span>堆的观察，发现每次<span>InstanceModel</span>对象生成的时候，都会附带出大量的<span>City</span>对象。由于一般应用中<span>City</span>的个数都有限，所以程序中专门对<span>City</span>对象作了缓存。为什么会产生大量<span>City</span>的临时对象呢？</span></p>
<p align=left><span>通过在<span>JProfile</span>中查看堆的情况，可以很清楚的看到上述引用关系。这很正常啊？纳闷中，反复查看堆、对象、引用关系等信息，终于发现了线索。那就是，被引用的<span>City</span>对象中只有<span>ID</span>值，没有中文名称等其他信息。这就让我们找到了突破口，通过与开发工程师的交谈，被告知只使用了<span>ID</span>值，没有使用其他的属性。于是我们找到<span>iBatis</span>加载<span>baseView</span>对象的映射文件：</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; </span><span>&lt;</span><span>resultMap</span><span> </span><span>id</span><span>=</span><span>"baseView"</span><span> </span><span>class</span><span>=</span><span>"View"</span><span>&gt;</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &#8230;</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&lt;</span><span>result</span><span> </span><span>column</span><span>=</span><span>"CITYCODE"</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>property</span><span>=</span><span>"InstanceModel.city.id"</span><span> </span><span>jdbcType</span><span>=</span><span>"NUMERIC"</span><span> </span><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /&gt;</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; </span><span>&lt;/</span><span>resultMap</span><span>&gt;</span></p>
<p align=left><span>注意，在上面这个定义文件中，加载<span>View</span>对象的时候，从同一张数据库表中，加载了<span>View</span>所属的<span>City</span>的代码（<span>id</span>）。但是<span>iBatis</span>框架在达到这个目的的同时，生成了一个临时<span>City</span>对象，并把<span>ID</span>赋了值。这就是原因！！</span></p>
<p align=left><span>好了，原因找到了，优化的方案自然就出来了。只需要去掉<span>InstanceModel</span>对<span>City</span>对象的引用，直接取<span>City</span>的<span>ID</span>就行了！再次运行<span>JProfile</span>，发现不再生成大量的<span>City</span>临时对象，优化的目的达到了。</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>结论：使用<span>Hibernate</span>、<span>iBatis</span>等框架的时候，我们过于热衷于对象引用的方便，忽视了这种方便的代价。有时候，我们只为了使用一个简单类型的数据，却大量加载肥胖对象而不自知。然后抱怨框架效率低，有问题。其实回头看看，良好的数据库设计、良好的对象设计这些基本的东西，是任何框架都不能帮我们做的。同时感叹<span>JProfile</span>这种强大工具给我们带来的好处，让我感觉又回到了<span>DOS Debug </span>的时代。</span></p>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/126891.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-06-28 18:14 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126891.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Rhino Beginning</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126890.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Thu, 28 Jun 2007 10:13:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126890.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/126890.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126890.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/126890.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/126890.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;Rhino Beginning&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; General1.1&nbsp;&nbsp; Overview &nbsp;Overview of RhinoMost people who have used JavaScript before have done so by ...&nbsp;&nbsp;<a href='http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126890.html'>阅读全文</a><img src ="http://www.blogjava.net/hengheng123456789/aggbug/126890.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-06-28 18:13 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126890.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java Programming Style Guidelines</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126889.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Thu, 28 Jun 2007 10:12:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126889.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/126889.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126889.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/126889.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/126889.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 1 Introduction This document lists Java coding recommendations common in the Java development community.The recommendations are based on established standards collected from a number of sources, i...&nbsp;&nbsp;<a href='http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126889.html'>阅读全文</a><img src ="http://www.blogjava.net/hengheng123456789/aggbug/126889.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-06-28 18:12 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126889.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JESS Beginning</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126888.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Thu, 28 Jun 2007 10:11:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126888.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/126888.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126888.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/126888.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/126888.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;JESS Beginning&nbsp;1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; What is JESSJess is a rule engine and scripting environment written entirely in Sun's Java language by Ernest Friedman-Hi...&nbsp;&nbsp;<a href='http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126888.html'>阅读全文</a><img src ="http://www.blogjava.net/hengheng123456789/aggbug/126888.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-06-28 18:11 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/06/28/126888.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JUnit设计模式分析</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/06/04/121963.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Mon, 04 Jun 2007 10:15:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/06/04/121963.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/121963.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/06/04/121963.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/121963.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/121963.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;JUnit设计模式分析&nbsp;http://www.uml.org.cn/sjms/200442724.htm&nbsp;IT先锋资深顾问 grid liu&nbsp;&nbsp;这篇文章由grid liu发表在&lt;程序员〉上。grid liu在IT先锋中担任资深顾问，负责J2EE技术的顾问咨询和培训工作。 摘要&nbsp; JUnit是...&nbsp;&nbsp;<a href='http://www.blogjava.net/hengheng123456789/archive/2007/06/04/121963.html'>阅读全文</a><img src ="http://www.blogjava.net/hengheng123456789/aggbug/121963.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-06-04 18:15 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/06/04/121963.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EJB Stateless Session Begining</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/05/31/121221.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Thu, 31 May 2007 10:28:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/05/31/121221.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/121221.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/05/31/121221.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/121221.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/121221.html</trackback:ping><description><![CDATA[&nbsp;
<p align=center><span>EJB Stateless Session Begining</span></p>
<p>&nbsp;</p>
<p><span>参考：</span><span><a href="http://www.tusc.com.au/tutorial/html/index.html">http://www.tusc.com.au/tutorial/html/index.html</a></span></p>
<p>&nbsp;</p>
<p><span>一、</span><span>Enterprise Beans</span></p>
<p>&nbsp;</p>
<p><span>在</span><span>EJB</span><span>（</span><span>Enterprise Java Beans</span><span>）中定义了两种不同类别的</span><span>Enterprise Bean </span><span>：</span><span> </span></p>
<p><span><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>会话</span><span> Bean (Session Bean) </span></p>
<p><span><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>实体</span><span>Bean (Entity Bean) </span></p>
<p>&nbsp;</p>
<p><span><span>1.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>会话</span><span> Bean (Session Bean) </span></p>
<p><span>请把</span><span>Session Beans</span><span>看作任务而非持久数据，只有这样，你才能清晰地理解使用它的场合和原因。比如说，</span><span>Session Bean</span><span>可能会对数据库内的用户进行检索操作，但并不把用户表示为持久的业务对象。</span><span>Session Beans</span><span>可以同其他类型的</span><span>Java beans</span><span>通信，这种能力已经超出了数据库事务概念之外。在这种方式下工作的分布式应用程序特别适合于采用</span><span>Session Beans</span><span>。</span></p>
<p>&nbsp;</p>
<p><span>所有的</span><span>Session Beans</span><span>都派生于</span><span>javax.ejb.SessionBean</span><span>类。就像其名称那样，</span><span> Session Beans</span><span>只存在于单一客户会话中。这里的客户可能是</span><span>Java Servlet</span><span>、桌面应用程序、别的</span><span>EJB</span><span>乃至采用</span><span>Java Bean</span><span>的其他事务信息方式。</span><span>Session Bean</span><span>的生存期从客户程序发起接触开始，在客户通过调用</span><span>EJB</span><span>宿主接口的</span><span>remove()</span><span>方法显式破坏</span><span>bean</span><span>时终止。会话还会在预先设置的时间终止，而这种时间设置则由</span><span>EJB</span><span>容器内确定。考虑到服务器的资源，开发者往往会设法避免处理&#8220;超时&#8221;设置而在编写客户程序时做相应的延期处理。此外，开发者还应该在</span><span>EJB</span><span>容器重新启动的时候小心</span><span>Session Bean</span><span>的短暂寿命；客户程序可以重新获得同类</span><span>bean</span><span>的引用，但很有可能却不是同一</span><span>bean</span><span>。</span></p>
<p>&nbsp;</p>
<p><span>Session Beans</span><span>可以是无状态也可以是有状态的，因而两者会显示出不同的行为。</span><span>Session Bean</span><span>的状态概念类似于</span><span>HTTP</span><span>设置：客户程序和服务器之间的交互（在这种情况下就是</span><span>bean</span><span>自身）发生在定义的环境之内。有状态的</span><span>Session Bean</span><span>会在多个方法调用的情况下保存客户和</span><span>bean</span><span>的有关信息。有状态的</span><span>Session Bean</span><span>只能同一个客户程序通讯，而无状态</span><span>Session bean</span><span>的实例却可以同时和若干个客户程序通讯。</span></p>
<p>&nbsp;</p>
<p><span>会话</span><span> Bean </span><span>是调用它的客户端代码要完成的工作。当客户端与服务器建立联系，那么一个会话</span><span> Bean </span><span>就建立起来了。根据会话</span><span> Bean </span><span>的状态不同有分为</span><span>: </span></p>
<p>&nbsp;</p>
<p><span>A. </span><span>状态会话</span><span> Bean (Stateful Session Bean) </span></p>
<p><span>B. </span><span>无状态会话</span><span> Bean (Stateless Session Bean) </span></p>
<p><span>1.1 </span><span>状态会话</span><span> Bean (Stateful Session Bean) </span></p>
<p><span>当客户机和服务器建立连接之后，状态会话</span><span> Bean (Stateful Session Bean) </span><span>将一直在客户机和服务器之间保持着用户的某个状态。例如：用户使用银行的</span><span>ATM</span><span>时，经过验证之后，用户可以连续执行多次操作，在这个过程当中，用户的合法状态将一直被保留，直到她将信用卡取出，结束这次操作。这时，状态会话</span><span> Bean (Stateful Session Bean) </span><span>也就被销毁。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>1.2</span><span>无状态会话</span><span> Bean (Stateless Session Bean) </span></p>
<p><span>当客户机和服务器建立连接之后，无状态会话</span><span> Bean (Stateless Session Bean)</span><span>处理单一的用户请求或商务过程。无状态会话</span><span> Bean (Stateless Session Bean)</span><span>不需要从以前的请求中提取任何状态。例如，用户的用户密码确认。用户输入密码后，发送请求。组件返回真或假来确认用户，一旦过程完成，无状态会话</span><span> Bean (Stateless Session Bean) </span><span>也宣告结束。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>2. </span><span>实体</span><span>Bean (Entity Bean) </span></p>
<p><span>实体</span><span>Bean (Entity Bean)</span><span>只是数据模型，它不包括商务逻辑。实体</span><span>Bean (Entity Bean)</span><span>可以将关系</span><span>/</span><span>对象数据库的数据映射到内存中供其它组件使用。实体</span><span>Bean (Entity Bean)</span><span>是一直存在的，而且具有很高的容错性能。实体</span><span>Bean (Entity Bean)</span><span>能供允许多用户同时访问。</span></p>
<p>&nbsp;</p>
<p><span>二、会话</span><span> Bean (Session Bean) </span></p>
<p>&nbsp;</p>
<p><span>Ejb</span><span>的执行过程是被放在一个</span><span>EJB</span><span>容器中进行的，所以客户端不会直接调用我们写好的</span><span>Enterprise Bean </span><span>，而是调用</span><span>EJB</span><span>容器生成的一个</span><span>EJBObject (EJB</span><span>对象</span><span>)</span><span>来实现。那么，我们在编写服务器端的</span><span>Enterprise Bean </span><span>时，就要考虑这点。既然客户端不能直接访问，就由</span><span>EJBObject</span><span>来代劳，所以在编写服务器端时，就要编写服务器端的一个接口（</span><span>Remote</span><span>）用来与客户机联系，实力化</span><span>EJBObject</span><span>。要生成</span><span>EJBObject </span><span>就要调有</span><span>Home </span><span>接口，来建立这个实力。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>以下是会话</span><span> Bean </span><span>的代码分析：</span><span> </span></p>
<p>&nbsp;</p>
<p><span>A.Enterprise Bean </span><span>类：</span><span>sailorsy.class </span></p>
<p>&nbsp;</p>
<p><span>1.setSessionContext(SessionContext ctx)</span><span>方法</span><span> </span></p>
<p><span>它是</span><span>EJB</span><span>容器和</span><span>Enterprise Bean</span><span>互相作用的关口。</span><span> </span></p>
<p><span>import java.rmi.*; </span></p>
<p><span>import javax.ejb.*; </span></p>
<p><span>public class sailorsy implements SessionBean{ </span></p>
<p><span>private SessionContext ctx=null; </span></p>
<p><span>public voic setSessionContext(SessionContext ctx){ </span></p>
<p><span>this.ctx=ctx; </span></p>
<p><span>}//setSessionContext </span></p>
<p><span>}//class sailorsy </span></p>
<p><span>2.ejbCreate(</span><span>&#8230;</span><span>)</span><span>方法</span><span> </span></p>
<p><span>它可以初始化</span><span>Enterprise Bean ,</span><span>可以定义不同的</span><span>ejbCreate(</span><span>&#8230;</span><span>)</span><span>方法，每个方法所带的参数不同。但是，必许要存在至少一种。</span><span> </span></p>
<p><span>import java.rmi.*; </span></p>
<p><span>import javax.ejb.*; </span></p>
<p><span>public class sailorsy implements SessionBean{ </span></p>
<p><span>private SessionContext ctx=null; </span></p>
<p><span>public voic setSessionContext(SessionContext ctx){ </span></p>
<p><span>this.ctx=ctx; </span></p>
<p><span>}//setSessionContext </span></p>
<p><span>public void ejbCreate() { </span></p>
<p><span>}//ejbCreate </span></p>
<p><span>}//class sailorsy </span></p>
<p><span>3.ejbPassivate()</span><span>方法</span><span> </span></p>
<p><span>如果初始化的</span><span>Enterprise Bean </span><span>过多，</span><span>EJB</span><span>容器将其中的一些挂起（</span><span>passivate</span><span>）</span><span>,</span><span>释放他们所占用的空间。</span><span> </span></p>
<p><span>import java.rmi.*; </span></p>
<p><span>import javax.ejb.*; </span></p>
<p><span>public class sailorsy implements SessionBean{ </span></p>
<p><span>private SessionContext ctx=null; </span></p>
<p>&nbsp;</p>
<p><span>public voic setSessionContext(SessionContext ctx){ </span></p>
<p><span>this.ctx=ctx; </span></p>
<p><span>}//setSessionContext </span></p>
<p>&nbsp;</p>
<p><span>public void ejbCreate() { </span></p>
<p><span>}//ejbCreate </span></p>
<p><span>public void ejbPassivate() { </span></p>
<p><span>}//ejbPassivate </span></p>
<p>&nbsp;</p>
<p><span>}//class sailorsy </span></p>
<p><span>4.ejbActivate()</span><span>方法</span><span> </span></p>
<p><span>和</span><span>ejbPassivate</span><span>正好相反，它将被挂起的</span><span>Bean</span><span>从新调回。</span><span> </span></p>
<p><span>import java.rmi.*; </span></p>
<p><span>import javax.ejb.*; </span></p>
<p><span>public class sailorsy implements SessionBean{ </span></p>
<p><span>private SessionContext ctx=null; </span></p>
<p>&nbsp;</p>
<p><span>public voic setSessionContext(SessionContext ctx){ </span></p>
<p><span>this.ctx=ctx; </span></p>
<p><span>}//setSessionContext</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p align=left><strong><span>Creating a Stateless Session Bean</span></strong></p>
<p align=left><span>This chapter covers how to create a stateless session EJB component. This bean will be responsible for authenticating the user by communicating with the database using Data Access Object (DAO) which encapsulates Java Database Connectivity (JDBC) code. A DAO has all attributes (fields) and behavior (methods) corresponding to the bean it is being used for. </span></p>
<p align=left>&nbsp;</p>
<p align=left><span><br clear=left></span></p>
<p align=left><span>All customers, supplier and manager of MyStore have been assigned a unique username and userid to access services of MyStore, but in order to access these services all these entities have to first login into the system (MyStore). The method for authentication is named <strong>loginUser</strong>, which takes <strong>two String parameters, username and password and returns the userID if authentication is successful. </strong></span></p>
<p align=left><em><span>Note : This method loginUser is a business method, normally business methods carry out operations or processing on values EJB components. From clients perspective, clients can see only business methods and invoke them on bean.</span></em></p>
<p align=left><strong><span>Tasks :</span></strong></p>
<ol type=1>
    <li><span>Create a J2EE project named MyStore.</span></li>
    <li><span>Create a Stateless Session Bean named StoreAccess.</span></li>
    <li><span>Add a business method in bean named loginUser with the following signature</span></li>
</ol>
<p align=left><strong><span>public String loginUser (String username, String password)</span></strong></p>
<ol type=1 start=4>
    <li><span>Create a DAO named StoreAccessDAOImpl under package au.com.tusc.dao. Generate the DAO interface.</span></li>
    <li><span>Implement the method named loginUser, generated in DAO interface, in StoreAccessDAOImpl. Method signature is </span></li>
</ol>
<p align=left><strong><span>public String loginUser (String username, String password) </span></strong></p>
<ol type=1 start=6>
    <li><span>Add callback methods and implement them.</span></li>
    <li><span>Deploy StoreAccess bean.</span></li>
    <li><span>Create your test client named SessionClient under package au.com.tusc.client.</span></li>
    <li><span>Run your client and test the bean.</span></li>
</ol>
<p align=left><strong><span>Create J2EE Project :</span></strong></p>
<p align=left><span>Now, lets start to write our first component of this tutorial.</span></p>
<p align=left><strong><span>Go to File &gt; New &gt; LombozJ2EE Project, project creation wizard will pop up.</span></strong></p>
<p align=left><strong><span>Insert Project Name MyStore &gt; Next .</span></strong></p>
<p align=left><strong><span>Under Java Settings Check source, should be MyStore/src , libraries pointing to $JAVA_HOME &gt; Go Next as shown in fig below. </span></strong></p>
<p align=left><em><span>Note: This step is shown in chapter1, as there is a bug in eclipse 2.1, so its important that you check your library settings are right.</span></em></p>
<p align=left><span><br clear=left></span></p>
<p align=left><strong><span>Under Create J2EE Module, select Web Modules tab &gt; Add.., enter Module name as OnlineStore &gt; OK as shown in figure below.</span></strong></p>
<p align=left><span><br clear=left></span></p>
<p align=left><strong><span>Under Create J2EE Module, select EJB Modules tab &gt; Add.., enter Module name as MyStoreMgr &gt; OK .</span></strong></p>
<p align=left><strong><span>Under Create J2EE Module, select Targeted Servers tab &gt; Select JBOSS 3.2.1 ALL &gt; Add.. &gt; Finish.</span></strong></p>
<p align=left>&nbsp;</p>
<p align=left><strong><span>Create Stateless Bean :</span></strong></p>
<p align=left>&nbsp;</p>
<p align=left><strong><span>Go To Package Explorer &gt; Expand Mystore (project) node &gt; select src, right click and menu will pop up.</span></strong></p>
<p align=left><strong><span>On pop up menu &gt; New &gt; Lomboz EJB Creation Wizard.</span></strong></p>
<p align=left><strong><span>Enter package name au.com.tusc.session, bean name StoreAccess and select bean type as stateless &gt; Finish.</span></strong></p>
<p align=left><strong><span>This will create a package named au.com.tusc.session under src and StoreAccessBean under that package as shown in the figure below.</span></strong></p>
<p align=left><span><br clear=left></span></p>
<p align=left><strong><span>As we can see from the figure below it has created a class level tag @ejb.bean, which has assigned the bean type, name and its JNDI name which will be generated in Home interface. This tag will also generate deployment descriptors in ejb-jar.xml and jboss.xml file as well once you generate your EJB classes, which is covered later on in this chapter.</span></strong></p>
<p align=left><span><br clear=left></span></p>
<p align=left><em><span>Note: It will generate the bean name, jndi-name and type of bean in the file. Also, the name of file is appended with word 'Bean' as you gave the name of the bean as StoreAccess only. Again, be careful with naming conventions, specifying the bean name only in the wizard without adding the word 'Bean' to the name as the wizard appends that for you. </span></em></p>
<p align=left><em><span>Expand MyStoreMgr/META-INF node under Package Explorer. You will find there are seven files which are generated by Lomboz using Xdoclet as shown in the figure below. </span></em></p>
<p align=left><span><br clear=left></span></p>
<p align=left><span>Now we are going to generate all the interfaces including Home, Remote, DAO and other helper classes. We will explain why later on, but for the time being just follow the steps.</span></p>
<p align=left><span>But before we get too excited, there are a few concepts to cover here.</span></p>
<p align=left><strong><span>Go to MyStoreMgr/META-INF &gt; select and open ejbGenerate.xml.</span></strong></p>
<p align=left><em><span>Note: Lomboz uses this file to generate required interfaces and helper classes, so in the event that you have special needs then you will have to customize this file. See ejbdoclet under the Xdoclet documentation.</span></em></p>
<p align=left><em><span>'ejbGenerate.xml' file is generated only once when you create your EJB module. So any changes made in this file will be reflected even if you modify your bean class and generate your classes again and again.</span></em></p>
<table cellPadding=0 width="100%" border=0>
    <thead>
        <tr>
            <td vAlign=top width="50%">
            <p align=left><span>As we can see from the code snippet of file shown in figure at right, there are following tags defined.</span></p>
            <p align=left><span>&lt;dataobject/&gt; is defined for generating data Objects for holding values of EJB component's persistent fields, which correspond to columns in the associated table in the database. </span></p>
            <p align=left><em><span>Note: &lt;dataobject/&gt; has been deprecated in favour of Value Object which is more powerful in terms of relationships (1-1, 1-n and n-m). </span></em></p>
            <p align=left><span>&lt;utilobject/&gt; Creates method for generating GUID and for accessing Remote and Local Home objects. </span></p>
            <p align=left><span>&lt;remoteinterface/&gt; Generates remote interfaces for EJBs.</span></p>
            <p align=left><span>&lt;</span><span>localinterface/&gt; Generates local interfaces for EJBs.</span></p>
            <p align=left><span>&lt;homeinterface /&gt; Generates remote home interfaces for EJBs.</span></p>
            <p align=left><span>&lt;localhomeinterface/&gt;Generates local home interfaces for EJBs.</span></p>
            <p align=left><span>&lt;entitypk/&gt;Generates primary key classes for entity EJBs.</span></p>
            <p align=left><span>&lt;entitybmp/&gt;Creates entity bean classes for BMP entity EJBs.</span></p>
            <p align=left><span>&lt;entitycmp/&gt;</span></p>
            <p align=left><span>&lt;session/&gt; Generates session bean class.</span></p>
            <p align=left><em><span>Note : There is no tag for generating a DAO.</span></em></p>
            <p align=left><em><span>So, we have to include this &lt;dao/&gt; tag.</span></em></p>
            <p align=left><em><span>For details, please refer ejbdoclet under Xdoclet documentation.</span></em></p>
            </td>
            <td vAlign=top width="50%">
            <p align=left><span><br clear=left></span></p>
            </td>
        </tr>
    </thead>
    <tbody>
    </tbody>
</table>
<p align=left>&nbsp;</p>
<table cellSpacing=4 cellPadding=0 width="100%" border=0>
    <thead>
        <tr>
            <td vAlign=top width="50%">
            <p align=left><span>As we can see from the code snippet from this file the following tags are defined.</span></p>
            <p align=left><span>&lt;jboss/&gt; is a JBOSS specific tag required for JBOSS. You have to specify datasource, datasourcemapping and preferredrelationmapping. As it differs for different databases, so you may have to specify values appropriate to your environment. If these tags are commented out in JBOSS they default to the correct values for the built-in Hypersonic SQL database, but for the moment we'll set them anyway.</span></p>
            </td>
            <td vAlign=top width="50%">
            <p align=left><span><br clear=left></span></p>
            </td>
        </tr>
    </thead>
    <tbody>
    </tbody>
</table>
<p align=left>&nbsp;</p>
<p align=left><span>The other two files which are of importance to us are ejb-jar.xml and jboss.xml. The file ejb-jar.xml has all the deployment descriptors for beans and jboss.xml has the JBOSS specific deployment descriptors required by JBOSS.</span></p>
<p align=left><em><span>Note : ejb-jar.xml file is generated every time you generate interface and helper classes for your bean. For the first time, it is empty, and jboss.xml will be generated every time when you will generate your classes for your bean.</span></em></p>
<p align=left>&nbsp;</p>
<p align=left><strong>&nbsp;</strong></p>
<p align=left><strong><span>Setup DAO :</span></strong></p>
<p align=left>&nbsp;</p>
<p align=left><span>Now, let's customize ejbGenerate.xml for setting up a DAO. </span></p>
<p align=left><strong><span>We have included a &lt;dao&gt; tag specifying the destination directory for the generated DAO interface and what pattern to be used.</span></strong></p>
<p align=left><span><br clear=left></span><em><span>Note : For details, please refer ejbdoclet under Xdoclet documentation.</span></em></p>
<table cellSpacing=4 cellPadding=0 width="100%" border=0>
    <thead>
        <tr>
            <td vAlign=top width="51%">
            <p align=left><span>We have included the datasource, datasoucremapping and preferredrelationmapping as shown in code snippet of ejbGenerate.xml file on right. </span></p>
            <p align=left><span>datasource="java:/DefaultDS" is a local JNDI name for data source to be used.</span></p>
            <p align=left><span>datsourcemapping="Hypersonic SQL" maps data object/value objects and their types to columns and data types associated with these columns.</span></p>
            <p align=left><span>preferredrelationmapping="foreign-key" defines type of database to be used. </span></p>
            <p align=left><em><span>Note : For more details, please refer JBOSS documentation.</span></em></p>
            <p align=left>&nbsp;</p>
            <p align=left><span>Since we are using the Hypersonic database, these parameters are appropriate to that. These parameters relate to the configuration file standardjbosscmp-jdbc.xml which controls the CMP-to-JDBC mappings for JBOSS. This resides in $JBOSS_HOME/server/conf/ , e.g. /opt/jboss/jboss-3.2.1/server/default/conf/.</span></p>
            <p align=left><span>Code snippet from standardjbosscmp-jdbc.xml is shown in figure at right.</span></p>
            </td>
            <td vAlign=top width="49%">
            <p align=left><span><br clear=left></span></p>
            <p align=left><span><br clear=left></span></p>
            </td>
        </tr>
    </thead>
    <tbody>
    </tbody>
</table>
<p align=left>&nbsp;</p>
<p align=left><em><span>Note : The way Xdoclet works is bit different from some conventional styles of programming, as the Xdoclet tags will generate these (home and remote) interfaces along with necessary helper classes, which then will used in Bean and DAO Implementation class. However, until these are generated, we cannot write any business methods in Bean and JDBC wrappers in the DAO Implementation class. If this seems confusing then just follow the steps, and hopefully it will become more clear. </span></em></p>
<p align=left><strong>&nbsp;</strong></p>
<p align=left><strong><span>Create DAO Interface :</span></strong></p>
<p align=left>&nbsp;</p>
<p align=left><span>Since we are going to use a DAO to access the database for this Stateless Bean, we have to create a DAOImpl class which will implement that generated DAO interface.</span></p>
<p align=left><strong><span>Go to src &gt; add package named au.com.tusc.dao &gt; Add a class StoreAccessDAOImpl in that package</span></strong><span>.</span></p>
<p align=left><span><br clear=left></span></p>
<p align=left><strong><span>Now go to your Bean class and declare this tag at the class level (that is at the top) as shown below to generate the DAO interface.</span></strong></p>
<p align=left><span><span>&nbsp;&nbsp; </span></span><span>@ejb.dao class="au.com.tusc.session.StoreAccessDAO"</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>impl-class="au.com.tusc.dao.StoreAccessDAOImpl"</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><br clear=left></span></p>
<p align=left><strong><span>Expand StoreAccessBean node under Package Explorer. Right click and a pop up menu will appear. </span></strong></p>
<p align=left><strong><span>On that menu go to Lomboz J2EE &gt; Add EJB to module. Select EJB '[MyStoreMgr]' &gt; OK.</span></strong></p>
<p align=left><span><br clear=left></span></p>
<p align=left><strong><span>Expand MyStoreMgr node under MyStore Project in Package Explorer. Right click and a menu will pop up.</span></strong></p>
<p align=left><strong><span>Go to Lomboz J2EE &gt; Generate EJB Classes as shown in the figure below.</span></strong></p>
<p align=left><span><br clear=left></span></p>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <thead>
        <tr>
            <td vAlign=top width="70%">
            <p align=left><strong><span>EJB interfaces and helper classes are generated under ejbsrc/au.com.tusc.session directory as shown in the figure at the right. </span></strong></p>
            <p align=left><span>Seven files are generated. </span></p>
            <p align=left><span>StoreAccess is the remote object interface.</span></p>
            <p align=left><span>StoreAccessLocal is the local object interface.</span></p>
            <p align=left><span>StoreAccessSession extends our bean class named StoreAccesBean.</span></p>
            <p align=left><span>StoreAccessHome is the remote home interface.</span></p>
            <p align=left><span>StoreAccessLocalHome is the local home interface.</span></p>
            <p align=left><span>StoreAccessUtil is a helper class which has methods for accessing Home and LocalHome interface along with generating GUID.</span></p>
            <p align=left><span>StoreAccesDAO is the DAO interface which we will use to implement our StoreAccessDAOImpl under au.com.tusc.dao.</span></p>
            <p align=left><strong><span>StoreAccessDAO is generated by this tag declared in StoreAccesBean shown below. If you don't declare this tag in that file it won't generate this interface.</span></strong></p>
            <p align=left><span>&nbsp;</span><span>@ejb.dao class=au.com.tusc.session.StoreAccessDAO</span></p>
            <p align=left><span>&nbsp;</span><span>impl-class=au.com.tusc.dao.StoreAccessDAOImpl</span></p>
            <p align=left><strong><span>Other files of interest which are generated are ejb-jar.xml and jboss.xml under MyStoreMgr/META-INF. </span></strong></p>
            </td>
            <td vAlign=top width="30%">
            <p align=left><span><br clear=left></span></p>
            </td>
        </tr>
    </thead>
    <tbody>
    </tbody>
</table>
<p align=left>&nbsp;</p>
<table cellSpacing=4 cellPadding=0 width="100%" border=0>
    <thead>
        <tr>
            <td vAlign=top width="42%">
            <p align=left><strong><span>As shown in the figure on the right, a few descriptors are generated in the ejb-jar.xml file.</span></strong></p>
            <p align=left><strong><span>These descriptors are generated by the following tag declared in the StoreAccesBean file.</span></strong></p>
            <p align=left><span>@ejb.bean name ="StoreAccess"</span></p>
            <p align=left><span>jndi-name="StoreAccessBean"</span></p>
            <p align=left><span>type="Stateless"<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></p>
            <p align=left><strong><span>This tag is added by Lomboz's bean creation wizard.</span></strong></p>
            </td>
            <td vAlign=top width="58%">
            <p align=right><span><br clear=left></span></p>
            </td>
        </tr>
    </thead>
    <tbody>
    </tbody>
</table>
<p align=left><span>T<strong>his tag also generates the following descriptors in jboss.xml as shown in the code snippet below.</strong></span></p>
<p align=left><span><br clear=left><strong>So now we know which tags are responsible for generating classes, interfaces and descriptors</strong>.</span></p>
<p align=left><strong><span>Add Business Method :</span></strong></p>
<p align=left><strong><span>Next step is to add a business method in the bean.</span></strong></p>
<p align=left><strong><span>Go to StoreAccesBean &gt; Right click &gt; Select New on pop up menu &gt; Select Lomboz Ejb Method Wizard.</span></strong></p>
<p align=left><span><br clear=left></span></p>
<p align=left><strong><span>Add a business method with the following signature: public String loginUser (String username, String password).</span></strong></p>
<p align=left><strong><span>Select Method Type as Business and Interface as Remote as shown in the figure below..</span></strong></p>
<p align=left><span><br clear=left></span></p>
<p align=left><strong><span>This wizard generates a loginUser method in our bean class, with the method level tag '@ejb.interface' shown below.</span></strong></p>
<p align=left><span><br clear=left></span></p>
<p align=left><strong><span>This tag is responsible for generating this method in the Remote Interface (in this case it is StoreAccess which will be created once you generate your classes). This tag is covered later on in this chapter. </span></strong></p>
<p align=left>&nbsp;</p>
<table cellSpacing=4 cellPadding=0 width="100%" border=0>
    <thead>
        <tr>
            <td vAlign=top width="52%">
            <p align=left><strong><span>Now, This business method needs to invoke a method on the DAO, which will communicate with the database.</span></strong></p>
            <p align=left><strong><span>Therefore we add another tag on this method, so that a method with this signature is generated in DAO interface which we can implement in the DAOImpl class. Then this business method can invoke the method in DAOImpl class to get the desired result.</span></strong></p>
            <p align=left><span>@dao.call name="loginUser"</span></p>
            <p align=left><strong><span>So add this tag at the method level as shown in the figure at right.</span></strong></p>
            <p align=left><strong><span>Now generate your EJB classes again as shown in the steps we went through earlier.</span></strong></p>
            <p align=left><em><span>Note: OK, OK! For reference these are the steps you have to follow.</span></em></p>
            <p align=left><em><span>Expand 'MyStoreMgr' node under 'MyStore' Project in Package Explorer.</span></em></p>
            <p align=left><em><span>Right click and a pop up menu will appear.</span></em></p>
            <p align=left><em><span>Go to Lomboz J2EE &gt; Generate EJB Classes.</span></em></p>
            </td>
            <td vAlign=top width="48%">
            <p align=left><span><br clear=left></span></p>
            </td>
        </tr>
    </thead>
    <tbody>
    </tbody>
</table>
<p align=left><strong><span>After generating the classes, we look at first the generated DAO interface and then the generated Session Class.</span></strong></p>
<p align=left><strong><span>In StoreAcessDAO two methods are generated.</span></strong></p>
<p align=left><strong><span>1. init() by default.</span></strong></p>
<p align=left><strong><span>2. loginUser(), generated by tag shown below. </span></strong></p>
<p align=left><span>@dao.call name="loginUser"</span></p>
<p align=left><span><br clear=left><em><span>Note: Please do not edit any class generated by Xdoclect</span></em></span><em><span>.</span></em></p>
<p align=left><strong><span>In StoreAcessSession two methods of our interest are </span></strong></p>
<p align=left><strong><span>1. getDAO() creates instance of DAOImpl calss.</span></strong></p>
<p align=left><strong><span>2. loginUser(), calls loginUser method in DAOImpl class, which we have to implement. </span></strong></p>
<p align=left><strong><span>Code snippet from 'StoreAccessSession'.</span></strong></p>
<p align=left><span><br clear=left></span></p>
<p align=left><strong><span>Implement DAO Interface :</span></strong></p>
<p align=left><strong><span>Now, we will implement methods in the StoreAccessDAOImpl class.</span></strong></p>
<table cellSpacing=4 cellPadding=0 width="100%" border=0>
    <thead>
        <tr>
            <td vAlign=top width="45%">
            <p align=left><strong><span>First import the following packages.</span></strong></p>
            <p align=left><span>javax.naming.InitialContext;</span></p>
            <p align=left><span>javax.sql.DataSource;</span></p>
            <p align=left><span>java.sql.Connection;</span></p>
            <p align=left><span>java.sql.PreparedStatement;</span></p>
            <p align=left><span>java.sql.ResultSet;</span></p>
            <p align=left><span>java.sql.SQLException;</span></p>
            <p align=left><strong><span>Change your class declaration so that StoreAccessDAOImpl implements StoreAccessDAO.</span></strong></p>
            <p align=left><strong><span>Add a field to store the JDBC resource factory reference.</span></strong></p>
            <p align=left><strong><span>private</span></strong><span> DataSource jdbcFactory;</span></p>
            <p align=left><strong><span>In init() method, locate the reference "jdbc/DefaultDS" using the JNDI API, and store the reference in variable jdbcFactory.</span></strong></p>
            <p align=left><strong><span>Lookup string is </span></strong><span>"java:comp/env/jdbc/DefaultDS".</span></p>
            <p align=left><span>Code Snippet is shown in the figure on the right.</span></p>
            <p align=left><span>Now add the required code in loginUser().</span></p>
            </td>
            <td vAlign=top width="55%">
            <p align=left><span><br clear=right></span></p>
            </td>
        </tr>
    </thead>
    <tbody>
    </tbody>
</table>
<p align=left>&nbsp;</p>
<table cellSpacing=4 cellPadding=0 width="100%" border=0>
    <thead>
        <tr>
            <td vAlign=top width="37%">
            <p align=left><strong><span>In method loginUser(), first get the connection to the database using the jdbcFactory.</span></strong></p>
            <p align=left><strong><span>Create a SQL statement which searches for userid in the table StoreAccess where userid and password is provided for each user. </span></strong></p>
            <p align=left><strong><span>Return userid if successful, else raise SQLException.</span></strong></p>
            <p align=left><span>Code snippet is shown in the figure on the right.</span></p>
            <p align=left><span>Go back to your loginUser method in StoreAccessBean class.</span></p>
            </td>
            <td vAlign=top width="63%">
            <p align=left><span><br clear=left></span></p>
            </td>
        </tr>
    </thead>
    <tbody>
    </tbody>
</table>
<p align=left><strong><span>In StoreAcessBean class under the loginUser method just add some debug statements, as shown below in this code snippet.</span></strong></p>
<p align=left><span><br clear=left><em><span>Note : We don't have to call the loginUser method in StoreAccessDAOImpl, as it being invoked by the loginUser method in StoreAccessSession class which inherits StoreAccessBean class, that is the StoreAccessSession class has overridden this method.</span></em></span></p>
<p align=left><em><span>Code snippet from StoreAccessSession shown below.</span></em></p>
<p align=left><span><br clear=left></span></p>
<p align=left><strong><span>Add Callback Methods :</span></strong></p>
<p align=left><span>Now, add callback methods to complete this bean as shown below.</span></p>
<ol type=1>
    <li><span>setSessionContext.</span></li>
    <li><span>UnsetSessionContext.</span></li>
</ol>
<p align=left><em><span>Note : These callback methods are invoked by the EJB container.</span></em></p>
<p align=left><strong><span>Add a field to store sessionContext.</span></strong></p>
<p align=left><strong><span>protected</span></strong><span> <span>SessionContext</span> <span>ctx;</span></span></p>
<p align=left><strong><span>Add method setSessionContext with sessionContext as parameter and assign that to the sessionContext variable as shown below in the code snippet.</span></strong></p>
<p align=left><span><br clear=left><strong>Similarly add method unsetSessionContext, assign context variable to null as shown above.</strong></span></p>
<p align=left><em><span>Note : StoreAccessSession class inherits the StoreAccessBean abstract class and implements </span></em><em><span>SessionBean, which will override all methods of interface SessionBean. So after finishing the methods in the bean class, generate your EJB classes again. SessionContext methods will be overridden as shown in figure below. </span></em><em><span>Code snippet from StoreAccessSession shown below.</span></em></p>
<p align=left><span><br clear=left></span></p>
<p align=left><strong><span>Now let's look at the generated Home and Remote interfaces.</span></strong></p>
<p align=left><strong><span>In the case of the Remote interface all business methods declared in the bean are also generated with the same signature. This is due to the class level tag declared in the StoreAccess Bean as discussed above after adding business methods. Code snippet for tag is shown below. </span></strong></p>
<p align=left><span><br clear=left></span></p>
<p align=left><strong><span>So, loginUser is generated in a Remote Interface called StoreAccess as shown below because of this tag. </span></strong></p>
<p align=left><span><br clear=left></span></p>
<p align=left><strong><span>In the case of the Home Interface only one method is created named 'create', which is generated by default because of the &lt;homeinterface/&gt; tag in ejbGenerate.xml as shown below.</span></strong></p>
<p align=left><span><br clear=left></span></p>
<p align=left><strong><span>Also, other then that, it has JNDI_NAME and COMP_NAME (which is the logical name to lookup the component) is also generated, these are generated because of this tag declared at class level in 'StoreAccessBean' class shown below in figure. </span></strong></p>
<p align=left><span><br clear=left><em><span>Note : For further options associated with these tags please refer to the 'ejbdoclet' documentation in Xdoclet.</span></em></span></p>
<p align=left><strong><span>Now, all the aspects are pretty much covered, and our bean's functionality is complete. Now for the deployment descriptors..</span></strong></p>
<p align=left>&nbsp;</p>
<p align=left><strong><span>Deploy Bean :</span></strong></p>
<p align=left>&nbsp;</p>
<p align=left><span>In order to deploy our bean we have to declare a few tags in the StoreAccessBean class as shown below in the code snippet.</span></p>
<p align=left><span><br clear=left></span></p>
<p align=left><strong><span>Add the tag shown below in at the class level (at the top).</span></strong></p>
<p align=left><span>@ejb.resource</span><span>-</span><span>ref</span><span> <span>res</span><span>-</span><span>ref</span><span>-</span><span>name="jdbc/DefaultDS"</span></span></p>
<p align=left><span>res</span><span>-</span><span>type="javax.sql.Datasource"</span></p>
<p align=left><span>res</span><span>-</span><span>auth="Container"</span></p>
<p align=left><strong><span>This tag will generate deployment descriptors in ejb-jar.xml, as the bean has to know which datasource you are going to connect to, what is its type, etc. This will generate these descriptors as shown in code snippet below.</span></strong></p>
<p align=left><span><br clear=left></span></p>
<p align=left><strong><span>Add the tag shown below in StoreAccessBean at the class level (at the top).</span></strong></p>
<p align=left><span>@jboss.resource</span><span>-</span><span>ref</span><span> <span>res</span><span>-</span><span>ref</span><span>-</span><span>name="jdbc/DefaultDS" jndi</span><span>-</span><span>name="java:/DefaultDS<strong>"</strong></span></span></p>
<p align=left><strong><span>This tag will generate deployment descriptors in jboss.xml, as the application server has to know with what jndi-name datasource it has been registered with. This will generate these descriptors as shown in the code snippet below.</span></strong></p>
<p align=left><span><br clear=left></span></p>
<p align=left><span>Now, everything is complete, and it's time to deploy the bean.</span></p>
<p align=left><strong><span>First, regenerate your EJB classes as shown in the steps above for the final time.</span></strong></p>
<p align=left><em><span>Note : We have regenerated the classes again and again, in order to explain every step and its result. Once you are familiar with these steps you will need much fewer of these iterations. Either way, it doesn't matter, as your implementation always remains untouched by this process.</span></em></p>
<p align=left><strong><span>Go to Lomboz J2EE View &gt; expand node MyStore &gt; expand MyStoreMgr &gt; select 'Jboss 3.2.1 ALL' .</span></strong></p>
<p align=left><strong><span>Right click &gt; select Debug Sever on the pop up menu as shown in figure below.</span></strong></p>
<p align=left><span><br clear=left></span></p>
<p align=left><strong><span>Go to MyStoreMgr node in LombozJ2EE view &gt; right click &gt; select Deploy on the pop up menu as shown in the figure below</span></strong><span>.</span></p>
<p align=left><span><br clear=left></span></p>
<p align=left><span>And now wait for your deployment result.</span></p>
<p align=left><span>If everything goes fine, you will have this message under your console as shown in the figure below.</span></p>
<p align=left><span><br clear=left></span></p>
<p align=left><span>So, now our bean is deployed successfully, let's create our test client, which will invoke the loginUser method on 'StoreAccessBean'.</span></p>
<p align=left><strong>&nbsp;</strong></p>
<p align=left><strong><span>Create your Test Client :</span></strong></p>
<p align=left>&nbsp;</p>
<p align=left><span>G<strong>o to Project MytStore node &gt; select src node &gt; right click.</strong></span></p>
<p align=left><strong><span>Select New on pop up menu &gt; select Lomboz EJB Test Client Wizard</span></strong><span> as shown in the figure below. </span></p>
<p align=left><span><br clear=left></span></p>
<p align=left><strong><span>Select package name au.com.tusc.client, name as SessionClient and select Ejb Home as au.com.tusc.session.StoreAccessHome and Ejb Interface as au.com.tusc.session.StoreAccess</span></strong><span> <strong>as shown in the figure below</strong>.</span></p>
<p align=left><span><br clear=left></span></p>
<p align=left><span>This will generate the required methods for you in your SessionClient class and you have to just invoke the loginUser method on the bean as shown below.</span></p>
<p align=left><span><br clear=left></span></p>
<p align=left><span>Now the last step is to write code in your client.</span></p>
<p align=left><strong><span>So add these lines under the testBean </span></strong><span>method as shown in figure below<strong>. </strong></span></p>
<p align=left><span>System.out.println(</span><span>"Request from client : "</span><span>);</span></p>
<p align=left><span>System.out.println(</span><span>"Reply from Server: Your userid is "</span><span> <span>+</span></span></p>
<p align=left><span>myBean.loginUser(</span><span>"ANDY"</span><span>,</span><span>"PASSWD"</span><span>));</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><br clear=left></span></p>
<p align=left><strong>&nbsp;</strong></p>
<p align=left><strong><span>Test your Client :</span></strong></p>
<p align=left>&nbsp;</p>
<p align=left><strong><span>Now, in order to test your client, Select SessionClient node &gt; Go at top level menu and select the icon with the 'Running Man'</span></strong><span>.</span></p>
<p align=left><strong><span>On that select 'Run as' &gt; select 'Java Application'</span></strong><span>, as shown below.</span></p>
<p align=left><span><br clear=left></span></p>
<p align=left><strong><span>Now under your console, if you get your reply for 'ANDY' as 'U2', then your call is successful as shown below.</span></strong></p>
<p align=left><span><br clear=left></span></p>
<p align=left><em><span>Note : So our Stateless Session Bean is deployed and tested successfully and from now onwards you should be comfortable using Lomboz. In future we will not go into the detail of the steps for using Lomboz and will concentrate more on other aspects of beans.</span></em></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>小结</span></p>
<p><span>通过表示</span><span>J2EE</span><span>应用程序中的任务或者行动。</span><span>Session Beans</span><span>可以因此而处理大量的状态。尤其是在同其他</span><span>EJB</span><span>合用的情况下。理解</span><span>Session Beans</span><span>的瞬时现象对开发者的工作会带来莫大的帮助。有状态和无状态</span><span>Beans</span><span>的细微差别就如同充分利用其行为一样重要。在掌握以上的概念之后，正确的设计和实现</span><span>Session Beans</span><span>必然会显著改进</span><span>EJB</span><span>应用程序的功能和效率。</span></p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/121221.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-05-31 18:28 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/05/31/121221.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Servlet Begining</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/05/31/121220.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Thu, 31 May 2007 10:27:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/05/31/121220.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/121220.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/05/31/121220.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/121220.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/121220.html</trackback:ping><description><![CDATA[&nbsp;
<p align=center><span>Servlet Begining</span></p>
<p>&nbsp;</p>
<p><span>一、</span><span> Servlet</span><span>简介</span></p>
<p><span>　　</span><span>1</span><span>．</span><span>Servlet </span><span>是什么？</span></p>
<p><span>　　</span><span>Servlet</span><span>是使用</span><span>Java Servlet </span><span>应用程序设计接口（</span><span>API</span><span>）及相关类和方法的</span><span> Java </span><span>程序。除了</span><span> Java Servlet API</span><span>，</span><span>Servlet </span><span>还可以使用用以扩展和添加到</span><span> API </span><span>的</span><span> Java </span><span>类软件包。</span><span>Servlet </span><span>在启用</span><span> Java </span><span>的</span><span> Web </span><span>服务器上或应用服务器上运行并扩展了该服务器的能力。</span><span>Java servlet</span><span>对于</span><span>Web</span><span>服务器就好象</span><span>Java applet</span><span>对于</span><span>Web</span><span>浏览器。</span><span>Servlet</span><span>装入</span><span>Web</span><span>服务器并在</span><span>Web</span><span>服务器内执行，而</span><span>applet</span><span>装入</span><span>Web</span><span>浏览器并在</span><span>Web</span><span>浏览器内执行。</span><span>Java Servlet API </span><span>定义了一个</span><span>servlet </span><span>和</span><span>Java</span><span>使能的服务器之间的一个标准接口，这使得</span><span>Servlets</span><span>具有跨服务器平台的特性。</span></p>
<p><span>　　</span><span>Servlet </span><span>通过创建一个框架来扩展服务器的能力，以提供在</span><span> Web </span><span>上进行请求和响应服务。当客户机发送请求至服务器时，服务器可以将请求信息发送给</span><span> Servlet</span><span>，并让</span><span> Servlet </span><span>建立起服务器返回给客户机的响应。</span> <span>当启动</span><span> Web </span><span>服务器或客户机第一次请求服务时，可以自动装入</span><span> Servlet</span><span>。装入后，</span><span> Servlet </span><span>继续运行直到其它客户机发出请求。</span><span>Servlet </span><span>的功能涉及范围很广。例如，</span><span>Servlet </span><span>可完成如下功能：</span><span> </span></p>
<p><span>　　</span><span>(1) </span><span>创建并返回一个包含基于客户请求性质的动态内容的完整的</span><span> HTML</span><span>页面。</span><span> </span></p>
<p><span>　　</span><span>(2) </span><span>创建可嵌入到现有</span><span> HTML </span><span>页面中的一部分</span><span> HTML </span><span>页面（</span><span>HTML </span><span>片段）。</span><span> </span></p>
<p><span>　　</span><span>(3) </span><span>与其它服务器资源（包括数据库和基于</span><span> Java </span><span>的应用程序）进行通信。</span><span> </span></p>
<p><span>　　</span><span>(4) </span><span>用多个客户机处理连接，接收多个客户机的输入，并将结果广播到多个客户机上。例如，</span><span>Servlet </span><span>可以是多参与者的游戏服务器。</span><span> </span></p>
<p><span>　　</span><span>(5) </span><span>当允许在单连接方式下传送数据的情况下，在浏览器上打开服务器至</span><span>applet</span><span>的新连接，并将该连接保持在打开状态。当允许客户机和服务器简单、高效地执行会话的情况下，</span><span>applet</span><span>也可以启动客户浏览器和服务器之间的连接。可以通过定制协议或标准（如</span><span> IIOP</span><span>）进行通信。</span><span> </span></p>
<p><span>　　</span><span>(6) </span><span>对特殊的处理采用</span><span> MIME </span><span>类型过滤数据，例如图像转换和服务器端包括（</span><span>SSI</span><span>）。</span><span> </span></p>
<p><span>　　</span><span>(7) </span><span>将定制的处理提供给所有服务器的标准例行程序。例如，</span><span>Servlet </span><span>可以修改如何认证用户。</span><span> </span></p>
<p><span>　　</span><span>2</span><span>．</span><span>Servlet </span><span>的生命周期</span></p>
<p><span>　　</span><span>Servlet </span><span>的生命周期始于将它装入</span><span> Web </span><span>服务器的内存时，并在终止或重新装入</span><span> Servlet </span><span>时结束。</span></p>
<p><span>　　</span><span>(1) </span><span>初始化</span></p>
<p><span>　在下列时刻装入</span><span> Servlet</span><span>：</span><span> </span></p>
<p><span><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>如果已配置自动装入选项，则在启动服务器时自动装入</span><span> </span></p>
<p><span><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>在服务器启动后，客户机首次向</span><span> Servlet </span><span>发出请求时</span><span> </span></p>
<p><span><span>l<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>重新装入</span><span> Servlet </span><span>时装入</span><span> Servlet </span><span>后，服务器创建一个</span><span> Servlet </span><span>实例并且调用</span><span> Servlet </span><span>的</span><span> init() </span><span>方法。在初始化阶段，</span><span>Servlet </span><span>初始化参数被传递给</span><span> Servlet </span><span>配置对象。</span><span> </span></p>
<p><span>　　</span><span>(2) </span><span>请求处理</span></p>
<p><span>　　对于到达服务器的客户机请求，服务器创建特定于请求的一个&#8220;请求&#8221;对象和一个&#8220;响应&#8221;对象。服务器调用</span><span> Servlet </span><span>的</span><span> service() </span><span>方法，该方法用于传递&#8220;请求&#8221;和&#8220;响应&#8221;对象。</span><span>service() </span><span>方法从&#8220;请求&#8221;对象获得请求信息、处理该请求并用&#8220;响应&#8221;对象的方法以将响应传回客户机。</span><span>service() </span><span>方法可以调用其它方法来处理请求，例如</span><span> doGet()</span><span>、</span><span>doPost() </span><span>或其它的方法。</span><span> </span></p>
<p><span>　　</span><span>(3) </span><span>终止</span></p>
<p><span>　　当服务器不再需要</span><span> Servlet, </span><span>或重新装入</span><span> Servlet </span><span>的新实例时，服务器会调用</span><span> Servlet </span><span>的</span><span> destroy() </span><span>方法。</span><span> </span></p>
<p><span>　　</span><span>3. Java Servlet API</span></p>
<p><span>　　</span><span>Java Servlet </span><span>开发工具（</span><span>JSDK</span><span>）提供了多个软件包，在编写</span><span> Servlet </span><span>时需要用到这些软件包。其中包括两个用于所有</span><span> Servlet </span><span>的基本软件包：</span><span>javax.servlet </span><span>和</span><span> javax.servlet.http</span><span>。可从</span><span>sun</span><span>公司的</span><span>Web</span><span>站点下载</span><span> Java Servlet </span><span>开发工具。</span> <span>下面主要介绍</span><span>javax.servlet.http</span><span>提供的</span><span>HTTP Servlet</span><span>应用编程接口。</span></p>
<p><span>　　</span><span>HTTP Servlet </span><span>使用一个</span><span> HTML </span><span>表格来发送和接收数据。要创建一个</span><span> HTTP Servlet</span><span>，请扩展</span><span> HttpServlet </span><span>类，</span> <span>该类是用专门的方法来处理</span><span> HTML </span><span>表格的</span><span> GenericServlet </span><span>的一个子类。</span><span> HTML </span><span>表单是由</span><span> &lt;FORM&gt; </span><span>和</span><span> &lt;/FORM&gt; </span><span>标记定义的。表单中典型地包含输入字段（如文本输入字段、复选框、单选按钮和选择列表）和用于提交数据的按钮。当提交信息时，它们还指定服务器应执行哪一个</span><span>Servlet</span><span>（或其它的程序）。</span><span> HttpServlet </span><span>类包含</span><span> init()</span><span>、</span><span>destroy()</span><span>、</span><span>service() </span><span>等方法。其中</span><span> init() </span><span>和</span><span> destroy() </span><span>方法是继承的。</span></p>
<p><span>　　</span><span>(1) init() </span><span>方法</span></p>
<p><span>　　在</span><span> Servlet </span><span>的生命期中，仅执行一次</span><span> init() </span><span>方法。它是在服务器装入</span><span> Servlet </span><span>时执行的。</span> <span>可以配置服务器，以在启动服务器或客户机首次访问</span><span> Servlet </span><span>时装入</span><span> Servlet</span><span>。</span> <span>无论有多少客户机访问</span><span> Servlet</span><span>，都不会重复执行</span><span> init() </span><span>。</span><span> </span></p>
<p><span>　　缺省的</span><span> init() </span><span>方法通常是符合要求的，但也可以用定制</span><span> init() </span><span>方法来覆盖它，典型的是管理服务器端资源。</span> <span>例如，可能编写一个定制</span><span> init() </span><span>来只用于一次装入</span><span> GIF </span><span>图像，改进</span><span> Servlet </span><span>返回</span><span> GIF </span><span>图像和含有多个客户机请求的性能。另一个示例是初始化数据库连接。缺省的</span><span> init() </span><span>方法设置了</span><span> Servlet </span><span>的初始化参数，并用它的</span><span> ServletConfig </span><span>对象参数来启动配置，</span> <span>因此所有覆盖</span><span> init() </span><span>方法的</span><span> Servlet </span><span>应调用</span><span> super.init() </span><span>以确保仍然执行这些任务。在调用</span><span> service() </span><span>方法之前，应确保已完成了</span><span> init() </span><span>方法。</span><span> </span></p>
<p><span>　　</span><span>(2) service() </span><span>方法</span></p>
<p><span>　　</span><span>service() </span><span>方法是</span><span> Servlet </span><span>的核心。每当一个客户请求一个</span><span>HttpServlet </span><span>对象，该对象的</span><span>service() </span><span>方法就要被调用，而且传递给这个方法一个&#8220;请求&#8221;（</span><span>ServletRequest</span><span>）对象和一个&#8220;响应&#8221;（</span><span>ServletResponse</span><span>）对象作为参数。</span> <span>在</span><span> HttpServlet </span><span>中已存在</span><span> service() </span><span>方法。缺省的服务功能是调用与</span><span> HTTP </span><span>请求的方法相应的</span><span> do </span><span>功能。例如，</span> <span>如果</span><span> HTTP </span><span>请求方法为</span><span> GET</span><span>，则缺省情况下就调用</span><span> doGet() </span><span>。</span><span>Servlet </span><span>应该为</span><span> Servlet </span><span>支持的</span><span> HTTP </span><span>方法覆盖</span><span> do </span><span>功能。因为</span><span> HttpServlet.service() </span><span>方法会检查请求方法是否调用了适当的处理方法，不必要覆盖</span><span> service() </span><span>方法。只需覆盖相应的</span><span> do </span><span>方法就可以了。</span></p>
<p><span>　当一个客户通过</span><span>HTML </span><span>表单发出一个</span><span>HTTP POST</span><span>请求时，</span><span>doPost</span><span>（）方法被调用。与</span><span>POST</span><span>请求相关的参数作为一个单独的</span><span>HTTP </span><span>请求从浏览器发送到服务器。当需要修改服务器端的数据时，应该使用</span><span>doPost()</span><span>方法。</span></p>
<p><span>　当一个客户通过</span><span>HTML </span><span>表单发出一个</span><span>HTTP GET</span><span>请求或直接请求一个</span><span>URL</span><span>时，</span><span>doGet()</span><span>方法被调用。与</span><span>GET</span><span>请求相关的参数添加到</span><span>URL</span><span>的后面，并与这个请求一起发送。当不会修改服务器端的数据时，应该使用</span><span>doGet()</span><span>方法。</span></p>
<p><span>　　</span><span>Servlet</span><span>的响应可以是下列几种类型：</span></p>
<p><span>　　一个输出流，浏览器根据它的内容类型（如</span><span>text/HTML</span><span>）进行解释。</span></p>
<p><span>　　一个</span><span>HTTP</span><span>错误响应</span><span>, </span><span>重定向到另一个</span><span>URL</span><span>、</span><span>servlet</span><span>、</span><span>JSP</span><span>。</span></p>
<p><span>　　</span><span>(3) destroy() </span><span>方法</span></p>
<p><span>　　</span><span>destroy() </span><span>方法仅执行一次，即在服务器停止且卸装</span><span>Servlet </span><span>时执行该方法。典型的，将</span><span> Servlet </span><span>作为服务器进程的一部分来关闭。缺省的</span><span> destroy() </span><span>方法通常是符合要求的，但也可以覆盖它，典型的是管理服务器端资源。例如，如果</span><span> Servlet </span><span>在运行时会累计统计数据，则可以编写一个</span><span> destroy() </span><span>方法，该方法用于在未装入</span><span> Servlet </span><span>时将统计数字保存在文件中。另一个示例是关闭数据库连接。</span><span> </span></p>
<p><span>当服务器卸装</span><span> Servlet </span><span>时，将在所有</span><span> service() </span><span>方法调用完成后，或在指定的时间间隔过后调用</span><span> destroy() </span><span>方法。一个</span><span>Servlet </span><span>在运行</span><span>service() </span><span>方法时可能会产生其它的线程，因此请确认在调用</span><span> destroy() </span><span>方法时，这些线程已终止或完成。</span><span> </span></p>
<p><span>　　</span><span>(4) GetServletConfig</span><span>（）方法</span></p>
<p><span>　　</span><span>GetServletConfig</span><span>（）方法返回一个</span><span> ServletConfig </span><span>对象，该对象用来返回初始化参数和　　</span><span>ServletContext</span><span>。</span><span>ServletContext </span><span>接口提供有关</span><span>servlet </span><span>的环境信息。</span></p>
<p><span>　　</span><span>(5) GetServletInfo</span><span>（）方法</span></p>
<p><span>　　</span><span>GetServletInfo</span><span>（）方法是一个可选的方法，它提供有关</span><span>servlet </span><span>的信息，如作者、版本、版权。</span></p>
<p><span>　　当服务器调用</span><span>sevlet </span><span>的</span><span>Service</span><span>（）、</span><span>doGet</span><span>（）和</span><span>doPost</span><span>（）这三个方法时，均需要</span> <span>&#8220;请求&#8221;和&#8220;响应&#8221;对象作为参数。&#8220;请求&#8221;对象提供有关请求的信息，而&#8220;响应&#8221;对象提供了一个将响应信息返回给浏览器的一个通信途径。</span><span>javax.servlet </span><span>软件包中的相关类为</span><span>ServletResponse</span><span>和</span><span>ServletRequest</span><span>，而</span><span>javax.servlet.http </span><span>软件包中的相关类为</span><span>HttpServletRequest </span><span>和</span><span> HttpServletResponse</span><span>。</span><span>Servlet </span><span>通过这些对象与服务器通信并最终与客户机通信。</span><span>Servlet </span><span>能通过调用&#8220;请求&#8221;对象的方法获知客户机环境，服务器环境的信息和所有由客户机提供的信息。</span><span>Servlet </span><span>可以调用&#8220;响应&#8221;对象的方法发送响应，该响应是准备发回客户机的。</span></p>
<p><span>　　</span><span>1.2 </span><span>创建</span><span>HTTP Servlet</span></p>
<p><span>　　创建一个</span><span> HTTP Servlet</span><span>，通常涉及下列四个步骤：</span></p>
<p><span>　　</span><span>1. </span><span>扩展</span><span> HttpServlet </span><span>抽象类。</span><span> </span></p>
<p><span>　　</span><span>2. </span><span>重载适当的方法。</span><span>]</span><span>如覆盖（或称为重写）</span><span>doGet() </span><span>或</span><span>doPost()</span><span>方法。</span><span> </span></p>
<p><span>　　</span><span>3. </span><span>如果有</span><span> HTTP </span><span>请求信息的话，获取该信息。用</span><span> HttpServletRequest </span><span>对象来检索</span><span> HTML </span><span>表格所</span></p>
<p><span>　　提交的数据或</span><span> URL </span><span>上的查询字符串。&#8220;请求&#8221;对象含有特定的方法以检索客户机提供的信息，有</span><span>3</span><span>个可用的方法：</span></p>
<p><span>　</span><span>getParameterNames()</span><span>，</span></p>
<p><span>　</span><span>getParameter()</span><span>，</span></p>
<p><span>　</span><span>getParameterValues()</span><span>。</span></p>
<p><span>　　</span><span>4. </span><span>生成</span><span> HTTP </span><span>响应。</span><span>HttpServletResponse </span><span>对象生成响应，并将它返回到发出请求的客户机上。它</span></p>
<p><span>的方法允许设置&#8220;请求&#8221;</span> <span>标题和&#8220;响应&#8221;主体。&#8220;响应&#8221;对象还含有</span><span> getWriter() </span><span>方法以返回一个</span><span> PrintWriter </span><span>对象。使用</span><span> PrintWriter </span><span>的</span><span> print() </span><span>和</span><span> println() </span><span>方法以编写</span><span> Servlet </span><span>响应来返回给客户机。或者，直接使用</span><span>out</span><span>对象输出有关</span><span>HTML</span><span>文档内容。</span></p>
<p><span>　　一个</span><span>servlet</span><span>样例</span><span>(ServletSample.java)</span><span>如下：</span></p>
<p><span>　　</span><span>import java.io.*;</span></p>
<p><span>　　</span><span>import java.util.*;</span></p>
<p><span>　　</span><span>import javax.servlet.*;</span></p>
<p><span>　　</span><span>import javax.servlet.http.*; </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>public class ServletSample extends HttpServlet { // </span><span>第一步：</span> <span>扩展</span><span> HttpServlet </span><span>抽象类。</span></p>
<p><span>　　</span></p>
<p><span>　　</span><span>public void doGet (HttpServletRequest request, HttpServletResponse response) </span></p>
<p><span>　　</span><span>throws ServletException, IOException { // </span><span>第二步：重写</span><span>doGet()</span><span>方法</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>String myName = ""; // </span><span>第三步：获取</span><span>HTTP </span><span>请求信息</span></p>
<p><span>　　</span><span>java.util.Enumeration keys = request.getParameterNames();</span></p>
<p><span>　　</span><span>while (keys.hasMoreElements());</span></p>
<p><span>　　</span><span>{</span></p>
<p><span>　　</span><span>key = (String) keys.nextElement();</span></p>
<p><span>　　</span><span>if (key.equalsIgnoreCase("myName"))</span></p>
<p><span>　　</span><span>myName = request.getParameter(key); </span></p>
<p><span>　　</span><span>}</span></p>
<p><span>　　</span><span>if (myName == "")</span></p>
<p><span>　　</span><span>myName = "Hello";</span></p>
<p><span>　　</span><span>// </span><span>第四步：生成</span><span> HTTP </span><span>响应。</span></p>
<p><span>　　</span><span>response.setContentType("text/html"); </span></p>
<p><span>　　</span><span>response.setHeader("Pragma", "No-cache");</span></p>
<p><span>　　</span><span>response.setDateHeader("Expires", 0);</span></p>
<p><span>　　</span><span>response.setHeader("Cache-Control", "no-cache");</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>out.println("&lt;head&gt;&lt;title&gt;Just a basic servlet&lt;/title&gt;&lt;/head&gt;");</span></p>
<p><span>　　</span><span>out.println("&lt;body&gt;");</span></p>
<p><span>　　</span><span>out.println("&lt;h1&gt;Just a basic servlet&lt;/h1&gt;");</span></p>
<p><span>　　</span><span>out.println ("&lt;p&gt;" + myName + ", this is a very basic servlet that writes an HTML</span></p>
<p><span>　　</span><span> page.");</span></p>
<p><span>　　</span><span>out.println ("&lt;p&gt;For instructions on running those samples on your WebSphere</span><span>应用服务器</span><span>, </span><span>　　</span><span>"+</span></p>
<p><span>　　</span><span>"open the page:");</span></p>
<p><span>　　</span><span>out.println("&lt;pre&gt;http://&lt;em&gt;your.server.name&lt;/em&gt;/IBMWebAs/samples/index.aspl&lt;/pre&gt;");</span></p>
<p><span>　　</span><span>out.println("where &lt;em&gt;your.server.name&lt;/em&gt; is the hostname of your WebSphere</span><span>应用服</span></p>
<p><span>　　务器</span><span>."); </span></p>
<p><span>　　</span><span>out.println("&lt;/body&gt;&lt;/html&gt;"); </span></p>
<p><span>　　</span><span>out.flush(); </span></p>
<p><span>　　</span><span>}</span></p>
<p><span>　　</span><span>}</span></p>
<p><span>上述</span><span>ServletSample</span><span>类扩展</span><span> HttpServlet </span><span>抽象类、重写</span><span>doGet()</span><span>方法。在重写的</span><span>doGet()</span><span>方法中，获取</span><span>HTTP </span><span>请求中的一个任选的参数（</span><span>myName</span><span>），该参数可作为调用的</span><span> URL </span><span>上的查询参数传递到</span><span> Servlet</span><span>。使用示例如下：</span></p>
<p><span>http://your.server.name/servlet/ServletSample?myname=Michael</span><span>。</span></p>
<p><span>　　</span><span>1.3 </span><span>调用</span><span> Servlet</span></p>
<p><span>　　要调用</span><span> Servlet </span><span>或</span><span> Web </span><span>应用程序，请使用下列任一种方法：由</span><span> URL </span><span>调用、在</span><span> &lt;FORM&gt; </span><span>标记中调用、在</span><span> &lt;SERVLET&gt;</span><span>标记中调用、在</span><span> JSP </span><span>文件中调用、在</span><span> ASP </span><span>文件中调用。</span></p>
<p><span>　　</span><span>1. </span><span>由</span><span> URL </span><span>调用</span><span> Servlet</span></p>
<p><span>　　这里有两种用</span><span> Servlet </span><span>的</span><span> URL </span><span>从浏览器中调用该</span><span> Servlet </span><span>的方法：</span><span> </span></p>
<p><span>　　</span><span>(1) </span><span>指定</span><span> Servlet </span><span>名称：当用</span><span> WebSphere</span><span>应用服务器</span> <span>管理器来将一个</span><span> Servlet </span><span>实例添加（注册）到服务器配置中时，必须指定&#8220;</span><span>Servlet </span><span>名称&#8221;参数的值。例如，可以指定将</span><span>hi</span><span>作为</span><span>HelloWorldServlet </span><span>的</span><span> Servlet </span><span>名称。要调用该</span><span> Servlet</span><span>，需打开</span><span> http://your.server.name/servlet/hi</span><span>。也可以指定</span><span> Servlet </span><span>和类使用同一名称（</span><span>HelloWorldServlet</span><span>）。在这种情况下，将由</span><span> http://your.server.name/servlet/HelloWorldServlet </span><span>来调用</span><span> Servlet </span><span>的实例。</span></p>
<p><span>　　</span><span>(2) </span><span>指定</span><span> Servlet </span><span>别名：用</span><span> WebSphere</span><span>应用服务器</span> <span>管理器来配置</span><span> Servlet </span><span>别名，该别名是用于调用</span><span> Servlet </span><span>的快捷</span><span> URL</span><span>。快捷</span><span> URL </span><span>中不包括</span><span> Servlet </span><span>名称。</span><span> </span></p>
<p><span>　　</span><span>2. </span><span>在</span><span> &lt;FORM&gt; </span><span>标记中指定</span><span> Servlet</span></p>
<p><span>　　可以在</span><span> &lt;FORM&gt; </span><span>标记中调用</span><span> Servlet</span><span>。</span><span>HTML </span><span>格式使用户能在</span><span> Web </span><span>页面（即从浏览器）上输入数据，并向</span><span> Servlet </span><span>提交数据。例如：</span></p>
<p><span>　　</span><span>&lt;FORM METHOD="GET" ACTION="/servlet/myservlet"&gt;</span></p>
<p><span>　　</span><span>&lt;OL&gt;</span></p>
<p><span>　　</span><span>&lt;INPUT TYPE="radio" NAME="broadcast" VALUE="am"&gt;AM&lt;BR&gt;</span></p>
<p><span>　　</span><span>&lt;INPUT TYPE="radio" NAME="broadcast" VALUE="fm"&gt;FM&lt;BR&gt;</span></p>
<p><span>　　</span><span>&lt;/OL&gt;</span></p>
<p><span>　　（用于放置文本输入区域的标记、按钮和其它的提示符。）</span></p>
<p><span>　　</span><span>&lt;/FORM&gt;</span></p>
<p><span>　　</span><span>ACTION </span><span>特性表明了用于调用</span><span> Servlet </span><span>的</span><span> URL</span><span>。关于</span><span>METHOD </span><span>的特性，如果用户输入的信息是通过</span><span> GET </span><span>方法向</span><span> Servlet </span><span>提交的，则</span><span> Servlet </span><span>必须优先使用</span><span> doGet() </span><span>方法。反之，如果用户输入的信息是通过</span><span> POST </span><span>方法向</span><span> Servlet </span><span>提交的，则</span><span> Servlet </span><span>必须优先使用</span><span> doPost() </span><span>方法。使用</span><span> GET </span><span>方法时，用户提供的信息是查询字符串表示的</span><span> URL </span><span>编码。无需对</span><span> URL </span><span>进行编码，因为这是由表单完成的。然后</span><span> URL </span><span>编码的查询字符串被附加到</span><span> Servlet URL </span><span>中，则整个</span><span> URL </span><span>提交完成。</span><span>URL </span><span>编码的查询字符串将根据用户同可视部件之间的交互操作，将用户所选的值同可视部件的名称进行配对。例如，考虑前面的</span><span> HTML </span><span>代码段将用于显示按钮</span><span>(</span><span>标记为</span><span> AM </span><span>和</span><span> FM)</span><span>，如果用户选择</span><span> FM </span><span>按钮，则查询字符串将包含</span><span> name=value </span><span>的配对操作为</span><span>broadcast=fm</span><span>。因为在这种情况下，</span><span>Servlet </span><span>将响应</span><span> HTTP </span><span>请求，因此</span><span> Servlet </span><span>应基于</span><span> HttpServlet </span><span>类。</span><span>Servlet </span><span>应根据提交给它的查询字符串中的用户信息使用的</span><span> GET </span><span>或</span><span> POST </span><span>方法，而相应地使用</span><span> doGet() </span><span>或</span><span> doPost() </span><span>方法。</span><span> </span></p>
<p><span>　　</span><span>3</span><span>．在</span><span> &lt;SERVLET&gt; </span><span>标记中指定</span><span> Servlet</span></p>
<p><span>　　当使用</span><span> &lt;SERVLET&gt; </span><span>标记来调用</span><span> Servlet </span><span>时，如同使用</span><span> &lt;FORM&gt; </span><span>标记一样，无需创建一个完整的</span><span> HTML </span><span>页面。作为替代，</span><span>Servlet </span><span>的输出仅是</span><span> HTML </span><span>页面的一部分，且被动态嵌入到原始</span><span> HTML </span><span>页面中的其它静态文本中。所有这些都发生在服务器上，且发送给用户的仅是结果</span><span> HTML </span><span>页面。建议在</span><span> Java </span><span>服务器页面（</span><span>JSP</span><span>）文件中使用</span><span> &lt;SERVLET&gt; </span><span>标记。请参阅有关</span><span> JSP </span><span>技术</span></p>
<p><span>　　原始</span><span> HTML </span><span>页面中包含</span><span> &lt;SERVLET&gt; </span><span>和</span><span> &lt;/SERVLET&gt; </span><span>标记。</span><span> Servlet </span><span>将在这两个标记中被调用，且</span><span> Servlet </span><span>的响应将覆盖这两个标记间的所有东西和标记本身。如果用户的浏览器可以看到</span><span> HTML </span><span>源文件，则用户将看不到</span><span> &lt;SERVLET&gt; </span><span>和</span><span> &lt;/SERVLET&gt; </span><span>标记。要在</span><span> Domino Go Webserver </span><span>上使用该方法，请启用服务器上的服务器端包括功能。部分启用过程将会涉及到添加特殊文件类型</span><span> SHTML</span><span>。当</span><span> Web </span><span>服务器接收到一个扩展名为</span><span> SHTML </span><span>的</span><span> Web </span><span>页面请求时，它将搜索</span><span> &lt;SERVLET&gt; </span><span>和</span><span> &lt;/SERVLET&gt; </span><span>标记。对于所有支持的</span><span> Web </span><span>服务器，</span><span>WebSphere</span><span>应用服务器</span> <span>将处理</span><span> SERVLET </span><span>标记间的所有信息。下列</span><span> HTML </span><span>代码段显示了如何使用该技术。</span><span> </span></p>
<p><span>　　</span><span>&lt;SERVLET NAME="myservlet" CODE="myservlet.class" CODEBASE="url" initparm1="value"&gt;</span></p>
<p><span>　　</span><span>&lt;PARAM NAME="parm1" VALUE="value"&gt;</span></p>
<p><span>　　</span><span>&lt;/SERVLET&gt;</span></p>
<p><span>　　使用</span><span> NAME </span><span>和</span><span> CODE </span><span>属性带来了使用上的灵活性。可以只使用其中一个属性，也可以同时使用两个属性。</span><span> NAME </span><span>属性指定了</span><span> Servlet </span><span>的名称（使用</span><span> WebSphere</span><span>应用服务器</span> <span>管理器配置的），或不带</span><span> .class </span><span>扩展名的</span><span> Servlet </span><span>类名。</span><span>CODE </span><span>属性指定了</span><span> Servlet </span><span>类名。使用</span><span> WebSphere</span><span>应用服务器</span> <span>时，建议指定</span><span> NAME </span><span>和</span><span> CODE</span><span>，或当</span><span> NAME </span><span>指定了</span><span> Servlet </span><span>名称时，仅指定</span><span> NAME</span><span>。如果仅指定了</span><span> CODE</span><span>，则会创建一个</span><span> NAME=CODE </span><span>的</span><span> Servlet </span><span>实例。装入的</span><span> Servlet </span><span>将假设</span><span> Servlet </span><span>名称与</span><span> NAME </span><span>属性中指定的名称匹配。然后，其它</span><span> SHTML </span><span>文件可以成功地使用</span><span> NAME </span><span>属性来指定</span><span> Servlet </span><span>的名称，并调用已装入的</span><span> Servlet</span><span>。</span><span>NAME </span><span>的值可以直接在要调用</span><span> Servlet </span><span>的</span><span> URL </span><span>中使用。如果</span><span> NAME </span><span>和</span><span> CODE </span><span>都存在，且</span><span> NAME </span><span>指定了一个现有</span><span> Servlet</span><span>，则通常使用</span><span> NAME </span><span>中指定的</span><span> Servlet</span><span>。由于</span><span> Servlet </span><span>创建了部分</span><span> HTML </span><span>文件，所以当创建</span><span> Servlet </span><span>时，将可能会使用</span><span> HttpServlet </span><span>的一个子类，并优先使用</span><span> doGet() </span><span>方法（因为</span><span> GET </span><span>方法是提供信息给</span><span> Servlet </span><span>的缺省方法）。另一个选项是优先使用</span><span> service() </span><span>方法。另外，</span><span> CODEBASE </span><span>是可选的，它指定了装入</span><span> Servlet </span><span>的远程系统的</span><span> URL</span><span>。请使用</span><span> WebSphere</span><span>应用服务器</span> <span>管理器来从</span><span> JAR </span><span>文件配置远程</span><span> Servlet </span><span>装入系统。</span><span> </span></p>
<p><span>　　在上述的标记示例中，</span><span>initparm1 </span><span>是初始化参数名，</span><span>value </span><span>是该参数的值。可以指定多个&#8220;名称</span><span>-</span><span>值&#8221;对的集合。利用</span><span> ServletConfig </span><span>对象（被传递到</span><span> Servlet </span><span>的</span><span> init() </span><span>方法中）的</span><span> getInitParameterNames() </span><span>和</span><span> getInitParameter() </span><span>方法来查找参数名和参数值的字符串数组。在示例中，</span><span>parm1 </span><span>是参数名，并在初始化</span><span> Servlet </span><span>后被才被设置某个值。因为只能通过使用&#8220;请求&#8221;对象的方法来使用以</span><span> &lt;PARAM&gt; </span><span>标记设置的参数，所以服务器必须调用</span><span> Servlet service() </span><span>方法，以从用户处传递请求。要获得有关用户的请求信息，请使用</span><span> getParameterNames()</span><span>、</span><span>getParameter() </span><span>和</span><span> getParameterValues() </span><span>方法。</span></p>
<p><span>　　初始化参数是持续的。假设一台客户机通过调用一个包含某些初始化参数的</span><span> SHTML </span><span>文件来调用</span><span> Servlet</span><span>。并假设第二台客户机通过调用第二个</span><span> SHTML </span><span>文件来调用同一个</span><span> Servlet</span><span>，且该</span><span> SHTML </span><span>中未指定任何初始化参数。那么第一次调用</span><span> Servlet </span><span>时所设置的初始化参数将一直可用，并且通过所有其它</span><span> SHTML </span><span>文件而调用的所有后继</span><span> Servlet </span><span>都不会更改该参数。直到</span><span> Servlet </span><span>调用了</span><span> destroy() </span><span>方法后，才能重新设置初始化参数。例如，如果另一个</span><span> SHTML </span><span>文件指定了另一个不同的初始化参数值，虽然已此时已装入了</span><span> Servlet</span><span>，但该值仍将被忽略。</span></p>
<p><span>　　</span><span>4</span><span>．在</span><span> JSP </span><span>文件中调用</span><span> Servlet</span></p>
<p><span>　　可以从</span><span> JavaServer </span><span>页面（</span><span>JSP</span><span>）文件中调用</span><span> Servlet</span><span>。请参阅</span><span>JSP</span><span>技术部分。</span></p>
<p><span>　　</span><span>5</span><span>．在</span><span> ASP </span><span>文件中调用</span><span> Servlet</span></p>
<p><span>　　如果在</span><span> Microsoft Internet Information Server</span><span>（</span><span>IIS</span><span>）上有遗留的</span><span> ASP </span><span>文件，并且无法将</span><span> ASP </span><span>文件移植成</span><span> JSP </span><span>文件时，可用</span><span> ASP </span><span>文件来调用</span><span> Servlet</span><span>。在</span><span> WebSphere</span><span>应用服务器</span> <span>中的</span><span> ASP </span><span>支持包括一个用于嵌入</span><span> Servlet </span><span>的</span><span> ActiveX </span><span>控制，下面介绍</span><span>ActiveX </span><span>控制</span><span>AspToServlet </span><span>的方法和属性。</span><span> </span></p>
<p><span>该方法说明如下：</span></p>
<p><span>　　</span><span>(1) String ExecServletToString(String servletName)</span><span>；执行</span><span> ServletName</span><span>，并将其输出返回到一个字符串中。</span><span> </span></p>
<p><span>　　</span><span>(2) ExecServlet(String servletName)</span><span>；执行</span><span> ServletName</span><span>，并将其输出直接发送至</span><span> HTML </span><span>页面。</span><span> </span></p>
<p><span>　　</span><span>(3) String VarValue(String varName)</span><span>；获得一预置变量值（其它格式）。</span></p>
<p><span>　　</span><span>(4) VarValue(String varName, String newVal)</span><span>；设置变量值。变量占据的总大小应小于</span><span> 0.5 </span><span>个千字节（</span><span>Kbyte</span><span>）。且仅对配置文件使用这些变量。</span><span> </span></p>
<p><span>　　其属性如下：</span><span> </span></p>
<p><span>　</span><span>Boolean WriteHeaders</span><span>；若该属性为真，则</span><span> Servlet </span><span>提供的标题被写入用户处。缺省值为假。</span><span> </span></p>
<p><span>　</span><span>Boolean OnTest</span><span>；若该属性为真，服务器会将消息记录到生成的</span><span> HTML </span><span>页面中。缺省值为假。</span></p>
<p><span>　　下列</span><span>ASP </span><span>脚本示例是以</span><span> Microsoft Visual Basic Scripting</span><span>（</span><span>VBScript</span><span>）书写的。</span></p>
<p><span>　　</span><span>&lt;%</span></p>
<p><span>　　</span><span>' Small sample asp file to show the capabilities of the servlets and the ASP GateWay ...</span></p>
<p><span>　　</span><span>%&gt;</span></p>
<p><span>　　</span><span>&lt;H1&gt; Starting the ASP-&gt;Java Servlet demo&lt;/H1&gt; </span></p>
<p><span>　　</span><span>&lt;% </span></p>
<p><span>　　</span><span>' Create a Servlet gateway object and initialize it ...</span></p>
<p><span>　　</span><span>Set javaasp = Server.CreateObject("AspToServlet.AspToServlet")</span></p>
<p><span>　　</span><span>' Setting these properties is only for the sake of demo.</span></p>
<p><span>　　</span><span>' These are the default values ...</span></p>
<p><span>　　</span><span>javaasp.OnTest = False</span></p>
<p><span>　　</span><span>javaasp.WriteHeaders = False</span></p>
<p><span>　　</span><span>' Add several variables ...</span></p>
<p><span>　　</span><span>javaasp.VarValue("gal") = "lag" </span></p>
<p><span>　　</span><span>javaasp.VarValue("pico")= "ocip"</span></p>
<p><span>　　</span><span>javaasp.VarValue("tal") = "lat" </span></p>
<p><span>　　</span><span>javaasp.VarValue("paz") = "zap"</span></p>
<p><span>　　</span><span>javaasp.VarValue("variable name with spaces") = "variable value with spaces"</span></p>
<p><span>　　</span><span>%&gt;</span></p>
<p><span>　　</span><span>&lt;BR&gt;</span></p>
<p><span>　　</span><span>Lets check the variables</span></p>
<p><span>　　</span><span>&lt;% </span></p>
<p><span>　　</span><span>Response.Write("variable gal = ")</span></p>
<p><span>　　</span><span>Response.Write(javaasp.VarValue("gal")) </span></p>
<p><span>　　</span><span>%&gt;</span></p>
<p><span>　　</span><span>&lt;BR&gt;</span></p>
<p><span>　　</span><span>&lt;% </span></p>
<p><span>　　</span><span>Response.Write("variable pico = " &amp; javaasp.VarValue("pico")) </span></p>
<p><span>　　</span><span>%&gt;</span></p>
<p><span>　　</span></p>
<p><span>　　</span><span>&lt;BR&gt;</span></p>
<p><span>　　</span><span>&lt;HR&gt;</span></p>
<p><span>　　</span><span>&lt;%</span></p>
<p><span>　　</span><span>galout = javaasp.ExecServletToString("SnoopServlet") </span></p>
<p><span>　　</span><span>If javaasp.WriteHeaders = True Then </span></p>
<p><span>　　</span><span>%&gt;</span></p>
<p><span>　　</span><span>Headers were written &lt;%</span></p>
<p><span>　　</span><span>Else</span></p>
<p><span>　　</span><span>%&gt;</span></p>
<p><span>　　</span><span>Headers were not written &lt;%</span></p>
<p><span>　　</span><span>End If </span></p>
<p><span>　　</span><span>Response.Write(galout)</span></p>
<p><span>　　</span><span>%&gt;</span></p>
<p><span>&lt;H1&gt; The End ...&lt;/H1&gt;</span></p>
<p>&nbsp;</p>
<p><span>public void ejbCreate() { </span></p>
<p><span>}//ejbCreate </span></p>
<p><span>public void ejbPassivate() { </span></p>
<p><span>}//ejbPassivate </span></p>
<p>&nbsp;</p>
<p><span>public void ejbActivate() { </span></p>
<p><span>}//ejbActivate </span></p>
<p>&nbsp;</p>
<p><span>}//class sailorsy </span></p>
<p><span>5.ejbRemove()</span><span>方法</span><span> </span></p>
<p><span>它可以清除</span><span>EJB</span><span>容器中的</span><span>Bean</span><span>。</span><span> </span></p>
<p><span>import java.rmi.*; </span></p>
<p><span>import javax.ejb.*; </span></p>
<p><span>public class sailorsy implements SessionBean{ </span></p>
<p><span>private SessionContext ctx=null; </span></p>
<p>&nbsp;</p>
<p><span>public voic setSessionContext(SessionContext ctx){ </span></p>
<p><span>this.ctx=ctx; </span></p>
<p><span>}//setSessionContext </span></p>
<p>&nbsp;</p>
<p><span>public void ejbCreate() { </span></p>
<p><span>}//ejbCreate </span></p>
<p>&nbsp;</p>
<p><span>public void ejbPassivate() { </span></p>
<p><span>}//ejbPassivate </span></p>
<p>&nbsp;</p>
<p><span>public void ejbActivate() { </span></p>
<p><span>}//ejbActivate </span></p>
<p>&nbsp;</p>
<p><span>public void ejbRemove() { </span></p>
<p><span>}//ejbRemove </span></p>
<p>&nbsp;</p>
<p><span>public String showname(){ </span></p>
<p><span>return "Hello,my name is sailorsy"; </span></p>
<p><span>}//</span><span>自己的商务方法</span><span> </span></p>
<p><span>}//class sailorsy </span></p>
<p><span>以上这些是</span><span>EJB</span><span>必需的回调方法，我们可以在里面加入自己的方法，加入自己的商务逻辑。</span><span> </span></p>
<p><span>B.Home </span><span>接口</span><span>: sailorsyHome </span></p>
<p><span>import java.rmi.*; </span></p>
<p><span>import javax.ejb.*; </span></p>
<p>&nbsp;</p>
<p><span>public interface sailorsyHome extends EJBHome { </span></p>
<p><span>public sailorsyRemote create() throws RemoteException, CreateException; </span></p>
<p><span>} </span></p>
<p><span>C. Remote</span><span>接口：</span><span>sailorsyRemote </span></p>
<p><span>import java.rmi.*; </span></p>
<p><span>import javax.ejb.*; </span></p>
<p>&nbsp;</p>
<p><span>public interface sailorsyRemote extends EJBObject { </span></p>
<p><span>public java.lang.String showname() throws RemoteException; </span></p>
<p><span>} </span></p>
<p>&nbsp;</p>
<p><span>三</span><span>.</span><span>调用会话</span><span> Bean</span><span>：</span><span>sailorsyTestClient1 </span></p>
<p>&nbsp;</p>
<p><span>import javax.naming.*; </span></p>
<p><span>import javax.ejb.*; </span></p>
<p><span>import javax.rmi.PortableRemoteObject; </span></p>
<p><span>import java.rmi.*; </span></p>
<p>&nbsp;</p>
<p><span>public class sailorsyTestClient1 { </span></p>
<p><span>private sailorsyHome sailorsyHomeObject = null; </span></p>
<p>&nbsp;</p>
<p><span>//Construct the EJB test client </span></p>
<p><span>public sailorsyTestClient1() { </span></p>
<p><span>try { </span></p>
<p><span>//</span><span>以下是客户端使用</span><span>JNDI</span><span>定位</span><span>Home</span><span>对象。</span><span> </span></p>
<p><span>Context ctx = new InitialContext(); </span></p>
<p>&nbsp;</p>
<p><span>//look up jndi name </span></p>
<p><span>Object ref = ctx.lookup("sailorsy"); </span></p>
<p>&nbsp;</p>
<p><span>//cast to Home interface </span></p>
<p><span>sailorsyHomeObject = (sailorsyHome) PortableRemoteObject.narrow(ref, sailorsyHome.class); </span></p>
<p>&nbsp;</p>
<p><span>} </span></p>
<p><span>catch(Exception e) { </span></p>
<p><span>e.printStackTrace(); </span></p>
<p><span>} </span></p>
<p><span>} </span></p>
<p>&nbsp;</p>
<p><span>//---------------------------------------------------------------------------- </span></p>
<p><span>// Utility Methods </span></p>
<p><span>//---------------------------------------------------------------------------- </span></p>
<p>&nbsp;</p>
<p><span>public sailorsyHome getHome() { </span></p>
<p><span>return sailorsyHomeObject; </span></p>
<p><span>} </span></p>
<p><span>//Main method </span></p>
<p>&nbsp;</p>
<p><span>public static void main(String[] args) throws Exception{ </span></p>
<p><span>sailorsyTestClient1 client = new sailorsyTestClient1(); </span></p>
<p><span>sailorsyRemote sr=client.getHome() .create() ; </span></p>
<p><span>String s=sr.showname() ; </span></p>
<p><span>System.out.print(s); </span></p>
<p><span>// Use the getHome() method of the client object to call Home interface </span></p>
<p><span>// methods that will return a Remote interface reference. Then </span></p>
<p><span>// use that Remote interface reference to access the EJB. </span></p>
<p><span>} </span></p>
<p><span>} </span></p>
<p><span>以上的</span><span>EJB</span><span>在</span><span>win2000+jbuilder5/jbuilder6+BAS4.5</span><span>经过测试</span></p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/121220.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-05-31 18:27 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/05/31/121220.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Rule Engine Beginning</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/05/31/121219.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Thu, 31 May 2007 10:26:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/05/31/121219.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/121219.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/05/31/121219.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/121219.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/121219.html</trackback:ping><description><![CDATA[&nbsp;
<p align=center><span>Rule Engine Beginning</span></p>
<p>&nbsp;</p>
<p><span>引自：</span><span><a href="http://www.enet.com.cn/article/2007/0226/A20070226451769.shtml">http://www.enet.com.cn/article/2007/0226/A20070226451769.shtml</a></span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>　　引言</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　目前，</span><span>Java</span><span>社区推动并发展了一种引人注目的新技术——</span><span>Java</span><span>规则引擎（</span><span>Rule Engine</span><span>）。利用它就可以在应用系统中分离商业决策者的商业决策逻辑和应用开发者的技术决策，并把这些商业决策放在中心数据库或其他统一的地方，让它们能在运行时可以动态地管理和修改，从而为企业保持灵活性和竞争力提供有效的技术支持。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　规则引擎的原理</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>1</span><span>、基于规则的专家系统（</span><span>RBES</span><span>）简介</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>Java</span><span>规则引擎起源于基于规则的专家系统，而基于规则的专家系统又是专家系统的其中一个分支。专家系统属于人工智能的范畴，它模仿人类的推理方式，使用试探性的方法进行推理，并使用人类能理解的术语解释和证明它的推理结论。为了更深入地了解</span><span>Java</span><span>规则引擎，下面简要地介绍基于规则的专家系统。</span><span>RBES</span><span>包括三部分：</span><span>Rule Base</span><span>（</span><span>knowledge base</span><span>）、</span><span>Working Memory</span><span>（</span><span>fact base</span><span>）和</span><span>Inference Engine</span><span>。它们的结构如下系统所示：</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span> </span></p>
<p><span>　　图</span><span>1 </span><span>基于规则的专家系统构成</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　如图</span><span>1</span><span>所示，推理引擎包括三部分：模式匹配器（</span><span>Pattern Matcher</span><span>）、议程（</span><span>Agenda</span><span>）和执行引擎（</span><span>Execution Engine</span><span>）。推理引擎通过决定哪些规则满足事实或目标，并授予规则优先级，满足事实或目标的规则被加入议程。模式匹配器决定选择执行哪个规则，何时执行规则；议程管理模式匹配器挑选出来的规则的执行次序；执行引擎负责执行规则和其他动作。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　和人类的思维相对应，推理引擎存在两者推理方式：演绎法（</span><span>Forward-Chaining</span><span>）和归纳法（</span><span>Backward-Chaining</span><span>）。演绎法从一个初始的事实出发，不断地应用规则得出结论（或执行指定的动作）。而归纳法则是根据假设，不断地寻找符合假设的事实。</span><span>Rete</span><span>算法是目前效率最高的一个</span><span>Forward-Chaining</span><span>推理算法，许多</span><span>Java</span><span>规则引擎都是基于</span><span>Rete</span><span>算法来进行推理计算的。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　推理引擎的推理步骤如下：</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>(1)</span><span>将初始数据（</span><span>fact</span><span>）输入</span><span>Working Memory</span><span>。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>(2)</span><span>使用</span><span>Pattern Matcher</span><span>比较规则库（</span><span>rule base</span><span>）中的规则（</span><span>rule</span><span>）和数据（</span><span>fact</span><span>）。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>(3)</span><span>如果执行规则存在冲突（</span><span>conflict</span><span>），即同时激活了多个规则，将冲突的规则放入冲突集合。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>(4)</span><span>解决冲突，将激活的规则按顺序放入</span><span>Agenda</span><span>。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>(5)</span><span>使用执行引擎执行</span><span>Agenda</span><span>中的规则。重复步骤</span><span>2</span><span>至</span><span>5</span><span>，直到执行完毕所有</span><span>Agenda</span><span>中的规则。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　上述即是规则引擎的原始架构，</span><span>Java</span><span>规则引擎就是从这一原始架构演变而来的。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>2</span><span>、规则引擎相关构件</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　规则引擎是一种根据规则中包含的指定过滤条件，判断其能否匹配运行时刻的实时条件来执行规则中所规定的动作的引擎。与规则引擎相关的有四个基本概念，为更好地理解规则引擎的工作原理，下面将对这些概念进行逐一介绍。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>1)</span><span>信息元（</span><span>Information Unit</span><span>）</span><span> </span></p>
<p>&nbsp;</p>
<p><span>信息元是规则引擎的基本建筑块，它是一个包含了特定事件的所有信息的对象。这些信息包括：消息、产生事件的应用程序标识、事件产生事件、信息元类型、相关规则集、通用方法、通用属性以及一些系统相关信息等等。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>2)</span><span>信息服务（</span><span>Information Services</span><span>）</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　信息服务产生信息元对象。每个信息服务产生它自己类型相对应的信息元对象。即特定信息服务根据信息元所产生每个信息元对象有相同的格式，但可以有不同的属性和规则集。需要注意的是，在一台机器上可以运行许多不同的信息服务，还可以运行同一信息服务的不同实例。但无论如何，每个信息服务只产生它自己类型相对应的信息元。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>3)</span><span>规则集（</span><span>Rule Set</span><span>）</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　顾名思义，规则集就是许多规则的集合。每条规则包含一个条件过滤器和多个动作。一个条件过滤器可以包含多个过滤条件。条件过滤器是多个布尔表达式的组合，其组合结果仍然是一个布尔类型的。在程序运行时，动作将会在条件过滤器值为真的情况下执行。除了一般的执行动作，还有三类比较特别的动作，它们分别是：放弃动作（</span><span>Discard Action</span><span>）、包含动作（</span><span>Include Action</span><span>）和使信息元对象内容持久化的动作。前两种动作类型的区别将在</span><span>2.3</span><span>规则引擎工作机制小节介绍。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>4)</span><span>队列管理器（</span><span>Queue Manager</span><span>）</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　队列管理器用来管理来自不同信息服务的信息元对象的队列。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　下面将研究规则引擎的这些相关构件是如何协同工作的。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　如图</span><span>2</span><span>所示，处理过程分为四个阶段进行：信息服务接受事件并将其转化为信息元，然后这些信息元被传给队列管理器，最后规则引擎接收这些信息元并应用它们自身携带的规则加以执行，直到队列管理器中不再有信息元。</span><span> </span></p>
<p>&nbsp;</p>
<p>&#160;</p>
<p><span>　　图</span><span>2 </span><span>处理过程协作图</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>3</span><span>、规则引擎的工作机制</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　下面专门研究规则引擎的内部处理过程。如图</span><span>3</span><span>所示，规则引擎从队列管理器中依次接收信息元，然后依规则的定义顺序检查信息元所带规则集中的规则。如图所示，规则引擎检查第一个规则并对其条件过滤器求值，如果值为假，所有与此规则相关的动作皆被忽略并继续执行下一条规则。如果第二条规则的过滤器值为真，所有与此规则相关的动作皆依定义顺序执行，执行完毕继续下一条规则。该信息元中的所有规则执行完毕后，信息元将被销毁，然后从队列管理器接收下一个信息元。在这个过程中并未考虑两个特殊动作：放弃动作（</span><span>Discard Action</span><span>）和包含动作（</span><span>Include Action</span><span>）。放弃动作如果被执行，将会跳过其所在信息元中接下来的所有规则，并销毁所在信息元，规则引擎继续接收队列管理器中的下一个信息元。包含动作其实就是动作中包含其它现存规则集的动作。包含动作如果被执行，规则引擎将暂停并进入被包含的规则集，执行完毕后，规则引擎还会返回原来暂停的地方继续执行。这一过程将递归进行。</span><span> </span></p>
<p>&nbsp;</p>
<p>&#160;</p>
<p><span>　　图</span><span>3 </span><span>规则引擎工作机制</span><span> </span></p>
<p>&nbsp;</p>
<p><span>Java</span><span>规则引擎的工作机制与上述规则引擎机制十分类似，只不过对上述概念进行了重新包装组合。</span><span>Java</span><span>规则引擎对提交给引擎的</span><span>Java</span><span>数据对象进行检索，根据这些对象的当前属性值和它们之间的关系，从加载到引擎的规则集中发现符合条件的规则，创建这些规则的执行实例。这些实例将在引擎接到执行指令时、依照某种优先序依次执行。一般来讲，</span><span>Java</span><span>规则引擎内部由下面几个部分构成：工作内存（</span><span>Working Memory</span><span>）即工作区，用于存放被引擎引用的数据对象集合；规则执行队列，用于存放被激活的规则执行实例</span><span>;</span><span>静态规则区，用于存放所有被加载的业务规则，这些规则将按照某种数据结构组织，当工作区中的数据发生改变后，引擎需要迅速根据工作区中的对象现状，调整规则执行队列中的规则执行实例。</span><span>Java</span><span>规则引擎的结构示意图如图</span><span>4</span><span>所示。</span></p>
<p>&nbsp;</p>
<p>&#160;</p>
<p><span>　　图</span><span>4 Java</span><span>规则引擎工作机制</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　当引擎执行时，会根据规则执行队列中的优先顺序逐条执行规则执行实例，由于规则的执行部分可能会改变工作区的数据对象，从而会使队列中的某些规则执行实例因为条件改变而失效，必须从队列中撤销，也可能会激活原来不满足条件的规则，生成新的规则执行实例进入队列。于是就产生了一种&#8220;动态&#8221;的规则执行链，形成规则的推理机制。这种规则的&#8220;链式&#8221;反应完全是由工作区中的数据驱动的。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　任何一个规则引擎都需要很好地解决规则的推理机制和规则条件匹配的效率问题。规则条件匹配的效率决定了引擎的性能，引擎需要迅速测试工作区中的数据对象，从加载的规则集中发现符合条件的规则，生成规则执行实例。</span><span>1982</span><span>年美国卡耐基&#183;梅隆大学的</span><span>Charles L. Forgy</span><span>发明了一种叫</span><span>Rete</span><span>算法，很好地解决了这方面的问题。目前世界顶尖的商用业务规则引擎产品基本上都使用</span><span>Rete</span><span>算法。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　　　</span><span>Java</span><span>规则引擎</span><span>API</span><span>——</span><span>JSR-94 </span></p>
<p>&nbsp;</p>
<p><span>　　为了使规则引擎技术标准化，</span><span>Java</span><span>社区制定了</span><span>Java</span><span>规则引擎</span><span>API</span><span>（</span><span>JSR94</span><span>）规范。它为</span><span>Java</span><span>平台访问规则引擎定义了一些简单的</span><span>API</span><span>。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>Java</span><span>规则引擎</span><span>API</span><span>在</span><span>javax.rules</span><span>包中定义，是访问规则引擎的标准企业级</span><span>API</span><span>。</span><span>Java</span><span>规则引擎</span><span>API</span><span>允许客户程序使用统一的方式和不同厂商的规则引擎产品交互，就如同使用</span><span>JDBC</span><span>编写独立于厂商访问不同的数据库产品一样。</span><span>Java</span><span>规则引擎</span><span>API</span><span>包括创建和管理规则集合的机制，在工作区中添加，删除和修改对象的机制，以及初始化，重置和执行规则引擎的机制。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>1</span><span>、</span><span>Java</span><span>规则引擎</span><span>API</span><span>体系结构</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>Java</span><span>规则引擎</span><span>API</span><span>主要由两大类</span><span>API</span><span>组成</span><span>: </span><span>规则管理</span><span>API(The Rules Administrator API)</span><span>和运行时客户</span><span>API(The Runtime Client API)</span><span>。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>1)</span><span>规则管理</span><span>API </span></p>
<p>&nbsp;</p>
<p><span>　　规则管理</span><span>API</span><span>在</span><span>javax.rules.admin</span><span>中定义，包含装载规则以及与规则对应的动作</span><span>(</span><span>执行集</span><span> execution sets)</span><span>以及实例化规则引擎。规则可以从外部资源中装载，比如</span><span>URI</span><span>，</span><span>Input streams</span><span>，</span><span> XML streams</span><span>和</span><span>readers</span><span>等等。同时规则管理</span><span>API</span><span>还提供了注册和取消注册执行集以及对执行集进行维护的机制。使用</span><span>admin</span><span>包定义规则有助于对客户访问运行规则进行控制管理，它通过在执行集上定义许可权使得未经授权的用户无法访问受控规则。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　规则管理</span><span>API</span><span>使用类</span><span>RuleServiceProvider</span><span>来获得规则管理器</span><span>(RuleAdministrator)</span><span>接口的实例。该接口提供方法注册和取消注册执行集。规则管理器提供了本地和远程的</span><span>RuleExecutionSetProvider</span><span>，它负责创建规则执行集（</span><span>RuleExecutionSet</span><span>）。规则执行集可以从如</span><span>XML streams</span><span>，</span><span> binary streams</span><span>等来源中创建。这些数据来源及其内容经汇集和序列化后传送到远程的运行规则引擎的服务器上。在大多数应用程序中，远程规则引擎或远程规则数据来源的情况并不多。为了避免这些情况中的网络开销，</span><span>API</span><span>规定了可以从运行在同一</span><span>JVM</span><span>中规则库中读取数据的本地</span><span>RuleExecutionSetProvider</span><span>。规则执行集接口除了拥有能够获得有关规则执行集的方法，还有能够检索在规则执行集中定义的所有规则对象。这使得客户能够知道规则集中的规则对象并且按照自己需要来使用它们。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>2)</span><span>运行时客户</span><span>API </span></p>
<p>&nbsp;</p>
<p><span>　　运行时</span><span>API</span><span>在</span><span>javax.rules</span><span>包中定义，为规则引擎用户运行规则获得结果提供了类和方法。运行时客户只能访问那些使用规则管理</span><span>API</span><span>注册过的规则，运行时</span><span>API</span><span>帮助用户获得规则会话，并在这个会话中执行规则。</span></p>
<p>&nbsp;</p>
<p><span>　　运行时</span><span>API</span><span>提供了对厂商规则引擎</span><span>API</span><span>的访问方法，这类似于</span><span>JDBC</span><span>。类</span><span>RuleServiceProvider</span><span>提供了对具体规则引擎实现的运行时和管理</span><span>API</span><span>的访问，规则引擎厂商通过该类将其规则引擎实现提供给客户，并获得</span><span>RuleServiceProvider</span><span>唯一标识规则引擎的</span><span>URL</span><span>。此</span><span>URL</span><span>的标准用法是使用类似于&#8220;</span><span>com.mycompany.myrulesengine.rules.RuleServiceProvider</span><span>&#8221;这样的</span><span>Internet</span><span>域名空间，这保证了访问</span><span>URL</span><span>的唯一性。类</span><span>RuleServiceProvider</span><span>内部实现了规则管理和运行时访问所需的接口。所有的</span><span>RuleServiceProvider</span><span>要想被客户所访问都必须用</span><span>RuleServiceProviderManager</span><span>进行注册，注册方式类似于</span><span>JDBC API</span><span>的</span><span>DriverManager</span><span>和</span><span>Driver</span><span>。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　运行时接口是运行时</span><span>API</span><span>的关键部分。运行时接口提供了用于创建规则会话</span><span>(RuleSession)</span><span>的方法，规则会话是用来运行规则的。运行时</span><span>API</span><span>同时也提供了访问在</span><span>service provider</span><span>注册过的所有规则执行集</span><span>(RuleExecutionSets)</span><span>。规则会话接口定义了客户使用的会话的类型，客户根据自己运行规则的方式可以选择使用有状态会话或者无状态会话。无状态会话的工作方式就像一个无状态会话</span><span>bean</span><span>。客户可以发送单个输入对象或一列对象来获得输出对象。当客户需要一个与规则引擎间的专用会话时，有状态会话就很有用。输入的对象通过</span><span>addObject() </span><span>方法可以加入到会话当中。同一个会话当中可以加入多个对象。对话中已有对象可以通过使用</span><span>updateObject()</span><span>方法得到更新。只要客户与规则引擎间的会话依然存在，会话中的对象就不会丢失。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>RuleExecutionSetMetaData</span><span>接口提供给客户让其查找规则执行集的元数据</span><span>(metadata)</span><span>。元数据通过规则会话接口</span><span>(RuleSession Interface)</span><span>提供给用户。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>2</span><span>、</span><span>Java</span><span>规则引擎</span><span>API</span><span>安全问题</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　规则引擎</span><span>API</span><span>将管理</span><span>API</span><span>和运行时</span><span>API</span><span>加以分开，从而为这些包提供了较好粒度的安全控制。规则引擎</span><span>API</span><span>并没有提供明显的安全机制，它可以和</span><span>J2EE</span><span>规范中定义的标准安全</span><span>API</span><span>联合使用。安全可以由以下机制提供，如</span><span>Java </span><span>认证和授权服务</span><span> (JAAS)</span><span>，</span><span>Java</span><span>加密扩展</span><span>(JCE)</span><span>，</span><span>Java</span><span>安全套接字扩展</span><span>(JSSE)</span><span>，或者其它定制的安全</span><span>API</span><span>。使用</span><span>JAAS</span><span>可以定义规则执行集的许可权限，从而只有授权用户才能访问。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>3</span><span>、异常与日志</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　规则引擎</span><span>API</span><span>定义了</span><span>javax.rules.RuleException</span><span>作为规则引擎异常层次的根类。所有其它异常都继承于这个根类。规则引擎中定义的异常都是受控制的异常</span><span>(checked exceptions)</span><span>，所以捕获异常的任务就交给了规则引擎。规则引擎</span><span>API</span><span>没有提供明确的日志机制，但是它建议将</span><span>Java Logging API</span><span>用于规则引擎</span><span>API</span><span>。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>JSR 94 </span><span>为规则引擎提供了公用标准</span><span>API</span><span>，仅仅为实现规则管理</span><span>API</span><span>和运行时</span><span>API</span><span>提供了指导规范，并没有提供规则和动作该如何定义以及该用什么语言定义规则，也没有为规则引擎如何读和评价规则提供技术性指导。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　结束语</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　规则引擎技术为管理多变的业务逻辑提供了一种解决方案。规则引擎既可以管理应用层的业务逻辑又可以使表示层的页面流程可订制。这就给软件架构师设计大型信息系统提供了一项新的选择。而</span><span>Java</span><span>规则引擎在</span><span>Java</span><span>社区制定标准规范以后必将获得更大发展。</span></p>
<p>&nbsp;</p>
<p><span>建议大家参考：</span><span><a href="http://www.blogjava.net/guangnian0412/archive/2006/06/01.html">http://www.blogjava.net/guangnian0412/archive/2006/06/01.html</a></span></p>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/121219.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-05-31 18:26 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/05/31/121219.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Event Beginning</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/05/30/120962.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Wed, 30 May 2007 10:40:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/05/30/120962.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/120962.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/05/30/120962.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/120962.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/120962.html</trackback:ping><description><![CDATA[&nbsp;
<p align=center><span>Event Beginning</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>引自：</span><span><a href="http://blog.csdn.net/bear110/archive/2006/06/30/854507.aspx">http://blog.csdn.net/bear110/archive/2006/06/30/854507.aspx</a></span></p>
<p>&nbsp;</p>
<p><span>如果你已经能够熟练使用</span><span>jdk</span><span>为我们提供的事件监听器，并且很熟悉</span><span>MouseEvent, KeyEvent, WindowEvent</span><span>等等这些</span><span>jdk</span><span>为我们准备好的事件，那么想必你对</span><span>java</span><span>的事件机制已经有所理解。但是也许你还是觉得虽然用起来没什么问题，但是原理还是有些糊涂，那么下面我们再进一步自己实现这些事件和监听器，我们把这个取名为自定义事件。</span></p>
<p><span>&nbsp;</span></p>
<p><span>其实自定义事件在</span><span>java</span><span>中很有用处，我们有的时候想让自己的程序产生一个事件，但有不希望（或者不可能）用鼠标，键盘之类的输入设备进行操作，比如你写一个应用程序，在这个程序中一旦收到邮件就对邮件进行相关处理，对于&#8220;收到邮件&#8221;这个事件，</span><span>jdk</span><span>中就没有定义。对于这样的事件，以及对于这样的事件的监听器，我们只能自己动手完成了。</span></p>
<p><span>&nbsp;</span></p>
<p><span>那么下面就以实例开始我们这个&#8220;创新&#8221;的过程：首先，我们要明确</span><span>jdk</span><span>中需要的资源：类</span><span>EventObject</span><span>作为父类用来生成我们自己的事件类，接口</span><span>EventListener</span><span>用来实现我们自己的监听器；剩下的事情就是如何注册这些事件以及测试他们了。</span></p>
<p><span>让我们一步一步实现它吧：</span></p>
<p><span>（</span><span>1</span><span>）通过</span><span>DemoEvent.java</span><span>文件创建</span><span>DemoEvent</span><span>类，这个类继承</span><span>EventObject</span><span>。这个类的构造函数的参数传递了产生这个事件的事件源（比如各种控件），方法</span><span>getSource</span><span>用来获得这个事件源的引用。</span></p>
<p><span>DemoEvent.java</span></p>
<p><span>package demo.listener;</span></p>
<p><span>&nbsp;</span></p>
<p><span>import java.util.EventObject;</span></p>
<p><span>&nbsp;</span></p>
<p><span>public class DemoEvent extends EventObject</span></p>
<p><span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Object obj;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>public DemoEvent(Object source)</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>super(source);</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>obj = source;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>public Object getSource()</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return obj;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>public void say()</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println("This is say method...");</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p><span>} </span></p>
<p>&nbsp;</p>
<p><span>&nbsp;</span></p>
<p><span>（</span><span>2</span><span>）定义新的事件监听接口，该接口继承自</span><span>EventListener</span><span>；该接口包含对</span><span>DemeEvent</span><span>事件的处理程序：</span></p>
<p><span>DemoListener.java</span></p>
<p><span>package demo.listener;</span></p>
<p><span>&nbsp;</span></p>
<p><span>import java.util.EventListener;</span></p>
<p><span>&nbsp;</span></p>
<p><span>public interface DemoListener extends EventListener</span></p>
<p><span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>public void demoEvent(DemoEvent dm);</span></p>
<p><span>} </span></p>
<p>&nbsp;</p>
<p><span>&nbsp;</span></p>
<p><span>通过上面的接口我们再定义事件监听类，这些类具体实现了监听功能和事件处理功能。回想一下上文中那四种实现方式，我们这里不正是使用了其中的第三种——外部类写法的方式吗？</span></p>
<p><span>Listener1.java</span></p>
<p><span>package demo.listener;</span></p>
<p><span>&nbsp;</span></p>
<p><span>public class Listener1 implements DemoListener</span></p>
<p><span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>public void demoEvent(DemoEvent de)</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println("Inside listener1...");</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p><span>} </span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>Listener2.java</span></p>
<p><span>package demo.listener;</span></p>
<p><span>&nbsp;</span></p>
<p><span>public class Listener2 implements DemoListener</span></p>
<p><span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>public void demoEvent(DemoEvent de)</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println("Inside listener2...");</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p><span>} </span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>Listener3.java</span></p>
<p><span>package demo.listener;</span></p>
<p><span>&nbsp;</span></p>
<p><span>public class Listener3 implements DemoListener</span></p>
<p><span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>public void demoEvent(DemoEvent de)</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>System.out.println("Inside listener3...");</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p><span>} </span></p>
<p>&nbsp;</p>
<p><span>&nbsp;</span></p>
<p><span>（</span><span>3</span><span>）通过</span><span>DemeSource.java</span><span>文件创造一个事件源类，它用一个</span><span>java.utile.Vector</span><span>对象来存储所有的事件监听器对象，存储方式是通过</span><span>addListener(..)</span><span>这样的方法。</span><span>notifyDemeEvent(..)</span><span>是触发事件的方法，用来通知系统：事件发生了，你调用相应的处理函数（回调函数）吧。</span></p>
<p><span>DemoSource.java</span></p>
<p><span>&nbsp;</span></p>
<p><span>package demo.listener;</span></p>
<p><span>import java.util.*;</span></p>
<p><span>&nbsp;</span></p>
<p><span>public class DemoSource</span></p>
<p><span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>private Vector repository = new Vector();</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>DemoListener dl;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>public DemoSource()</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span>&nbsp;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>public void addDemoListener(DemoListener dl)</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>repository.addElement(dl);</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>public void notifyDemoEvent()</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Enumeration enum = repository.elements();</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>while(enum.hasMoreElements())</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>dl = (DemoListener)enum.nextElement();</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>dl.demoEvent(new DemoEvent(this));</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p><span>}</span></p>
<p><span>&nbsp;</span></p>
<p>&nbsp;</p>
<p><span>&nbsp;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></p>
<p><span>（</span><span>4</span><span>）好了，最后写一个测试程序测试一下我们自定义的事件吧，这段程序应该不难理解吧：）</span></p>
<p><span>TestDemo.java</span></p>
<p><span>&nbsp;</span></p>
<p><span>package demo.listener;</span></p>
<p><span>&nbsp;</span></p>
<p><span>public class TestDemo</span></p>
<p><span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>DemoSource ds;</span></p>
<p><span>&nbsp;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>public TestDemo()</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>try{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>ds = new DemoSource();</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Listener1 l1 = new Listener1();</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Listener2 l2 = new Listener2();</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Listener3 l3 = new Listener3();</span></p>
<p><span>&nbsp;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>ds.addDemoListener(l1);</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>ds.addDemoListener(l2);</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>ds.addDemoListener(l3);</span></p>
<p><span>&nbsp;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>ds.notifyDemoEvent();</span></p>
<p><span>&nbsp;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}catch(Exception ex)</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{ex.printStackTrace();}</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p><span>&nbsp;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>public static void main(String args[])</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>new TestDemo();</span></p>
<p><span><span>&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;</span>}</span></p>
<p><span>} </span></p>
<p>&nbsp;</p>
<p><span>引自：</span><span><a href="http://blog.csdn.net/Arhero/archive/2004/11/23/192486.aspx">http://blog.csdn.net/Arhero/archive/2004/11/23/192486.aspx</a></span></p>
<p>&nbsp;</p>
<p><span><span>一、</span></span><span>java</span><span>事件处理机制</span></p>
<p>&nbsp;</p>
<p><span>java</span><span>中采取的是面向对象的机制。如在</span><span>java</span><span>中，要实现自定义事件处理，必须经过如下的步骤：</span></p>
<p><span>1 </span><span>开发自定义事件类。</span></p>
<p><span>2 </span><span>定义监听者接口。</span></p>
<p><span>3 </span><span>定义事件激发者的接口。</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>public void add</span><span>监听者（监听者）；</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>public void remove</span><span>监听者（监听者）；</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>protected void process</span><span>事件（事件）；</span></p>
<p><span>4 </span><span>实现事件激发者</span><span>.</span></p>
<p><span>5 </span><span>实现监听这接口。</span></p>
<p>&nbsp;</p>
<p><span>java</span><span>中的事件机制是很好理解的。当一个事件激发事，就调用</span><span>process</span><span>事件方法。这个事件方法会将所有的监听者一一执行它监听该事件的接口。（如果消息不消费，允许传递的话。）当然这也不是必须的，因为</span><span>process</span><span>方法是自己写的，可以自行决定它执行的动作。</span></p>
<p>&nbsp;</p>
<p><span>实际上，</span><span>java</span><span>还有一种简单的事件处理机制。那就是目前不予推荐的继承模式。由于简单性，又不能不说这也可以是编程的一种选择。但是它在处理事件时，却只有一种选择，那就是扩展激发事件的构件并将事件处理代码嵌入到扩展部分。要做的步骤是：</span></p>
<p><span>1 </span><span>覆盖事件处理函数。</span></p>
<p><span>如</span><span>Applet</span><span>中的</span><span>public boolean mouseDown(Event evt, int x, int y).</span></p>
<p><span>如果要激发和处理自定义事件</span><span>,</span><span>如果比较多</span><span>, </span><span>可以仿照</span><span>awt</span><span>的做法：</span></p>
<p><span>激发事件</span><span>processEvent()---&gt;</span><span>定位</span><span>---&gt;process</span><span>适当</span><span>Event()---&gt;</span><span>将事件传递到事件处理函数</span></p>
<p>&nbsp;</p>
<p><span><span>二、</span></span><span>EventHandler</span></p>
<p>&nbsp;</p>
<p><span>EventHandler </span><span>类为动态生成事件侦听器提供支持，这些侦听器的方法执行一条涉及传入事件对象和目标对象的简单语句。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>EventHandler </span><span>类由交互工具（比如应用程序生成器）使用，这些工具允许开发人员在</span><span> bean </span><span>之间建立连接。通常是建立从用户界面</span><span> bean</span><span>（事件</span><span> source</span><span>）到应用程序逻辑</span><span> bean</span><span>（</span><span>target</span><span>）的连接。大多数这类有效连接隔离了应用程序逻辑与用户界面。例如，用于从</span><span> JCheckBox </span><span>到接受</span><span> boolean </span><span>值的方法之间连接的</span><span> EventHandler </span><span>可以提取复选框的状态，并将其直接传递给该方法，从而使该方法与用户界面层隔离。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>内部类是处理来自用户界面的事件的另一种更常见方法。</span><span>EventHandler </span><span>类只处理可能使用内部类的事件的子集。不过，</span><span>EventHandler </span><span>使用长期持久方案要比使用内部类更有效。同样，在同一接口被实现很多次的大型应用程序中，使用</span><span> EventHandler </span><span>可以减少应用程序的磁盘和内存占用。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>使用</span><span> EventHandler </span><span>创建侦听器占用内存如此之少的原因是，</span><span>EventHandler </span><span>所依赖的</span><span> Proxy </span><span>类共享了同一接口的实现。例如，如果使用</span><span> EventHandler </span><span>的</span><span> create </span><span>方法生成某个应用程序中的所有</span><span> ActionListener</span><span>，则所有动作侦听器都将是单个类（由</span><span> Proxy </span><span>类创建）的实例。通常，基于</span><span> Proxy </span><span>类的侦听器要求为每个侦听器类型（接口）创建一个侦听器类，而使用内部类时要求为每个侦听器（实现接口的对象）创建一个类。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>通常不需要直接处理</span><span> EventHandler </span><span>实例。相反，可使用</span><span> EventHandler </span><span>的</span><span> create </span><span>方法之一创建实现给定侦听器接口的对象。此侦听器对象在后台使用一个</span><span> EventHandler </span><span>对象来封装关于事件的信息、发生事件时接收消息的对象、要发送的消息（方法）和方法的任意参数。以下部分给出了如何使用</span><span> create </span><span>方法创建侦听器对象的示例。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>使用</span><span> EventHandler </span><span>的示例</span><span>:</span></p>
<p>&nbsp;</p>
<p><span>EventHandler </span><span>最简单的使用方法是安装一个侦听器，不带参数地在目标对象上调用某个方法。在以下示例中，将创建一个在</span><span> javax.swing.JFrame </span><span>的实例上调用</span><span> toFront </span><span>方法的</span><span> ActionListener</span><span>。</span><span> </span></p>
<p><span>myButton.addActionListener(</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>(ActionListener)EventHandler.create(ActionListener.class, frame, "toFront"));</span></p>
<p><span>当按下</span><span> myButton </span><span>时，将执行</span><span> frame.toFront() </span><span>语句。通过定义</span><span> ActionListener </span><span>接口的新实现并将其实例添加到按钮中，用户可以获得同样的效果，且具有额外的编译时类型安全：</span><span> </span></p>
<p><span>//Equivalent code using an inner class instead of EventHandler.</span></p>
<p><span>myButton.addActionListener(new ActionListener() {</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>public void actionPerformed(ActionEvent e) {</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>frame.toFront();</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p><span>});</span></p>
<p><span>EventHandler </span><span>的另一种最简单用法是从侦听器接口（通常是一个事件对象）中的方法的第一个参数中提取属性值，并用其设置目标对象中的属性值。在以下示例中，将创建一个</span><span> ActionListener</span><span>，它将目标对象的</span><span> nextFocusableComponent </span><span>属性设置为事件的</span><span> "source" </span><span>属性的值。</span><span> </span></p>
<p><span>EventHandler.create(ActionListener.class, target, "nextFocusableComponent", "source")</span></p>
<p><span>这将对应于以下内部类实现：</span><span> </span></p>
<p><span>//Equivalent code using an inner class instead of EventHandler.</span></p>
<p><span>new ActionListener() {</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>public void actionPerformed(ActionEvent e) {</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>button.setNextFocusableComponent((Component)e.getSource()); </span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p><span>}</span></p>
<p><span>EventHandler </span><span>最常见的用法可能是从事件对象的</span><span> source </span><span>中提取属性值，并将此值设置为目标对象的属性值。在以下示例中，将创建一个</span><span> ActionListener</span><span>，它将目标对象的</span><span> "label" </span><span>属性设置为事件源的</span><span> "text" </span><span>属性的值（</span><span>"source" </span><span>属性的值）。</span><span> </span></p>
<p><span>EventHandler.create(ActionListener.class, button, "label", "source.text")</span></p>
<p><span>这将对应于以下内部类实现：</span><span> </span></p>
<p><span>//Equivalent code using an inner class instead of EventHandler.</span></p>
<p><span>new ActionListener {</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>public void actionPerformed(ActionEvent e) {</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>button.setLabel(((JTextField)e.getSource()).getText()); </span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p><span>}</span></p>
<p><span>可以使用以</span><span> "." </span><span>字符分隔的任意数量的属性前缀来&#8220;限定&#8221;事件属性。采用出现在</span><span> "." </span><span>字符前面的&#8220;限定&#8221;名称作为将应用于事件对象的属性名称，最左边的最先应用。</span><span> </span></p>
<p><span>例如，以下动作侦听器</span><span> </span></p>
<p>&nbsp;</p>
<p><span>EventHandler.create(ActionListener.class, target, "a", "b.c.d")</span></p>
<p><span>可以写成以下内部类（假定所有属性都有规范的</span><span> getter </span><span>方法并返回适当的类型）：</span><span> </span></p>
<p><span>//Equivalent code using an inner class instead of EventHandler.</span></p>
<p><span>new ActionListener {</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>public void actionPerformed(ActionEvent e) {</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>target.setA(e.getB().getC().isD()); </span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p><span>}</span></p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/120962.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-05-30 18:40 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/05/30/120962.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CTI Beginning</title><link>http://www.blogjava.net/hengheng123456789/archive/2007/05/29/120748.html</link><dc:creator>哼哼</dc:creator><author>哼哼</author><pubDate>Tue, 29 May 2007 10:10:00 GMT</pubDate><guid>http://www.blogjava.net/hengheng123456789/archive/2007/05/29/120748.html</guid><wfw:comment>http://www.blogjava.net/hengheng123456789/comments/120748.html</wfw:comment><comments>http://www.blogjava.net/hengheng123456789/archive/2007/05/29/120748.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hengheng123456789/comments/commentRss/120748.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hengheng123456789/services/trackbacks/120748.html</trackback:ping><description><![CDATA[&nbsp;
<p align=center><span>CTI Beginning</span></p>
<p>&nbsp;(转)</p>
<p>&nbsp;</p>
<p><span>第二讲</span><span> CTI</span><span>通信基础知识</span></p>
<p>&nbsp;</p>
<p><span>2.1 </span><span>概述</span></p>
<p><span>CTI</span><span>是计算机语音集成（</span><span>Computer Telephony Integration</span><span>）的意思，简单的来说，就是如何将计算机与电信网络连接在一起并能自动化编程处理电话网络业务的一种技术。计算机这个东西在最初设计出来的时候，设计者们并没有为它考虑到做几个连接到各个网络的插口。例如，如果你想把计算机连接到局域网上，你必须在计算机上找到一个可以插局域网网线的接口，才能使计算机通过该接口与局域网连接在一起并访问其他已连接计算机的资源（比如拷贝文件等），这个角色（提供网线插口）目前由网卡来承担了，比如</span><span>3Com</span><span>的</span><span>10/100M</span><span>网卡。同样地，如果你想让计算机来接电话或通过计算机把电话打到你客户的公司并自动的由计算机向他问好，怎么办呢？此时你就必须首先把计算机和电话网连接起来然后再编写程序实现接电话或打电话。可是计算机天生并没有提供电话线的插口，于是，一些设备制造公司制造了和网卡类似的东西，但是它的目的不是和局域网相连，而是让计算机和电话线相连。这个和网卡类似的东西就叫做电话语音卡，有的人把他叫做</span><span>CTI</span><span>卡，它的责任是提供一个电话线路的插口并可以将电话线插到该插口里。然后使用制造此设备的公司提供的编程函数来编写这个语音卡的程序。</span></p>
<p>&nbsp;</p>
<p><span>和</span><span>3COM</span><span>提供网卡相似，现在已经不仅仅能够用来打电话和接电话了，还可以用来收发传真、拨打</span><span>IP</span><span>电话、制作企业自动总机、语音信箱、呼叫中心以及所谓的</span><span>IVR</span><span>系统。</span><span>IVR</span><span>系统</span><span>Interact Voice Response-</span><span>交互式语音应答的意思，它是</span><span>CTI</span><span>行业里应用得最广泛的系统，正如语音卡最初的目的是用来自动接电话和打电话一样，</span><span>IVR</span><span>正是一个用来自动接电话和打电话的计算机系统，比如使用手机拨打电信客户服务中心的电话</span><span>1000</span><span>号，电话打入之后你会听到计算机对你说&#8220;你好，欢迎使用电信客户服务中心&#8221;，当然，用市场上卖的企业总机也能实现自动应答的功能，但是，计算机提供了更复杂和更灵活的能力，它不但可以应答电话，还可以自动的收发传真、动态的把客户的数据记录到数据库等，这些能力是非计算机系统无法实现的。</span></p>
<p>&nbsp;</p>
<p><span>2.2 </span><span>电信技术概念和术语</span></p>
<p><span>以下提到的术语主要和模拟线路有关，其他的术语解释请参考相关的手册。</span></p>
<p>&nbsp;</p>
<p><span>2.2.1 </span><span>模拟信号和数字信号</span></p>
<p><span>我们每个家庭或公司都有电话机，并且都有一条线连接到电话机上，通过这个电话机可以打电话和接电话，一般情况下，该电话线叫做模拟电话线，因为它上面传输的是模拟信号，所谓模拟信号就是如果通过示波器来查看线路信号，可以看到信号随说话人声音的变化而变化，它是有规律变化的正弦波信号；而与此相对的数字线路就是传输数字信号的线路。数字线路上的信号使用示波器来看只能看到一些断续的电流跃变，用数学的概念来说就是模拟信号是连续信号，而数字信号是不连续信号（或离散信号）。数字信号之所以不连续是因为它的信号已经被进行了</span><span>A/D</span><span>转换（</span><span>A/D</span><span>转换是一种使用二进制数字组来代替电流或电压幅值的转换办法），</span><span>A/D</span><span>转换后的信号全部被</span><span>0</span><span>和</span><span>1</span><span>的二进制组代替，因此你在示波器上当然就只能看到代表</span><span>0</span><span>和代表</span><span>1</span><span>的电压的突变，或许</span><span>3V</span><span>代表</span><span>1</span><span>而</span><span>0V</span><span>代表</span><span>0</span><span>。</span></p>
<p>&nbsp;</p>
<p><span>在数据和语言通信领域中，最容易被混淆的地方之一是在&#8220;模拟&#8221;和&#8220;数字&#8221;两个词之</span> <span>间。大部分人知道&#8220;数字&#8221;是指信息以</span><span>1</span><span>和</span><span>0</span><span>的形式存在，但很少有人能将这一事实和以</span><span>1 </span><span>和</span><span>0</span><span>的格式移动语音信号这一现实需要这两者之间作心理上的联系。关于&#8220;模拟&#8221;这个词，</span> <span>人们可能只谈及到语言通信。这里将帮助你作出并理解这两个术语之间的联系。读完后，你可以知道你不仅将成为一名电气工程师，并且能很好地理解它们。如果我们必须理解</span> <span>某件东西的话，那是：模拟和数字方式是在任意媒介中传送信息的方法。有些媒介主要适用</span> <span>于模拟，还有一些适用于数字，而其他的两者都合。这有助于理解使用不同传输系统的原因。</span></p>
<p>&nbsp;</p>
<p><span>正如前面提及的，&#8220;网络&#8221;最初的发展只是为了提供语音通信业务。</span><span>AT</span><span>＆</span><span>T</span><span>通过</span><span>Bell</span><span>公</span> <span>司及其通信能力而建立的通信电路严格地使用了模拟技术。确实，它变成了一个数字世界，</span> <span>但它是围绕着语言模拟通信而建造的。那这一切是什么意思呢？</span></p>
<p>&nbsp;</p>
<p><span>在模拟通信系统中，原始信号（在这儿是指声音）被直接转化成了电信号。模拟信号的特性与两个常变量有关：信号的幅度</span> <span>和频率。电信号的强度（幅度）随声音的大小而变化，而电信号的频率随声音的音质或音调</span> <span>而改变。两个可变量（幅度和频率）的变化与原始声波成正比。</span></p>
<p>&nbsp;</p>
<p><span>一个更生动的例子是设想一些迪土高中的视觉显示，光的显示中能够反映音乐并随着音</span> <span>乐而变化。在模拟通信系统中，电信号（不是光）是不断改变的。迪士高演奏设备的灯光随着音乐节拍而改变和闪烁。在这儿，灯光随着信号的电气特性而改变。在电信术语中，可以说真正的声音是由撞击声波而产生的。这种声波的撞击实际上是空气分子的移动。专业术语称为压缩和膨胀。</span></p>
<p>&nbsp;</p>
<p><span>人声是一种很特殊的事物。当我们说话时将产生声音。在一个相对很短的时间周期内，</span> <span>我们实际上将空气波撞击到一起许多次。举个例子。先产生一个模拟正弦波，然后将其转化为电当量。很简单，假如能得到语音产生的声</span> <span>音并基于音质和强度对其进行修改，就可以得到这个正弦波，如果用磁场将声音</span> <span>转化为电，这个波形就将被产生。在零电压基准线附近将电流作</span><span>360</span><span>度的旋转。零线周围这个</span><span>360</span><span>度的波形被称为一个</span><span>HZ</span><span>——得名于指明这一概念的电气工程师。波形在零线开始，并</span> <span>随着能量的增加而上升，最终达到一个峰值后便开始下降；电能也将从这一高度下降至零线，且继续在零线下降．直到零线下的一点（这被称为波形的负侧）。继续至这一侧的峰值电压后能量也将到达峰值，并开始向零线回升。波形完成了一个</span><span>360</span><span>度的完整周期，一个</span> <span>完整的周期构成</span><span>1HZ</span><span>。</span></p>
<p>&nbsp;</p>
<p><span>人的声带能以每秒</span><span>100</span><span>到</span><span>5000</span><span>次的速度将声波撞击到一起。简而言之就是人声每秒可</span> <span>产生高达</span><span>5000</span><span>个周期。当转化为电当量后就有</span><span>5000HZ</span><span>。为了避免麻烦可简写为</span><span>5kHZ </span><span>（意</span> <span>味着&#8220;干&#8221;）。有了电当量，我们就有了声波的类比或模拟。这是一个不停变化的值或电能。</span> <span>幅度和频率每秒都将变化</span><span>100</span><span>～</span><span>5000</span><span>次。这是电话公司在电信业的开始时所会处理的。然而后来他们又发现人声每秒将产生</span><span>300</span><span>～</span><span>3300</span><span>个周期变化，或者以</span><span>3kHZ</span><span>的电周期作为标准</span> <span>。和任何通信信道容量一样，电话公司不想也没必要给用户提供得太多，刚好满足能运载语音对话就可以了。这些年来，随着网络的扩展，电话公司将通话带宽限制在</span><span>3kHz</span><span>信道容量。这主要是基于成本上的考虑。给定了受限的带宽，我们怎样经过网络进行对话并产生合</span> <span>适的原始语言复原信号呢？并且怎样做才更便宜呢？产生的频率范围是从</span><span>300</span><span>～</span><span>33001KHZ</span><span>。电话公司因此也限制我们仅在此范围内使用信道。在使用射频（</span><span>RF</span><span>）频谱时，电话公司</span> <span>将所有容量分为</span><span>4kHz</span><span>的块。在每一个</span><span>41KHZ</span><span>块（电线或无线电信道）上，他们安装了</span><span>300</span><span>到</span><span> 3300</span><span>压的频率带通滤波器。落入</span><span>RF</span><span>频谱分配区内的任何信号都可以通过。区域外的任何信号</span> <span>都将被滤除掉。这称为限带信道。因为语音最高可达</span><span>51</span><span>&#8217;</span><span>riz</span><span>，所以也存在对话中超过了这一频</span> <span>率范围（如有</span><span>S</span><span>和</span><span>P</span><span>音的单词）并被滤波器削平的情况。这可能听起来不太合理，但它确实会</span> <span>使线路有点不清楚。人耳和电话机都没有足够的灵敏度，因而也不会有太大的问题。一旦声音</span> <span>的电当量被产生了（通过电话机或其他设备），电就被送到了线路。</span></p>
<p>&nbsp;</p>
<p><span>当通话在线路上进行时，线路对电信号的电阻将减小它的幅度。信号会变得越来越弱。</span> <span>能量的损失将最终导致电能全部被吸收，或使信号不能被识别，这称为电信号的&#8220;衰减&#8221;。</span> <span>在信号被消耗完和消失之前只能传输一定的距离。可比喻为一个接力运动员的训练，运动员</span> <span>尽全力地绕着</span><span> 1</span><span>／</span><span>4</span><span>英里的跑道跑，当运动员到达</span><span> 1</span><span>／</span><span>4</span><span>英里的终点时，所有的力量和能量已经</span> <span>耗尽，运动员也精疲力竭了。假如没有人去接棒，他不得不绕着跑道再跑下去，</span> <span>那么第二圈将永远跑不完。也就是说这个运动员将绕着跑道跑直到失去知觉倒在地上为止。</span> <span>为了保持信号在线路上传输，人们使用放大器来增强信号强度。这些放大器</span> <span>通常的间隔为</span><span> 15 000</span><span>～</span><span>18000</span><span>英尺。一般情况下，在用户位置和电话中心局之间只需要一个放大器（最多两个）。中心局通常离用户位置较近，平均只有</span><span>5</span><span>～</span><span>7</span><span>英里。只有在偏远的位置才离中心局较远。</span></p>
<p>&nbsp;</p>
<p><span>发生在线路上的第二种现象与传输同在。噪声（由线路损耗、电线破损、闪电、电感</span> <span>应、热等因素引入的）以白噪声或懂懂声的形式存在。它们同时开始并导致信号的变差。噪</span> <span>声总是存在干线路上，电缆故障会使它增大，进而导致信号变差。不幸的是，随着信号在线</span> <span>路上的传输，噪声和倍号开始混杂在一起。放大器不能从实际的对话中将噪声辨别出来。因</span> <span>此放大器不仅增强了信号，它也增强了噪音。这样就产生了更强、但也更嘈杂的信号。而这</span> <span>些信号又导致极为嘈杂的电路。放大的结果随着距离而积累。放大器使用得越多，最终得到的信号就越差。许多长话线路被不断地放大。这并不意味着电话公司不想做得更</span> <span>好，而是与设备、电气性能和经济三者的组合有关系。</span></p>
<p>&nbsp;</p>
<p><span>有意思的是如果模拟技术仍然正在被广泛使用的话，一些数字信号处理（</span><span>DSP</span><span>）中的最新进步可以用来在一定程度净化被放大的语音传输。但一种产生纯信号的更好的方法在许多年以前就得到了发展。</span></p>
<p>&nbsp;</p>
<p><span>关于这些知识可以参考大学通信专业的《数字信号处理》一书，该书上对信号如何转换有详细的讲解。</span></p>
<p>&nbsp;</p>
<p><span>2.2.2 </span><span>模拟线路和数字线路</span></p>
<p><span>模拟线路就是承载模拟信号的线路而数字线路就是承载数字信号的线路。电信通信网是一个多层结构的复杂网络，它是模拟线路与数字线路的混合体，一般情况下，到用户的电话线（用户线路）是模拟信号的，而电话局与电话局之间（局间线路）的线路有各种形式，模拟、数字线路都有。而数字线路上又可以承载很多具体的业务应用，比如</span><span>ISDN</span><span>、中国</span><span>No.1</span><span>号线路、中国</span><span>No.7</span><span>号线路等等。它们使用数字信号来传输信息。由于通信双方必须遵照某个标准来进行通信，为了通用，国际上对这些信号的含义制定了具体的标准，很多国家在使用由</span><span>CCITT</span><span>建议的系列标准。在计算机领域把这些标准称为协议，比如</span><span>TCP/IP</span><span>协议、</span><span>H.323</span><span>协议等等；而在电信领域则被叫做信令。比如中国</span><span>No.1</span><span>号信令、中国</span><span>7</span><span>号信令等。其实信令和协议基本是一样的含义，一般情况下可以把它们等同来理解。</span></p>
<p>&nbsp;</p>
<p><span>2.2.3</span><span>信令的基本概念</span></p>
<p><span>如果要详细的来描述信令，可能需要更厚的一本专门的书才能做到。在本节里，我们只简单地对信令的基本知识做讲解，以使得我们在做模拟卡的程序开发之前，对模拟线路的通信方式和相关的信令有一点清楚的认识。相反的，如果说得太多了就有可能会喧宾夺主，由于本书的目的是一个逐步渐进引导学习的过程，不可能罗列太多的概念，起结果不但不能使学习过程更轻松，反而会适得其反使概念更模糊不清。</span></p>
<p>&nbsp;</p>
<p><span>上一个小节提到了，信令是通信双方用来控制通信过程的一种手段。下面举例来说明一个典型的信令过程：</span></p>
<p>&nbsp;</p>
<p><span>&#216; </span><span>当用户把电话听筒摘起的时候，电话机便向交换机发出一个摘机信号</span></p>
<p>&nbsp;</p>
<p><span>&#216; </span><span>交换机接收到此信号后，向用户的话机送拨号音&#8220;嗡&#8230;&#8230;&#8221;</span></p>
<p>&nbsp;</p>
<p><span>&#216; </span><span>此时开始拨号，并等待对方振铃</span></p>
<p>&nbsp;</p>
<p><span>&#216; </span><span>对方摘机，通话开始</span></p>
<p>&nbsp;</p>
<p><span>&#216; </span><span>通话完毕，挂机</span></p>
<p>&nbsp;</p>
<p><span>&#216; </span><span>系统释放线路的占用，恢复原样</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>在上面的过程里所提到的摘机、允许拨号信息和被叫的回铃音等等，主要是用来建立双方的通信关系，象这种用以建立、维持和解除通信关系的信息被统称为信令。</span></p>
<p>&nbsp;</p>
<p><span>一个用户在通过用户设备、交换设备、传输设备和另一用户通信的过程中，要用到许多的信令，为了更深刻的描述这一过程，下面使用图示来说明两个用户间如何通过交换局来进行通信的例子：</span></p>
<p>&nbsp;</p>
<p><span>主叫电话</span></p>
<p>&nbsp;</p>
<p><span>被叫电话</span></p>
<p>&nbsp;</p>
<p><span>发端局</span></p>
<p>&nbsp;</p>
<p><span>终端局</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>用户线</span> <span>中继线</span> <span>用户线</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>摘机信令</span></p>
<p>&nbsp;</p>
<p><span>拨号音</span></p>
<p>&nbsp;</p>
<p><span>拨号</span> <span>占用信令</span></p>
<p>&nbsp;</p>
<p><span>选择信令</span></p>
<p>&nbsp;</p>
<p><span>回铃音</span> <span>振铃信令</span></p>
<p>&nbsp;</p>
<p><span>应答信令</span> <span>摘机应答</span></p>
<p>&nbsp;</p>
<p><span>通话过程</span></p>
<p>&nbsp;</p>
<p><span>复原（挂机）</span> <span>后向挂机信令</span> <span>复原（挂机）</span></p>
<p>&nbsp;</p>
<p><span>前向拆线信令</span></p>
<p>&nbsp;</p>
<p><span>拆线证实信令</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>用户信令</span></p>
<p>&nbsp;</p>
<p><span>局间信令</span></p>
<p>&nbsp;</p>
<p><span>通话持续过程</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>用户通话流程</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>如上图所示：</span></p>
<p>&nbsp;</p>
<p><span>&#216; </span><span>当主叫用户摘机时，摘机信令被发送到发端局</span></p>
<p>&nbsp;</p>
<p><span>&#216; </span><span>发端局立即向主叫送拨号音，用户开始拨号，送出拨号信令</span></p>
<p>&nbsp;</p>
<p><span>&#216; </span><span>发端局根据电话号码选择路由和中继线路，向终端局发送中继占用信令</span></p>
<p>&nbsp;</p>
<p><span>&#216; </span><span>占用证实后发端局将被叫号码发送到终端局</span></p>
<p>&nbsp;</p>
<p><span>&#216; </span><span>终端局根据被叫的线路状态对被叫的线路震铃，并给主叫送回铃音或忙音</span></p>
<p>&nbsp;</p>
<p><span>&#216; </span><span>当被叫摘机时，摘机信令从被叫送到终端局并被转发到发端局，开始记费</span></p>
<p>&nbsp;</p>
<p><span>&#216; </span><span>双方开始通话</span></p>
<p>&nbsp;</p>
<p><span>&#216; </span><span>如果被叫用户先挂机，挂机信令由终端局发向发端局，发端局通知主叫挂机；如果主叫先挂机，发端局向终端局立即拆线并发送一个拆线信号给终端局，通知终端局拆线，终端局拆线后发送一个拆线证实信号给发端局</span></p>
<p>&nbsp;</p>
<p><span>&#216; </span><span>一切设备复原</span></p>
<p>&nbsp;</p>
<p><span>以上一个简单的通信模型，实际情况要比这个复杂得多。传输的信令数据的格式可能有所不同，比如直流脉冲、音频编码、分组消息等。</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>用来规范化信令传输过程的规则叫做信令方式。</span></p>
<p>&nbsp;</p>
<p><span>用来完成特定信令方式的全体通信设备总称为信令系统。</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>2.2.4 </span><span>信令的分类</span></p>
<p><span>可以将信令分为以下三类：</span></p>
<p>&nbsp;</p>
<p><span>1. </span><span>按照信令的传送方向</span> <span>&#8211;</span> <span>分为前向信令和后向信令两类。在通信过程中，主叫发出的信令叫做前向信令，发向主叫的信令叫做后项信令，区别如下：</span></p>
<p>&nbsp;</p>
<p><span>主叫发出信令</span> <span>&#8211;</span> <span>前向信令</span></p>
<p>&nbsp;</p>
<p><span>主叫接收信令</span> <span>&#8211;</span> <span>后项信令</span></p>
<p>&nbsp;</p>
<p><span>被叫发出信令</span> <span>&#8211;</span> <span>后项信令</span></p>
<p>&nbsp;</p>
<p><span>被叫接收信令</span> <span>&#8211;</span> <span>前向信令</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>2. </span><span>按照信令的工作范围</span></p>
<p>&nbsp;</p>
<p><span>按照工作范围，可将信令分为用户线信令和局间信令两类。</span></p>
<p>&nbsp;</p>
<p><span>用户线信令</span><span> - </span><span>也可叫用户信令，它是用户和交换局间使用的信令，它们在用户使用的模拟线路上传送。用户线信令主要包括：用户状态信令，选择信令、铃流和信号音。用户状态信令是由电话机的叉簧产生的，它闭合或切断支流电路，用以启动和恢复巨内设备，包括摘机信令和挂机信令，是直流信号；选择信令是用户拨出的被叫用户的电话号码数字信令，在使用号盘话机及直流脉冲话机的情况下，发出支流脉冲信令；在使用多频按键话机的情况下，发出双音多频信令（即</span><span>DTMF</span><span>信令）；铃流及信号音是交换机向用户设备发出的震铃信号或在话机的受话器中可以听到的声音：拨号音、回铃音、忙音、长途通知音、空号音等等。用户线比较简单，长期以来这部分信令的内容及功能一直没有大的变化。</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>局间信令</span> <span>&#8211;</span> <span>是交换机与交换机之间传输的信令，这中信令比较复杂，这种信令包括</span><span> </span></p>
<p>&nbsp;</p>
<p><span>了监视、选择和网络管理三种功能。此处不做讨论。请参考相关的书籍。</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>3. </span><span>按照信令的传送信道</span></p>
<p>&nbsp;</p>
<p><span>按照信令传送的信道来划分可分为随路信令（</span><span>CAS</span><span>）和公共信道信令（也叫做共路信令方式）。</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>如上面所说在模拟信令中，拨号和电话机按键信息使用两种方式的信号方式，脉冲和</span><span>DTMF</span><span>信令，一般现在的电话机都可以使用脉冲和</span><span>DTMF</span><span>信令两种方式，由于这两种方式在模拟卡编程中是一个重要的概念，我们使用下一节来讲解。</span></p>
<p>&nbsp;</p>
<p><span>2.2.5 </span><span>脉冲拨号和</span><span>DTMF</span><span>拨号</span></p>
<p><span>脉冲就是通过话机控制开关电流来形成直流脉冲的一种传送数字信息的方式；所谓</span><span>DTMF</span><span>是指</span><span>Dual-Tone Multiple Frequence</span><span>（双音多频）的意思，它是由两个不同频率的信号音来组合成一个信号音而成的。</span></p>
<p>&nbsp;</p>
<p><span>模拟用户线路使用脉冲和</span><span>DTMF</span><span>来传输代表电话键的信号。下面是这些信号音的列表：</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>2.3 </span><span>计算机语音技术相关标准</span></p>
<p><span>CTI</span><span>跨越计算机与电话两个领域，怎样将它们结合起来，怎样为它们的结合创建新的平台开发软件？标准无疑成为</span><span>CTI</span><span>发展中最至关重要的因素。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>ECMA</span><span>在</span><span>1988</span><span>年开始制定在计算机与交换机之间使用的标准协议，被称为计算机支持的电信应用（</span><span>CSTA</span><span>），这项标准的第一版和第二版分别于</span><span>1992</span><span>年和</span><span>1995</span><span>年得到了批准，该项标准侧重于程控交换机客户端的</span><span>CTI</span><span>解决方案。目前，</span><span>CSTA</span><span>已成为</span><span>PBX</span><span>和</span><span>ACD</span><span>等专用领域内的主导标准。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>1989</span><span>年，美国国家标准学会开发了交换计算机应用接口（</span><span>SCAI</span><span>），</span><span>SCAI</span><span>的第一版和第二版分别于</span><span>1993</span><span>年和</span><span>1995</span><span>年得到批准。该项标准特别侧重于程控交换机中公共网络（</span><span>Centrex</span><span>）方面的</span><span>CTI</span><span>解决方案。目前，这一协议的研究工作已停，其功能略逊于</span><span>CSTA</span><span>，但它的定义更为严格。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>ITU</span><span>曾致力于开发一种国际解决方案：</span><span>TASC</span><span>———用于交换机和计算机的电信应用，由于种种原因，</span><span>TASC</span><span>行动于</span><span>1994</span><span>年被束之高阁。</span></p>
<p>&nbsp;</p>
<p><span>　　目前，</span><span>CTI</span><span>领域中最多的标准还是应用编程接口（</span><span>API</span><span>）。提供者既有计算机硬件厂商，如</span><span>IBM</span><span>的</span><span>CallPath</span><span>和</span><span>Tandem</span><span>公司的</span><span>CAM</span><span>，又有软件供应商，如微软的</span><span>TAPI</span><span>和</span><span>Novell</span><span>的</span><span>TSAPI</span><span>，也有一些交换机供应商。</span></p>
<p>&nbsp;</p>
<p><span>　　微软的</span><span>Windows Telephony API</span><span>就是用</span><span>Windows</span><span>应用程序控制通信设备，如</span><span>PBX</span><span>等。</span><span>TAPI</span><span>提供了各种级别的功能：从简单的电话到全面扩展的电话。</span><span>Windows 3</span><span>．</span><span>X</span><span>将</span><span>TAPI</span><span>作为开发人员的工具箱提供；</span><span>Windows 95</span><span>和</span><span>Windows NT</span><span>将</span><span>TAPI</span><span>作为其标准组件提供。</span></p>
<p>&nbsp;</p>
<p><span>　　由于</span><span>Novell</span><span>公司目前在局域网操作系统市场上的统治地位，</span><span>Novell</span><span>电话服务</span><span>APT</span><span>（</span><span>TSAPI</span><span>）十分重要。</span><span>TSAPI</span><span>是</span><span>Novell</span><span>与</span><span>AT</span><span>＆</span><span>T</span><span>合作开发的，适用于</span><span>26</span><span>种交换机，于</span><span>1992</span><span>年发布。</span><span>TSAPI</span><span>是用于</span><span>CTI</span><span>的客户机／服务器方案，建立于</span><span>CSTA</span><span>协议定义基础之上。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>IBM</span><span>公司的</span><span>CTI API</span><span>是</span><span>CallPath</span><span>服务架构（</span><span>CSA</span><span>）的一部分，</span><span>1994</span><span>年，发布了支持客户机、服务器操作的升级版本。目前，</span><span>CallPath</span><span>支持的交换机数量最多，而且</span><span>IBM</span><span>的交换服务器中的交换接口软件很可能会形成</span><span>Versit TSAPI</span><span>的基础。</span></p>
<p>&nbsp;</p>
<p><span>　　尽管</span><span>TAPI</span><span>具有一些媒体控制功能，但上述</span><span>API</span><span>均着重致力于电话控制。媒体控制包括从设置一个语音识别资源的能力，到对视频显示选择的控制。在这方面，专注于</span><span>CTI</span><span>的厂商</span><span>Dialogic</span><span>以其信号处理系统架构（</span><span>SCSA</span><span>）开始从事这一领域的研究工作。</span><span>1995</span><span>年，标准被提交给新成立的企业计算机电话论坛（</span><span>ECTF</span><span>）。该论坛由范围广泛的</span><span>CTI</span><span>厂商组成，这些厂商共同对</span><span>SCSA</span><span>进行了开发和改造，将其发展成为一种媒体控制</span><span>API</span><span>标准，称为</span><span>S</span><span>．</span><span>100</span><span>，于</span><span>1996</span><span>年发布。媒体控制</span><span>API</span><span>的主要应用领域是建立基于</span><span>PC</span><span>机的媒体处理系统及基于</span><span>PC</span><span>机的语音处理系统的开发。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>1994</span><span>年，</span><span>AT</span><span>＆</span><span>T</span><span>、</span><span>Apple</span><span>、</span><span>IBM</span><span>和</span><span>Siemens</span><span>公司组成一个名为</span><span>Versit</span><span>的业界组织。该组织的目标是共同开发一种用于</span><span>CTI</span><span>的客户机／服务器架构，并将涵盖电话、</span><span>PBX</span><span>、计算机、网络、服务器和</span><span>PDA</span><span>的标准，它的目标还扩展到实现个人数据产的交换和来自不同厂商的语音、公告板和视频产品的相互连接。</span><span>Novell</span><span>公司则与</span><span>Versit</span><span>共同开发了</span><span>Versit TSAPI</span><span>。目前，</span><span>Versit TSAPI</span><span>或</span><span>S</span><span>．</span><span>100</span><span>能否成为业界的标准尚不清楚。</span></p>
<p>&nbsp;</p>
<p><span>在多媒体通信中，还有一个重要的业界组织就是国际多媒体电信会议协会（</span><span>IMTC</span><span>），</span><span>IMTC</span><span>的基本目标就是将所有参与多媒体电信会议产品和服务开发的组织联合起来，帮助制订所要求的标准并推动它的广泛采用。该协会提供了对</span><span>ITU</span><span>所采纳的</span><span>H</span><span>．</span><span>320</span><span>和</span><span>T</span><span>．</span><span>120</span><span>系列电信会议标准的地支持，还准备为</span><span>T</span><span>．</span><span>120</span><span>和</span><span>H</span><span>．</span><span>320</span><span>通信协议开发</span><span>API</span><span>。</span></p>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/hengheng123456789/aggbug/120748.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hengheng123456789/" target="_blank">哼哼</a> 2007-05-29 18:10 <a href="http://www.blogjava.net/hengheng123456789/archive/2007/05/29/120748.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>