﻿<?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-大鸟的学习乐园-文章分类-JAVA</title><link>http://www.blogjava.net/dunkbird/category/30985.html</link><description>路漫漫其修远兮，吾将上下而求索
</description><language>zh-cn</language><lastBuildDate>Sun, 05 Apr 2015 15:34:59 GMT</lastBuildDate><pubDate>Sun, 05 Apr 2015 15:34:59 GMT</pubDate><ttl>60</ttl><item><title>（转）关于Spring中ApplicationContext的说明</title><link>http://www.blogjava.net/dunkbird/articles/424061.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Thu, 02 Apr 2015 07:32:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/424061.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/424061.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/424061.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/424061.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/424061.html</trackback:ping><description><![CDATA[<div>http://blog.sina.com.cn/s/blog_5d6571df0100yaa5.html<br /><br /><p style="margin-top: 0px; margin-right: 0px; margin-left: 0px; padding: 0px; border: 0px; list-style: none; word-wrap: normal; word-break: normal; color: #464646; font-family: simsun; background-color: #bcd3e5;">一、简单的用ApplicationContext做测试的话,获得Spring中定义的Bean实例(对象).可以用:</p><p style="margin-top: 0px; margin-right: 0px; margin-left: 0px; padding: 0px; border: 0px; list-style: none; word-wrap: normal; word-break: normal; color: #464646; font-family: simsun; background-color: #bcd3e5;">ApplicationContext ac = new ClassPathXmlApplicationC<wbr><wbr>ontext("applicationContext.xml");<br />RegisterDAO registerDAO = (RegisterDAO)ac.getBean("RegisterDAO");</p><p style="margin-top: 0px; margin-right: 0px; margin-left: 0px; padding: 0px; border: 0px; list-style: none; word-wrap: normal; word-break: normal; color: #464646; font-family: simsun; background-color: #bcd3e5;">如果是两个以上:<br />ApplicationContext ac = new ClassPathXmlApplicationC<wbr><wbr>ontext(new String[]{"applicationContext.xml","dao.xml"});<br /></p><p style="margin-top: 0px; margin-right: 0px; margin-left: 0px; padding: 0px; border: 0px; list-style: none; word-wrap: normal; word-break: normal; color: #464646; font-family: simsun; background-color: #bcd3e5;">或者用通配符:<br />ApplicationContext ac = new ClassPathXmlApplicationC<wbr><wbr>ontext("classpath:/*.xml");</p><p style="margin-top: 0px; margin-right: 0px; margin-left: 0px; padding: 0px; border: 0px; list-style: none; word-wrap: normal; word-break: normal; color: #464646; font-family: simsun; background-color: #bcd3e5;"><br />二、ClassPathXmlApplicationC<wbr><wbr>ontext[只能读放在web-info/classes目录下的配置文件]和FileSystemXmlApplication<wbr><wbr>Context的区别<br /></p><p style="margin-top: 0px; margin-right: 0px; margin-left: 0px; padding: 0px; border: 0px; list-style: none; word-wrap: normal; word-break: normal; color: #464646; font-family: simsun; background-color: #bcd3e5;">classpath:前缀是不需要的,默认就是指项目的classpath路径下面;<br />如果要使用绝对路径,需要加上file:前缀表示这是绝对路径;</p><p style="margin-top: 0px; margin-right: 0px; margin-left: 0px; padding: 0px; border: 0px; list-style: none; word-wrap: normal; word-break: normal; color: #464646; font-family: simsun; background-color: #bcd3e5;">对于FileSystemXmlApplication<wbr><wbr>Context:<br />默认表示的是两种:</p><p style="margin-top: 0px; margin-right: 0px; margin-left: 0px; padding: 0px; border: 0px; list-style: none; word-wrap: normal; word-break: normal; color: #464646; font-family: simsun; background-color: #bcd3e5;">1.没有盘符的是项目工作路径,即项目的根目录;<br />2.有盘符表示的是文件绝对路径.</p><p style="margin-top: 0px; margin-right: 0px; margin-left: 0px; padding: 0px; border: 0px; list-style: none; word-wrap: normal; word-break: normal; color: #464646; font-family: simsun; background-color: #bcd3e5;">如果要使用classpath路径,需要前缀classpath:</p><p style="margin-top: 0px; margin-right: 0px; margin-left: 0px; padding: 0px; border: 0px; list-style: none; word-wrap: normal; word-break: normal; color: #464646; font-family: simsun; background-color: #bcd3e5;">public class HelloClient {</p><p style="margin-top: 0px; margin-right: 0px; margin-left: 0px; padding: 0px; border: 0px; list-style: none; word-wrap: normal; word-break: normal; color: #464646; font-family: simsun; background-color: #bcd3e5;">protected static final Log log = LogFactory.getLog(HelloClient.class);</p><p style="margin-top: 0px; margin-right: 0px; margin-left: 0px; padding: 0px; border: 0px; list-style: none; word-wrap: normal; word-break: normal; color: #464646; font-family: simsun; background-color: #bcd3e5;">public static void main(String[] args) {<br />// Resource resource = new ClassPathResource("appcontext.xml");<br />// BeanFactory factory = new XmlBeanFactory(resource);</p><p style="margin-top: 0px; margin-right: 0px; margin-left: 0px; padding: 0px; border: 0px; list-style: none; word-wrap: normal; word-break: normal; color: #464646; font-family: simsun; background-color: #bcd3e5;">// 用classpath路径<br />// ApplicationContext factory = new ClassPathXmlApplicationC<wbr><wbr>ontext("classpath:appcontext.xml");<br />// ApplicationContext factory = new ClassPathXmlApplicationC<wbr><wbr>ontext("appcontext.xml");</p><p style="margin-top: 0px; margin-right: 0px; margin-left: 0px; padding: 0px; border: 0px; list-style: none; word-wrap: normal; word-break: normal; color: #464646; font-family: simsun; background-color: #bcd3e5;">// ClassPathXmlApplicationC<wbr><wbr>ontext使用了file前缀是可以使用绝对路径的<br />// ApplicationContext factory = new ClassPathXmlApplicationC<wbr><wbr>ontext("file:F:/workspace/example/src/appcontext.xml");</p><p style="margin-top: 0px; margin-right: 0px; margin-left: 0px; padding: 0px; border: 0px; list-style: none; word-wrap: normal; word-break: normal; color: #464646; font-family: simsun; background-color: #bcd3e5;">// 用文件系统的路径,默认指项目的根路径<br />// ApplicationContext factory = new FileSystemXmlApplication<wbr><wbr>Context("src/appcontext.xml");<br />// ApplicationContext factory = new FileSystemXmlApplication<wbr><wbr>Context("webRoot/WEB-INF/appcontext.xml");<br /><br /></p><p style="margin-top: 0px; margin-right: 0px; margin-left: 0px; padding: 0px; border: 0px; list-style: none; word-wrap: normal; word-break: normal; color: #464646; font-family: simsun; background-color: #bcd3e5;">// 使用了classpath:前缀,这样,FileSystemXmlApplication<wbr><wbr>Context也能够读取classpath下的相对路径<br />// ApplicationContext factory = new FileSystemXmlApplication<wbr><wbr>Context("classpath:appcontext.xml");<br />// ApplicationContext factory = new FileSystemXmlApplication<wbr><wbr>Context("file:F:/workspace/example/src/appcontext.xml");</p><p style="margin-top: 0px; margin-right: 0px; margin-left: 0px; padding: 0px; border: 0px; list-style: none; word-wrap: normal; word-break: normal; color: #464646; font-family: simsun; background-color: #bcd3e5;">// 不加file前缀<br />ApplicationContext factory = new FileSystemXmlApplication<wbr><wbr>Context("F:/workspace/example/src/appcontext.xml");<br />IHelloWorld hw = (IHelloWorld)factory.getBean("helloworldbean");<br />log.info(hw.getContent("luoshifei"));<br />}<br />}</p></div><img src ="http://www.blogjava.net/dunkbird/aggbug/424061.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2015-04-02 15:32 <a href="http://www.blogjava.net/dunkbird/articles/424061.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JavaGUI应用程序部署</title><link>http://www.blogjava.net/dunkbird/articles/312169.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Fri, 05 Feb 2010 23:37:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/312169.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/312169.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/312169.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/312169.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/312169.html</trackback:ping><description><![CDATA[<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">JavaGUI应用程序部署<br />
</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt"><br />
JavaGUI程序发布分类</span></span></span><br />
<span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;1)&nbsp; Applet：可以嵌入到浏览器中，通过网页的方式展示给用户</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;2)&nbsp; application ：有两种发布方式</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;&nbsp;&#252; 打包成jar包通过bat的方式运行，或者通过第三方软件打成exe(后续会再详细介绍)</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;&nbsp;&#252; 通过Java Web Start的方式发布到服务器端，通过JNLP运行</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;相对来说第二种方式可能更好一些，免除了更新的麻烦。</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;用applet或者jws的方式发布，大部分都需要数字签名。<br />
</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt"><br />
<br />
为什么要签名</span></span></span><br />
<span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;其实签名不是必须的，如果你的程序只是单纯的绘图，显示，只要不访问网络资源也不访问本地文件，是不用签名的，<br />
&nbsp;但是如果要访问本地或网上资源就必须签名，<br />
&nbsp;比如读取本地文件或者访问数据库，这是由java的沙箱机制决定的，即jvm内部有一组安全检查规则，要通过检查之后才能访问特定资源。</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;如果要突破这个规则，可以有两个方法:</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;1) 修改jre权限文件如下</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;&nbsp;java.policy为grant {<br />
&nbsp;&nbsp;&nbsp;permission java.security.AllPermission;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;};</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;&nbsp;一般权限文件的目录如下C:"Program Files"Java"jre6"lib"security</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;&nbsp;但是修改每个客户端的权限文件，无论从时间还是操作上都是很麻烦的。</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;2)&nbsp; 签名，意思就是告诉用户，这个程序是谁发布的，是不是能信任，如果客户确定，ok，这个applet或者jws就可以访问外部资源了。<br />
<br />
</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt"><br />
如何签名</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;1)首先确保你已经完全安装了Java2的环境，有keytool工具，它位于JDK的bin目录下。这一般不会有问题。</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;2)到Dos状态下，进入你需发布应用程序的jar包所在的目录，运行下面这句话<br />
&nbsp;&nbsp; keytool -genkey -keystore myKeystore -alias jwstest -validity 1000<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 它将会提示你输入用户名、密码等，按照提示随便输入即可，不输入直接回车即可，<br />
&nbsp;&nbsp; 但一定要记住密码。运行结束它将会在当前路径下创建名为myKeystore的文件。</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;3)如果你想查看一下刚才生成的myKeystore文件的内容，可以使用下面这句话：<br />
&nbsp;&nbsp;keytool -list -keystore myKeystore<br />
&nbsp;&nbsp;显示出来应该类似如下：<br />
&nbsp;&nbsp;Keystore type: jks<br />
&nbsp;&nbsp;Keystore provider: SUN<br />
&nbsp;&nbsp;Your keystore contains 1 entry:<br />
&nbsp;&nbsp;jwstest, Tue Nov 23 19:29:32 PST 2001, keyEntry,<br />
&nbsp;&nbsp;Certificate fingerprint (Test):<br />
&nbsp;&nbsp;C3:A9:CD:F3:D3:AC:4D:3F:3C:5B:AF:9E:CF:0D:46:5C</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;4)对你需发布应用程序的jar包进行签名，运行下面这句话：<br />
&nbsp;&nbsp;jarsigner -keystore myKeystore yourtest.jar jwstest<br />
&nbsp;&nbsp;其中yourtest.jar是你的jar包名，你需要修改它，别的就不必修改了。<br />
&nbsp;&nbsp;运行时会提示你输入密码，就是你刚才在生成myKeystore文件时设定的密码。<br />
</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt"><br />
<br />
如果有很多jar包怎么办</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;在开发的过程中很可能会引用到第三方的jar包，而第三方的jar包又可能引用到其它的，所以可能有很多的jar包，需要和applet一起发布，有两个方法<br />
&nbsp;&nbsp;1) 分别打包签名，使用于包比较少，比如只有3、4个的情况<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2) 只 把applet的jar包签名，让用户确认访问授权，applet已经被用户授权，那么就可以在applet里改变安全管理器（SecurityManager）<br />
&nbsp;&nbsp;&nbsp;只需要继承SecurityManager类，创建自己的安全管理器类，然后覆盖checkPermission方法，允许访问任何资源。<br />
&nbsp;&nbsp;&nbsp;在applet的init方法中调用System.setSecurityManager把安全管理器设置为我们自定义的即可。</span></span></span></p>
<p><br />
<span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;class CustomManager extends SecurityManager {<br />
&nbsp;&nbsp;public void checkPermission(Permission perm, Object context) {<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;public void checkPermission(Permission perm) {<br />
&nbsp;&nbsp;}<br />
&nbsp;}<br />
&nbsp; </span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">其它一些相关资料如下</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;JDK中keytool常用命令</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;-genkey&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在用户主目录中创建一个默认文件".keystore",还会产生一个mykey的别名，mykey中包含用户的公钥、私钥和证书 <br />
&nbsp;-alias&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 产生别名<br />
&nbsp;-keystore&nbsp;&nbsp;&nbsp; 指定密钥库的名称(产生的各类信息将不在.keystore文件中<br />
&nbsp;-keyalg&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 指定密钥的算法&nbsp;&nbsp;&nbsp; <br />
&nbsp;-validity&nbsp;&nbsp;&nbsp; 指定创建的证书有效期多少天<br />
&nbsp;-keysize&nbsp;&nbsp;&nbsp;&nbsp; 指定密钥长度<br />
&nbsp;-storepass&nbsp;&nbsp; 指定密钥库的密码<br />
&nbsp;-keypass&nbsp;&nbsp;&nbsp;&nbsp; 指定别名条目的密码<br />
&nbsp;-dname&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 指定证书拥有者信息 例如：&nbsp; "CN=sagely,OU=atr,O=szu,L=sz,ST=gd,C=cn"<br />
&nbsp;-list&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 显示密钥库中的证书信息&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; keytool -list -v -keystore sage -storepass ....<br />
&nbsp;-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 显示密钥库中的证书详细信息<br />
&nbsp;-export&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将别名指定的证书导出到文件&nbsp; keytool -export -alias caroot -file caroot.crt<br />
&nbsp;-file&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 参数指定导出到文件的文件名<br />
&nbsp;-delete&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 删除密钥库中某条目&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; keytool -delete -alias sage -keystore sage<br />
&nbsp;-keypasswd&nbsp;&nbsp; 修改密钥库中指定条目口令&nbsp;&nbsp;&nbsp; keytool -keypasswd -alias sage -keypass .... -new .... -storepass ... -keystore sage<br />
&nbsp;-import&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将已签名数字证书导入密钥库&nbsp; keytool -import -alias sage -keystore sagely -file sagely.crt <br />
&nbsp;&nbsp;&nbsp;&nbsp; 导入已签名数字证书用keytool -list -v 以后可以明显发现多了认证链长度，并且把整个CA链全部打印出来。</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Keytool 是安全钥匙与证书的管理工具.它管理一个存储了私有钥匙和验证相应公共钥匙的与它们相关联的X.509 证书链的keystore(相当一个数据库).</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Keytool 是一个有效的安全钥匙和证书的管理工具. 它能够使用户使用数字签名来管理他们自己的私有/公共钥匙对,管理用来作自我鉴定的相关的证书,管理数据完整性和鉴定服务.它还能使用户在通信时缓存它们的公共钥匙.</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;一个证书是某一实体(个人,公司等)的数字签名,指出其他实体的公共钥匙(或其他信息)的详细的值.当数据被签名后,这个签名信息被用来检验数据的完整性和真实性.完整性指数据没有被修改和篡改,真实性指数据从任何产生和签名的一方真正的传输到达.</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Keytool 把钥匙和证书储存到一个keystore.默任的实现keystore的是一个文件.它用一个密码保护钥匙.</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;而另外的一个工具jarsigner用keystore中的信息产生或检验Java aRchive(jar文件)中的数字签名.</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Keystore有两个不同的入口:</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;1.钥匙入口:保存了非常敏感的加密的钥匙信息,并且是用一个保护的格式存储以防止未被授权的访问.以这种形式存储的钥匙是秘密钥匙,或是一个对应证书链中公有钥匙的私有钥匙.</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;2.信任证书入口:包含一个属于其他部分的单一公共钥匙证书.它之所以被称为"信任证书",是因为keystore信任的证书中的公共钥匙真正属于证书所有者的身份识别.</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Keystore的别名:</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;所有的keystore入口(钥匙和信任证书入口)是通过唯一的别名访问.别名是 不区分大小写的.如别名Hugo和hugo指向同一个keystore入口.</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;可以在加一个入口到keystore的时候使用-genkey参数来产生一个钥匙对(公共钥匙和私有钥匙)时指定别名.也可以用-import参数加一个证书或证书链到信任证书.</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;如:</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;keytool -genkey -alias duke -keypass dukekeypasswd</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;其中duke为别名,dukekeypasswd为duke别名的密码.这行命令的作用是产生一个新的公共/私有钥匙对.</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;假如你想修改密码,可以用:</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;keytool -keypasswd -alias duke -keypass dukekeypasswd -new newpass</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;将旧密码dukekeypasswd改为newpass.</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Keystore的产生:</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;1.当使用-genkey 或-import或-identitydb命令添加数据到一个keystore,而当这个keystore不存在时,产生一个keystore.默认名是.keystore,存放到user-home目录.</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;2.当用-keystore指定时,将产生指定的keystore.</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Keystore的实现:</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Keytool 类位于java.security包下,提供一个非常好的接口去取得和修改一个keystore中的信息. 目前有两个命令行:keytool和jarsinger,一个GUI工具Policy 可以实现keystore.由于keystore是公开的,用户可以用它写一些额外的安全应用程序.</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Keystore还有一个sun公司提供的內在实现.它把keystore作为一个文件来实现.利用了一个keystore类型(格式)"JKS".它用单独的密码保护每一个私有钥匙.也用可能不同的密码保护整个keystore的完整性.</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;支持的算法和钥匙大小:</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;keytool允许用户指定钥匙对和注册密码服务供应者所提供的签名算法.缺省的钥匙对产生算法是"DSA".假如私有钥匙是"DSA"类型,缺省签名算法是"SHA1withDSA",假如私有钥匙是"RSA"类型,缺省算法是"MD5withRSA".</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;当产生一个DSA钥匙对,钥匙必须在512-1024位之间.对任何算法的缺省钥匙大小是1024位.</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;证书:</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;一个证书是一个实体的数字签名,指出其他实体的公共钥匙有明确的值.</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;1.公共钥匙 :是同一个详细的实体的数字关联,并有意让所有想同这个实体发生信任关系的其他实体知道.公共钥匙用来检验签名;</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;2.数字签名:假如数据已被签名,并用身份存储在一个实体中,一个签名能够证明这个实体知道这个数据.这个数据用实体私有钥匙签名并递交;</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;3.身份:知道实体的方法.在一些系统中身份是公共钥匙,其他系统中可以是从一个X.509名字的邮件地址的Unix UID来的任何东西;</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;4.签名:一个签名用用实体私有钥匙来计算某些加密数据;</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;5.私有钥匙:是一些数字,每一个私有钥匙只能被特定的拥有该私有钥匙的实体知道.私有和公共钥匙存在所有用公共钥匙加密的系统的钥匙对中.一个公共钥匙加密(如DSA),一个私有钥匙与一个正确的公共钥匙通信.私有钥匙用来计算签名.</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;6.实体:一个实体可以是一个人,一个组织,一个程序,一台计算机,一个商业,一个银行,或其他你想信任的东西.</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Keytool应用实例:</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;1.产生一个keystore:</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;keytool -genkey -alias User(keystore的别名) -keyalg RSA -validity 7 -keystore keystore(指定keystore).</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;运行这个命令,系统提示:</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Enter keystore password:yourpassword(输入密码)</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;What is your first and last name?</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;[Unknown]: your name(输入你的名字)</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;What is the name of your organizational unit?</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;[Unknown]:your organizational(输入你所在组织单位的名字)</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;What is the name of your organization?</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;[Unknown]:your organization name (输入你所在组织的名字)</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;What is the name of your City or Locality?</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;[Unknown]:your city name(输入所在城市的名字)</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;What is the name of your State or Province?</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;[Unknown]:your provice name(输入所在省份名字)</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;What is the two-letter country code for this unit?</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;[Unknown]:cn(输入国家名字)</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Is CN=your name, OU=your organizaion, O="your organization name",</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;L=your city name, ST=your province name, C=cn correct?</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;[no]: yes</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;2.检查一个keystore:</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;keytool -list -v -keystore keystore</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Enter keystore password:your password(输入密码)</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;将显示keystore內容如:</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Keystore type: jks</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Keystore provider: SUN</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Your keystore contains 1 entry</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Alias name: yourname</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Creation date: Dec 20, 2001</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Entry type: keyEntry</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Certificate chain length: 1</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Certificate[1]:</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Owner: CN=yourname, OU=your organization, O="your organization name",</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;L=your city name, ST=your province name, C=CN</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Issuer: CN=Duke, OU=Java Software, O="Sun Microsystems, Inc.", L=Palo Alto, ST=CA, C=US</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Serial number: 3c22adc1</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Valid from: Thu Dec 20 19:34:25 PST 2001 until: Thu Dec 27 19:34:25 PST 2001</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Certificate fingerprints:</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;MD5: F1:5B:9B:A1:F7:16:CF:25:CF:F4:FF:35:3F:4C:9C:F0</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;SHA1: B2:00:50:DD:B6:CC:35:66:21:45:0F:96:AA:AF:6A:3D:E4:03:7C:74</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;3.输出keystore到一个文件:testkey:</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;keytool -export -alias duke -keystore keystore -rfc -file testkey</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;系统输出:</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Enter keystore password:your password(输入密码)</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Certificate stored in file &lt; td&gt;</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;4.输入证书到一个新的truststore:</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;keytool -import -alias dukecert -file testkey -keystore truststore</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;Enter keystore password:your new password.(输入truststore新密码)</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;5.检查truststore:</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;keytool -list -v -keystore truststore</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;系统将显示truststore的信息.</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;现在可以用适当的keystore运行你的应用程序.如:</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;java -Djavax.net.ssl.keyStore=keystore -Djavax.net.ssl.keyStorePassword=password Server</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;和: java -Djavax.net.ssl.trustStore=truststore</span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;-Djavax.net.ssl.trustStorePassword=trustword Client</span></span></span></p>
<p><br />
<span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;（转）by </span></span></span></p>
<p><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;&nbsp;&nbsp;张涛<br />
&nbsp;&nbsp;&nbsp; <a href="mailto:zht_dream@hotmail.com">zht_dream@hotmail.com</a></span></span></span><span style="color: #008000"><span style="font-family: 宋体"><span style="font-size: 10pt">&nbsp;</span></span></span></p>
<img src ="http://www.blogjava.net/dunkbird/aggbug/312169.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2010-02-06 07:37 <a href="http://www.blogjava.net/dunkbird/articles/312169.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>优秀程序员的十个习惯</title><link>http://www.blogjava.net/dunkbird/articles/308197.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Mon, 04 Jan 2010 10:06:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/308197.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/308197.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/308197.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/308197.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/308197.html</trackback:ping><description><![CDATA[在这个世界上，有数百万的人热衷于软件开发，他们有很多名字，如：软件工程师（Software Engineer），程序员（Programmer），编码人（Coder），开发人员（Developer）。经过一段时间后，这些人也许能够成为一个优秀的编码人员，他们会非常熟悉如何用计算机语言来完成自己的工作。但是，如果你要成为一个优秀的程序员，你还可以需要有几件事你需要注意，如果你能让下面十个条目成为你的习惯，那么你才能真正算得上是优秀程序员。
<p>1. <strong>学无止境</strong>。就算是你有了10年以上的程序员经历，你也得要使劲地学习，因为你在计算机这个充满一创造力的领域，每天都会有很多很多的新事物出现。你需要跟上时代的步伐。你需要去了解新的程序语言，以及了解正在发展中的程序语言，以及一些编程框架。还需要去阅读一些业内的新闻，并到一些热门的社区去参与在线的讨论，这样你才能明白和了解整个软件开发的趋势。在国内，一些著名的社区例如：CSDN，ITPUB，CHINAUINX等等，在国外，建议你经常上一上digg.com去看看各种BLOG的聚合。</p>
<p></p>
<p>2. <strong>掌握多种语言</strong>。程序语言总是有其最适合的领域。当你面对需要解决的问题时，你需要找到一个最适合的语言来解决这些问题。比如，如果你需要性能，可能C/C++是首选，如果你需要跨平台，可能Java是首选，如果你要写一个Web上的开发程序，那么PHP，ASP，Ajax，JSP可能会是你的选择，如果你要处理一些文本并和别的应用交互，可能Perl, Python会是最好的。所以，花一些时间去探索一下其它你并熟悉的程序语言，能让你的眼界变宽，因为你被武装得更好，你思考问题也就更为全面，这对于自己和项目都会有好的帮助。</p>
<p>3. <strong>理性面对不同的操作系统或技术</strong>。程序员们总是有自己心目中无可比拟的技术和操作系统，有的人喜欢Ubuntu，有的人喜欢Debian，还有的人喜欢Windows，以及FreeBSD，MacOSX或Solaris等等。看看我的BLOG(<a onclick="pageTracker._trackPageview('/outgoing/blog.csdn.net/haoel?referer=http%3A%2F%2Fwww.google.com%2Freader%2Fview%2F');" href="http://blog.csdn.net/haoel">http://blog.csdn.net/haoel</a>)中的那篇《<a onclick="pageTracker._trackPageview('/outgoing/blog.csdn.net/haoel/archive/2007/03/19/1533720.aspx?referer=http%3A%2F%2Fwww.google.com%2Freader%2Fview%2F');" href="http://blog.csdn.net/haoel/archive/2007/03/19/1533720.aspx" target="_blank">其实Unix很简单</a>》后的回复你就知道程序员们在维护起自己的忠爱时的那份执着了。只有一部分优秀的程序员明白不同操作系统的优势和长处和短处，这样，在系统选型的时候，才能做到真正的客观和公正，而不会让情绪影响到自己。同样，语言也是一样，有太多的程序员总是喜欢纠缠于语言的对比，如：Java和Perl。哪个刚刚出道的程序员没有争论去类似的话题呢？比如VC++和Delphi等等。争论这些东西只能表明自己的肤浅和浮燥。优秀的程序并不会执着于这些，而是能够理性的分析和理心地面对，从而才能客观地做出正确的选择。</p>
<p>4. <strong>别把自己框在单一的开发环境中。</strong> 再一次，正如上面所述，每个程序员都有自己忠爱的工具和技术，有的喜欢老的（比如我就喜欢Vi编辑程序），而有的喜欢新的比如gedit或是Emacs等。有的喜欢使用像VC++一样的图形界面的调试器，而我更喜欢GDB命令行方面的调式器。等等等等。程序员在使用什么样的工具上的争论还少吗？到处都是啊。使用什么样的工具本来无所谓，只要你能更好更快地达到你的目的。但是有一点是优秀程序员都应该了解的——那就是应该去尝试一下别的工作环境。没有比较，你永远不知道谁好谁不好，你也永远不知道你所不知道的。</p>
<p>5. <strong>使用版本管理工具管理你的代码。</strong>千万不要告诉我你不知道源码的版本管理，如果你的团队开发的源代码并没有版本管理系统，那么我要告诉你，你的软件开发还处于石器时代。赶快使用一个版式本管理工具吧。CVS 是一个看上去平淡无奇的版本工具，但它是被使用最广的版本管理系统，Subversion 是CVS的一个升级版，其正在开始接管CVS的领地。Git 又是一个不同的版本管理工具。还有Visual SourceSafe等。使用什么样的版本管理工具依赖于你的团队的大小和地理分布，你也许正在使用最有效率或最没有效率的工具来管理你的源代码。但一个优秀的程序员总是会使用一款源码版本管理工具来管理自己的代码。如果你要我推荐一个，我推荐你使用开源的Subversion。</p>
<p>6. <strong>是一个优秀的团队成员。</strong> 除非你喜欢独奏，除非你是孤胆英雄。但我想告诉你，今天，可能没有一个成熟的软件是你一个人能做的到的，你可能是你团队中最牛的大拿，但这并不意味着你就是好的团队成员。你的能力只有放到一个团队中才能施展开来。你在和你的团队成员交流中有礼貌吗？你是否经常和他们沟通，并且大家都喜欢和你在一起讨论问题？想一想一个足球队吧，你是这个队中好的成员吗？当别人看到你在场上的跑动时，当别人看到你的传球和接球和抢断时，你的团员成员能因为你的动作受到鼓舞吗？</p>
<p>7. <strong>把你的工作变成文档。</strong> 这一条目当然包括了在代码中写注释，但那还仅仅不够，你还需要做得更多。有良好的注释风格的代码是一个文档的基础，他能够让你和你的团队容易的明白你的意图和想法。写下文档，并不仅仅是怕我们忘了当时的想法，而且还是一种团队的离线交流的方法，更是一种知识传递的方法。记录下你所知道的一切会是一个好的习惯。因为，我相信你不希望别人总是在你最忙的时候来打断你问问题，或是你在休假的时候接到公司的电话来询问你问题。而你自己如果老是守着自己的东西，其结果只可能是让你自己长时间地深陷在这块东西内，而你就更本不可以去做更多的事情。包括向上的晋升。你可能以为&#8220;教会徒弟能饿死师父&#8221;，但我告诉你，你的保守会让你失去更多更好的东西，请你相信我，我绝不是在这里耸人听闻。</p>
<p>8. <strong>注意备份和安全。</strong> 可能你觉得这是一个&#8220;废话&#8221;，你已明白了备份的重要性。但是，我还是要在这里提出，丢失东西是我们人生中的一部份，你总是会丢东西，这点你永远无法避免。比如：你的笔记本电脑被人偷了，你的硬盘损坏了，你的电脑中病毒了，你的系统被人入侵了，甚至整个大楼被烧了，等等，等等。所以，做好备份工作是非常非常重要的事情，硬盘是不可信的，所以定期的刻录光盘或是磁带可能会是一个好的方法，网络也是不可信的，所以小心病毒和黑客，不但使用软件方面的安全策略，你更需要一个健全的管理制度。此外，尽量的让你的数据放在不同的地方，并做好定期（每日，每周，每月）的备份策略。</p>
<p>9. <strong>设计要足够灵活。</strong> 可能你的需求只会要求你实现一个死的东西，但是，你作为一个优秀的程序，你应该随时在思考这个死的东西是否可以有灵活的一面，比如把一些参数变成可以配置的，把一些公用的东西形成你的函数库以便以后重用，是否提供插件方面的功能？你的模块是否要以像积木一样随意组合？如果要有修改的话，你的设计是否能够马上应付？当然，灵活的设计可能并不是要你去重新发明轮子，你应该尽可能是使用标准化的东西。所谓灵话的设计就是要让让考虑更多需求之外的东西，把需求中这一类的问题都考虑到，而不是只处理需求中所说的那一特定的东西。比如说，需要需要的屏幕分辨率是800&#215;600，那么你的设计能否灵活于其他的分辨率？程序设计总是需要我们去处理不同的环境，以及未来的趋势。我们需要用动态的眼光去思考问题，而不是刻舟求剑。也许有一天，你今天写的程序就要移植到别的环境中去，那个时候你就能真正明白什么是灵活的设计了。</p>
<p>10. <strong>不要搬起石头砸自己的脚。</strong>程序员总是有一种不好的习惯，那就是总是想赶快地完成自己手上的工作。但情况却往往事已愿违。越是想做得快，就越是容易出问题，越是想做得快，就越是容易遗漏问题，最终，程序改过来改过去，按下葫芦起了瓢，最后花费的时间和精力反而更多。欲速而不达。优秀程序员的习惯是前面多花一些时间多作一些调查，试验一下不同的解决方案，如果时间允许，一个好的习惯是，每4个小时的编程，需要一个小时的休息，然后又是4个小时的编码。当然，这因人而异，但其目的就是让你时常回头看看，让你想一想这样三个问题：1）是否这么做是对的？2）是否这么做考虑到了所有的情况？3）是否有更好的方法？想好了再说，时常回头看看走过的路，时常总结一下过去事，会对你有很大的帮助。</p>
<img src ="http://www.blogjava.net/dunkbird/aggbug/308197.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2010-01-04 18:06 <a href="http://www.blogjava.net/dunkbird/articles/308197.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DOM 解析XML</title><link>http://www.blogjava.net/dunkbird/articles/307344.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Sat, 26 Dec 2009 03:08:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/307344.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/307344.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/307344.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/307344.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/307344.html</trackback:ping><description><![CDATA[<font color="blue" size="2">package</font> demo.xml;<br />
<br />
</font><font color="#0000aa" size="2"><em>//作者 sunchengjun</font></em><font color="black" size="2"><br />
</font><font color="#0000aa" size="2"><em>//时间 2006年11日5日</font></em><font color="black" size="2"><br />
<font color="blue" size="2">import</font> java.io.FileInputStream;<br />
<font color="blue" size="2">import</font> java.io.FileNotFoundException;<br />
<font color="blue" size="2">import</font> java.io.IOException;<br />
<font color="blue" size="2">import</font> java.io.InputStream;<br />
<br />
<font color="blue" size="2">import</font> javax.xml.parsers.DocumentBuilder;<br />
<font color="blue" size="2">import</font> javax.xml.parsers.DocumentBuilderFactory;<br />
<font color="blue" size="2">import</font> javax.xml.parsers.ParserConfigurationException;<br />
<br />
<font color="blue" size="2">import</font> org.w3c.dom.Document;<br />
<font color="blue" size="2">import</font> org.w3c.dom.Element;<br />
<font color="blue" size="2">import</font> org.w3c.dom.Node;<br />
<font color="blue" size="2">import</font> org.w3c.dom.NodeList;<br />
<font color="blue" size="2">import</font> org.xml.sax.SAXException;<br />
<br />
<font color="blue" size="2">public</font> <font color="blue" size="2">class</font> DOMParsePage {<br />
<br />
<font color="blue" size="2">public</font> DOMParsePage() {<br />
DocumentBuilderFactory domfac=DocumentBuilderFactory.newInstance();<br />
<font color="blue" size="2">try</font> {<br />
&nbsp;&nbsp;&nbsp;&nbsp; DocumentBuilder dombuilder=domfac.newDocumentBuilder();<br />
InputStream is=<font color="blue" size="2">new</font> FileInputStream(</font><font color="#00bb00" size="2">"C:/123.xml"</font><font color="black" size="2">);<br />
Document doc=dombuilder.parse(is);<br />
Element root=doc.getDocumentElement();<br />
NodeList books=root.getChildNodes(); <br />
<font color="blue" size="2">if</font>(books!=<font color="blue" size="2">null</font>){<br />
<font color="blue" size="2">for</font>(<font color="blue" size="2">int</font> i=0;i&lt;books.getLength();i++){<br />
Node book=books.item(i);<br />
&nbsp;&nbsp;&nbsp;&nbsp; <font color="blue" size="2">for</font>(Node node=book.getFirstChild();node!=<font color="blue" size="2">null</font>;node=node.getNextSibling())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
<font color="blue" size="2">if</font>(node.getNodeType()==Node.ELEMENT_NODE){&nbsp;&nbsp;<br />
<br />
<font color="blue" size="2">if</font>(node.getNodeName().equals(</font><font color="#00bb00" size="2">"title"</font><font color="black" size="2">)){<br />
&nbsp;&nbsp;&nbsp;&nbsp; <font color="red" size="2">String</font> bookname=node.getFirstChild().getNodeValue(); <br />
&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(bookname);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;<font color="blue" size="2">if</font>(node.getNodeName().equals(</font><font color="#00bb00" size="2">"author"</font><font color="black" size="2">)){<br />
&nbsp;&nbsp;&nbsp;&nbsp; <font color="red" size="2">String</font> author1=node.getFirstChild().getNodeValue(); <br />
&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(author1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;<font color="blue" size="2">if</font>(node.getNodeName().equals(</font><font color="#00bb00" size="2">"description"</font><font color="black" size="2">)){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; <font color="red" size="2">String</font> addtime=node.getFirstChild().getNodeValue();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; System.out.println(addtime);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; <font color="blue" size="2">if</font>(node.getNodeName().equals(</font><font color="#00bb00" size="2">"pubDate"</font><font color="black" size="2">)){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; <font color="red" size="2">String</font> price=node.getFirstChild().getNodeValue();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; System.out.println(price);<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
<br />
}<br />
<br />
}<br />
<font color="blue" size="2">catch</font> (ParserConfigurationException e) {<br />
&nbsp;&nbsp; e.printStackTrace();<br />
}<br />
&nbsp;&nbsp;&nbsp;&nbsp; <font color="blue" size="2">catch</font> (FileNotFoundException e) {<br />
&nbsp;&nbsp; e.printStackTrace();<br />
}<br />
<font color="blue" size="2">catch</font> (SAXException e) {<br />
e.printStackTrace();<br />
}<br />
<font color="blue" size="2">catch</font> (IOException e) {<br />
e.printStackTrace();<br />
}<br />
<br />
<br />
}<br />
<br />
<br />
<font color="blue" size="2">public</font> <font color="blue" size="2">static</font> <font color="blue" size="2">void</font> main(<font color="red" size="2">String</font>[] args) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="blue" size="2">new</font> DOMParsePage();<br />
}<br />
<br />
}<br />
</font>
<img src ="http://www.blogjava.net/dunkbird/aggbug/307344.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2009-12-26 11:08 <a href="http://www.blogjava.net/dunkbird/articles/307344.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jboss 4.2.2 只能localhost访问 不能通过ip访问解决</title><link>http://www.blogjava.net/dunkbird/articles/296730.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Mon, 28 Sep 2009 02:02:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/296730.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/296730.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/296730.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/296730.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/296730.html</trackback:ping><description><![CDATA[<p style="line-height: normal"><span class="Apple-style-span" style="color: rgb(51,51,51); line-height: 20px; font-family: Arial; webkit-border-horizontal-spacing: 2px; webkit-border-vertical-spacing: 2px">JBOSS版本：4.2GA</span></p>
<p style="line-height: normal">症状：服务器无法通过IP地址去访问，只能用127.0.0.1或者localhost来访问。</p>
<p style="line-height: normal">解决办法：</p>
<p style="line-height: normal">cmd 进入dos 到bin下 输入 run -b 192.168.50.39</p>
<p style="line-height: normal"><br style="line-height: normal" />
启动JBOSS的时候输入：run -b xxx.xxx.xxx.xxx<br style="line-height: normal" />
其中xxx.xxx.xxx.xxx为本机的IP地址。</p>
<p style="line-height: normal">原因：<br style="line-height: normal" />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> JBOSS 4.2以上版本服务启动如果不加任何参数的话,只监听127.0.0.1,就是说只能用127.0.0.1或者localhost访问，用本机的对外地址访问不了，同一网络内别的机子没法访问。除非你用参数-b ip地址 来绑定监听的地址才可以。<br style="line-height: normal" />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 这和以前版本的JBOSS不一样，以前版本的不加任何参数是监听本机所有的IP地址，现在必须使用参数-b 0.0.0.0才可以监听全部地址。<br style="line-height: normal" />
-----------------------引用自：<a style="line-height: normal" href="http://hi.baidu.com/iMake"><font style="line-height: normal" color="#006bad">http://hi.baidu.com/iMake</font></a><br style="line-height: normal" />
<br style="line-height: normal" />
方法2：<br style="line-height: normal" />
<span style="font-size: 10pt; line-height: normal">修改 jboss-4.2.0.GA\server\default\deploy\jboss-web.deployer\server.xml 把 Connector 下面的 address 改成对应的 IP 或者 0.0.0.0 就可以用 IP 访问了。</span></p>
<p style="line-height: normal">&nbsp;<wbr></p>
<p style="line-height: normal">JBOSS版本：4.2.2GA<br style="line-height: normal" />
症状：服务器无法通过IP地址去访问，只能用127.0.0.1或者localhost来访问。<br style="line-height: normal" />
解决办法：<br style="line-height: normal" />
启动JBOSS的时候输入：run -b xxx.xxx.xxx.xxx<br style="line-height: normal" />
其中xxx.xxx.xxx.xxx为本机的IP地址。<br style="line-height: normal" />
原因：<br style="line-height: normal" />
JBOSS 4.2以上版本服务启动如果不加任何参数的话,只监听127.0.0.1,就是说只能用127.0.0.1或者localhost访问，用本机的对外地址访问不了，同一网络内别的机子没法访问。除非你用参数-b ip地址 来绑定监听的地址才可以。<br style="line-height: normal" />
这和以前版本的JBOSS不一样，以前版本的不加任何参数是监听本机所有的IP地址，现在必须使用参数-b 0.0.0.0才可以监听全部地址。<br style="line-height: normal" />
<br style="line-height: normal" />
======================================<br style="line-height: normal" />
附，以下是我的具体解决方法：<br style="line-height: normal" />
在jboss-4.2.2.GA\bin目录下，新建start.bat文件，录入如下内容：<br style="line-height: normal" />
run.bat -b 0.0.0.0<br style="line-height: normal" />
保存即可。使用你新制作的start.bat文件启动服务之后就可以IP访问了。<br style="line-height: normal" />
</p>
<p>
<div style="display: inline"><strong id="t_4bc4c8510100cuhn"></strong></div>
</p>
<img src ="http://www.blogjava.net/dunkbird/aggbug/296730.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2009-09-28 10:02 <a href="http://www.blogjava.net/dunkbird/articles/296730.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ActiveMQ入门(转)</title><link>http://www.blogjava.net/dunkbird/articles/295286.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Wed, 16 Sep 2009 05:00:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/295286.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/295286.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/295286.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/295286.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/295286.html</trackback:ping><description><![CDATA[<div>1、环境：</div>
<div>Windows XP</div>
<div>apache-activemq-5.2.0-bin.zip</div>
<div>&nbsp;</div>
<div>2、安装</div>
<div>解压缩到apache-activemq-5.2.0-bin.zip到一个目录，比如C:\apache-activemq-5.2.0</div>
<div>&nbsp;</div>
<div>3、配置</div>
<div>配置就在C:\apache-activemq-5.2.0\conf目录下三个文件</div>
<div>activemq.xml</div>
<div>credentials.properties</div>
<div>log4j.properties</div>
<div>&nbsp;</div>
<div>4、启动ActiveMQ</div>
<div>运行C:\apache-activemq-5.2.0\bin\activemq.bat<br />
</div>
<div>5、测试</div>
<div>ActiveMQ默认使用的TCP连接端口是61616, 通过查看该端口的信息可以测试ActiveMQ是否成功启动 netstat -an|find "61616" </div>
<div><strong><br />
</strong></div>
<div><strong>C:\Documents and Settings\Administrator&gt;netstat -an|find "61616" <br />
&nbsp;&nbsp;&nbsp;&nbsp;TCP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0.0.0.0:61616&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0.0.0.0:0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LISTENING</strong> </div>
<div>
<div>6、监控</div>
<div>ActiveMQ5.0版本默认启动时，启动了内置的jetty服务器，提供一个demo应用和用于监控ActiveMQ的admin应用。<br />
admin：<a href="http://127.0.0.1:8161/admin/">http://127.0.0.1:8161/admin/</a> <br />
demo：<a href="http://127.0.0.1:8161/demo/">http://127.0.0.1:8161/demo/</a> </div>
</div>
<div><br />
</div>
<div>
<div>下面是ActiveMQ5.2的一个最简单例子！</div>
<div>环境还是apache-activemq-5.2.0-bin.zip，需要注意的是，开发时候，要将apache-activemq- 5.2.0-bin.zip解压缩后里面的activemq-all-5.2.0.jar包加入到classpath下面，这个包包含了所有jms接口 api的实现。</div>
</div>
<div><br />
</div>
<div>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://teamojiao.javaeye.com/blog/457569#"><img alt="复制代码" src="http://teamojiao.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span class="keyword">import</span><span>&nbsp;org.apache.activemq.ActiveMQConnection; &nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">import</span><span>&nbsp;org.apache.activemq.ActiveMQConnectionFactory; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="keyword">import</span><span>&nbsp;javax.jms.*; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="comment">/** </span>&nbsp;</span></li>
    <li><span><span class="comment">*&nbsp;消息的生产者（发送者） </span>&nbsp;</span></li>
    <li><span><span class="comment">* </span>&nbsp;</span></li>
    <li><span><span class="comment">*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;JmsSender&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;JMSException&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;ConnectionFactory&nbsp;：连接工厂，JMS&nbsp;用它创建连接 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ConnectionFactory&nbsp;connectionFactory&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;ActiveMQConnectionFactory( &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ActiveMQConnection.DEFAULT_USER, &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ActiveMQConnection.DEFAULT_PASSWORD, &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="string">"tcp://192.168.14.117:61616"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//JMS&nbsp;客户端到JMS&nbsp;Provider&nbsp;的连接 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Connection&nbsp;connection&nbsp;=&nbsp;connectionFactory.createConnection(); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connection.start(); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Session：&nbsp;一个发送或接收消息的线程 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Session&nbsp;session&nbsp;=&nbsp;connection.createSession(Boolean.TRUE,&nbsp;Session.AUTO_ACKNOWLEDGE); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Destination&nbsp;：消息的目的地;消息发送给谁. </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;获取session注意参数值my-queue是Query的名字 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Destination&nbsp;destination&nbsp;=&nbsp;session.createQueue(</span><span class="string">"my-queue"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;MessageProducer：消息生产者 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageProducer&nbsp;producer&nbsp;=&nbsp;session.createProducer(destination); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//设置不持久化 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//发送一条消息 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sendMsg(session,&nbsp;producer); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.commit(); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connection.close(); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;在指定的会话上，通过指定的消息生产者发出一条消息 </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;session&nbsp;&nbsp;&nbsp;&nbsp;消息会话 </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;producer&nbsp;消息生产者 </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;sendMsg(Session&nbsp;session,&nbsp;MessageProducer&nbsp;producer)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;JMSException&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//创建一条文本消息 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TextMessage&nbsp;message&nbsp;=&nbsp;session.createTextMessage(</span><span class="string">"Hello&nbsp;ActiveMQ！"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//通过消息生产者发出消息 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;producer.send(message); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span class="string">""</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
/**
* 消息的生产者（发送者）
*
*/
public class JmsSender {
public static void main(String[] args) throws JMSException {
// ConnectionFactory ：连接工厂，JMS 用它创建连接
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD,
"tcp://192.168.14.117:61616");
//JMS 客户端到JMS Provider 的连接
Connection connection = connectionFactory.createConnection();
connection.start();
// Session： 一个发送或接收消息的线程
Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
// Destination ：消息的目的地;消息发送给谁.
// 获取session注意参数值my-queue是Query的名字
Destination destination = session.createQueue("my-queue");
// MessageProducer：消息生产者
MessageProducer producer = session.createProducer(destination);
//设置不持久化
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
//发送一条消息
sendMsg(session, producer);
session.commit();
connection.close();
}
/**
* 在指定的会话上，通过指定的消息生产者发出一条消息
*
* @param session    消息会话
* @param producer 消息生产者
*/
public static void sendMsg(Session session, MessageProducer producer) throws JMSException {
//创建一条文本消息
TextMessage message = session.createTextMessage("Hello ActiveMQ！");
//通过消息生产者发出消息
producer.send(message);
System.out.println("");
}
}</pre>
&nbsp;</div>
<div>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://teamojiao.javaeye.com/blog/457569#"><img alt="复制代码" src="http://teamojiao.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span class="keyword">import</span><span>&nbsp;org.apache.activemq.ActiveMQConnection; &nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">import</span><span>&nbsp;org.apache.activemq.ActiveMQConnectionFactory; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="keyword">import</span><span>&nbsp;javax.jms.*; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="comment">/** </span>&nbsp;</span></li>
    <li><span><span class="comment">*&nbsp;消息的消费者（接受者） </span>&nbsp;</span></li>
    <li><span><span class="comment">* </span>&nbsp;</span></li>
    <li><span><span class="comment">*/</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;JmsReceiver&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;JMSException&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;ConnectionFactory&nbsp;：连接工厂，JMS&nbsp;用它创建连接 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ConnectionFactory&nbsp;connectionFactory&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;ActiveMQConnectionFactory( &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ActiveMQConnection.DEFAULT_USER, &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ActiveMQConnection.DEFAULT_PASSWORD, &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="string">"tcp://192.168.14.117:61616"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//JMS&nbsp;客户端到JMS&nbsp;Provider&nbsp;的连接 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Connection&nbsp;connection&nbsp;=&nbsp;connectionFactory.createConnection(); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connection.start(); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Session：&nbsp;一个发送或接收消息的线程 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Session&nbsp;session&nbsp;=&nbsp;connection.createSession(Boolean.TRUE,&nbsp;Session.AUTO_ACKNOWLEDGE); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Destination&nbsp;：消息的目的地;消息发送给谁. </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;获取session注意参数值xingbo.xu-queue是一个服务器的queue，须在在ActiveMq的console配置 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Destination&nbsp;destination&nbsp;=&nbsp;session.createQueue(</span><span class="string">"my-queue"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;消费者，消息接收者 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageConsumer&nbsp;consumer&nbsp;=&nbsp;session.createConsumer(destination); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">while</span><span>&nbsp;(</span><span class="keyword">true</span><span>)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TextMessage&nbsp;message&nbsp;=&nbsp;(TextMessage)&nbsp;consumer.receive(</span><span class="number">1000</span><span>); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(</span><span class="keyword">null</span><span>&nbsp;!=&nbsp;message) &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span class="string">"收到消息："</span><span>&nbsp;+&nbsp;message.getText()); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">else</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">break</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.close(); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connection.close(); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
/**
* 消息的消费者（接受者）
*
*/
public class JmsReceiver {
public static void main(String[] args) throws JMSException {
// ConnectionFactory ：连接工厂，JMS 用它创建连接
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD,
"tcp://192.168.14.117:61616");
//JMS 客户端到JMS Provider 的连接
Connection connection = connectionFactory.createConnection();
connection.start();
// Session： 一个发送或接收消息的线程
Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
// Destination ：消息的目的地;消息发送给谁.
// 获取session注意参数值xingbo.xu-queue是一个服务器的queue，须在在ActiveMq的console配置
Destination destination = session.createQueue("my-queue");
// 消费者，消息接收者
MessageConsumer consumer = session.createConsumer(destination);
while (true) {
TextMessage message = (TextMessage) consumer.receive(1000);
if (null != message)
System.out.println("收到消息：" + message.getText());
else
break;
}
session.close();
connection.close();
}
}</pre>
&nbsp;</div>
<div>
<div>启动ActiveMQ，然后开始执行：</div>
<div>先运行发送者，连续运行了三次，最后一次控制台输出：</div>
<div>
<div>
<div><br />
<br />
Process finished with exit code 0 <br />
</div>
</div>
</div>
<div>&nbsp;</div>
<div>后运行接受者，输出结果：</div>
<div>
<div>
<div>收到消息Hello ActiveMQ！ <br />
收到消息Hello ActiveMQ！ <br />
收到消息Hello ActiveMQ！ <br />
<br />
Process finished with exit code 0 <br />
</div>
</div>
</div>
<div>&nbsp;</div>
<div>注意：</div>
<div>其中的端口61616是ActiveMQ默认的配置，在activemq.xml中，</div>
</div>
<div><br />
</div>
<div>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Xml代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://teamojiao.javaeye.com/blog/457569#"><img alt="复制代码" src="http://teamojiao.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-xml">
    <li><span><span class="comments">&lt;!--&nbsp;The&nbsp;transport&nbsp;connectors&nbsp;ActiveMQ&nbsp;will&nbsp;listen&nbsp;to&nbsp;--&gt;</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">transportConnectors</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">transportConnector</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">"openwire"</span><span>&nbsp;</span><span class="attribute">uri</span><span>=</span><span class="attribute-value">"tcp://localhost:61616"</span><span>&nbsp;</span><span class="attribute">discoveryUri</span><span>=</span><span class="attribute-value">"multicast://default"</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">transportConnector</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">"ssl"</span><span>&nbsp;</span><span class="attribute">uri</span><span>=</span><span class="attribute-value">"ssl://localhost:61617"</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">transportConnector</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">"stomp"</span><span>&nbsp;</span><span class="attribute">uri</span><span>=</span><span class="attribute-value">"stomp://localhost:61613"</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">transportConnector</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">"xmpp"</span><span>&nbsp;</span><span class="attribute">uri</span><span>=</span><span class="attribute-value">"xmpp://localhost:61222"</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;/</span><span class="tag-name">transportConnectors</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="xml" style="display: none" name="code">   &lt;!-- The transport connectors ActiveMQ will listen to --&gt;
&lt;transportConnectors&gt;
&lt;transportConnector name="openwire" uri="tcp://localhost:61616" discoveryUri="multicast://default"/&gt;
&lt;transportConnector name="ssl" uri="ssl://localhost:61617"/&gt;
&lt;transportConnector name="stomp" uri="stomp://localhost:61613"/&gt;
&lt;transportConnector name="xmpp" uri="xmpp://localhost:61222"/&gt;
&lt;/transportConnectors&gt; </pre>
</div>
<div>&nbsp;</div>
<div>
<div>，建议不要改动，都用这个端口多好，就像ftp都用21端口，也没错。</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>这是官方的HelloWorld例子，不过看着不顺眼：</div>
</div>
<div><a href="http://activemq.apache.org/hello-world.html">http://activemq.apache.org/hello-world.html</a> </div>
<div><br />
</div>
<img src ="http://www.blogjava.net/dunkbird/aggbug/295286.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2009-09-16 13:00 <a href="http://www.blogjava.net/dunkbird/articles/295286.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JBoss和JMS(写的不错，抄来看看)</title><link>http://www.blogjava.net/dunkbird/articles/295055.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Mon, 14 Sep 2009 11:34:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/295055.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/295055.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/295055.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/295055.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/295055.html</trackback:ping><description><![CDATA[<p>1、介绍<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 本章介绍在Jboss中使用Java Messageing Service (JMS). 不是JMS指南，而是JBoss和JMS如何一起使用，如果你想看JMS的介绍，请参考 JMS Specification 或 JMS turorial.<br />
最近随着JBoss版本不断更新，对JMS支持越来越成熟，也造成JBoss各个版本之间的不同。在这里我主要介绍JBoss3.0.X版本。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 本章给出的例子比较简单，并指出了如何使用JMS的原理。所有的例子可以通过ant build file 来建立。<br />
为了能建立和运行此例子。我们使用两种方式来进行：一是使用Ant命令，二是使用JAR和JAVA基本命令。必须有下面的环境变量：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JAVA_HOME 安装JDK1.4的目录。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JBOSS_DIST 安装JBoss的目录。<br />
你必须安装JDK, 如果使用Ant必须安装 Ant。可以参考我前面文档的介绍。</p>
<p>2、概述<br />
&nbsp;&nbsp;&nbsp;&nbsp; 1） 什么是JMS<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JMS是Java API, 允许应用程序来建立、接收和读取消息。程序依靠这些API, 在运行时需要一个JMS实现接口，来提供管理和控制，这被称为JMS provider, 现在有几种不同的JMS Provider; 在JBoss中的叫做JbossMQ。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2） JMS 和J2EE<br />
&nbsp;&nbsp;&nbsp;&nbsp; JMS是在EJB和J2EE框架开发之前进行开发的，所以在JMS说明书中没有涉及到EJB或J2EE。<br />
EJB 和J2EE第一代版本中也没有涉及到JMS，一直到EJB1.1，在生成一个可用Beand的容器provider中JMS也不是必须的API。在J2EE1.2中JMS接口是必需的情况，但并不是非得要包含一个JMS Provider；在EJB2.0和J2EE1.3中又进行改变，应用服务器包含了一个JMS Provider，自从J2EE1。3需要EJB2.0，增加了以下两个JMS特性：<br />
w 一种新Bean类型定义， 也就是消息驱动Beam (MDB), 这种bean做为JMS消息监听者，可以异步地处理JMS消息。<br />
w JMS处理作为资源，来自一个Bean 的JMD 发布（发送）必须能和其他bean的全局事务环境共享。这个需要把JMS认为是一个容器管理资源，象JDBC的连接。<br />
&nbsp;&nbsp;&nbsp; 3） JMS 和JBoss<br />
&nbsp;&nbsp;&nbsp; JBoss从2.0版本以后都支持JMS。 在2.1中增加了MDB，从2.4版本开始JMS作为一个事务资源。<br />
JBoss中JMS的体系结构如下：JMS Provider, 叫做JbossMQ 。 是JBoss实现JMS 1.0.2规范的一部分，包括可选部分，象ASF（Application Service Facvility）。 JbossMQ处理和普遍JMS一样：建立 queues (队列)或topic(标题)，持久性等。 MDB (Message Driven Beans), 资源适配器。<br />
3、JMS Provider<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JBoss有它自己的JMS Provider 叫做JbossMQ。 适合与JMS 1.0.2 的JMS Provider，并且能用在所有平常的JMS程序中。为了清楚在JBoss中JMS是如何工作的，首先要清楚在JMS中涉及到的概念和术语，最好的办法是阅读JMS规范，下面给出了简单的JMS介绍。<br />
&nbsp;&nbsp;&nbsp; 1) JMS的简单介绍<br />
&nbsp;&nbsp;&nbsp;&nbsp; 当你发送一个消息，你不能直接发送到对此消息感兴趣的接受者。而是你发送到一个目的地。对此消息感兴趣的接受者必须连接到目的地，得到此消息或在目的地设置订阅。<br />
在JMS中有两种域：topics 和queues 。一个消息发送到一个topics ，可以有多个客户端。用topic发布允许一对多，或多对多通讯通道。消息的产生者被叫做publisher, 消息接受者叫做subscriber。<br />
queue 是另外一种方式，仅仅允许一个消息传送给一个客户。一个发送者将消息放在消息队列中，接受者从队列中抽取并得到消息，消息就会在队列中消失。第一个接受者抽取并得到消息后，其他人就不能在得到它。<br />
为了能发送和接收消息，必须得到一个JMS连接。该连接是使用JMS Provider得到连接的，在得到连接之后，建立一个会话(Session)。然后再建立publisher/sender 来发送消息或subscriber/receiver来接收消息。<br />
运行时，如果使用topic 那么publisher 或subscriber 通过一个topic来关联，如果使用queue ，则sender 或receiver通过queue来关联起来。<br />
通常，在JMS框架中运转的方法如下：<br />
(1) 得到一个JNDI初始化上下文(Context)；<br />
(2) 根据上下文来查找一个连接工厂TopicConnectFactory/ QueueConnectionFactory (有两种连接工厂，根据是topic/queue来使用相应的类型)；<br />
(3) 从连接工厂得到一个连接(Connect 有两种[TopicConnection/ QueueConnection]);<br />
(4) 通过连接来建立一个会话(Session);<br />
(5) 查找目的地(Topic/ Queue);<br />
(6) 根据会话以及目的地来建立消息制造者(TopicPublisher/QueueSender)和消费者(TopicSubscriber/ QueueReceiver).<br />
为了得到一个连接和得到一个目的地（用来关联publisher/sender 或subscriber/receiver），必须用provider-specific参数。<br />
通过JNDI来查找相应的连接工厂或目的地，JNDI适合于任何JMS Provider。但是查找用的名字是provider使用的。因此，在你使用的JMS Provider（其中包括JBossMQ），必须学会如何进行指定。JMS Provider中的任何设置，象连接特性，用到目的地等，在用到的Provider都有明确描述。<br />
2) 配置<br />
当使用一个JMS Provider时，有三个Provider-specific因素：<br />
w 得到一个JNDI初始化上下文<br />
w 用到的连接工厂的名字。<br />
w 对目的地的管理和命名协定。<br />
JBoss同它的JNDI一起执行。为了简单的JMS client， 配置和查找初始化上下文，同实现其他J2EE客户端一样。<br />
JMS-specific 来约束JBoss 的JMS provider (JBossMQ)。JbossMQ是通过xml 文件jbossmq-service.xml进行配置的，该文件放在在server\default\deploy下。<br />
在xml文件中最基本的三件事情：<br />
w 增加一个新的目的地<br />
w 配置用户<br />
w 获得可用连接工厂的名字。<br />
(1) 增加新的目的地<br />
w 在目的地的xml文件在jboss 3.x中是jbossmq-destinations-service.xml（server/../deploy）。在文件中已经存在几个缺省的目的地，所以你比较容易明白怎样增加到文件中。在例子中你需要一个topic目的地 spool，所以增加下面的语句到jbossmq-destinations-service.xml中。这种方式是长久存在的，不随着JBoss服务器关闭而消失。<br />
&lt;mbean code="org.jboss.mq.server.jmx.Topic"<br />
name="jboss.mq.destination:service=Topic,name=spool"&gt;<br />
&lt;depends optional-attribute-name="DestinationManager"&gt;jboss.mq:service=DestinationManager&lt;/depends&gt;<br />
&lt;/mbean&gt;<br />
w 另外一种方法是可以通过JMX HTML管理界面。通过<a href="http://localhost:8080/jmx-console"><font color="#108ac6">http://localhost:8080/jmx-console</font></a> 来访问。在jboss.mq 下查找service=DestinationManager 的连接。然后在createTopic()或createQueue()来建立，这种方法建立的目的地是临时性的，随着服务器开始存在，当当JBoss 服务器重新启动时，动态建立的目的地将会不存在。在JbossMQ中所有目的地都有一个目的地类型的前缀。对于topic前缀是topic ,对于queues前缀是queue。例如查找一个testTopic目的地，需要查找名字为&#8220;topic/testTopic&#8221;。<br />
在此种方法中有createTopic()或createQueue()分别有两种方法：一是有两个参数，二是有一个参数的。两个参数分别是：建立的目的地名称和JNDI名称。一个参数的只是目的地名称，对于JNDI名称默认是：[目的地类型(topic/queue) ]/目的地名称。<br />
在这里我们使用的是第一种方法。直接修改jbossmq-destinations-service.xml文件。<br />
(2) 管理用户<br />
在JMS中可能关联一个连接和一个用户，不幸的是没有明确的方法来限制访问JbossMQ或访问特殊的目的地到一个给定的用户。为了给大部分角色，在JbossMQ中不需要建立用户，除非想有一个持久topic订阅者。在这个例子中，用户是必须的。<br />
用户可以直接在文件jbossmq-state.xml（server/../conf）中添加。同样也可以使用JMX HTML管理界面来增加（jboss.mq-&gt;service=StateManager-&gt;addUser()）。<br />
&lt;User&gt;<br />
&lt;Name&gt;jacky&lt;/Name&gt;<br />
&lt;Password&gt;jacky&lt;/Password&gt;<br />
&lt;Id&gt;DurableSubscriberExample&lt;/Id&gt;<br />
&lt;/User&gt;&gt;</p>
<p>(3) 连接工厂<br />
JBossMQ 包括为topic和queue几个不同的连接工厂，每个连接工厂有自己特性。当通过JNDI来查找一个连接工厂时，需要知道此连接工厂的名称。所有可用连接工厂和它们的属性，名称都会在文件jbossmq-service.xml中。<br />
有三种类型连接工厂，依赖的通讯协议如下：<br />
OIL<br />
快速双向scoket通讯协议。它是缺省的。<br />
UIL<br />
超过一个socket协议，可以使用在通过防火墙访问，或者当客户端不能正确的查找到服务器的IP地址。<br />
RMI<br />
最早的协议，是稳定的，但是比较慢。<br />
JVM<br />
在JBoss 2.4之后增加的一个新的连接工厂类型。不需要用socket，当客户端和JbossMQ使用同样虚拟机时，可以使用。<br />
在JBoss2.4.1以后版本中，对于topic- 和 queue-目的地，连接工厂使用同样的名字。下表列出了在JBoss中JMS连接工厂：<br />
目的地类型 JNDI名字 连接工厂类型<br />
Topic/Queue java:/ConnectionFactory JVM<br />
Topic/Queue java:/XAConnectionFactory JVM支持XA事务<br />
Topic/Queue RMIConnectionFactory RMI<br />
Topic/Queue RMIXAConnectionFactory RMI支持XA事务<br />
Topic/Queue ConnectionFactory OIL<br />
Topic/Queue XAConnectionFactory OIL支持XA事务<br />
Topic/Queue UILConnectionFactory UIL<br />
Topic/Queue UILXAConnectionFactory UIL支持XA事务</p>
<p>3） JBoss中高级JMS配置<br />
在上边段落主要描述了和JbossMQ一起实行的基本配置工作。在本段来描述JMS其他配置。<br />
(1) JMS持久性管理<br />
JMS持久性管理(PM)负责存储消息，并且将消息标记为持久，如果服务器发生故障时，能保证消息不会丢失，并允许恢复持久性消息。持久性JMS消息可以使用不同的方法来完成。每个方法有自己优点和缺陷：<br />
PM 名字 优点 缺点<br />
File 比较稳定 速度慢<br />
Rollinglogged 速度比较快 此方法比较新，有些地方需要完善<br />
JDBC 对于稳定性和可量测性比较好 必须有JDBC<br />
Logged 速度快 Log files grow without bound, memory management problems during recovery<br />
在JBoss中缺省的持久性消息管理是File持久性管理。可以改变它，但必须对于一个JMS <br />
Server有且仅有一个持久性管理配置。所以你在JBoss管理界面的jboss.mq &#8211; &gt;<br />
service=PersistenceManager 只是看到一个。<br />
持久性管理的配置文件是jbossmq-service.xml。在server\..\deploy下。<br />
为了让大家了解持久性管理的各种方法，我下面来逐个介绍如何配置。<br />
w File持久性管理<br />
File持久性管理的概念就是为每一个持久性消息建立一个文件。消息持久性方法不是全部都能使用，但它是比较稳定的。<br />
File持久性管理在JBoss发布时，作为一个缺省的持久性管理。如果你打开jbossmq-service.xml文件，你会看到下面的XML：<br />
&lt;mbean code="org.jboss.mq.pm.file.PersistenceManager"<br />
name="jboss.mq:service=PersistenceManager"&gt;<br />
&lt;attribute &gt;db/jbossmq/file&lt;/attribute&gt;<br />
&lt;depends optional-attribute-name="MessageCache"&gt;jboss.mq:service=MessageCache&lt;/depends&gt;<br />
&lt;/mbean&gt;<br />
当设置Mbean配置时，File持久性管理允许你指定下面的属性：<br />
DataDircetory 是存放持久性消息的路径，会把生成的数据文件放在此目录下。</p>
<p>w 设置Rollinglogged持久性管理<br />
Rollinglogged持久性管理是比较新的一种持久性消息管理方法，因为它使用日志文件来持续多个消息，所以当建立一个文件时，不需要许多的I/O。<br />
定义Rollinglogged持久性管理：<br />
&lt;mbean code="org.jboss.mq.pm.rollinglogged.PersistenceManager"<br />
name="jboss.mq:service=PersistenceManager"&gt;<br />
&lt;attribute &gt;db/jbossmq/file&lt;/attribute&gt;<br />
&lt;depends optional-attribute-name="MessageCache"&gt;jboss.mq:service=MessageCache&lt;/depends&gt;<br />
&lt;/mbean&gt;<br />
Rollinglogged持久性管理中DataDirctory 存放持久性消息的路径，会把生成的数据文件放在此目录下。</p>
<p>w 设置JDBC持久性管理<br />
JDBC持久性管理使用数据库表来存储消息。需要一个JBoss配置的数据源来访问数据库。具体内容参考jbossmq-service.xml文件中的内容。<br />
w 设置Logged持久性管理<br />
Logged持久性管理是比较早的一个，在JBoss2.4.1以后版本中不在建议使用。现在有其他更好的办法。<br />
4、举例说明<br />
当我们清楚了以后内容后，现在我们来用JBoss实现一个例子来加深对JBoss和JMS的了解。<br />
在上面叙述中，我们知道明确使用JMS provider有三个基本的事情要做：配置JNDI初始化上下文，连接工厂的名字和使用目的地的名字。<br />
当编写产品的最好的事情是不受provider-specific 影响，使代码能在不同的JMS provider之间容易移植。在此这个例子没有聚焦在开发产品上，而是解释如何使用JbossMQ来工作。<br />
1) 初始化上下文<br />
w 配置JNDI的一个方法是通过属性文件jndi.properties。在这个文件中使用正确的值，并且把它所在的路径包含到classpath中，它比较容获得正确初始化上下文。<br />
jndi.properties文件的内容如下：<br />
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory<br />
java.naming.provider.url=localhost:1099<br />
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces<br />
把该文件放置的路径成为你的classpath的一部分。如果你使用这种方法，在初始化上下文时，代码比较简单: Context context = new IntialContext();1<br />
w 在某些情景下，可能需要手工配置JNDI；例如当运行的类文件中环境已经配置了一个初始化上下文，但不是你想用的上下文时，需要手工来配置一个上下文。设置在哈希表中的几个属性值，并且使用此哈希表来实例化一个上下文。定义语法：<br />
Hashtable props = new Hashtable();<br />
props.put(Context.INITIAL_CONTEXT_FACTORY,<br />
"org.jnp.interfaces.NamingContextFactory");<br />
props.put(Context.PROVIDER_URL, "localhost:1099");<br />
props.put("java.naming.rmi.security.manager", "yes");<br />
props.put(Context.URL_PKG_PREFIXES, "org.jboss.naming");</p>
<p>2) 查找连接工厂<br />
自有了上下文后，需要查找一个连接工厂。为了查找它，使用一个可用的名字。查找连接工厂的代码如下：<br />
对于一个topic目的地<br />
TopicConnectionFactory topicFactory = (TopicConnectionFactory) context.lookup (&#8220;ConnectionFactory&#8221;)<br />
Queue 目的地：<br />
QueueConnectionFactory queueFactory = (QueueConnectionFactory ) context.lookup (&#8220;ConnectionFactory&#8221;)<br />
3) 建立连接和会话<br />
在我们有了连接工厂后，建立一个连接，在此连接中建立一个会话。<br />
对于topic代码如下：<br />
//建立一个连接<br />
topicConnection = topicFactory.createTopicConnection();<br />
//建立一个会话<br />
topicSession = topicConnection.createTopicSession(false, //不需要事务<br />
Session.AUTO_ACKNOLEDGE //自动接收消息的收条。<br />
);<br />
对于queue代码如下：<br />
//建立一个连接<br />
queueConnection = queueFactory.createQueueConnection();<br />
//建立一个会话<br />
queueSession = queueConnection .createQueueSession(false, //不需要事务<br />
Session.AUTO_ACKNOLEDGE //自动接收消息的收条。<br />
);<br />
一个会话建立时，配置是否调用事务<br />
在事务Session中，当事务被提交后，自动接收，如果事务回滚，所有的被消费的消息将会被重新发送。<br />
在非事务Session中，如果没有调用事务处理，消息传递的方式有三种：<br />
Session.AUTO_ACKNOWLEDGE :当客户机调用的receive方法成功返回，或当MessageListenser 成功处理了消息，session将会自动接收消息的收条。<br />
Session.CLIENT_ACKNOWLEDGE ：客户机通过调用消息的acknowledge方法来接收消息。接收发生在session层。接收到一个被消费的消息时，将自动接收该session已经消费的所有消息。例如：如果消息的消费者消费了10条消息，然后接收15个被传递的消息，则前面的10个消息的收据都会在这15个消息中被接收。<br />
Session.DUPS_ACKNOWLEDGE ：指示session缓慢接收消息。</p>
<p>4) 查找目的地<br />
现在我们来介绍建立publishes/sends 或subscribles/receives消息。<br />
下面的代码列出来查找一个目的地：<br />
对于topic 查找一个testTopic目的地<br />
Topic topic = (Topic) context.lookup(&#8220;topic/testTopic&#8221;);</p>
<p>对于queue 查找一个testQueue目的地<br />
Queue queue= (Queue) context.lookup(&#8220;queue/testQueue&#8221;);<br />
注意：JbossM的前缀topic/ (queue/)通常被放在topic (queue)名字前面。<br />
在JMS中，当客户机扮演每种角色，象对于topic来将的publisher ,subscriber 或对于queue来将的sender, receiver， 都有自己不同类继承和不同函数。<br />
5) 建立一个消息制造者Message Producer (topic publisher/ queue sender)<br />
消息制造者是一个由session创建的对象，主要工作是发送消息到目的地。<br />
对于一个topic，需要通过TopicSession来创建一个TopicPublisher。代码如下：<br />
TopicPublisher topicPublisher = TopicSession.createPublisher(topic);</p>
<p>对于一个queue，需要通过QueueSession来创建一个QueueSender。代码如下：<br />
QueuePublisher queuePublisher = queueSession.createSender(queue);<br />
6) 消息发送<br />
建立一个TestMessage并且publish 它， 代码：<br />
TextMessage message = topicSession.createTestMessage();<br />
message.setText(msg);<br />
topicPublishe.publish(topic, message);<br />
建立一个TestMessage并且send它， 代码：<br />
TextMessage message = queueSession.createTestMessage();<br />
message.setText(msg);<br />
queueSender.send(queue, message);</p>
<p>7) 下面是一个完成的topic publisher 代码，文件名HelloPublisher.java ：<br />
import javax.naming.Context;<br />
import javax.naming.InitialContext;<br />
import javax.naming.NamingException;<br />
import javax.jms.TopicConnectionFactory;<br />
import javax.jms.TopicConnection;<br />
import javax.jms.TopicSession;<br />
import javax.jms.TopicPublisher;<br />
import javax.jms.Topic;<br />
import javax.jms.TextMessage;<br />
import javax.jms.Session;<br />
import javax.jms.JMSException;<br />
import java.util.Hashtable;<br />
public class HelloPublisher {</p>
<p>TopicConnection topicConnection;<br />
TopicSession topicSession;<br />
TopicPublisher topicPublisher;<br />
Topic topic;</p>
<p>public HelloPublisher(String factoryJNDI, String topicJNDI)<br />
throws JMSException, NamingException {<br />
Hashtable props=new Hashtable();<br />
props.put(Context.INITIAL_CONTEXT_FACTORY,"org.jnp.interfaces.NamingContextFactory");<br />
props.put(Context.PROVIDER_URL, "localhost:1099");<br />
props.put("java.naming.rmi.security.manager", "yes");<br />
props.put(Context.URL_PKG_PREFIXES, "org.jboss.naming");<br />
Context context = new InitialContext(props);<br />
TopicConnectionFactory topicFactory =<br />
(TopicConnectionFactory)context.lookup(factoryJNDI);<br />
topicConnection = topicFactory.createTopicConnection();<br />
topicSession = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);</p>
<p>topic = (Topic)context.lookup(topicJNDI);</p>
<p>topicPublisher = topicSession.createPublisher(topic);</p>
<p>}</p>
<p>public void publish(String msg) throws JMSException {</p>
<p>TextMessage message = topicSession.createTextMessage();<br />
message.setText(msg);<br />
topicPublisher.publish(topic, message);<br />
}</p>
<p>public void close() throws JMSException {<br />
topicSession.close();<br />
topicConnection.close();<br />
}</p>
<p>public static void main(String[] args) {<br />
try {<br />
HelloPublisher publisher = new HelloPublisher(<br />
"ConnectionFactory", "topic/testTopic");<br />
for (int i = 1; i &lt; 11; i++) {<br />
String msg = "Hello World no. " + i;<br />
System.out.println("Publishing message: " + msg);<br />
publisher.publish(msg);<br />
}<br />
publisher.close();<br />
} catch(Exception ex) {<br />
System.err.println(<br />
"An exception occurred while testing HelloPublisher25: " + ex);<br />
ex.printStackTrace();<br />
}<br />
}<br />
}<br />
我们知道，使用JMS不仅能发送（send）/发布（publish）消息，也能获得（send）/发布（publish）的消息。在时间方式有良种方法来做：<br />
w 同步（Synchronously）：需要手工的去得到消息，为了得到一个消息客户机调用方法得到消息，直到消息到达或在规定的时间内没有到达而超时。我们在例子中没有说明这部分，大家可以实验一下。<br />
w 异步（Asynchronously）：你需要定义一个消息监听器(MessageListener),实现该接口。当消息达到时，JMS provider通过调用该对象的 onMessage方法来传递消息。<br />
从原则来将，topic和queue都是异步的，但是在这两种目的地中有不同的类和方法。首先，必须定义一个MessageListener接口。 <br />
8) 建立一个MessageListener<br />
在建立了你需要的subscriber/receiver，并且登记了监听器后。就可以调用连接的start方法得到JMS provider 发送到的消息了。如果在登记监听器之前调用start方法，很可能会丢失消息。<br />
public void onMessage(Message m) {<br />
try {<br />
String msg = ((TextMessage)m).getText();<br />
System.out.println("HelloSubscriber got message: " + msg);<br />
} catch(JMSException ex) {<br />
System.err.println("Could not get text message: " + ex);<br />
ex.printStackTrace();<br />
}<br />
}<br />
9) 建立消息消费者<br />
对于topic来将：<br />
//建立一个订阅者<br />
topicSubscriber = topicSession.createSubscriber(topic);<br />
//设置消息监听器，<br />
topicSubscriber.setMessageListener(this)<br />
//连接开始<br />
topicConnection.start();<br />
对于queue来将：<br />
//建立一个订阅者<br />
queueReceiver = queueSession.createReceiver(queue);<br />
//设置消息监听器，<br />
queueReceiver .setMessageListener(this)<br />
//连接开始<br />
queueConnection.start();<br />
10) 完整的代码，放在文件HelloSubscriber.java中，如下：<br />
import javax.naming.Context;<br />
import javax.naming.InitialContext;<br />
import javax.naming.NamingException;</p>
<p>import javax.jms.TopicConnectionFactory;<br />
import javax.jms.TopicConnection;<br />
import javax.jms.TopicSession;<br />
import javax.jms.TopicSubscriber;<br />
import javax.jms.Topic;<br />
import javax.jms.Message;<br />
import javax.jms.TextMessage;<br />
import javax.jms.Session;<br />
import javax.jms.MessageListener;<br />
import javax.jms.JMSException;</p>
<p>public class HelloSubscriber implements MessageListener {<br />
TopicConnection topicConnection;<br />
TopicSession topicSession;<br />
TopicSubscriber topicSubscriber;<br />
Topic topic;<br />
public HelloSubscriber(String factoryJNDI, String topicJNDI)<br />
throws JMSException, NamingException<br />
{<br />
Context context = new InitialContext();<br />
TopicConnectionFactory topicFactory =<br />
(TopicConnectionFactory)context.lookup(factoryJNDI);<br />
topicConnection = topicFactory.createTopicConnection();<br />
topicSession = topicConnection.createTopicSession(<br />
false, Session.AUTO_ACKNOWLEDGE);<br />
topic = (Topic)context.lookup(topicJNDI);<br />
topicSubscriber = topicSession.createSubscriber(topic);<br />
topicSubscriber.setMessageListener(this);<br />
System.out.println(<br />
"HelloSubscriber subscribed to topic: " + topicJNDI);<br />
topicConnection.start();<br />
}<br />
public void onMessage(Message m) {<br />
try {<br />
String msg = ((TextMessage)m).getText();<br />
System.out.println("HelloSubscriber got message: " + msg);<br />
} catch(JMSException ex) {<br />
System.err.println("Could not get text message: " + ex);<br />
ex.printStackTrace();<br />
}<br />
}<br />
public void close() throws JMSException {<br />
topicSession.close();<br />
topicConnection.close();<br />
}<br />
public static void main(String[] args) {<br />
try {<br />
HelloSubscriber subscriber = new HelloSubscriber(<br />
"TopicConnectionFactory",<br />
"topic/testTopic");<br />
} catch(Exception ex) {<br />
System.err.println(<br />
"An exception occurred while testing HelloSubscriber: " + ex);<br />
ex.printStackTrace();<br />
}<br />
}<br />
}</p>
<p>11) 编辑、运行程序<br />
直接使用命令（java） <br />
w 开启命令操作符。设置classpath : <br />
set classpath=C:\jboss-3.0.6_tomcat-4.1.18\client\jbossall-client.jar;C:\jboss-3.0.6_tomcat-4.1.18\client\jboss-j2ee.jar;C:\jboss-3.0.6_tomcat-4.1.18\client\jnp-client.jar;C:\jboss-3.0.6_tomcat-4.1.18\client\log4j.jar;.<br />
w 首先运行订阅消息端：java HelloSubscriber<br />
w 再开启另外一个命令窗口设置classpath : <br />
set classpath=C:\jboss-3.0.6_tomcat-4.1.18\client\jbossall-client.jar;C:\jboss-3.0.6_tomcat-4.1.18\client\jboss-j2ee.jar;C:\jboss-3.0.6_tomcat-4.1.18\client\jnp-client.jar;C:\jboss-3.0.6_tomcat-4.1.18\client\log4j.jar;.<br />
w 运行发布消息端：java HelloPublisher<br />
5、补充<br />
在最后我们解释JBoss-specific特性：如何用代码来管理目的地。JBoss各个版本可能不同，但是差别不大。我使用的是jboss3.0.6。<br />
实现这个目的有两种不同的方法，依赖于是否代码是在和JBoss同样的虚拟机还是独立独立的。它们都包括调用一个通过service=DestinationManager 登记的JMX Bean。这个Mbean 有四个方法来管理目的地：createTopic()，createQueue()，destroyTopic()，destroyQueue()。<br />
在代码中实现管理目的地在影射怎样调用MBean有不同的地方。如果程序虚拟机和Mbean服务器一样，可以直接调用。<br />
建立一个topic 目的地的代码如下：<br />
MBeanServer server = (MBeanServer)<br />
MBeanServerFactory.findMBeanServer(null).iterator().next();<br />
server.invoke(new ObjectName("JBossMQ", "service", "DestinationManager"),<br />
method,<br />
new Object[] { &#8220;myTopic&#8221; },<br />
new String[] { "java.lang.String" });</p>
<p>如果程序和Mbean服务器的虚拟机不同，需要通过一个JMX adapter。一个JMX adapter是一个HTML GUI。用程序通过URL来调用Mbean。代码如下：<br />
import java.io.InputStream;<br />
import java.net.URL;<br />
import java.net.HttpURLConnection;<br />
import javax.management.MBeanServerFactory;<br />
import javax.management.MBeanServer;<br />
import javax.management.ObjectName;<br />
import javax.jms.Topic;<br />
import javax.jms.Queue;<br />
public class DestinationHelper {<br />
static final String HOST = "localhost";<br />
static final int PORT = 8080;<br />
static final String BASE_URL_ARG = "/jmx-console/HtmlAdaptor?"; <br />
public static void createDestination(Class type, String name) <br />
throws Exception<br />
{<br />
String method = null;<br />
if (type == Topic.class) { method = "createTopic"; }<br />
else if (type == Queue.class) { method = "createQueue";}<br />
invoke(method, name); <br />
}</p>
<p>public static void destroyDestination(Class type, String name) <br />
throws Exception<br />
{<br />
String method = null;<br />
if (type == Topic.class) { method = "destroyTopic"; }<br />
else if (type == Queue.class) { method = "destroyQueue";}<br />
invoke(method, name);<br />
}</p>
<p>protected static void invoke(String method, String destName) <br />
throws Exception<br />
{<br />
try {<br />
MBeanServer server = (MBeanServer) MBeanServerFactory.findMBeanServer(null).iterator().next();<br />
invokeViaMBean(method, destName);<br />
}catch(Exception ex) { invokeViaUrl(method, destName);} <br />
}<br />
protected static void invokeViaUrl(String method, String destName) <br />
throws Exception<br />
{<br />
String action = "action=invokeOp&amp;methodIndex=6&amp;name=jboss.mq%3Aservice%3DDestinationManager&amp;arg0=" + destName;<br />
String arg = BASE_URL_ARG + action;<br />
URL url = new URL("http", HOST, PORT, arg);<br />
HttpURLConnection con = (HttpURLConnection)url.openConnection();<br />
con.connect();</p>
<p>InputStream is = con.getInputStream();<br />
java.io.ByteArrayOutputStream os = new java.io.ByteArrayOutputStream();<br />
byte[] buff = new byte[1024];<br />
for(;;) {<br />
int size = is.read( buff );<br />
if (size == -1 ) { break; }<br />
os.write(buff, 0, size);<br />
}<br />
os.flush();</p>
<p>if (con.getResponseCode() != HttpURLConnection.HTTP_OK ) {<br />
throw new Exception ("Could not invoke url: " + con.getResponseMessage() );<br />
} else {<br />
System.out.println("Invoked URL: " + method + " for destination " + destName + "got resonse: " + os.toString());<br />
} <br />
}<br />
protected static void invokeViaMBean(String method, String destName) <br />
throws Exception<br />
{<br />
MBeanServer server = (MBeanServer)MBeanServerFactory.findMBeanServer(null).iterator().next();<br />
server.invoke(new ObjectName("JBossMQ", "service", "DestinationManager"),<br />
method,<br />
new Object[] { destName },<br />
new String[] { "java.lang.String" });<br />
}<br />
public static void main(String[] args) {<br />
try {<br />
if (args.length &gt;0){<br />
destroyDestination(Topic.class,"myCreated");<br />
}else {<br />
createDestination(Topic.class,"myCreated");<br />
}<br />
}catch(Exception ex) {<br />
System.out.println("Error in administering destination: " + ex);<br />
ex.printStackTrace();<br />
}<br />
}</p>
<p>}<br />
编辑命令：<br />
javac -classpath C:\jboss-3.0.6_tomcat-4.1.18\client\jbossall-client.jar;C:\jboss-3.0.6_tomcat-4.1.18\lib\jboss-jmx.jar;. DestinationHelper.java<br />
运行命令<br />
java -classpath C:\jboss-3.0.6_tomcat-4.1.18\client\jbossall-client.jar;C:\jboss-3.0.6_tomcat-4.1.18\lib\jboss-jmx.jar;. DestinationHelper<br />
当运行完后查看<a href="http://localhost:8080/jmx-console"><font color="#108ac6">http://localhost:8080/jmx-console</font></a>下面的jboss.mq.destination中有name=myCreated,service=Topic <br />
表明你建立成功。当JBoss关闭重新启动时。该目的地不会在存在。</p>
<img src ="http://www.blogjava.net/dunkbird/aggbug/295055.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2009-09-14 19:34 <a href="http://www.blogjava.net/dunkbird/articles/295055.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java concurrent 探秘（2）</title><link>http://www.blogjava.net/dunkbird/articles/295038.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Mon, 14 Sep 2009 09:07:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/295038.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/295038.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/295038.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/295038.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/295038.html</trackback:ping><description><![CDATA[<p><font size="4">BlockingQueue</font><br />
支持两个附加操作的 Queue，这两个操作是：检索元素时等待队列变为非空，以及存储元素时等待空间变得可用。</p>
<p>BlockingQueue 不接受 null 元素。试图 add、put 或 offer 一个 null 元素时，某些实现会抛出 NullPointerException。null 被用作指示 poll 操作失败的警戒值。</p>
<p>BlockingQueue 可以是限定容量的。它在任意给定时间都可以有一个 remainingCapacity，超出此容量，便无法无阻塞地 put 额外的元素。<br />
没有任何内部容量约束的 BlockingQueue 总是报告 Integer.MAX_VALUE 的剩余容量。</p>
<p>BlockingQueue 实现主要用于生产者-使用者队列，但它另外还支持 Collection 接口。因此，举例来说，使用 remove(x) 从队列中移除任意一个元素是有可能的。<br />
然而，这种操作通常不 会有效执行，只能有计划地偶尔使用，比如在取消排队信息时。</p>
<p>BlockingQueue 实现是线程安全的。所有排队方法都可以使用内部锁定或其他形式的并发控制来自动达到它们的目的。<br />
然而，大量的 Collection 操作（addAll、containsAll、retainAll 和 removeAll）没有 必要自动执行，除非在实现中特别说明。<br />
因此，举例来说，在只添加了 c 中的一些元素后，addAll(c) 有可能失败（抛出一个异常）。</p>
<p>BlockingQueue 实质上不 支持使用任何一种&#8220;close&#8221;或&#8220;shutdown&#8221;操作来指示不再添加任何项。<br />
这种功能的需求和使用有依赖于实现的倾向。例如，一种常用的策略是：对于生产者，插入特殊的 end-of-stream 或 poison 对象，并根据使用者获取这些对象的时间来对它们进行解释。</p>
<p>下面的例子演示了这个阻塞队列的基本功能。</p>
<p><font color="#0000ff">import java.util.concurrent.BlockingQueue;<br />
import java.util.concurrent.ExecutorService;<br />
import java.util.concurrent.Executors;<br />
import java.util.concurrent.LinkedBlockingQueue;</font></p>
<p><font color="#0000ff">public class MyBlockingQueue extends Thread {<br />
public static BlockingQueue&lt;String&gt; queue = new LinkedBlockingQueue&lt;String&gt;(3);</font></p>
<p><font color="#0000ff">private int index;</font></p>
<p><font color="#0000ff">public MyBlockingQueue(int i) {<br />
&nbsp;&nbsp; this.index = i;<br />
}</font></p>
<p><font color="#0000ff">public void run() {<br />
&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp; queue.put(String.valueOf(this.index));<br />
&nbsp;&nbsp;&nbsp; System.out.println("{" + this.index + "} in queue!");<br />
&nbsp;&nbsp; } catch (Exception e) {<br />
&nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
&nbsp;&nbsp; }<br />
}</font></p>
<p><font color="#0000ff">public static void main(String args[]) {<br />
&nbsp;&nbsp; ExecutorService service = Executors.newCachedThreadPool();<br />
&nbsp;&nbsp; for (int i = 0; i &lt; 10; i++) {<br />
&nbsp;&nbsp;&nbsp; service.submit(new MyBlockingQueue(i));<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; Thread thread = new Thread() {<br />
&nbsp;&nbsp;&nbsp; public void run() {<br />
&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (true) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep((int) (Math.random() * 1000));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(MyBlockingQueue.queue.isEmpty())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String str = MyBlockingQueue.queue.take();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(str + " has take!");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp; };<br />
&nbsp;&nbsp; service.submit(thread);<br />
&nbsp;&nbsp; service.shutdown();<br />
}<br />
}<br />
</font>---------------------执行结果-----------------<br />
<font color="#ff0000">{0} in queue!<br />
{1} in queue!<br />
{2} in queue!<br />
{3} in queue!<br />
0 has take!<br />
{4} in queue!<br />
1 has take!<br />
{6} in queue!<br />
2 has take!<br />
{7} in queue!<br />
3 has take!<br />
{8} in queue!<br />
4 has take!<br />
{5} in queue!<br />
6 has take!<br />
{9} in queue!<br />
7 has take!<br />
8 has take!<br />
5 has take!<br />
9 has take!</font></p>
<p>-----------------------------------------</p>
<p><br />
<font size="4">CompletionService</font></p>
<p>将生产新的异步任务与使用已完成任务的结果分离开来的服务。生产者 submit 执行的任务。使用者 take 已完成的任务，<br />
并按照完成这些任务的顺序处理它们的结果。例如，CompletionService 可以用来管理异步 IO ，执行读操作的任务作为程序或系统的一部分提交，<br />
然后，当完成读操作时，会在程序的不同部分执行其他操作，执行操作的顺序可能与所请求的顺序不同。</p>
<p>通常，CompletionService 依赖于一个单独的 Executor 来实际执行任务，在这种情况下，<br />
CompletionService 只管理一个内部完成队列。ExecutorCompletionService 类提供了此方法的一个实现。</p>
<p><br />
<font color="#0000ff">import java.util.concurrent.Callable;<br />
import java.util.concurrent.CompletionService;<br />
import java.util.concurrent.ExecutorCompletionService;<br />
import java.util.concurrent.ExecutorService;<br />
import java.util.concurrent.Executors;</font></p>
<p><font color="#0000ff">public class MyCompletionService implements Callable&lt;String&gt; {<br />
private int id;<br />
<br />
public MyCompletionService(int i){<br />
&nbsp;&nbsp; this.id=i;<br />
}<br />
public static void main(String[] args) throws Exception{<br />
&nbsp;&nbsp; ExecutorService service=Executors.newCachedThreadPool();<br />
&nbsp;&nbsp; CompletionService&lt;String&gt; completion=new ExecutorCompletionService&lt;String&gt;(service);<br />
&nbsp;&nbsp; for(int i=0;i&lt;10;i++){<br />
&nbsp;&nbsp;&nbsp; completion.submit(new MyCompletionService(i));<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; for(int i=0;i&lt;10;i++){<br />
&nbsp;&nbsp;&nbsp; System.out.println(completion.take().get());<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; service.shutdown();<br />
}<br />
public String call() throws Exception {<br />
&nbsp;&nbsp; Integer time=(int)(Math.random()*1000);<br />
&nbsp;&nbsp; try{<br />
&nbsp;&nbsp;&nbsp; System.out.println(this.id+" start");<br />
&nbsp;&nbsp;&nbsp; Thread.sleep(time);<br />
&nbsp;&nbsp;&nbsp; System.out.println(this.id+" end");<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; catch(Exception e){<br />
&nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; return this.id+":"+time;<br />
}<br />
}</font></p>
<p><br />
<font size="4">CountDownLatch</font></p>
<p><br />
一个同步辅助类，在完成一组正在其他线程中执行的操作之前，它允许一个或多个线程一直等待。</p>
<p>用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法，所以在当前计数到达零之前，await 方法会一直受阻塞。<br />
之后，会释放所有等待的线程，await 的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。如果需要重置计数，请考虑使用 CyclicBarrier。</p>
<p>CountDownLatch 是一个通用同步工具，它有很多用途。将计数 1 初始化的 CountDownLatch 用作一个简单的开/关锁存器，<br />
或入口：在通过调用 countDown() 的线程打开入口前，所有调用 await 的线程都一直在入口处等待。<br />
用 N 初始化的 CountDownLatch 可以使一个线程在 N 个线程完成某项操作之前一直等待，或者使其在某项操作完成 N 次之前一直等待。</p>
<p>CountDownLatch 的一个有用特性是，它不要求调用 countDown 方法的线程等到计数到达零时才继续，<br />
而在所有线程都能通过之前，它只是阻止任何线程继续通过一个 await。 <br />
一下的例子是别人写的，非常形象。</p>
<p><font color="#0000ff">import java.util.concurrent.CountDownLatch;<br />
import java.util.concurrent.ExecutorService;<br />
import java.util.concurrent.Executors;</font></p>
<p><font color="#0000ff">public class TestCountDownLatch {<br />
public static void main(String[] args) throws InterruptedException {<br />
&nbsp;&nbsp; // 开始的倒数锁<br />
&nbsp;&nbsp; final CountDownLatch begin = new CountDownLatch(1);<br />
&nbsp;&nbsp; // 结束的倒数锁<br />
&nbsp;&nbsp; final CountDownLatch end = new CountDownLatch(10);<br />
&nbsp;&nbsp; // 十名选手<br />
&nbsp;&nbsp; final ExecutorService exec = Executors.newFixedThreadPool(10);<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp; for (int index = 0; index &lt; 10; index++) {<br />
&nbsp;&nbsp;&nbsp; final int NO = index + 1;<br />
&nbsp;&nbsp;&nbsp; Runnable run = new Runnable() {<br />
&nbsp;&nbsp;&nbsp;&nbsp; public void run() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; begin.await();//一直阻塞<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep((long) (Math.random() * 10000));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("No." + NO + " arrived");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (InterruptedException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } finally {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end.countDown();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; };<br />
&nbsp;&nbsp;&nbsp; exec.submit(run);<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; System.out.println("Game Start");<br />
&nbsp;&nbsp; begin.countDown();<br />
&nbsp;&nbsp; end.await();<br />
&nbsp;&nbsp; System.out.println("Game Over");<br />
&nbsp;&nbsp; exec.shutdown();<br />
}<br />
}<br />
</font>CountDownLatch最重要的方法是countDown()和await()，前者主要是倒数一次，后者是等待倒数到0，如果没有到达0，就只有阻塞等待了。</p>
<p><br />
<font size="4">CyclicBarrier</font></p>
<p>一个同步辅助类，它允许一组线程互相等待，直到到达某个公共屏障点 (common barrier point)。<br />
在涉及一组固定大小的线程的程序中，这些线程必须不时地互相等待，此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用，所以称它为循环 的 barrier。</p>
<p>CyclicBarrier 支持一个可选的 Runnable 命令，在一组线程中的最后一个线程到达之后（但在释放所有线程之前），<br />
该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态，此屏障操作 很有用。</p>
<p>示例用法：下面是一个在并行分解设计中使用 barrier 的例子，很经典的旅行团例子：<br />
<font color="#0000ff">import java.text.SimpleDateFormat;<br />
import java.util.Date;<br />
import java.util.concurrent.BrokenBarrierException;<br />
import java.util.concurrent.CyclicBarrier;<br />
import java.util.concurrent.ExecutorService;<br />
import java.util.concurrent.Executors;<br />
public class TestCyclicBarrier {<br />
// 徒步需要的时间: Shenzhen, Guangzhou, Shaoguan, Changsha, Wuhan<br />
private static int[] timeWalk = { 5, 8, 15, 15, 10 };<br />
// 自驾游<br />
private static int[] timeSelf = { 1, 3, 4, 4, 5 };<br />
// 旅游大巴<br />
private static int[] timeBus = { 2, 4, 6, 6, 7 };<br />
<br />
static String now() {<br />
&nbsp;&nbsp;&nbsp; SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");<br />
&nbsp;&nbsp;&nbsp; return sdf.format(new Date()) + ": ";<br />
}</font></p>
<p><font color="#0000ff">static class Tour implements Runnable {<br />
&nbsp;&nbsp;&nbsp; private int[] times;<br />
&nbsp;&nbsp;&nbsp; private CyclicBarrier barrier;<br />
&nbsp;&nbsp;&nbsp; private String tourName;<br />
&nbsp;&nbsp;&nbsp; public Tour(CyclicBarrier barrier, String tourName, int[] times) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.times = times;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.tourName = tourName;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.barrier = barrier;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; public void run() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(times[0] * 1000);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(now() + tourName + " Reached Shenzhen");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; barrier.await();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(times[1] * 1000);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(now() + tourName + " Reached Guangzhou");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; barrier.await();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(times[2] * 1000);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(now() + tourName + " Reached Shaoguan");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; barrier.await();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(times[3] * 1000);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(now() + tourName + " Reached Changsha");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; barrier.await();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(times[4] * 1000);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(now() + tourName + " Reached Wuhan");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; barrier.await();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (InterruptedException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (BrokenBarrierException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
}</font></p>
<p><font color="#0000ff">public static void main(String[] args) {<br />
&nbsp;&nbsp;&nbsp; // 三个旅行团<br />
&nbsp;&nbsp;&nbsp; CyclicBarrier barrier = new CyclicBarrier(3);<br />
&nbsp;&nbsp;&nbsp; ExecutorService exec = Executors.newFixedThreadPool(3);<br />
&nbsp;&nbsp;&nbsp; exec.submit(new Tour(barrier, "WalkTour", timeWalk));<br />
&nbsp;&nbsp;&nbsp; exec.submit(new Tour(barrier, "SelfTour", timeSelf));<br />
//当我们把下面的这段代码注释后，会发现，程序阻塞了，无法继续运行下去。<br />
&nbsp;&nbsp;&nbsp; exec.submit(new Tour(barrier, "BusTour", timeBus));<br />
&nbsp;&nbsp;&nbsp; exec.shutdown();<br />
}<br />
} </font></p>
<p>CyclicBarrier最重要的属性就是参与者个数，另外最要方法是await()。当所有线程都调用了await()后，就表示这些线程都可以继续执行，否则就会等待。</p>
<p><font size="4">Future</font></p>
<p>Future 表示异步计算的结果。它提供了检查计算是否完成的方法，以等待计算的完成，并检索计算的结果。<br />
计算完成后只能使用 get 方法来检索结果，如有必要，计算完成前可以阻塞此方法。取消则由 cancel 方法来执行。<br />
还提供了其他方法，以确定任务是正常完成还是被取消了。一旦计算完成，就不能再取消计算。<br />
如果为了可取消性而使用 Future但又不提供可用的结果，则可以声明 Future&lt;?&gt; 形式类型、并返回 null 作为基础任务的结果。</p>
<p>这个我们在前面CompletionService已经看到了，这个Future的功能，而且这个可以在提交线程的时候被指定为一个返回对象的。</p>
<p><br />
<font size="4">ScheduledExecutorService</font></p>
<p>一个 ExecutorService，可安排在给定的延迟后运行或定期执行的命令。</p>
<p>schedule 方法使用各种延迟创建任务，并返回一个可用于取消或检查执行的任务对象。scheduleAtFixedRate 和 scheduleWithFixedDelay 方法创建并执行某些在取消前一直定期运行的任务。</p>
<p>用 Executor.execute(java.lang.Runnable) 和 ExecutorService 的 submit 方法所提交的命令，通过所请求的 0 延迟进行安排。<br />
schedule 方法中允许出现 0 和负数延迟（但不是周期），并将这些视为一种立即执行的请求。</p>
<p>所有的 schedule 方法都接受相对 延迟和周期作为参数，而不是绝对的时间或日期。将以 Date 所表示的绝对时间转换成要求的形式很容易。<br />
例如，要安排在某个以后的日期运行，可以使用：schedule(task, date.getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS)。<br />
但是要注意，由于网络时间同步协议、时钟漂移或其他因素的存在，因此相对延迟的期满日期不必与启用任务的当前 Date 相符。<br />
Executors 类为此包中所提供的 ScheduledExecutorService 实现提供了便捷的工厂方法。</p>
<p>一下的例子也是网上比较流行的。</p>
<p><font color="#0000ff">import static java.util.concurrent.TimeUnit.SECONDS;<br />
import java.util.Date;<br />
import java.util.concurrent.Executors;<br />
import java.util.concurrent.ScheduledExecutorService;<br />
import java.util.concurrent.ScheduledFuture;</font></p>
<p><font color="#0000ff">public class TestScheduledThread {<br />
public static void main(String[] args) {<br />
&nbsp;&nbsp; final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);<br />
&nbsp;&nbsp; final Runnable beeper = new Runnable() {<br />
&nbsp;&nbsp;&nbsp; int count = 0;</font></p>
<p><font color="#0000ff">&nbsp;&nbsp;&nbsp; public void run() {<br />
&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(new Date() + " beep " + (++count));<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp; };<br />
&nbsp;&nbsp; // 1秒钟后运行，并每隔2秒运行一次<br />
&nbsp;&nbsp; final ScheduledFuture beeperHandle = scheduler.scheduleAtFixedRate(beeper, 1, 2, SECONDS);<br />
&nbsp;&nbsp; // 2秒钟后运行，并每次在上次任务运行完后等待5秒后重新运行<br />
&nbsp;&nbsp; final ScheduledFuture beeperHandle2 = scheduler.scheduleWithFixedDelay(beeper, 2, 5, SECONDS);<br />
&nbsp;&nbsp; // 30秒后结束关闭任务，并且关闭Scheduler<br />
&nbsp;&nbsp; scheduler.schedule(new Runnable() {<br />
&nbsp;&nbsp;&nbsp; public void run() {<br />
&nbsp;&nbsp;&nbsp;&nbsp; beeperHandle.cancel(true);<br />
&nbsp;&nbsp;&nbsp;&nbsp; beeperHandle2.cancel(true);<br />
&nbsp;&nbsp;&nbsp;&nbsp; scheduler.shutdown();<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp; }, 30, SECONDS);<br />
}<br />
}</font></p>
<p>这样我们就把concurrent包下比较重要的功能都已经总结完了，希望对我们理解能有帮助。</p>
<img src ="http://www.blogjava.net/dunkbird/aggbug/295038.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2009-09-14 17:07 <a href="http://www.blogjava.net/dunkbird/articles/295038.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java concurrent 探秘（1）</title><link>http://www.blogjava.net/dunkbird/articles/295037.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Mon, 14 Sep 2009 09:06:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/295037.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/295037.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/295037.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/295037.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/295037.html</trackback:ping><description><![CDATA[&nbsp;我们都知道，在JDK1.5之前，Java中要进行业务并发时，通常需要有程序员独立完成代码实现，当然也有一些开源的框架提供了这些功能，但是这些依然没有JDK自带的功能使用起来方便。而当针对高质量Java多线程并发程序设计时,为防止死蹦等现象的出现，比如使用java之前的wait()、notify()和synchronized等，每每需要考虑性能、死锁、公平性、资源管理以及如何避免线程安全性方面带来的危害等诸多因素，往往会采用一些较为复杂的安全策略，加重了程序员的开发负担.万幸的是，在JDK1.5出现之后，Sun大神（Doug Lea）终于为我们这些可怜的小程序员推出了java.util.concurrent工具包以简化并发完成。开发者们借助于此，将有效的减少竞争条件（race conditions）和死锁线程。concurrent包很好的解决了这些问题，为我们提供了更实用的并发程序模型。
<p><br />
Executor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ：具体Runnable任务的执行者。<br />
ExecutorService&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ：一个线程池管理者，其实现类有多种，我会介绍一部分。我们能把Runnable,Callable提交到池中让其调度。<br />
Semaphore&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ：一个计数信号量<br />
ReentrantLock&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ：一个可重入的互斥锁定 Lock，功能类似synchronized，但要强大的多。<br />
Future&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ：是与Runnable,Callable进行交互的接口，比如一个线程执行结束后取返回的结果等等，还提供了cancel终止线程。<br />
BlockingQueue&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ：阻塞队列。<br />
CompletionService&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : ExecutorService的扩展，可以获得线程执行结果的<br />
CountDownLatch&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ：一个同步辅助类，在完成一组正在其他线程中执行的操作之前，它允许一个或多个线程一直等待。 <br />
CyclicBarrier&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ：一个同步辅助类，它允许一组线程互相等待，直到到达某个公共屏障点 <br />
Future&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ：Future 表示异步计算的结果。<br />
ScheduledExecutorService ：一个 ExecutorService，可安排在给定的延迟后运行或定期执行的命令。</p>
<p>接下来逐一介绍</p>
<p><font size="4">Executors主要方法说明<br />
</font><strong><font size="2">newFixedThreadPool</font>（</strong>固定大小线程池）<br />
创建一个可重用固定线程集合的线程池，以共享的无界队列方式来运行这些线程（只有要请求的过来，就会在一个队列里等待执行）。如果在关闭前的执行期间由于失败而导致任何线程终止，那么一个新线程将代替它执行后续的任务（如果需要）。</p>
<p><strong>newCachedThreadPool</strong>（无界线程池，可以进行自动线程回收）<br />
创建一个可根据需要创建新线程的线程池，但是在以前构造的线程可用时将重用它们。对于执行很多短期异步任务的程序而言，这些线程池通常可提高程序性能。调用 execute 将重用以前构造的线程（如果线程可用）。如果现有线程没有可用的，则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。因此，长时间保持空闲的线程池不会使用任何资源。注意，可以使用 ThreadPoolExecutor 构造方法创建具有类似属性但细节不同（例如超时参数）的线程池。</p>
<p><strong>newSingleThreadExecutor</strong>（单个后台线程）<br />
创建一个使用单个 worker 线程的 Executor，以无界队列方式来运行该线程。（注意，如果因为在关闭前的执行期间出现失败而终止了此单个线程，那么如果需要，一个新线程将代替它执行后续的任务）。可保证顺序地执行各个任务，并且在任意给定的时间不会有多个线程是活动的。与其他等效的 newFixedThreadPool(1) 不同，可保证无需重新配置此方法所返回的执行程序即可使用其他的线程。</p>
<p>这些方法返回的都是ExecutorService对象，这个对象可以理解为就是一个线程池。<br />
这个线程池的功能还是比较完善的。可以提交任务submit()可以结束线程池shutdown()。</p>
<p><font color="#0000ff">import java.util.concurrent.ExecutorService;<br />
import java.util.concurrent.Executors;</font></p>
<p><font color="#0000ff">public class MyExecutor extends Thread {<br />
private int index;<br />
public MyExecutor(int i){<br />
&nbsp;&nbsp; this.index=i;<br />
}<br />
public void run(){<br />
&nbsp;&nbsp; try{<br />
&nbsp;&nbsp;&nbsp; System.out.println("["+this.index+"] start....");<br />
&nbsp;&nbsp;&nbsp; Thread.sleep((int)(Math.random()*1000));<br />
&nbsp;&nbsp;&nbsp; System.out.println("["+this.index+"] end.");<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; catch(Exception e){<br />
&nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
&nbsp;&nbsp; }<br />
}<br />
<br />
public static void main(String args[]){<br />
&nbsp;&nbsp; ExecutorService service=Executors.newFixedThreadPool(4);<br />
&nbsp;&nbsp; for(int i=0;i&lt;10;i++){<br />
&nbsp;&nbsp;&nbsp; service.execute(new MyExecutor(i));<br />
&nbsp;&nbsp;&nbsp; //service.submit(new MyExecutor(i));<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; System.out.println("submit finish");<br />
&nbsp;&nbsp; service.shutdown();<br />
}<br />
}</font></p>
<p>虽然打印了一些信息，但是看的不是非常清晰，这个线程池是如何工作的，我们来将休眠的时间调长10倍。<br />
Thread.sleep((int)(Math.random()*10000));</p>
<p>再来看，会清楚看到只能执行4个线程。当执行完一个线程后，才会又执行一个新的线程，也就是说，我们将所有的线程提交后，线程池会等待执行完最后shutdown。我们也会发现，提交的线程被放到一个&#8220;无界队列里&#8221;。这是一个有序队列（BlockingQueue，这个下面会说到）。</p>
<p>另外它使用了Executors的静态函数生成一个固定的线程池，顾名思义，线程池的线程是不会释放的，即使它是Idle。<br />
这就会产生性能问题，比如如果线程池的大小为200，当全部使用完毕后，所有的线程会继续留在池中，相应的内存和线程切换（while(true)+sleep循环）都会增加。<br />
如果要避免这个问题，就必须直接使用ThreadPoolExecutor()来构造。可以像通用的线程池一样设置&#8220;最大线程数&#8221;、&#8220;最小线程数&#8221;和&#8220;空闲线程keepAlive的时间&#8221;。</p>
<p><br />
这个就是线程池基本用法。<br />
<br />
<font size="4">Semaphore</font><br />
一个计数信号量。从概念上讲，信号量维护了一个许可集合。如有必要，在许可可用前会阻塞每一个 acquire()，然后再获取该许可。每个 release() 添加一个许可，从而可能释放一个正在阻塞的获取者。但是，不使用实际的许可对象，Semaphore 只对可用许可的号码进行计数，并采取相应的行动。</p>
<p>Semaphore 通常用于限制可以访问某些资源（物理或逻辑的）的线程数目。例如，下面的类使用信号量控制对内容池的访问：</p>
<p>这里是一个实际的情况，大家排队上厕所，厕所只有两个位置，来了10个人需要排队。</p>
<p><font color="#0000ff">import java.util.concurrent.ExecutorService;<br />
import java.util.concurrent.Executors;<br />
import java.util.concurrent.Semaphore;</font></p>
<p><font color="#0000ff">public class MySemaphore extends Thread {<br />
Semaphore position;<br />
private int id;<br />
public MySemaphore(int i,Semaphore s){<br />
&nbsp;&nbsp; this.id=i;<br />
&nbsp;&nbsp; this.position=s;<br />
}<br />
<br />
public void run(){<br />
&nbsp;&nbsp; try{<br />
&nbsp;&nbsp;&nbsp; if(position.availablePermits()&gt;0){<br />
&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("顾客["+this.id+"]进入厕所，有空位");<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; else{<br />
&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("顾客["+this.id+"]进入厕所，没空位，排队");<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; position.acquire();<br />
&nbsp;&nbsp;&nbsp; System.out.println("顾客["+this.id+"]获得坑位");<br />
&nbsp;&nbsp;&nbsp; Thread.sleep((int)(Math.random()*1000));<br />
&nbsp;&nbsp;&nbsp; System.out.println("顾客["+this.id+"]使用完毕");<br />
&nbsp;&nbsp;&nbsp; position.release();<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; catch(Exception e){<br />
&nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
&nbsp;&nbsp; }<br />
}<br />
public static void main(String args[]){<br />
&nbsp;&nbsp; ExecutorService list=Executors.newCachedThreadPool();<br />
&nbsp;&nbsp; Semaphore position=new Semaphore(2);<br />
&nbsp;&nbsp; for(int i=0;i&lt;10;i++){<br />
&nbsp;&nbsp;&nbsp; list.submit(new MySemaphore(i+1,position));<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; list.shutdown();<br />
&nbsp;&nbsp; position.acquireUninterruptibly(2);<br />
&nbsp;&nbsp; System.out.println("使用完毕，需要清扫了");<br />
&nbsp;&nbsp; position.release(2);<br />
}<br />
}</font></p>
<p>&nbsp;</p>
<p><font size="4">ReentrantLock</font><br />
一个可重入的互斥锁定 Lock，它具有与使用 synchronized 方法和语句所访问的隐式监视器锁定相同的一些基本行为和语义，但功能更强大。</p>
<p>ReentrantLock 将由最近成功获得锁定，并且还没有释放该锁定的线程所拥有。当锁定没有被另一个线程所拥有时，调用 lock 的线程将成功获取该锁定并返回。如果当前线程已经拥有该锁定，此方法将立即返回。可以使用 isHeldByCurrentThread() 和 getHoldCount() 方法来检查此情况是否发生。</p>
<p>此类的构造方法接受一个可选的公平参数。<br />
当设置为 true时，在多个线程的争用下，这些锁定倾向于将访问权授予等待时间最长的线程。否则此锁定将无法保证任何特定访问顺序。<br />
与采用默认设置（使用不公平锁定）相比，使用公平锁定的程序在许多线程访问时表现为很低的总体吞吐量（即速度很慢，常常极其慢），但是在获得锁定和保证锁定分配的均衡性时差异较小。不过要注意的是，公平锁定不能保证线程调度的公平性。因此，使用公平锁定的众多线程中的一员可能获得多倍的成功机会，这种情况发生在其他活动线程没有被处理并且目前并未持有锁定时。还要注意的是，未定时的 tryLock 方法并没有使用公平设置。因为即使其他线程正在等待，只要该锁定是可用的，此方法就可以获得成功。</p>
<p>建议总是 立即实践，使用 try 块来调用 lock，在之前/之后的构造中，最典型的代码如下： <br />
class X {<br />
&nbsp;&nbsp; private final ReentrantLock lock = new ReentrantLock();<br />
&nbsp;&nbsp; // ...</p>
<p>&nbsp;&nbsp; public void m() { <br />
&nbsp;&nbsp;&nbsp;&nbsp; lock.lock(); // block until condition holds<br />
&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // ... method body<br />
&nbsp;&nbsp;&nbsp;&nbsp; } finally {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lock.unlock()<br />
&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp; }<br />
}</p>
<p>我的例子：<br />
<font color="#0000ff">import java.util.concurrent.ExecutorService;<br />
import java.util.concurrent.Executors;<br />
import java.util.concurrent.locks.ReentrantLock;</font></p>
<p><font color="#0000ff">public class MyReentrantLock extends Thread{<br />
TestReentrantLock lock;<br />
private int id;<br />
public MyReentrantLock(int i,TestReentrantLock test){<br />
&nbsp;&nbsp; this.id=i;<br />
&nbsp;&nbsp; this.lock=test;<br />
}<br />
<br />
public void run(){<br />
&nbsp;&nbsp; lock.print(id);<br />
}</font></p>
<p><font color="#0000ff">public static void main(String args[]){<br />
&nbsp;&nbsp; ExecutorService service=Executors.newCachedThreadPool();<br />
&nbsp;&nbsp; TestReentrantLock lock=new TestReentrantLock();<br />
&nbsp;&nbsp; for(int i=0;i&lt;10;i++){<br />
&nbsp;&nbsp;&nbsp; service.submit(new MyReentrantLock(i,lock));<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; service.shutdown();<br />
}<br />
}<br />
class TestReentrantLock{<br />
private ReentrantLock lock=new ReentrantLock();<br />
public void print(int str){<br />
&nbsp;&nbsp; try{<br />
&nbsp;&nbsp;&nbsp; lock.lock();<br />
&nbsp;&nbsp;&nbsp; System.out.println(str+"获得");<br />
&nbsp;&nbsp;&nbsp; Thread.sleep((int)(Math.random()*1000));<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; catch(Exception e){<br />
&nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; finally{<br />
&nbsp;&nbsp;&nbsp; System.out.println(str+"释放");<br />
&nbsp;&nbsp;&nbsp; lock.unlock();<br />
&nbsp;&nbsp; }<br />
}<br />
}</font></p>
<img src ="http://www.blogjava.net/dunkbird/aggbug/295037.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2009-09-14 17:06 <a href="http://www.blogjava.net/dunkbird/articles/295037.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java 线程池的原理与实现</title><link>http://www.blogjava.net/dunkbird/articles/291429.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Mon, 17 Aug 2009 01:58:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/291429.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/291429.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/291429.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/291429.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/291429.html</trackback:ping><description><![CDATA[最近在学习线程池、内存控制等关于提高程序运行性能方面的编程技术，在网上看到有一哥们写得不错，故和大家一起分享。<br />
<br />
[分享]Java 线程池的原理与实现<br />
<br />
<br />
这几天主要是狂看源程序，在弥补了一些以前知识空白的同时，也学会了不少新的知识（比如 NIO），或者称为新技术吧。<br />
线程池就是其中之一，一提到线程，我们会想到以前《操作系统》的生产者与消费者，信号量，同步控制等等。<br />
一提到池，我们会想到数据库连接池，但是线程池又如何呢？<br />
<br />
<br />
<strong>建议</strong>：在阅读本文前，先理一理同步的知识，特别是syncronized同步关键字的用法。<br />
关于我对同步的认识，要缘于大三年的一本书，书名好像是 Java 实战，这本书写得实在太妙了，真正的从理论到实践，从截图分析到.class字节码分析。哇，我想市场上很难买到这么精致的书了。作为一个Java爱好者，我觉得绝对值得一读。<br />
我对此书印象最深之一的就是：equal()方法，由浅入深，经典！<br />
还有就是同步了，其中提到了我的几个编程误区，以前如何使用同步提高性能等等，通过学习，使我对同步的认识进一步加深。<br />
<br />
<br />
<font size="3"><strong>简单介绍</strong></font><br />
<br />
&nbsp;&nbsp;&nbsp; 创建线程有两种方式：继承Thread或实现Runnable。Thread实现了Runnable接口，提供了一个空的run()方法，所以不论是继承Thread还是实现Runnable，都要有自己的run()方法。<br />
&nbsp;&nbsp;&nbsp; 一个线程创建后就存在，调用start()方法就开始运行（执行run()方法），调用wait进入等待或调用sleep进入休眠期，顺利运行完毕或休眠被中断或运行过程中出现异常而退出。<br />
<br />
<strong>wait和sleep比较：</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sleep方法有：sleep(long millis)，sleep(long millis, long nanos)，调用sleep方法后，当前线程进入休眠期，暂停执行，但该线程继续拥有监视资源的所有权。到达休眠时间后线程将继续执行，直到完成。若在休眠期另一线程中断该线程，则该线程退出。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wait方法有：wait()，wait(long timeout)，wait(long timeout, long nanos)，调用wait方法后，该线程放弃监视资源的所有权进入等待状态；<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wait()：等待有其它的线程调用notify()或notifyAll()进入调度状态，与其它线程共同争夺监视。wait()相当于wait(0)，wait(0, 0)。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wait(long timeout)：当其它线程调用notify()或notifyAll()，或时间到达timeout亳秒，或有其它某线程中断该线程，则该线程进入调度状态。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wait(long timeout, long nanos)：相当于wait(1000000*timeout + nanos)，只不过时间单位为纳秒。<br />
<br />
<br />
<br />
<font color="#ff0000" size="3"><strong>线程池：</strong></font><br />
&nbsp;&nbsp;&nbsp; 多线程技术主要解决处理器单元内多个线程执行的问题，它可以显著减少处理器单元的闲置时间，增加处理器单元的吞吐能力。<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 假设一个服务器完成一项任务所需时间为：T1 创建线程时间，T2 在线程中执行任务的时间，T3 销毁线程时间。<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 如果：T1 + T3 远大于 T2，则可以采用线程池，以提高服务器性能。<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 一个线程池包括以下四个基本组成部分：<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 1、线程池管理器（ThreadPool）：用于创建并管理线程池，包括 创建线程池，销毁线程池，添加新任务；<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 2、工作线程（PoolWorker）：线程池中线程，在没有任务时处于等待状态，可以循环的执行任务；<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 3、任务接口（Task）：每个任务必须实现的接口，以供工作线程调度任务的执行，它主要规定了任务的入口，任务执行完后的收尾工作，任务的执行状态等；<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 4、任务队列（taskQueue）：用于存放没有处理的任务。提供一种缓冲机制。<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 线程池技术正是关注如何缩短或调整T1,T3时间的技术，从而提高服务器程序性能的。它把T1，T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段，这样在服务器程序处理客户请求时，不会有T1，T3的开销了。<br />
<br />
&nbsp;&nbsp;&nbsp; 线程池不仅调整T1,T3产生的时间段，而且它还显著减少了创建线程的数目，看一个例子：<br />
<br />
&nbsp;&nbsp;&nbsp; 假设一个服务器一天要处理50000个请求，并且每个请求需要一个单独的线程完成。在线程池中，线程数一般是固定的，所以产生线程总数不会超过线程池中线程的数目，而如果服务器不利用线程池来处理这些请求则线程总数为50000。一般线程池大小是远小于50000。所以利用线程池的服务器程序不会为了创建50000而在处理请求时浪费时间，从而提高效率。<br />
<br />
<br />
<strong>/** 线程池类，工作线程作为其内部类 **/</strong><br />
<br />
package org.ymcn.util;<br />
<br />
import java.util.Collections;<br />
import java.util.Date;<br />
import java.util.LinkedList;<br />
import java.util.List;<br />
<br />
import org.apache.log4j.Logger;<br />
<br />
/**<br />
* 线程池<br />
* 创建线程池，销毁线程池，添加新任务<br />
* <br />
* @author obullxl<br />
*/<br />
public final class ThreadPool {<br />
&nbsp;&nbsp;&nbsp; private static Logger logger = Logger.getLogger(ThreadPool.class);<br />
&nbsp;&nbsp;&nbsp; private static Logger taskLogger = Logger.getLogger("TaskLogger");<br />
<br />
&nbsp;&nbsp;&nbsp; private static boolean debug = taskLogger.isDebugEnabled();<br />
&nbsp;&nbsp;&nbsp; // private static boolean debug = taskLogger.isInfoEnabled();<br />
&nbsp;&nbsp;&nbsp; /* 单例 */<br />
&nbsp;&nbsp;&nbsp; private static ThreadPool instance = ThreadPool.getInstance();<br />
<br />
&nbsp;&nbsp;&nbsp; public static final int SYSTEM_BUSY_TASK_COUNT = 150;<br />
&nbsp;&nbsp;&nbsp; /* 默认池中线程数 */<br />
&nbsp;&nbsp;&nbsp; public static int worker_num = 5;<br />
&nbsp;&nbsp;&nbsp; /* 已经处理的任务数 */<br />
&nbsp;&nbsp;&nbsp; private static int taskCounter = 0;<br />
<br />
&nbsp;&nbsp;&nbsp; public static boolean systemIsBusy = false;<br />
<br />
&nbsp;&nbsp;&nbsp; private static List&lt;Task&gt; taskQueue = Collections<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; .synchronizedList(new LinkedList&lt;Task&gt;());<br />
&nbsp;&nbsp;&nbsp; /* 池中的所有线程 */<br />
&nbsp;&nbsp;&nbsp; public PoolWorker[] workers;<br />
<br />
&nbsp;&nbsp;&nbsp; private ThreadPool() {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; workers = new PoolWorker[5];<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; workers.length; i++) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; workers[i] = new PoolWorker(i);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; private ThreadPool(int pool_worker_num) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; worker_num = pool_worker_num;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; workers = new PoolWorker[worker_num];<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; workers.length; i++) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; workers[i] = new PoolWorker(i);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; public static synchronized ThreadPool getInstance() {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (instance == null)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return new ThreadPool();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return instance;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp; * 增加新的任务<br />
&nbsp;&nbsp;&nbsp; * 每增加一个新任务，都要唤醒任务队列<br />
&nbsp;&nbsp;&nbsp; * @param newTask<br />
&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public void addTask(Task newTask) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; synchronized (taskQueue) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; newTask.setTaskId(++taskCounter);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; newTask.setSubmitTime(new Date());<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; taskQueue.add(newTask);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* 唤醒队列, 开始执行 */<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; taskQueue.notifyAll();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; logger.info("Submit Task&lt;" + newTask.getTaskId() + "&gt;: "<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; + newTask.info());<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp; * 批量增加新任务<br />
&nbsp;&nbsp;&nbsp; * @param taskes<br />
&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public void batchAddTask(Task[] taskes) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (taskes == null || taskes.length == 0) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; synchronized (taskQueue) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; taskes.length; i++) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (taskes[i] == null) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; continue;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; taskes[i].setTaskId(++taskCounter);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; taskes[i].setSubmitTime(new Date());<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; taskQueue.add(taskes[i]);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* 唤醒队列, 开始执行 */<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; taskQueue.notifyAll();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; taskes.length; i++) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (taskes[i] == null) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; continue;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; logger.info("Submit Task&lt;" + taskes[i].getTaskId() + "&gt;: "<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; + taskes[i].info());<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp; * 线程池信息<br />
&nbsp;&nbsp;&nbsp; * @return<br />
&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public String getInfo() {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; StringBuffer sb = new StringBuffer();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sb.append("\nTask Queue Size:" + taskQueue.size());<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; workers.length; i++) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sb.append("\nWorker " + i + " is "<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; + ((workers[i].isWaiting()) ? "Waiting." : "Running."));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return sb.toString();<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp; * 销毁线程池<br />
&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public synchronized void destroy() {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; worker_num; i++) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; workers[i].stopWorker();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; workers[i] = null;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; taskQueue.clear();<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp; * 池中工作线程<br />
&nbsp;&nbsp;&nbsp; * <br />
&nbsp;&nbsp;&nbsp; * @author obullxl<br />
&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; private class PoolWorker extends Thread {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; private int index = -1;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* 该工作线程是否有效 */<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; private boolean isRunning = true;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* 该工作线程是否可以执行新任务 */<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; private boolean isWaiting = true;<br />
<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public PoolWorker(int index) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; this.index = index;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; start();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public void stopWorker() {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; this.isRunning = false;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public boolean isWaiting() {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return this.isWaiting;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; * 循环执行任务<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; * 这也许是线程池的关键所在<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public void run() {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while (isRunning) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Task r = null;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; synchronized (taskQueue) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while (taskQueue.isEmpty()) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* 任务队列为空，则等待有新任务加入从而被唤醒 */<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; taskQueue.wait(20);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } catch (InterruptedException ie) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; logger.error(ie);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* 取出任务执行 */<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; r = (Task) taskQueue.remove(0);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (r != null) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; isWaiting = false;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (debug) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; r.setBeginExceuteTime(new Date());<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; taskLogger.debug("Worker&lt;" + index<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; + "&gt; start execute Task&lt;" + r.getTaskId() + "&gt;");<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (r.getBeginExceuteTime().getTime()<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; - r.getSubmitTime().getTime() &gt; 1000)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; taskLogger.debug("longer waiting time. "<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; + r.info() + ",&lt;" + index + "&gt;,time:"<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; + (r.getFinishTime().getTime() - r<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; .getBeginExceuteTime().getTime()));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* 该任务是否需要立即执行 */<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (r.needExecuteImmediate()) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; new Thread(r).start();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } else {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; r.run();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (debug) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; r.setFinishTime(new Date());<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; taskLogger.debug("Worker&lt;" + index<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; + "&gt; finish task&lt;" + r.getTaskId() + "&gt;");<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (r.getFinishTime().getTime()<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; - r.getBeginExceuteTime().getTime() &gt; 1000)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; taskLogger.debug("longer execution time. "<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; + r.info() + ",&lt;" + index + "&gt;,time:"<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; + (r.getFinishTime().getTime() - r<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; .getBeginExceuteTime().getTime()));<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } catch (Exception e) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; logger.error(e);<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; isWaiting = true;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; r = null;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
<br />
<strong>/** 任务接口类 **/</strong><br />
<br />
package org.ymcn.util;<br />
<br />
import java.util.Date;<br />
<br />
/**<br />
* 所有任务接口<br />
* 其他任务必须继承访类<br />
* <br />
* @author obullxl<br />
*/<br />
public abstract class Task implements Runnable {<br />
&nbsp;&nbsp;&nbsp; // private static Logger logger = Logger.getLogger(Task.class);<br />
&nbsp;&nbsp;&nbsp; /* 产生时间 */<br />
&nbsp;&nbsp;&nbsp; private Date generateTime = null;<br />
&nbsp;&nbsp;&nbsp; /* 提交执行时间 */<br />
&nbsp;&nbsp;&nbsp; private Date submitTime = null;<br />
&nbsp;&nbsp;&nbsp; /* 开始执行时间 */<br />
&nbsp;&nbsp;&nbsp; private Date beginExceuteTime = null;<br />
&nbsp;&nbsp;&nbsp; /* 执行完成时间 */<br />
&nbsp;&nbsp;&nbsp; private Date finishTime = null;<br />
<br />
&nbsp;&nbsp;&nbsp; private long taskId;<br />
<br />
&nbsp;&nbsp;&nbsp; public Task() {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; this.generateTime = new Date();<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp; * 任务执行入口<br />
&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public void run() {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; * 相关执行代码<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; * <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; * beginTransaction();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; * <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; * 执行过程中可能产生新的任务 subtask = taskCore();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; * <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; * commitTransaction();<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; * <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; * 增加新产生的任务 ThreadPool.getInstance().batchAddTask(taskCore());<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp; * 所有任务的核心 所以特别的业务逻辑执行之处<br />
&nbsp;&nbsp;&nbsp; * <br />
&nbsp;&nbsp;&nbsp; * @throws Exception<br />
&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public abstract Task[] taskCore() throws Exception;<br />
<br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp; * 是否用到数据库<br />
&nbsp;&nbsp;&nbsp; * <br />
&nbsp;&nbsp;&nbsp; * @return<br />
&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; protected abstract boolean useDb();<br />
<br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp; * 是否需要立即执行<br />
&nbsp;&nbsp;&nbsp; * <br />
&nbsp;&nbsp;&nbsp; * @return<br />
&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; protected abstract boolean needExecuteImmediate();<br />
<br />
&nbsp;&nbsp;&nbsp; /**<br />
&nbsp;&nbsp;&nbsp; * 任务信息<br />
&nbsp;&nbsp;&nbsp; * <br />
&nbsp;&nbsp;&nbsp; * @return String<br />
&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; public abstract String info();<br />
<br />
&nbsp;&nbsp;&nbsp; public Date getGenerateTime() {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return generateTime;<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; public Date getBeginExceuteTime() {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return beginExceuteTime;<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; public void setBeginExceuteTime(Date beginExceuteTime) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; this.beginExceuteTime = beginExceuteTime;<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; public Date getFinishTime() {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return finishTime;<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; public void setFinishTime(Date finishTime) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; this.finishTime = finishTime;<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; public Date getSubmitTime() {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return submitTime;<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; public void setSubmitTime(Date submitTime) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; this.submitTime = submitTime;<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; public long getTaskId() {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return taskId;<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; public void setTaskId(long taskId) {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; this.taskId = taskId;<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
}<br />
<br />
<br />
<br />
<a href="http://hi.baidu.com/obullxl/blog/item/ee50ad1ba8e8ff1f8718bf66.html">转自：http://hi.baidu.com/obullxl/blog/item/ee50ad1ba8e8ff1f8718bf66.html</a>
<img src ="http://www.blogjava.net/dunkbird/aggbug/291429.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2009-08-17 09:58 <a href="http://www.blogjava.net/dunkbird/articles/291429.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java 自带的线程池--转载</title><link>http://www.blogjava.net/dunkbird/articles/291424.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Mon, 17 Aug 2009 01:49:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/291424.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/291424.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/291424.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/291424.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/291424.html</trackback:ping><description><![CDATA[<p>从 Java 5 开始，Java 提供了自己的线程池。线程池就是一个线程的容器，每次只执行额定数量的线程。 java.util.concurrent.ThreadPoolExecutor 就是这样的线程池。它很灵活，但使用起来也比较复杂，本文就对其做一个介绍。</p>
<p>&nbsp;</p>
<p><br />
首先是构造函数。以最简单的构造函数为例：</p>
<p>view plaincopy to clipboardprint?<br />
public ThreadPoolExecutor(&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int corePoolSize,&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int maximumPoolSize,&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long keepAliveTime,&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TimeUnit unit,&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BlockingQueue&lt;Runnable&gt; workQueue) <br />
public ThreadPoolExecutor(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int corePoolSize,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int maximumPoolSize,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long keepAliveTime,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TimeUnit unit,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BlockingQueue&lt;Runnable&gt; workQueue)</p>
<p>看起来挺复杂的。这里介绍一下。</p>
<p>corePoolSize 指的是保留的线程池大小。 <br />
maximumPoolSize 指的是线程池的最大大小。 <br />
keepAliveTime 指的是空闲线程结束的超时时间。 <br />
unit 是一个枚举，表示 keepAliveTime 的单位。 <br />
workQueue 表示存放任务的队列。</p>
<p>我们可以从线程池的工作过程中了解这些参数的意义。线程池的工作过程如下：</p>
<p>&nbsp;</p>
<p><br />
1、线程池刚创建时，里面没有一个线程。任务队列是作为参数传进来的。不过，就算队列里面有任务，线程池也不会马上执行它们。</p>
<p>2、当调用 execute() 方法添加一个任务时，线程池会做如下判断：</p>
<p>&nbsp;&nbsp;&nbsp; a. 如果正在运行的线程数量小于 corePoolSize，那么马上创建线程运行这个任务；</p>
<p>&nbsp;&nbsp;&nbsp; b. 如果正在运行的线程数量大于或等于 corePoolSize，那么将这个任务放入队列。</p>
<p>&nbsp;&nbsp;&nbsp; c. 如果这时候队列满了，而且正在运行的线程数量小于 maximumPoolSize，那么还是要创建线程运行这个任务；</p>
<p>&nbsp;&nbsp;&nbsp; d. 如果队列满了，而且正在运行的线程数量大于或等于 maximumPoolSize，那么线程池会抛出异常，告诉调用者&#8220;我不能再接受任务了&#8221;。</p>
<p>3、当一个线程完成任务时，它会从队列中取下一个任务来执行。</p>
<p>4、当一个线程无事可做，超过一定的时间（keepAliveTime）时，线程池会判断，如果当前运行的线程数大于 corePoolSize，那么这个线程就被停掉。所以线程池的所有任务完成后，它最终会收缩到 corePoolSize 的大小。</p>
<p>这样的过程说明，并不是先加入任务就一定会先执行。假设队列大小为 10，corePoolSize 为 3，maximumPoolSize 为 6，那么当加入 20 个任务时，执行的顺序就是这样的：首先执行任务 1、2、3，然后任务 4~13 被放入队列。这时候队列满了，任务 14、15、16 会被马上执行，而任务 17~20 则会抛出异常。最终顺序是：1、2、3、14、15、16、4、5、6、7、8、9、10、11、12、13。下面是一个线程池使用的例子：</p>
<p>view plaincopy to clipboardprint?<br />
public static void main(String[] args) {&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; BlockingQueue&lt;Runnable&gt; queue = new LinkedBlockingQueue&lt;Runnable&gt;();&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 6, 1, TimeUnit.DAYS, queue);&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; 20; i++) {&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; executor.execute(new Runnable() {&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run() {&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(1000);&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (InterruptedException e) {&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(String.format("thread %d finished", this.hashCode()));&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; executor.shutdown();&nbsp;&nbsp; <br />
} <br />
public static void main(String[] args) {<br />
&nbsp;&nbsp;&nbsp; BlockingQueue&lt;Runnable&gt; queue = new LinkedBlockingQueue&lt;Runnable&gt;();<br />
&nbsp;&nbsp;&nbsp; ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 6, 1, TimeUnit.DAYS, queue);<br />
<br />
&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; 20; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; executor.execute(new Runnable() {<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(1000);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (InterruptedException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(String.format("thread %d finished", this.hashCode()));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; executor.shutdown();<br />
}</p>
<p><br />
对这个例子的说明如下：</p>
<p><br />
1、BlockingQueue 只是一个接口，常用的实现类有 LinkedBlockingQueue 和 ArrayBlockingQueue。用 LinkedBlockingQueue 的好处在于没有大小限制。这样的话，因为队列不会满，所以 execute() 不会抛出异常，而线程池中运行的线程数也永远不会超过 corePoolSize 个，keepAliveTime 参数也就没有意义了。</p>
<p>2、shutdown() 方法不会阻塞。调用 shutdown() 方法之后，主线程就马上结束了，而线程池会继续运行直到所有任务执行完才会停止。如果不调用 shutdown() 方法，那么线程池会一直保持下去，以便随时添加新的任务。</p>
<p>到这里对于这个线程池还只是介绍了一小部分。ThreadPoolExecutor 具有很强的可扩展性，不过扩展它的前提是要熟悉它的工作方式。后面的文章将会介绍如何扩展 ThreadPoolExecutor 类。</p>
<p>&nbsp;</p>
<p>本文来自CSDN博客，转载请标明出处：<a href="http://blog.csdn.net/YidingHe/archive/2009/02/14/3889785.aspx">http://blog.csdn.net/YidingHe/archive/2009/02/14/3889785.aspx</a></p>
<img src ="http://www.blogjava.net/dunkbird/aggbug/291424.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2009-08-17 09:49 <a href="http://www.blogjava.net/dunkbird/articles/291424.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java中XML的四种解析器(dom,sax,jdom,dom4j)原理及性能比较</title><link>http://www.blogjava.net/dunkbird/articles/291420.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Mon, 17 Aug 2009 01:46:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/291420.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/291420.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/291420.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/291420.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/291420.html</trackback:ping><description><![CDATA[<table style="table-layout: fixed; width: 100%">
    <tbody>
        <tr>
            <td>
            <div class="cnt" id="blog_text">
            <div class="cnt">
            <p><font face="Arial" color="#008000" size="2">1）DOM(JAXP Crimson解析器) <br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准。DOM是以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中寻找 特定信息。分析该结构通常需要加载整个文档和构造层次结构，然后才能做任何工作。由于它是基于信息层次的，因而DOM被认为是基于树或基于对象的。DOM 以及广义的基于树的处理具有几个优点。首先，由于树在内存中是持久的，因此可以修改它以便应用程序能对数据和结构作出更改。它还可以在任何时候在树中上下 导航，而不是像SAX那样是一次性的处理。DOM使用起来也要简单得多。</font></p>
            <p><font face="Arial" color="#008000" size="2">2）SAX</font></p>
            <p><font face="Arial" color="#008000" size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SAX处理的优点非常类似于流媒体的优点。分析能够立即开始，而不是等待所有的数据被处理。而且，由于应用程序只是在读取数据时检查数据，因此不需要将数 据存储在内存中。这对于大型文档来说是个巨大的优点。事实上，应用程序甚至不必解析整个文档；它可以在某个条件得到满足时停止解析。一般来说，SAX还比 它的替代者DOM快许多。 <br />
            选择DOM还是选择SAX？ 对于需要自己编写代码来处理XML文档的开发人员来说， 选择DOM还是SAX解析模型是一个非常重要的设计决策。 DOM采用建立树形结构的方式访问XML文档，而SAX采用的事件模型。 </font></p>
            <p><font face="Arial" color="#008000" size="2">　　DOM解析器把XML文档转化为一个包含其内容的 树，并可以对树进行遍历。用DOM解析模型的优点是编程容易，开发人员只需要调用建树的指令，然后利用navigation APIs访问所需的树节点来完成任务。可以很容易的添加和修改树中的元素。然而由于使用DOM解析器的时候需要处理整个XML文档，所以对性能和内存的要 求比较高，尤其是遇到很大的XML文件的时候。由于它的遍历能力，DOM解析器常用于XML文档需要频繁的改变的服务中。 </font></p>
            <p><font face="Arial" color="#008000" size="2">　　SAX解析器采用了基于事件的模型，它在解析 XML文档的时候可以触发一系列的事件，当发现给定的tag的时候，它可以激活一个回调方法，告诉该方法制定的标签已经找到。SAX对内存的要求通常会比 较低，因为它让开发人员自己来决定所要处理的tag。特别是当开发人员只需要处理文档中所包含的部分数据时，SAX这种扩展能力得到了更好的体现。但用 SAX解析器的时候编码工作会比较困难，而且很难同时访问同一个文档中的多处不同数据。 </font></p>
            <p><font face="Arial" color="#008000" size="2">3）JDOM&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; http://www.jdom.org/</font></p>
            <p><font face="Arial" color="#008000" size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JDOM的目的是成为Java特定文档模型，它简化与XML的交互并且比使用DOM实现更快。由于是第一个Java特定模型，JDOM一直得到大力推广和 促进。正在考虑通过&#8220;Java规范请求JSR-102&#8221;将它最终用作&#8220;Java标准扩展&#8221;。从2000年初就已经开始了JDOM开发。 </font></p>
            <p><font face="Arial" color="#008000" size="2">　　JDOM与DOM主要有两方面不同。首先，JDOM仅使用具体类而不使用接口。这在某些方面简化了API，但是也限制了灵活性。第二，API大量使用了Collections类，简化了那些已经熟悉这些类的Java开发者的使用。 </font></p>
            <p><font face="Arial" color="#008000" size="2">　　JDOM文档声明其目的是&#8220;使用20%(或更少) 的精力解决80%(或更多)Java/XML问题&#8221;(根据学习曲线假定为20%)。JDOM对于大多数Java/XML应用程序来说当然是有用的，并且大 多数开发者发现API比DOM容易理解得多。JDOM还包括对程序行为的相当广泛检查以防止用户做任何在XML中无意义的事。然而，它仍需要您充分理解 XML以便做一些超出基本的工作(或者甚至理解某些情况下的错误)。这也许是比学习DOM或JDOM接口都更有意义的工作。 </font></p>
            <p><font face="Arial" color="#008000" size="2">　　JDOM自身不包含解析器。它通常使用SAX2解 析器来解析和验证输入XML文档(尽管它还可以将以前构造的DOM表示作为输入)。它包含一些转换器以将JDOM表示输出成SAX2事件流、DOM模型或 XML文本文档。JDOM是在Apache许可证变体下发布的开放源码。</font></p>
            <p><font face="Arial" color="#008000" size="2">4）DOM4J http://dom4j.sourceforge.net/ <br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 虽然DOM4J代表了完全独立的开发结果，但最初，它是JDOM的一种智能分支。它合并了许多超出基本XML文档表示的功能，包括集成的XPath支持、 XML Schema支持以及用于大文档或流化文档的基于事件的处理。它还提供了构建文档表示的选项，它通过DOM4J API和标准DOM接口具有并行访问功能。从2000下半年开始，它就一直处于开发之中。 </font></p>
            <p><font face="Arial" color="#008000" size="2">　　为支持所有这些功能，DOM4J使用接口和抽象基 本类方法。DOM4J大量使用了API中的Collections类，但是在许多情况下，它还提供一些替代方法以允许更好的性能或更直接的编码方法。直接 好处是，虽然DOM4J付出了更复杂的API的代价，但是它提供了比JDOM大得多的灵活性。 </font></p>
            <p><font face="Arial" color="#008000" size="2">　　在添加灵活性、XPath集成和对大文档处理的目 标时，DOM4J的目标与JDOM是一样的：针对Java开发者的易用性和直观操作。它还致力于成为比JDOM更完整的解决方案，实现在本质上处理所有 Java/XML问题的目标。在完成该目标时，它比JDOM更少强调防止不正确的应用程序行为。 </font></p>
            <p><font face="Arial" color="#008000" size="2">　　DOM4J是一个非常非常优秀的Java XML API，具有性能优异、功能强大和极端易用使用的特点，同时它也是一个开放源代码的软件。如今你可以看到越来越多的Java软件都在使用DOM4J来读写 XML，特别值得一提的是连Sun的JAXM也在用DOM4J。 </font></p>
            <p><br />
            <font face="Arial" color="#008000" size="2">2.. 比较</font></p>
            <p><font face="Arial" color="#008000" size="2">1）DOM4J性能最好，连Sun的JAXM也在用DOM4J。目前许多开源项目中大量采用DOM4J，例如大名鼎鼎的Hibernate也用DOM4J来读取XML配置文件。如果不考虑可移植性，那就采用DOM4J.</font></p>
            <p><font face="Arial" color="#008000" size="2">2）JDOM和DOM在性能测试时表现不佳，在测试 10M文档时内存溢出。在小文档情况下还值得考虑使用DOM和JDOM。虽然JDOM的开发者已经说明他们期望在正式发行版前专注性能问题，但是从性能观 点来看，它确实没有值得推荐之处。另外，DOM仍是一个非常好的选择。DOM实现广泛应用于多种编程语言。它还是许多其它与XML相关的标准的基础，因为 它正式获得W3C推荐(与基于非标准的Java模型相对)，所以在某些类型的项目中可能也需要它(如在JavaScript中使用DOM)。</font></p>
            <p><font face="Arial" color="#008000" size="2">3）SAX表现较好，这要依赖于它特定的解析方式－事件驱动。一个SAX检测即将到来的XML流，但并没有载入到内存(当然当XML流被读入时，会有部分文档暂时隐藏在内存中)。</font></p>
            <p><font face="Arial" color="#008000" size="2">3. 四种xml操作方式的基本使用方法</font></p>
            <p><font face="Arial" color="#008000" size="2">xml文件：</font></p>
            <p><font face="Arial" color="#008000" size="2">&lt;?xml version="1.0" encoding="utf-8" ?&gt; <br />
            &lt;Result&gt;<br />
            &nbsp;&nbsp; &lt;VALUE&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;NO DATE="2005"&gt;A1&lt;/NO&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ADDR&gt;GZ&lt;/ADDR&gt;<br />
            &nbsp;&nbsp; &lt;/VALUE&gt;<br />
            &nbsp;&nbsp; &lt;VALUE&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;NO DATE="2004"&gt;A2&lt;/NO&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ADDR&gt;XG&lt;/ADDR&gt;<br />
            &lt;/VALUE&gt;<br />
            &lt;/Result&gt;</font></p>
            <p><font face="Arial" color="#008000" size="2">1）DOM</font></p>
            <p><font face="Arial" color="#008000" size="2">import java.io.*;<br />
            import java.util.*;<br />
            import org.w3c.dom.*;<br />
            import javax.xml.parsers.*; </font></p>
            <p><font face="Arial" color="#008000" size="2">public class MyXMLReader{ <br />
            public static void main(String arge[]){ </font></p>
            <p><font face="Arial" color="#008000" size="2">　　long lasting =System.currentTimeMillis(); <br />
            try{ <br />
            File f=new File("data_10k.xml"); <br />
            DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance(); <br />
            DocumentBuilder builder=factory.newDocumentBuilder(); <br />
            Document doc = builder.parse(f); <br />
            NodeList nl = doc.getElementsByTagName("VALUE"); <br />
            for (int i=0;i＜nl.getLength();i++){ <br />
            System.out.print("车牌号码:" + doc.getElementsByTagName("NO").item(i).getFirstChild().getNodeValue()); <br />
            System.out.println("车主地址:" + doc.getElementsByTagName("ADDR").item(i).getFirstChild().getNodeValue()); <br />
            } <br />
            }catch(Exception e){ <br />
            e.printStackTrace(); <br />
            } </font></p>
            <p><font face="Arial" color="#008000" size="2">2）SAX</font></p>
            <p><font face="Arial" color="#008000" size="2">import org.xml.sax.*;<br />
            import org.xml.sax.helpers.*;<br />
            import javax.xml.parsers.*; </font></p>
            <p><font face="Arial" color="#008000" size="2">public class MyXMLReader extends DefaultHandler { </font></p>
            <p><font face="Arial" color="#008000" size="2">　java.util.Stack tags = new java.util.Stack(); <br />
            public MyXMLReader() { <br />
            super();<br />
            &nbsp;&nbsp; } </font></p>
            <p><font face="Arial" color="#008000" size="2">　public static void main(String args[]) { <br />
            long lasting = System.currentTimeMillis(); <br />
            try { <br />
            SAXParserFactory sf = SAXParserFactory.newInstance(); <br />
            SAXParser sp = sf.newSAXParser(); <br />
            MyXMLReader reader = new MyXMLReader(); <br />
            sp.parse(new InputSource("data_10k.xml"), reader); <br />
            } catch (Exception e) { <br />
            e.printStackTrace(); <br />
            } </font></p>
            <p><font face="Arial" color="#008000" size="2">　　System.out.println("运行时间：" + (System.currentTimeMillis() - lasting) + "毫秒");} <br />
            public void characters(char ch[], int start, int length) throws SAXException { <br />
            String tag = (String) tags.peek(); <br />
            if (tag.equals("NO")) { <br />
            System.out.print("车牌号码：" + new String(ch, start, length));<br />
            &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; if (tag.equals("ADDR")) { <br />
            System.out.println("地址:" + new String(ch, start, length));<br />
            &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp; } </font></p>
            <p><font face="Arial" color="#008000" size="2">　　public void startElement(String uri,String localName,String qName,Attributes attrs) { <br />
            tags.push(qName);}<br />
            } </font></p>
            <p><font face="Arial" color="#008000" size="2">3） JDOM</font></p>
            <p><font face="Arial" color="#008000" size="2">import java.io.*;<br />
            import java.util.*;<br />
            import org.jdom.*;<br />
            import org.jdom.input.*; </font></p>
            <p><font face="Arial" color="#008000" size="2">public class MyXMLReader { </font></p>
            <p><font face="Arial" color="#008000" size="2">　public static void main(String arge[]) { <br />
            long lasting = System.currentTimeMillis(); <br />
            try { <br />
            SAXBuilder builder = new SAXBuilder(); <br />
            Document doc = builder.build(new File("data_10k.xml")); <br />
            Element foo = doc.getRootElement(); <br />
            List allChildren = foo.getChildren(); <br />
            for(int i=0;i＜allChildren.size();i++) { <br />
            System.out.print("车牌号码:" + ((Element)allChildren.get(i)).getChild("NO").getText()); <br />
            System.out.println("车主地址:" + ((Element)allChildren.get(i)).getChild("ADDR").getText()); <br />
            } <br />
            } catch (Exception e) { <br />
            e.printStackTrace(); <br />
            } </font></p>
            <p><font face="Arial" color="#008000" size="2">}</font></p>
            <p><font face="Arial" color="#008000" size="2">4）DOM4J</font></p>
            <p><font face="Arial" color="#008000" size="2">import java.io.*;<br />
            import java.util.*;<br />
            import org.dom4j.*;<br />
            import org.dom4j.io.*; </font></p>
            <p><font face="Arial" color="#008000" size="2">public class MyXMLReader { </font></p>
            <font face="Arial" color="#008000" size="2">　public static void main(String arge[]) { <br />
            long lasting = System.currentTimeMillis(); <br />
            try { <br />
            File f = new File("data_10k.xml"); <br />
            SAXReader reader = new SAXReader(); <br />
            Document doc = reader.read(f); <br />
            Element root = doc.getRootElement(); <br />
            Element foo; <br />
            for (Iterator i = root.elementIterator("VALUE"); i.hasNext();) { <br />
            foo = (Element) i.next(); <br />
            System.out.print("车牌号码:" + foo.elementText("NO")); <br />
            System.out.println("车主地址:" + foo.elementText("ADDR")); <br />
            } <br />
            } catch (Exception e) { <br />
            e.printStackTrace(); <br />
            &nbsp;&nbsp;&nbsp; } </font></div>
            </div>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/dunkbird/aggbug/291420.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2009-08-17 09:46 <a href="http://www.blogjava.net/dunkbird/articles/291420.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java字节流和字符流</title><link>http://www.blogjava.net/dunkbird/articles/279552.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Tue, 02 Jun 2009 05:14:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/279552.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/279552.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/279552.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/279552.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/279552.html</trackback:ping><description><![CDATA[<p style="margin: 0cm 0cm 0pt"><span style="font-size: small"><span style="font-family: Times New Roman">Java</span>流操作</span></p>
<p>&nbsp;<br />
<span style="font-size: medium; background-color: #ff0000">对于我们常用的GBK中，英文是占用1个字节，中文是2个 <br />
对于UTF-8，英文是1个，中文是3个 <br />
对于Unicode，英文中文都是2个</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: small"><span style="font-family: Times New Roman">Java</span>的流操作分为字节流和字符流两种。</span></p>
<p style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt"><span style="font-family: Times New Roman"><span style="font-size: small">1、&nbsp;</span></span><span style="font-size: small">字节流</span></p>
<p style="margin: 0cm 0cm 0pt 18pt"><span style="font-size: small">所有的读操作都继承自一个公共超类<span style="font-family: Times New Roman">java.io.InputStream</span>类。</span></p>
<p style="margin: 0cm 0cm 0pt 18pt"><span style="font-size: small">所有的写操作都继承自一个公共超类<span style="font-family: Times New Roman">java.io.OutputStream</span>类。</span></p>
<p style="margin: 0cm 0cm 0pt 18pt"><span style="font-size: small"><span style="font-family: Times New Roman">InputStream</span>和<span style="font-family: Times New Roman">OutputStream</span>都是抽象类。</span></p>
<p style="margin: 0cm 0cm 0pt 18pt"><span style="font-size: small"><span style="font-family: Times New Roman">InputStream</span>有<span style="font-family: Times New Roman">6</span>个低级输入流：</span></p>
<table style="border-collapse: collapse" cellspacing="0" cellpadding="0" border="1">
    <tbody>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 213.05pt; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">低级流</span></p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 213.05pt; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">流的用途</span></p>
            </td>
        </tr>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small; font-family: Times New Roman">ByteArrayInputStream</span></p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">从内存数组中读取数据字节</span></p>
            </td>
        </tr>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small; font-family: Times New Roman">FileInputStream</span></p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">从本地文件系统中读取数据字节</span></p>
            </td>
        </tr>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small; font-family: Times New Roman">PipedInputStream</span></p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">从线程管道中读取数据字节</span></p>
            </td>
        </tr>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small; font-family: Times New Roman">StringBufferInputStream</span></p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">从字符串中读取数据字节</span></p>
            </td>
        </tr>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small; font-family: Times New Roman">SequenceInputStream</span></p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">从两个或多个低级流中读取数据字节，当到达流的末尾时从一个流转到另一个流</span></p>
            </td>
        </tr>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small; font-family: Times New Roman">System.in</span></p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">从用户控制台读取数据字节</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="margin: 0cm 0cm 0pt 18pt"><span style="font-size: small"><span style="font-family: Times New Roman">InputStream</span>还有一个子类：过滤器流<span style="font-family: Times New Roman">java.io.FilterInputStream</span>。过滤器流即能把基本流包裹起来，提供更多方便的用法。</span></p>
<p style="margin: 0cm 0cm 0pt 18pt"><span style="font-size: small"><span style="font-family: Times New Roman">FilterInputStream </span>类的构造方法为<span style="font-family: Times New Roman">FilterInputStream(InputStream)</span>，在指定的输入流之上，创建一个输入流过滤器。</span></p>
<p style="margin: 0cm 0cm 0pt 18pt"><span style="font-size: small"><span style="font-family: Times New Roman">FilterInputStream</span>的常用的子类如下：</span></p>
<table style="border-collapse: collapse" cellspacing="0" cellpadding="0" border="1">
    <tbody>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 213.05pt; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">过滤器输入流</span></p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 213.05pt; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">流的用途</span></p>
            </td>
        </tr>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small; font-family: Times New Roman">BufferedInputStream</span></p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">缓冲区对数据的访问，以提高效率</span></p>
            </td>
        </tr>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small; font-family: Times New Roman">DataInputStream</span></p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">从输入流中读取基本数据类型，如<span style="font-family: Times New Roman">int</span>、<span style="font-family: Times New Roman">float</span>、<span style="font-family: Times New Roman">double</span>或者甚至一行文本</span></p>
            </td>
        </tr>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small; font-family: Times New Roman">LineNumberInputStream</span></p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">在翻译行结束符的基础上，维护一个计数器，该计数器表明正在读取的是哪一行。</span></p>
            </td>
        </tr>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small; font-family: Times New Roman">PushbackInputStream</span></p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">允许把数据字节向后推到流的首部</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: small"><span style="font-family: Times New Roman">OutputStream</span>（略）</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 18pt"><span style="font-size: small"><span style="font-family: Times New Roman">OutputStream</span>的结构基本和<span style="font-family: Times New Roman">InputStream</span>是一样的。</span></p>
<p style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt"><span style="font-family: Times New Roman"><span style="font-size: small">2、&nbsp;</span></span><span style="font-size: small">字符流</span></p>
<p style="margin: 0cm 0cm 0pt 18pt"><span style="font-size: small">注：是在<span style="font-family: Times New Roman">jdk1.1</span>里面引进的，上面字节流是在<span style="font-family: Times New Roman">jdk1.0</span>引进的。当用于处理文本数据时，选择字符流比字节流更好。但对只出路基本数据类型的开发者，可以继续使用字节流。</span></p>
<p style="margin: 0cm 0cm 0pt 18pt"><span style="font-size: small">所有的读操作都继承自一个公共超类<span style="font-family: Times New Roman">java.io.Reader</span>类。</span></p>
<p style="margin: 0cm 0cm 0pt 18pt"><span style="font-size: small">所有的写操作都继承自一个公共超类<span style="font-family: Times New Roman">java.io.Writer</span>类。</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: small"><span style="font-family: Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>同样<span style="font-family: Times New Roman">Reader</span>和<span style="font-family: Times New Roman">Writer</span>也是抽象类。</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="font-size: small"><span style="font-family: Times New Roman">Reader</span>的常用的子类如下：</span></p>
<table style="border-collapse: collapse" cellspacing="0" cellpadding="0" border="1">
    <tbody>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 213.05pt; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">低级读取器</span></p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 213.05pt; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">流的用途</span></p>
            </td>
        </tr>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt">CharArrayReader</p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">从字符数组中读取数据</span></p>
            </td>
        </tr>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt">InputStreamReader</p>
            <p>&nbsp;</p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p>&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="font-size: small"><span style="font-family: Times New Roman">FileReader</span>（InputStreamReader的子类） </span></p>
            <p>&nbsp;</p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">从本地文件系统中读取字符序列</span></p>
            </td>
        </tr>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt">StringReader</p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">从字符串中读取字符序列</span></p>
            </td>
        </tr>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt">PipedReader</p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 213.05pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="284">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">从线程管道中读取字符序列</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt">InputStreamReader重点讲解：</p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt">InputStreamReader是从输入流中读取数据，连接输入流于读取器。如：</p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt"><span style="font-size: 12pt"><span style="font-family: Times New Roman">new InputStreamReader(System.in) </span></span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: 12pt"><span style="font-family: Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>构造方法：</p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; text-align: left" align="left">InputStreamReader<span style="color: #000000">(InputStream) </span></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt; text-align: left" align="left">用缺省的字符编码方式，创建一个 InputStreamReader。</p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; text-align: left" align="left"><a href="http://mce_host/admin/blogs/185580/mk:@MSITStoreF:/精华/jdk.chm::"><span style="color: windowtext; text-decoration: none">InputStreamReader</a><span style="color: #000000">(InputStream, String) </span></span></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt; text-align: left" align="left">用已命名的字符编码方式，创建一个 InputStreamReader。</p>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: 12pt"><span style="font-family: Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>常用的过滤器读取器：</p>
<table style="border-collapse: collapse" cellspacing="0" cellpadding="0" border="1">
    <tbody>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 221.4pt; padding-top: 0cm; background-color: transparent" valign="top" width="295">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">过滤器读取器 </span></p>
            <p>&nbsp;</p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 204.7pt; padding-top: 0cm; background-color: transparent" valign="top" width="273">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">流的用途</span></p>
            </td>
        </tr>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 221.4pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="295">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small; font-family: Times New Roman">BufferedReader</span></p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 204.7pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="273">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">缓冲数据的访问，以提高效率</span></p>
            </td>
        </tr>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 221.4pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="295">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small"><span style="font-family: Times New Roman">&nbsp;LineNumberReader</span>（<span style="font-family: Times New Roman">BufferedReader</span>的子类）</span></p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 204.7pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="273">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">维护一个计数器，该计数器表明正在读取的是哪一行。</span></p>
            </td>
        </tr>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 221.4pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="295">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small"><span style="font-family: Times New Roman">FilterReader</span>（抽象类）</span></p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 204.7pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="273">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">提供一个类创建过滤器时可以扩展这个类</span></p>
            </td>
        </tr>
        <tr>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 221.4pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="295">
            <p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="font-size: small"><span style="font-family: Times New Roman">PushbackReader</span>（<span style="font-family: Times New Roman">FilterReader</span>的子类）</span></p>
            </td>
            <td style="padding-right: 5.4pt; padding-left: 5.4pt; border-left-color: #d4d0c8; padding-bottom: 0cm; width: 204.7pt; border-top-color: #d4d0c8; padding-top: 0cm; background-color: transparent" valign="top" width="273">
            <p style="margin: 0cm 0cm 0pt"><span style="font-size: small">允许把文本数据推回到读取器的流中</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt">这些过滤器读取器都可以传入一个<span style="font-size: 12pt"><span style="font-family: Times New Roman">Reader</span></span>作为构造方法的参数。</p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="font-size: 12pt"><span style="font-family: Times New Roman">Writer</span></span>（略）</p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt"><span style="font-size: small"><span style="font-family: Times New Roman">Writer</span>的结构基本和<span style="font-family: Times New Roman">Reader</span>是一样的。</span></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt"><span style="font-size: small">字节流是最基本的，字符流是为了处理字符而提出来的。</span></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt"><span style="font-size: small">new BufferedReader(new InputStreamReader(client.getInputStream()));解释：</span></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt"><span style="font-size: small">client.getInputStream()是字节流；</span></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt"><span style="font-size: small">InputStreamReader把字节流转换成字符流；</span></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: 21pt"><span style="font-size: small">BufferedReader缓冲字符流，使得能够使用readline()等方法，直接读取一行。</span></p>
<p>
<p>
<p>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/dunkbird/aggbug/279552.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2009-06-02 13:14 <a href="http://www.blogjava.net/dunkbird/articles/279552.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于J2EE Tranaction的几个基本概念</title><link>http://www.blogjava.net/dunkbird/articles/242856.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Wed, 26 Nov 2008 11:09:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/242856.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/242856.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/242856.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/242856.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/242856.html</trackback:ping><description><![CDATA[<p style="text-indent: 2em">Transaction不管在J2EE还是.NET领域中都是相当重要的一个组成部分。尽管很多与Transaction相关的概念在两个不同的平台中都是相通的，但是它们在Transaction的实现方面却有着很多的不同。想对.NET下的Transaction有更深入了解的朋友，可以参考<a href="http://www.cnblogs.com/idior">idior</a>兄写的<a href="http://www.cnblogs.com/idior/archive/2005/08/15/214300.html">Transaction in ADO.net 2.0</a>。在以下的篇幅里面，我就J2EE中与Transaction相关的几个概念做些讲述。</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.什么是Transaction？所谓Transaction是指一系列不可分割的改动数据库的操作。在这个解释中，有三个关键词：一系列，不可分割以及改动。仅仅是一个改动数据库的操作是没有Transaction可言，只有&#8220;一系列&#8221;操作(一组SQL语句)才可能组成Transaction；&#8220;不可分割&#8221;就意味着一致性和完整性，要么这一系列操作全部commit，要么就全部rollback；如果一系列的操作只包含enquiry操作，那么这些操作也不是Transaction。&nbsp;</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2.在J2EE中，Transaction主要有几大类，具体有几种？在J2EE中，Transaction主要有Bean-Managed Transaction和Container-Managed Transaction两大类。其中在Bean-Managed Transaction中还会分为JDBC Transaction和JTA Transaction两种。</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3.什么是JDBC Transaction？它有怎样的特点？JDBC Transaction是指由Database本身去管理的事务。其最大的特点就是通过显示调用Connection接口的commit和rollback方法来完成事务的提交和回滚。事务结束的边界是commit或者rollback方法的调用，而开始的边界则不是那么明显了，它会开始于组成当前事务的所有statement中的第一个被执行的时候。具体代码如下：</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" border="0"  alt="" /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" border="0"  alt="" />class&nbsp;CreditDAoImpl&nbsp;implements&nbsp;CreditDAO&nbsp;<img src="http://www.cnblogs.com/Images/dot.gif" border="0"  alt="" />{</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;Connection&nbsp;conn&nbsp;=&nbsp;getConnection();</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" border="0"  alt="" /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;transfer(Currency&nbsp;amount,&nbsp;Account&nbsp;fromAccount,&nbsp;Account&nbsp;toAccount)&nbsp;throws&nbsp;CreditException&nbsp;<img src="http://www.cnblogs.com/Images/dot.gif" border="0"  alt="" />{</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" border="0"  alt="" /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;<img src="http://www.cnblogs.com/Images/dot.gif" border="0"  alt="" />{</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;conn.setAutoCommit(false);</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;depositToAccount(conn,&nbsp;toAccount,&nbsp;amount);</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;withdrawFromAccount(conn,&nbsp;fromAccount,&nbsp;amount);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;conn.commit();</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" border="0"  alt="" /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Exception&nbsp;e)&nbsp;<img src="http://www.cnblogs.com/Images/dot.gif" border="0"  alt="" />{</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" border="0"  alt="" /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;<img src="http://www.cnblogs.com/Images/dot.gif" border="0"  alt="" />{</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;conn.rollback();</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;CreditException(e.getMessage());</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" border="0"  alt="" /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(SQLException&nbsp;e1)&nbsp;<img src="http://www.cnblogs.com/Images/dot.gif" border="0"  alt="" />{</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;CreditException(e.getMessage());</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" border="0"  alt="" />}</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4.什么是JTA Transaction？它有怎样的特点呢？JTA Transaction是指由J2EE Transaction manager去管理的事务。其最大的特点是调用UserTransaction接口的begin，commit和rollback方法来完成事务范围的界定，事务的提交和回滚。JTA Transaction可以实现同一事务对应不同的数据库，但是它仍然无法实现事务的嵌套。具体的代码如下[1]：</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" border="0"  alt="" /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" border="0"  alt="" />public&nbsp;void&nbsp;withdrawCash(double&nbsp;amount)&nbsp;<img src="http://www.cnblogs.com/Images/dot.gif" border="0"  alt="" />{</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;UserTransaction&nbsp;ut&nbsp;=&nbsp;context.getUserTransaction();</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" border="0"  alt="" /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;try&nbsp;<img src="http://www.cnblogs.com/Images/dot.gif" border="0"  alt="" />{</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ut.begin();</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;updateChecking(amount);</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;machineBalance&nbsp;-=&nbsp;amount;</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;insertMachine(machineBalance);</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ut.commit();</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" border="0"  alt="" /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Exception&nbsp;ex)&nbsp;<img src="http://www.cnblogs.com/Images/dot.gif" border="0"  alt="" />{</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" border="0"  alt="" /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;<img src="http://www.cnblogs.com/Images/dot.gif" border="0"  alt="" />{</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ut.rollback();</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" border="0"  alt="" /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(SystemException&nbsp;syex)&nbsp;<img src="http://www.cnblogs.com/Images/dot.gif" border="0"  alt="" />{</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;EJBException</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;("Rollback&nbsp;failed:&nbsp;"&nbsp;+&nbsp;syex.getMessage());</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;EJBException&nbsp;</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;("Transaction&nbsp;failed:&nbsp;"&nbsp;+&nbsp;ex.getMessage());</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" border="0"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p style="text-indent: 2em"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" border="0"  alt="" />}</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5.什么是Container-Managed Transaction？它又有怎样的特点呢？Container-Managed Transaction，顾名思义，就是由Container负责管理的Transaction，当然这样Transaction是出现在EJB的范畴中。Container-Managed Transaction最大的特点是不需要显式界定事务的边界，也不需要显式的提交或者回滚事务，这一切都由Container来替我们完成。我们需要做的就是设定在一个Bean中，哪些方法是跟事务相关的，同时设定它们的Transaction Attribute既可。</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Transaction的Scope是相当重要的，特别是在一个Bean的方法中调用另外一个Bean的方法。为了便于说明问题，我们把这两个方法分别称为methodA和methodB。当methodA调用methodB的时候，methodB在事务的层面上对调用者methodA有怎样的限制(methodB中是否存在事务)以及methodA如何在事务的层面上实现对methodB的调用(是否需要重新创建一个新的事务来处理methodB的调用)都需要通过Transaction Attribute来设定的。具体的Transaction Attribute有以下六种：Required，RequiresNew，Mandatory，NotSupported，Supports和Never。有关Transaction Attribute的介绍，可以参阅J2EE Tutorial中<a href="http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/Transaction3.html">关于Container-Managed Transaction的介绍</a>。</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [1] 代码来自SUN的J2EE Tutorial中关于<a href="http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/Transaction4.html">Bean-Managed Transaction</a>的介绍 </p>
<img src ="http://www.blogjava.net/dunkbird/aggbug/242856.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2008-11-26 19:09 <a href="http://www.blogjava.net/dunkbird/articles/242856.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Bean托管事务在J2EE中的挂起</title><link>http://www.blogjava.net/dunkbird/articles/242853.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Wed, 26 Nov 2008 11:00:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/242853.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/242853.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/242853.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/242853.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/242853.html</trackback:ping><description><![CDATA[<strong>【IT168技术文档】<br />
<br />
</strong>　　您有没有想过，为什么会有六种事务划分属性（NotSupported、Required、Supports、RequiresNew、Mandatory和Never）？这六种都是由容器托管事务 (CMT)的bean来支持的，但如果使用的是bean托管事务(BMT)，EJB规范所能提供的功能难道就只有通过UserTransaction接口启动和提交/回滚事务吗？显然，CMT模型好像更强大，比如，BMT不能使当前事务挂起然后恢复，这就意味着在BMT bean中无法仿真RequiresNew和NotSupported划分，至少是在使用UserTransaction接口时。 <br />
<br />
　　虽然EJB规范并没有解释为什么会存在以上所提到的不对称情况，但是在BMT模型中依然有一种用来使事务挂起然后恢复的合法方式。如果曾经研究过javax.transaction包的内容，您可能会注意到，与UserTransaction接口一起的还有一个TransactionManager接口，它看起来就像一个扩展的UserTransaction：同样的方法——begin()、commit()和rollback()，再加上suspend()和resume()。 <br />
<br />
　　如果能从EJB中得到一个TransactionManager实现，我们就可以实现编程式地使事务挂起然后恢复的目标。虽然J2EE 1.3和EJB 2.0规范都未提到TransactionManager的可用性，但它们也都没有明确表示禁止使用它。此外，对于CMT事务划分，容器是从内部使用Java Transaction API (JTA)，因此，我们几乎可以100%地肯定：TransactionManager是存在的，惟一的问题只是在代码中获得对它的引用。 <br />
<br />
　　在这篇文章中，我们将了解如何利用几个流行的容器来获得一个TransactionManager，以及如何用它来扩展bean托管事务的功能，使它们和容器托管事务一样强大。我们也将简述一些涉及使用这些高级功能的风险，在文章的结尾，我们还将探讨如何在流行的Spring框架中使用TransactionManager。 <br />
<br />
　　<strong>在各种J2EE服务器中获得TransactionManager的引用 <br />
</strong><br />
　　J2EE和EJB规范没有描述任何获得TransactionManager引用的标准方法，每个J2EE容器供应商可以随意将其放置在任何地方，甚至不需提供任何机制，就可以从应用程序代码中对它进行访问。但在实践中，如今所有的容器都有获取它的机制。以下是一些如何从最流行的J2EE容器获得TransactionManager引用的例子。 <br />
<br />
　　<strong>抛出一个UserTransaction (WebLogic、Orion、OC4J) <br />
<br />
</strong>　　任何一个兼容J2EE的容器都必须使UserTransaction对象在JNDI中的java:comp/UserTransaction下可用。因为UserTransaction接口是TransactionManager的子集，所以一些J2EE容器供应商选择为它们提供一种通用的实现。WebLogic 8、Orion 2和Oracle的OC4J EJB3预览版都是这种方法的例子。在这些容器中，只要从JNDI中获得一个UserTransaction对象，再把它转到TransactionManager，就可以获得对TransactionManager的引用。这可能是最简单的一种情况。 <br />
private TransactionManager getFromUserTransaction()<br />
throws Exception{<br />
InitialContext ctx = new InitialContext();<br />
UserTransaction ut = (UserTransaction)<br />
ctx.lookup("java:comp/UserTransaction");<br />
if (ut instanceof TransactionManager){<br />
log("UserTransaction also TransactionManager");<br />
return (TransactionManager)ut;<br />
}<br />
return null;<br />
} <br />
直接从JNDI中获取TransactionManager (JBoss、WebLogic) <br />
<br />
　　在JBoss 3和WebLogic 8中，可从JNDI获取TransactionManager（虽然名称不一样），因此可以通过简单的查找而获得： <br />
<br />
<p>private TransactionManager getFromJNDI()<br />
throws Exception {<br />
InitialContext ctx = new InitialContext();<br />
try {<br />
// WebLogic <br />
return (TransactionManager)<br />
ctx.lookup("javax.transaction.TransactionManager");<br />
}<br />
catch (Exception e) { }</p>
<p>try {<br />
// JBoss <br />
return (TransactionManager)<br />
ctx.lookup("java:/TransactionManager");<br />
}<br />
catch (Exception e) { }<br />
return null;<br />
} </p>
<br />
<br />
<strong>从一个定制的工厂获取TransactionManager (Websphere) <br />
<br />
</strong>　　在WebSphere 4/5/6中，TransactionManager的引用要从工厂类中获取。但是，麻烦的是，工厂类的名称随WebSphere版本的不同而有所改变。 <br />
<br />
<p>public TransactionManager getFromWebsphereFactory()<br />
throws Exception{<br />
try{<br />
// WebSphere 5.1 or 6.0 <br />
return<br />
com.ibm.ws.Transaction.TransactionManagerFactory<br />
.getTransactionManager();<br />
}<br />
catch (ClassNotFoundException ex){}</p>
<p>try{<br />
// WebSphere 5.0 <br />
return<br />
com.ibm.ejs.jts.jta.TransactionManagerFactory<br />
.getTransactionManager();<br />
}<br />
catch (ClassNotFoundException ex){}</p>
<p>try{<br />
// WebSphere 4.0 <br />
com.ibm.ejs.jts.jta.JTSXA..getTransactionManager();<br />
}<br />
catch (ClassNotFoundException ex){ }</p>
<p>return null;<br />
} </p>
<img src ="http://www.blogjava.net/dunkbird/aggbug/242853.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2008-11-26 19:00 <a href="http://www.blogjava.net/dunkbird/articles/242853.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【JBoss学习】Eclipse＋JBoss学习入门</title><link>http://www.blogjava.net/dunkbird/articles/204110.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Fri, 30 May 2008 07:52:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/204110.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/204110.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/204110.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/204110.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/204110.html</trackback:ping><description><![CDATA[<p align="justify">&nbsp;</p>
<p><font size="2">刚刚开始学习JBoss，学习了一个入门级的小例子，对于刚接触JBoss和Eclipse的菜鸟来说很有帮助的，现在把我的试验过程介绍一下。<br />
首先，打开Eclipse，新建——其它——JBoss IDE——J2EE Projects——J2EE 1.4 Projects<br />
下一步<br />
填入项目名称：HelloWorld<br />
项目内容可以选择使用缺省值或者自己制定存储空间<br />
下一步<br />
在源选单下，添加文件夹，分别命名为j2src（存放java文件）和src（存放部署文件），缺省输出文件夹改为：HelloWorld/bin<br />
完成</font></p>
<p><font size="2">在包资源管理器中，右键单击j2src，选择新建——包，输入包名：sample.server。</font></p>
<p><font size="2">右键单击sample.server，选择新建——接口，输入接口名字：HelloWorld，此为远程接口，是指对于客户端而言所能看到的调用接口，该接口内容为：</font></p>
<p><font size="2">/**<br />
&nbsp;*HelloWorld.java<br />
&nbsp;*/<br />
package sample.server;</font></p>
<p><font size="2">import javax.ejb.EJBObject;</font></p>
<p><font size="2">/**<br />
&nbsp;* @author Administrator<br />
&nbsp;*<br />
&nbsp;* TODO 要更改此生成的类型注释的模板，请转至<br />
&nbsp;* 窗口 － 首选项 － Java － 代码样式 － 代码模板<br />
&nbsp;*/<br />
public interface HelloWorld extends EJBObject {<br />
&nbsp;public String hello() throws java.rmi.RemoteException;<br />
}</font></p>
<p><font size="2">同样的，新建Home接口HelloWorldHome，我们可以把Home接口看做是一个制造EJB的工厂，它告诉EJB容器：&#8220;我的客户要我生成一个EJB，现在我把这个任务交给你啦！&#8221;<br />
/**<br />
&nbsp;* HelloWorldHome.java<br />
&nbsp;*/<br />
package sample.server;<br />
import javax.ejb.EJBHome;<br />
/**<br />
&nbsp;* @author Administrator<br />
&nbsp;*<br />
&nbsp;* TODO 要更改此生成的类型注释的模板，请转至<br />
&nbsp;* 窗口 － 首选项 － Java － 代码样式 － 代码模板<br />
&nbsp;*/<br />
public interface HelloWorldHome extends EJBHome {<br />
&nbsp;HelloWorld create() throws java.rmi.RemoteException,<br />
&nbsp;&nbsp;&nbsp;javax.ejb.CreateException;<br />
}<br />
下面就是EJB的实现，右键单击sample.server，新建——其它——JBoss IDE——EJB Components——Session Bean，输入名称：HelloWorldBean，类型为Stateless，Remote，选择创建来自超类的构造函数，继承的抽象方法，ejbCreate() method。完成。</font></p>
<p><font size="2">/**<br />
&nbsp;* HelloWorldBean.java<br />
&nbsp;*/</font></p>
<p><font size="2">package sample.server;</font></p>
<p><font size="2">import java.rmi.RemoteException;</font></p>
<p><font size="2">import javax.ejb.EJBException;<br />
import javax.ejb.SessionBean;<br />
import javax.ejb.SessionContext;</font></p>
<p><font size="2">import javax.ejb.CreateException;</font></p>
<p><font size="2">/**<br />
&nbsp;* @ejb.bean name="HelloWorld"<br />
&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; display-name="Name for HelloWorld"<br />
&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; description="Description for HelloWorld"<br />
&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jndi-name="ejb/HelloWorld"<br />
&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; type="Stateless"<br />
&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; view-type="remote"<br />
&nbsp;*/<br />
public class HelloWorldBean implements SessionBean {</font></p>
<p><font size="2">&nbsp;/**<br />
&nbsp; * <br />
&nbsp; */<br />
&nbsp;public HelloWorldBean() {<br />
&nbsp;&nbsp;super();<br />
&nbsp;&nbsp;// TODO 自动生成构造函数存根<br />
&nbsp;}</font></p>
<p><font size="2">&nbsp;/* （非 Javadoc）<br />
&nbsp; * @see javax.ejb.SessionBean#setSessionContext(javax.ejb.SessionContext)<br />
&nbsp; */<br />
&nbsp;public void setSessionContext(SessionContext ctx)<br />
&nbsp;&nbsp;throws EJBException,<br />
&nbsp;&nbsp;RemoteException {<br />
&nbsp;&nbsp;// TODO 自动生成方法存根</font></p>
<p><font size="2">&nbsp;}</font></p>
<p><font size="2">&nbsp;/* （非 Javadoc）<br />
&nbsp; * @see javax.ejb.SessionBean#ejbRemove()<br />
&nbsp; */<br />
&nbsp;public void ejbRemove() throws EJBException, RemoteException {<br />
&nbsp;&nbsp;// TODO 自动生成方法存根</font></p>
<p><font size="2">&nbsp;}</font></p>
<p><font size="2">&nbsp;/* （非 Javadoc）<br />
&nbsp; * @see javax.ejb.SessionBean#ejbActivate()<br />
&nbsp; */<br />
&nbsp;public void ejbActivate() throws EJBException, RemoteException {<br />
&nbsp;&nbsp;// TODO 自动生成方法存根</font></p>
<p><font size="2">&nbsp;}</font></p>
<p><font size="2">&nbsp;/* （非 Javadoc）<br />
&nbsp; * @see javax.ejb.SessionBean#ejbPassivate()<br />
&nbsp; */<br />
&nbsp;public void ejbPassivate() throws EJBException, RemoteException {<br />
&nbsp;&nbsp;// TODO 自动生成方法存根</font></p>
<p><font size="2">&nbsp;}</font></p>
<p><font size="2">&nbsp;/**<br />
&nbsp; * Default create method<br />
&nbsp; * <br />
&nbsp; * @throws CreateException<br />
&nbsp; * @ejb.create-method<br />
&nbsp; */<br />
&nbsp;public void ejbCreate() throws CreateException {<br />
&nbsp;&nbsp;// TODO Auto-generated method stub<br />
&nbsp;}<br />
&nbsp;public String hello()<br />
&nbsp;{<br />
&nbsp;&nbsp;System.out.println("hello()");<br />
&nbsp;&nbsp;return "Hello,world";<br />
&nbsp;}<br />
}<br />
服务器端程序编好，下一步就要做部署工作了。</font></p>
<p><font size="2">右键选择src，新建目录META-INF，在该目录下，新建——其它——JBoss-IDE——Descriptors——EJB 2.1 Deployment Descriptor，默认名字为ejb-jar.xml，完成。<br />
ejb-jar.xml：</font></p>
<p><font size="2">《?xml version="1.0" encoding="UTF-8"?》<br />
《ejb-jar version="2.1"<br />
&nbsp;xmlns="<a href="http://java.sun.com/xml/ns/j2ee">http://java.sun.com/xml/ns/j2ee</a>"<br />
&nbsp;xmlns:xsi="<a href="http://www.w3.org/2001/XMLSchema-instance">http://www.w3.org/2001/XMLSchema-instance</a>"<br />
&nbsp;xsi:schemaLocation="<a href="http://java.sun.com/xml/ns/j2ee">http://java.sun.com/xml/ns/j2ee</a><br />
&nbsp;<a href="http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd">http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd</a>"》<br />
《ejb-jar》<br />
《enterprise-beans》<br />
&nbsp;&nbsp;《session》<br />
&nbsp;&nbsp;&nbsp;《ejb-name》HelloWorldBean《/ejb-name》<br />
&nbsp;&nbsp;&nbsp;《home》sample.server.HelloWorldHome《/home》<br />
&nbsp;&nbsp;&nbsp;《remote》sample.server.HelloWorld《/remote》<br />
&nbsp;&nbsp;&nbsp;《ejb-class》sample.server.HelloWorldBean《/ejb-class》<br />
&nbsp;&nbsp;&nbsp;《session-type》Stateful《/session-type》<br />
&nbsp;&nbsp;&nbsp;《transaction-type》Bean《/transaction-type》<br />
&nbsp;&nbsp;《/session》<br />
&nbsp;《/enterprise-beans》<br />
《/ejb-jar》</font></p>
<p><font size="2">（备注：在此，由于网页显示的原因，将&lt;&gt;符号改成了《》，所以，在实际应用中应改为&lt;&gt;，以正常工作。同时，ejb-jar.xml开头的版本标记文字会因jboss版本不同而不同，希望大家注意）<!--l version="1.0" encoding="UTF-8--></font></p>
<p><font size="2">这样我们就完成了一个简单的会话EJB的编写，下一步是打包。<br />
同时选择j2src和src两个目录，右键单击选择导出——jar——选择导出目标，可以放在定义的HelloWorld目录下，起个名字叫HelloWorld.jar，则会在包资源管理器中看到一个文件HelloWorld.jar。</font></p>
<p><font size="2">光有EJB，没有客户端，对我们来说毫无用处，所以下一步我们就要编写客户端程序。<br />
同样的，在j2src下创建包sample.client。<br />
在该包下新建类，类名为HelloWorldClient，添加接口：sample.server.HelloWorld，<br />
/**<br />
&nbsp;* HelloWorldClient.java<br />
&nbsp;*/</font></p>
<p><font size="2">sample.server.HelloWorldHome。</font></p>
<p><font size="2">package sample.client;</font></p>
<p><font size="2">import java.util.Hashtable;</font></p>
<p><font size="2">import javax.naming.Context;<br />
import javax.naming.InitialContext;</font></p>
<p><font size="2">import sample.server.HelloWorld;<br />
import sample.server.HelloWorldHome;</font></p>
<p><font size="2">/**<br />
&nbsp;* @author Administrator<br />
&nbsp;*<br />
&nbsp;* TODO 要更改此生成的类型注释的模板，请转至<br />
&nbsp;* 窗口 － 首选项 － Java － 代码样式 － 代码模板<br />
&nbsp;*/<br />
public class HelloWorldClient{<br />
&nbsp;public static void main(String [] args){<br />
&nbsp;&nbsp;Hashtable env = new Hashtable();<br />
&nbsp;&nbsp;env.put(Context.INITIAL_CONTEXT_FACTORY,"org.jnp.interfaces.NamingContextFactory");<br />
&nbsp;&nbsp;env.put(Context.PROVIDER_URL,"localhost:1099");<br />
/**<br />
&nbsp;* 默认是把服务器端EJB部署在本机上，如果部署在其它机器上，比如192.168.0.1，则将localhost&nbsp; * 改为192.168.0.1即可<br />
&nbsp;*/<br />
&nbsp;&nbsp;env.put("Java.naming.factory.url.pkgs","org.jboss.naming:org.jnp.interfaces");<br />
&nbsp;&nbsp;try{<br />
&nbsp;&nbsp;&nbsp;Context ctx = new InitialContext(env);<br />
&nbsp;&nbsp;&nbsp;Object obj = ctx.lookup("HelloWorldBean");<br />
&nbsp;&nbsp;&nbsp;HelloWorldHome home =(HelloWorldHome)javax.rmi.PortableRemoteObject.narrow(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj, HelloWorldHome.class );<br />
&nbsp;&nbsp;&nbsp;HelloWorld helloWorld = home.create();<br />
&nbsp;&nbsp;&nbsp;System.out.println(helloWorld.hello());<br />
&nbsp;&nbsp;&nbsp;helloWorld.remove();<br />
&nbsp;&nbsp;}catch(Exception e){<br />
&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;System.out.println("Exception:"+e.getMessage());<br />
&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br />
&nbsp;}<br />
}</font></p>
<p><font size="2">下面就可以编译运行了。<br />
手动启动JBoss，直接运行JBoss\bin\目录下的run.bat即可，这个过程时间长短跟计算机的配置有关，配置高的计算机几秒钟就可以了，比较传统的计算机则需要等上1分多钟甚至更长，不过你不需要专门等着它的运行，你双击run.bat后，不用管它，你可以先做一些其他的事情，比如给mm发条短信啊什么的，等你发完短信后，你会发现JBoss已经运行成功，并会告诉你启动JBoss花了多长时间：Started in 1m:36s:870ms，呵呵，我的机器比较传统哈。<br />
选择包资源管理器中的HelloWorld.jar，右键单击选择Deployment——Deploy to，<br />
选择jboss 4.0(default)[file:/D:/jboss4/server/default/deploy/]<br />
则系统会自动把HelloWorld.jar文件拷贝到jboss的/server/default/deploy/目录下，jboss的运行窗口将出现<br />
10:09:50,679 INFO&nbsp; [EjbModule] Deploying HelloWorldBean<br />
10:09:52,051 INFO&nbsp; [org.jboss.ejb.EJBDeployer] Deployed: file:/D:/jboss4/server/default/deploy/HelloWorld.jar<br />
服务器端运行成功<br />
右键选择HelloWorldClient.java，选择运行——运行，在左边选择java应用程序下的HelloWorldClient，右边选择类路径，在引导程序条目下添加外部JAR，分别jboss的client目录下的jboss-j2ee.jar、log4j.jar、jboss-client.jar。然后单击运行，就会看到底下控制台上显示的&#8220;Hello，World&#8221;，哈哈，成功了，这可跟一般的&#8220;HelloWorld&#8221;不太一样哦。</font></p>
<img src ="http://www.blogjava.net/dunkbird/aggbug/204110.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2008-05-30 15:52 <a href="http://www.blogjava.net/dunkbird/articles/204110.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用JBoss Eclipse IDE 开发J2EE应用系统(摘自jdon)</title><link>http://www.blogjava.net/dunkbird/articles/204036.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Fri, 30 May 2008 02:50:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/204036.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/204036.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/204036.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/204036.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/204036.html</trackback:ping><description><![CDATA[<h3 align="left">JBoss推出的Eclipse IDE开发工具越来越强大，当初刚刚推出来时，因为其内置xdoclet功能被人看好，和Lomboz整合在一起开发J2EE，可是，Lomoz不是那么好安装的，至少我自己安装5次成功2次。同时，JBoss的Eclipse IDE功能走向齐全，比较成熟完备，只需要JBoss的Eclipse IDE就可以，不必需要Lomboz了，我们开发一个J2EE应用程序完全没有必要那么麻烦了。
<p>　　JBoss Eclipse IDE主要支持J2EE的WEB和EJB开发，实则提供ant和xdoclet自动提示等方便功能，还提供Hibernate EJB 3.0 JBoss AOP等开发，内置Jsp编辑器。可实现J2EE模块打包和设定部署，结合JBoss服务器进行调试等。</p>
<p>　　安装JBoss Eclipse IDE到Eclipse中有两种方式，注意Eclipse的插件安装非常注意版本，这是需要非常小心的：</p>
<p>　　第一种：下载安装：在网址http://www.jboss.org/products/jbosside下载</p>
<p><a href="http://jboss.sourceforge.net/jbosside/updates" target="_blank">　　第二种：配置Eclipse的find and install，将bookmark http://jboss.sourceforge.net/jbosside/updates</a></p>
<p><a href="http://jboss.sourceforge.net/jbosside/updates" target="_blank">　　</a>如果是Eclipse 3.0，就下载支持3.0插件，如果是Eclipse 3.1，就下载支持3.1，注意不能是3.1M8 等，后面有M的也不行。</p>
<p><a href="http://jboss.sourceforge.net/jbosside/updates" target="_blank">　　</a>安装完成后，参考JBoss的开发指南一步步操作即可：</p>
<p><a href="http://jboss.sourceforge.net/jbosside/updates" target="_blank">　　</a><a href="http://docs.jboss.com/jbosside/tutorial/build/en/html/" target="_blank"><strong>http://docs.jboss.com/jbosside/tutorial/build/en/html/</strong></a></p>
<p><a href="http://jboss.sourceforge.net/jbosside/updates" target="_blank">　　</a>当然，除了Eclipse这样的开发工具，我们还需要事先搭建J2EE运行环境：JBoss+MySQL，我们这个组合也称为Eclipse+JBoss+MySQL无敌开源免费J2EE/EJB开发组合。:)</p>
<p><a href="http://jboss.sourceforge.net/jbosside/updates" target="_blank">　　</a>为了达到熟练开发，xDoclet虽然由Eclipse配置后自动生成，但是有关JNDI调用将需要手工写一些xDoclet标签，<a href="http://www.devx.com/Java/Article/20578" target="_blank">读完这篇文章http://www.devx.com/Java/Article/20578</a>就基本了解xDoclet了。剩余的就是查xDcolet使用手册，不过在开发时，使用Ctrl+Space按键可自动提示标签语法。</p>
<p><a href="http://jboss.sourceforge.net/jbosside/updates" target="_blank">　　</a>在按照JBossIDE开发指南开发这样一个J2EE应用时，有些小问题需要自己解决，如没有MANIFEST.MF需要自己创建一个；application.xml中需要手工写正确等。总之，前提需要对WEB或EJB知识有一个了解，知道哪些问题属于J2EE问题；哪些属于自己的粗心问题。</p>
<p><a href="http://jboss.sourceforge.net/jbosside/updates" target="_blank">　　</a>我已经开发了一个Web+EJB的J2EE例程源码在<a href="http://www.jdon.com/my/train/controllAction.do" target="_blank">VIP教程区</a>,其中Session是使用Local，而非remote。使用Local在一台服务器里运行时，性能比较快。</p>
<br />
<br />
</h3>
<img src ="http://www.blogjava.net/dunkbird/aggbug/204036.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2008-05-30 10:50 <a href="http://www.blogjava.net/dunkbird/articles/204036.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java的数据库连接编程（JDBC）技术</title><link>http://www.blogjava.net/dunkbird/articles/199356.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Thu, 08 May 2008 13:36:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/199356.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/199356.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/199356.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/199356.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/199356.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;只有注册用户登录后才能阅读该文。<a href='http://www.blogjava.net/dunkbird/articles/199356.html'>阅读全文</a><img src ="http://www.blogjava.net/dunkbird/aggbug/199356.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2008-05-08 21:36 <a href="http://www.blogjava.net/dunkbird/articles/199356.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA 遍历文件</title><link>http://www.blogjava.net/dunkbird/articles/195940.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Fri, 25 Apr 2008 05:17:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/195940.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/195940.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/195940.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/195940.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/195940.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;只有注册用户登录后才能阅读该文。<a href='http://www.blogjava.net/dunkbird/articles/195940.html'>阅读全文</a><img src ="http://www.blogjava.net/dunkbird/aggbug/195940.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2008-04-25 13:17 <a href="http://www.blogjava.net/dunkbird/articles/195940.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>eclipse+tomcat+lomboz的安装配置说明</title><link>http://www.blogjava.net/dunkbird/articles/195169.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Wed, 23 Apr 2008 09:11:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/195169.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/195169.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/195169.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/195169.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/195169.html</trackback:ping><description><![CDATA[<p>这几天想做这个，按照网上其他兄弟发的文章配置了一下，发现其中不少问题，按照他们写得文章总是配置不成功，最后发现了原因，文章里要求&#8220;注意&#8221;的地方就是出错的地方，所以写这篇文章修正一下<br />
<br />
一、软件下载：<br />
<br />
注意：（一共5个，一个都不能少，很多网友发表的相同文章里只写了需要下载安装tomcat的软件，而没有写还需要下载eclipse里的tomcat插件，导致很多网友安装后eclipse里不能正常显示tomcat）<br />
1、java<br />
这里使用的是jdk1.4.2。<br />
下载地址： http://dlc.sun.com/jdk/j2sdk-1_4_2_07-windows-i586-p.exe； <br />
2、tomcat<br />
这里的tomcat的版本是5.0的，安装版或是解压版都是可以的。<br />
下载地址： http://apache.linuxforum.net/dist/jakarta/tomcat-5/v5.0.28/bin/jakarta-tomcat-5.0.28.exe <br />
<br />
3、tomcat插件<br />
tomcatPluginV3.zip(下载之前需要查看插件是否适合eclipse的版本)<br />
下载地址： http://www.sysdeo.com/eclipse/tomcatPluginV3.zip <br />
<br />
4、eclipse<br />
开发IDE eclipse-SDK-3.0.1-win32.zip<br />
下载地址： http://sunsite.informatik.rwth-aachen.de/eclipse/downloads/drops/R-3.0.1-200409161125/download.php?dropFile=eclipse-SDK-3.0.1-win32.zip <br />
语言包 NLpack-eclipse-SDK-3.0.x-win32.zip<br />
下载地址： http://sunsite.informatik.rwth-aachen.de/eclipse/downloads/drops/L-3.0.1_Translations-200409161125/NLpack-eclipse-SDK-3.0.x-win32.zip <br />
<br />
5、lomboz插件<br />
lomboz插件需要下载两个部分，一个是emf环境，另一个是lomboz插件<br />
下载地址： http://eclipse.mirrors.tds.net/tools/emf/downloads/drops/2.0.1/R200409171617/emf-sdo-runtime-2.0.1.zip <br />
下载地址： http://download.forge.objectweb.org/lomboz/org.objectweb.lomboz_3.0.1.N20050106.zip <br />
<br />
<br />
二、软件安装：<br />
<br />
1、java安装<br />
运行可执行文件j2sdk-1_4_2_07-windows-i586-p.exe，<br />
安装结束后需配置环境变量，在我的电脑-&gt;属*-&gt;高级-&gt;环境变量-&gt;系统变量中添加以下环境变量<br />
CLASSPATH: %JAVA_HOME%lib;%TOMCAT_HOME%commonlib<br />
JAVA_HOME: c:j2sdk1.4.2<br />
PATH: %SystemRoot%system32;%SystemRoot%;%SystemRoot%System32Wbem;C:Program FilesATI TechnologiesATI Control <br />
Panel;%JAVA_HOME%in;%TOMCAT_HOME%in<br />
<br />
<br />
2、tomcat安装<br />
<br />
解压版的直接解压就可以了，然后配置环境变量TOMCAT_HOME = C:Program FilesApache Software FoundationTomcat 5.0，安装版的要注意的两点，一个是安装完之后tomcat的服务就能够启动的了，但是还是要配置TOMCAT_HOME；第二个就是需要查看一下安装程序是不是把tomcat服务注册成为windows的启动服务，需要到&#8220;服务&#8221;里查看，如果有这个选项就把它设置为手动启动，并且先停止这个服务。<br />
[测试]：使用startup.bat命令，服务正常启动之后，ie浏览器里输入<br />
http://localhost:8080/ 如果出现正常的小猫页面，那就应该没有问题了。<br />
<br />
3、eclipse安装<br />
eclipse的安装很简单，只要解压，然后把eclipse目录复制到盘符下就可以了，启动的时候，系统会自动寻找jvm，当然可以再以后配置，但是好像是必须先安装jdk。我这里是放在D:eclipse下<br />
<br />
4、tomcat插件安装，emf插件安装，lomboz插件安装，<br />
tomcatPluginV3.zip解压后将文件夹com.sysdeo.eclipse.tomcat_3.0.0拷贝到D:eclipseplugins<br />
emf插件和lomboz插件解压后将feature和plugins目录拷贝到 D:eclipse 即可<br />
<br />
三、eclipse配置<br />
<br />
配置Java <br />
在Eclipse中点击windows-&gt;preferences,在出现的窗口中选择java-&gt;Installed JRES,这时可以在右边的窗口中看到己经有一项目，名字为j2re1.4.2_04。我们再在这里点击右面的"Add"按钮，增加一个JRE，在出现的对话框中输入： <br />
JRE Type: Standard VM <br />
JRE name: 可以随意输入一个名字 <br />
JRE home directory:这里选择你的JDK的安装目录，好比你的JDK装在F:J2SDK，那么这里就是选择F:J2SDK这个目录。 <br />
其它的可以都不管，点击OK就新增了一个JRE了。 <br />
<br />
这里修改完了之后回到preferences对话框中的Java-&gt;Build Path这一项，点击Build Path后，在右面的面板中我们选择Source and output folder下面的Folders这一项，而两个Source folder name和Output folder name的值我们不修改，保存为系统默认值，但是下面的As JRE library use:我们要选择为JRE_LIB variable这一项，不能为默认值JRE container，最后点击下面的Apply按钮。这一步千万不要忘记了，不然刚才的都是白做了。 <br />
<br />
4：设置Lomboz <br />
在Preferences窗口中选定Lomboz，然后把右边面板中的JDK Tools.jar选择为你安装好JDK后，在JAVA_HOMELIB目录下面的tools.jar文件就可以了，一定不要搞错了，如果你的JDK是安装在F:J2SDK下面，那么这里的值就应该是F:J2SDKlib ools.jar，是其它的都不对。其它的保持为默认值。 <br />
接着把Lomboz这一项展开，关键要设置的地方是Server Definitions这一项，另外两项Code Generation和JSP Editor可以不管。展开Lomboz的Server Definitions后，在Server types里选择Apache Tomcat v4.1.0(这是按照我的机器上的配置进行设置的，如果你安装的是其它版本的TOMCAT，你就要选择对应的选项)，主要设置如下： <br />
Properties <br />
Application Server Directory:这是我的TOMCAT 4.1.30的安装目录，我装在F: omcat下面，所以它的值就是F:/tomcat <br />
Address:127.0.0.1 <br />
Port：80(因为我在TOMCAT中把8080改为80了，所以这里就是80了，以你的TOMCAT的监听端口为准) <br />
Classpath Variable Name: TOMCAT_HOME(可以修改成其它的字符串) <br />
Classpath Variable: F:/tomcat(TOMCAT的安装目录) <br />
然后点击Apply按钮。 <br />
Server Classpath: <br />
JDK_TOOLS <br />
${classPathVariableName}/bin/bootstrap.jar <br />
${classPathVariableName}/common/servlet.jar <br />
${classPathVariableName}/common/jasper-runtime.jar <br />
然后点击Apply按钮。 <br />
<br />
Client Classpath: <br />
这里为空，什么也没有。 <br />
<br />
Project Classpath: <br />
JDK_TOOLS <br />
${classPathVariableName}/bin/bootstrap.jar <br />
${classPathVariableName}/common/servlet.jar <br />
${classPathVariableName}/common/jasper-runtime.jar <br />
然后点击Apply按钮。 <br />
这里的 Server Classpath:和Project Classpath:我设置的是一样的。<br />
<br />
注意：（以上配置 Server Classpath与 Project Classpath时，可能因为tomcat版本的不同而*.jar的文件位置也不同，如果时tomcat5.x版的 ,则${classPathVariableName}/common/servlet.jar 与 ${classPathVariableName}/common/jasper-runtime.jar 应为${classPathVariableName}/common/lib/servlet-api.jar 与 ${classPathVariableName}/common/lib/jasper-runtime.jar ，比4.x版的多了一层lib目录。） <br />
5：修改文件 <br />
把Eclipse_homepluginscom.objectlearn.jdt.j2ee_3.0.1servers 下面对应的server文件打开，比如我安装的TOMCAT是4.1.30版的，那么就把tomcat410.server这个文件打开，把里面的-Djava.endorsed.dirs="${serverRootDirectory}/bin;${serverRootDirectory}/common/endorsed" <br />
改成 <br />
-Djava.endorsed.dirs="${serverRootDirectory}/common/endorsed" <br />
一共有两处，都要修改，修改完之后保存，退出，重新启动Eclipse，这一步很重要，一定要做，不然的话你在Lomboz中启动TOMCAT的时候会再现很多莫明其妙的异常的<br />
注意：如果用的是tomcat5.x版的可能没有以上东西要改 <br />
<br />
6：调出Lomboz各个菜单 <br />
启动Eclipse，然后点击windows-&gt;Customize Perspective,在出现的对话框中的Shortcuts页面中首先选中左边面板中的Lomboz J2EE Wizards，这时右边的面板中会出现很多选项的，同时也把它们各项前面的对钩打上。 <br />
然后在这个Shortcuts面板中改变Submenus:的值，选择Show View，接着在出现的面板的左边里选中Lomboz J2EE，同时也要把它前面的方框中打上对钩。 <br />
最后是更换Customize Perspective对话框中的面板到Commands这一页： <br />
在Commands这一页中选定Lomboz Actions同时也把它们各项前面的对钩打上。 <br />
所有的设置完毕。 <br />
这样一切做完之后，Eclipse和Lomboz的环境就配置好了，你可以进行开发各种程序了。 <br />
个人体会： <br />
可能在第5步中有些机器上可以不做，因为有不同的TOMCAT版本，不过我机器一定要改了才行，不然的话是不能正常启动TOMCAT的。我个人使用TOMCAT4.1.30版的，是因为我觉得这个版本的比较小，运行起来也比较快，比5.0以上版本的要快多了，而且也要相对稳定一些(个人看法，不代表其它人的)，还有就是对于Eclipse 3.0的，可以参照上面的说明进行配置，基本上也可以行得通的，没有什么比较大的问题。<strong></strong></p>
 <img src ="http://www.blogjava.net/dunkbird/aggbug/195169.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2008-04-23 17:11 <a href="http://www.blogjava.net/dunkbird/articles/195169.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>你是否了解这些常被问起的问题- -java</title><link>http://www.blogjava.net/dunkbird/articles/195021.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Wed, 23 Apr 2008 04:45:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/195021.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/195021.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/195021.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/195021.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/195021.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;只有注册用户登录后才能阅读该文。<a href='http://www.blogjava.net/dunkbird/articles/195021.html'>阅读全文</a><img src ="http://www.blogjava.net/dunkbird/aggbug/195021.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2008-04-23 12:45 <a href="http://www.blogjava.net/dunkbird/articles/195021.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何才能依次逐个读一个文件夹中的所有文件? </title><link>http://www.blogjava.net/dunkbird/articles/195016.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Wed, 23 Apr 2008 04:39:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/195016.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/195016.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/195016.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/195016.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/195016.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;只有注册用户登录后才能阅读该文。<a href='http://www.blogjava.net/dunkbird/articles/195016.html'>阅读全文</a><img src ="http://www.blogjava.net/dunkbird/aggbug/195016.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2008-04-23 12:39 <a href="http://www.blogjava.net/dunkbird/articles/195016.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>j2ee的学习笔记（2）转</title><link>http://www.blogjava.net/dunkbird/articles/195014.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Wed, 23 Apr 2008 04:37:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/195014.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/195014.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/195014.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/195014.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/195014.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;只有注册用户登录后才能阅读该文。<a href='http://www.blogjava.net/dunkbird/articles/195014.html'>阅读全文</a><img src ="http://www.blogjava.net/dunkbird/aggbug/195014.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2008-04-23 12:37 <a href="http://www.blogjava.net/dunkbird/articles/195014.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>j2ee学习笔记（转）</title><link>http://www.blogjava.net/dunkbird/articles/195004.html</link><dc:creator>大鸟</dc:creator><author>大鸟</author><pubDate>Wed, 23 Apr 2008 04:27:00 GMT</pubDate><guid>http://www.blogjava.net/dunkbird/articles/195004.html</guid><wfw:comment>http://www.blogjava.net/dunkbird/comments/195004.html</wfw:comment><comments>http://www.blogjava.net/dunkbird/articles/195004.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/dunkbird/comments/commentRss/195004.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dunkbird/services/trackbacks/195004.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;只有注册用户登录后才能阅读该文。<a href='http://www.blogjava.net/dunkbird/articles/195004.html'>阅读全文</a><img src ="http://www.blogjava.net/dunkbird/aggbug/195004.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dunkbird/" target="_blank">大鸟</a> 2008-04-23 12:27 <a href="http://www.blogjava.net/dunkbird/articles/195004.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>