﻿<?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/freeman1984/category/26086.html</link><description>STANDING ON THE SHOULDERS OF GIANTS
</description><language>zh-cn</language><lastBuildDate>Mon, 14 Dec 2015 10:54:57 GMT</lastBuildDate><pubDate>Mon, 14 Dec 2015 10:54:57 GMT</pubDate><ttl>60</ttl><item><title>JAVA Thread Dump 分析综述</title><link>http://www.blogjava.net/freeman1984/archive/2015/12/14/428645.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 14 Dec 2015 10:04:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2015/12/14/428645.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/428645.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2015/12/14/428645.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/428645.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/428645.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转载自:http://blog.csdn.net/rachel_luo/article/details/8920596最近在做性能测试，需要对线程堆栈进行分析，在网上收集了一些资料，学习完后，将相关知识整理在一起，输出文章如下。一、Thread Dump介绍1.1什么是Thread Dump？Thread Dump是非常有用的诊断Java应用问题的工具。每一个Java虚拟机都有及时生成所有线程在某...&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2015/12/14/428645.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/428645.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2015-12-14 18:04 <a href="http://www.blogjava.net/freeman1984/archive/2015/12/14/428645.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于java RMI在多网卡下(或者启动360，百度，腾讯等wifi共享下)无法连接问题(java.rmi.ConnectException: Connection refused to host: xx)</title><link>http://www.blogjava.net/freeman1984/archive/2014/12/05/421085.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 05 Dec 2014 06:08:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2014/12/05/421085.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/421085.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2014/12/05/421085.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/421085.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/421085.html</trackback:ping><description><![CDATA[<strong>场景</strong>：java RMI 在服务端者启动360 wifi共享，报错java.rmi.ConnectException: Connection refused to host: xx。<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;也就是服务端在调用时使用了wifi共享网卡的地址。此地址在RMI客户端pc上无法ping通。（因为没有连接此wifi。当然RMI客户端pc如果连接此wifi是不会报错的）。<br /><strong>想关资料：<br /><br /></strong>http://docs.huihoo.com/java/rmi/whitepage/index.html<strong><br /></strong>比较全的解释RMI的英文资料：http://docs.oracle.com/javase/1.5.0/docs/guide/rmi/faq.html#netunknownhost<br /><div>http://www.blogjava.net/shaolijun/archive/2007/05/22/119213.html</div><br />
<strong>测试代码</strong>：<br /><br />(一)服务端：<br /><ul><li><span style="font-size: 10pt;">服务接口</span></li></ul>

<div style="font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all; background-color: #eeeeee;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">import</span>&nbsp;java.rmi.Remote;<br />
<span style="color: #0000FF; ">import</span>&nbsp;java.rmi.RemoteException;<br />
<span style="color: #008000; ">/**</span><span style="color: #008000; "><br />
&nbsp;*&nbsp;rmi&nbsp;remote&nbsp;接口<br />
&nbsp;*&nbsp;</span><span style="color: #808080; ">@author</span><span style="color: #008000; ">&nbsp;joe<br />
&nbsp;*&nbsp;@2014-12-5&nbsp;@上午11:49:10<br />
&nbsp;</span><span style="color: #008000; ">*/</span><br />
<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">interface</span>&nbsp;RmiInterface&nbsp;<span style="color: #0000FF; ">extends</span>&nbsp;Remote{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;String&nbsp;say(String&nbsp;name)&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;RemoteException;<br />
<br />
}</div><ul><li><span style="font-size: 10pt;">接口实现</span></li></ul>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">import</span>&nbsp;java.rmi.RemoteException;<br /><span style="color: #0000FF; ">import</span>&nbsp;java.rmi.server.UnicastRemoteObject;<br /><br /><br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;RmiServer&nbsp;<span style="color: #0000FF; ">extends</span>&nbsp;UnicastRemoteObject&nbsp;<span style="color: #0000FF; ">implements</span>&nbsp;RmiInterface{<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">final</span>&nbsp;<span style="color: #0000FF; ">long</span>&nbsp;serialVersionUID&nbsp;=&nbsp;1L;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">protected</span>&nbsp;RmiServer()&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;RemoteException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">super</span>();<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;String&nbsp;say(String&nbsp;name)&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;RemoteException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;"hello，"+name;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</div><ul><li><span style="font-size: 10pt;">发布服务</span></li></ul><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;main(String[]&nbsp;args)&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;MalformedURLException,&nbsp;RemoteException,&nbsp;AlreadyBoundException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RmiServer&nbsp;server=<span style="color: #0000FF; ">new</span>&nbsp;RmiServer();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LocateRegistry.createRegistry(8808);&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Naming.rebind("//10.10.XX.XX:8808/SAMPLE-SERVER",&nbsp;server);&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}</div><br />(二)客户端 调用服务：<br /><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;main(String[]&nbsp;args)&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;Exception&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RmiInterface&nbsp;server=(RmiInterface)&nbsp;Naming.lookup("//10.10.116.XX:8808/SAMPLE-SERVER");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(server.say("张三"));<br />&nbsp;&nbsp;&nbsp;&nbsp;}</div><br />此时报错，java.rmi.ConnectException: Connection refused to host: 192.168.23.X。<br /><br />RMI的调用原理基本如下：<br /><img src="http://www.blogjava.net/images/blogjava_net/freeman1984/rmi1.png" width="1341" height="365" alt="" /><br /><strong>大致翻译如下</strong>：首先客户端必须通过Naming.lookup得到服务端服务的一个指针或者叫指针，一旦拥有的这个应用，客户端将使用服务的引用里面包含的主机名(ip)和端口来访问服务。<br />&nbsp; &nbsp; 也就是说：虽然我们就服务端的IP和端口去<span style="font-size: 13px; background-color: #eeeeee;">Naming.lookup("//10.10.116.XX:8808/SAMPLE-SERVER");</span>，但是服务端返回的服务的引用里面包含的ip并不是lookup时的ip。<br />官方说法：<br /><strong><span style="font-family: Simsun; font-size: medium; line-height: normal; background-color: #ffffff;">【In many&nbsp;</span><a href="http://docs.oracle.com/javase/1.5.0/docs/guide/rmi/faq.html#nethostname" style="font-family: Simsun; font-size: medium; line-height: normal;">versions of the JDK</a><span style="font-family: Simsun; font-size: medium; line-height: normal; background-color: #ffffff;">&nbsp;(all versions of the JDK except in&nbsp;</span><a href="http://docs.oracle.com/javase/1.5.0/docs/guide/rmi/faq.html#nethostname.1.1" style="font-family: Simsun; font-size: medium; line-height: normal;">v1.1</a><span style="font-family: Simsun; font-size: medium; line-height: normal; background-color: #ffffff;">&nbsp;and the&nbsp;</span><a href="http://docs.oracle.com/javase/1.5.0/docs/guide/rmi/faq.html#nethostname.latestReleases" style="font-family: Simsun; font-size: medium; line-height: normal;">latest releases)</a><span style="font-family: Simsun; font-size: medium; line-height: normal; background-color: #ffffff;">, Java RMI may default to using an unresolvable server hostname (for example: unqualified names, Windows Internet Naming Service (WINS) names, or unqualified DHCP names). When a Java RMI client invokes a remote method using a reference that contains an unresolvable server hostname, the client will throw an&nbsp;</span><code style="line-height: normal;">UnknownHostException</code><span style="font-family: Simsun; font-size: medium; line-height: normal; background-color: #ffffff;">.】</span></strong><p style="font-family: Simsun; font-size: medium; line-height: normal;">In order to generate functional remote references, Java RMI servers must be able to supply a fully qualified hostname or IP address that is resolvable from all Java RMI clients (an example of a fully qualified hostname is&nbsp;<samp>foo.bar.com</samp>). If a Java RMI program provides a remote callback operation, then that program serves a Java RMI object and consequently, must be able to determine a resolvable hostname to use as its server hostname in the remote references it passes to Java RMI clients. VMs that make calls to applets that serve remote objects may throw<code>UnknownHostException</code>s because the applet has failed to provide a usable server hostname.</p><p style="font-family: Simsun; font-size: medium; line-height: normal;">If your Java RMI application throws an&nbsp;<code>UnknownHostException</code>, you can look at the resulting stack trace to see if the hostname that the client is using to contact its remote server is incorrect or not fully qualified.【&nbsp;<strong>If necessary, you can set the&nbsp;<code>java.rmi.server.hostname</code>&nbsp;property on the server to the correct IP address or hostname of the server machine and Java RMI will use this property's value to generate remote references to the server.】</strong></p>解决办法就是在服务端发布注册服务的之前设置：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->System.setProperty("java.rmi.server.hostname",&nbsp;指定IP);</div><br />对应到本文例子就是：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;main(String[]&nbsp;args)&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;MalformedURLException,&nbsp;RemoteException,&nbsp;AlreadyBoundException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RmiServer&nbsp;server=<span style="color: #0000FF; ">new</span>&nbsp;RmiServer();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>System.setProperty("java.rmi.server.hostname",&nbsp;指定IP);</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LocateRegistry.createRegistry(8808);&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Naming.rebind("//10.10.116.74:8808/SAMPLE-SERVER",&nbsp;server);&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}</div><br />但是此时还是报相同的错没法访问，百思不得其解，原来<span style="font-family: Simsun; font-size: medium; line-height: normal;"><code><strong>java.rmi.server.hostname</strong>的设置必须在服务对象创建之前。<br /></code></span><div style="font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all; background-color: #eeeeee;"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;main(String[]&nbsp;args)&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;MalformedURLException,&nbsp;RemoteException,&nbsp;AlreadyBoundException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>&nbsp;System.setProperty("java.rmi.server.hostname",&nbsp;指定IP);</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RmiServer&nbsp;server=<span style="color: #0000FF; ">new</span>&nbsp;RmiServer();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LocateRegistry.createRegistry(8808);&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Naming.rebind("//10.10.116.74:8808/SAMPLE-SERVER",&nbsp;server);&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}</div><div>为什么呢：<br />&nbsp; &nbsp;&nbsp;<span style="font-size: 13px; background-color: #eeeeee;">RmiServer&nbsp;</span>这个实现类使用了UnicastRemoteObject去联接RMI系统。在我们的例子中，我们是直接的从UnicastRemoteObject这个类上继承的，事实上并不一定要这样做，当然也可以不是从UnicastRmeoteObject上继承，那必须使用它的exportObject()方法去联接到RMI。如果一个类继承自UnicastRemoteObject，那么它必须提供一个构造函数并且声明抛出一个RemoteException对象。当这个构造函数调用了super()，它久激活UnicastRemoteObject中的代码完成RMI的连接和远程对象的初始化。而此时应该已经决定了使用哪个hostname来实例化远程对象。因此必须在服务对象创建之前指定绑定的hostname。<br /><br />~~~完。</div><img src ="http://www.blogjava.net/freeman1984/aggbug/421085.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2014-12-05 14:08 <a href="http://www.blogjava.net/freeman1984/archive/2014/12/05/421085.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Quartz+Spring的集群配置(转)</title><link>http://www.blogjava.net/freeman1984/archive/2012/05/11/377882.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 11 May 2012 03:02:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2012/05/11/377882.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/377882.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2012/05/11/377882.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/377882.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/377882.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 原来配置的Quartz是通过spring配置文件生效的，发现在非集群式的服务器上运行良好，但是将工程部署到水平集群服务器上去后改定时功能不能正常运行，没有任何错误日志，于是从jar包、JDK版本、cronExpression到服务器类型，甚至查到了服务器操作系统的类型，都没能找到解决的办法，后来才知道是集群惹的祸！ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb...&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2012/05/11/377882.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/377882.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2012-05-11 11:02 <a href="http://www.blogjava.net/freeman1984/archive/2012/05/11/377882.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java.awt.headless=true</title><link>http://www.blogjava.net/freeman1984/archive/2012/02/27/370850.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 27 Feb 2012 07:59:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2012/02/27/370850.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/370850.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2012/02/27/370850.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/370850.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/370850.html</trackback:ping><description><![CDATA[<p><font face="宋体">对于一个Java服务器来说经常要处理一些图形元素，例如地图的创建或者图形和图表等。这些API基本上总是需要运行一个X-server以便能使用AWT（Abstract Window Toolkit，抽象窗口工具集）。然而，运行一个不必要的X-server并不是一种好的网络管理方式。<br /><br />这个解决方案依赖于你的Java版本。如果你运行在JDK1.4上，那么你将有机会运行headless服务器。<br /><br />-Djava.awt.headless=true <br />对于JDK1.3及更低的版本，有个来自eTeks的PJA工具包（Pure Java AWT Toolkit，纯Java AWT工具集）可以使用。它是一个在配置上与Sun的1.4版非常相似的headlessJava服务器，这种配置方式包含一组-D属性标志。</font><br /><br />
<p>否则会报<br /><font face="Verdana">Can&#8217;t connect to X11 window server using &#8216;:0.0&#8242; as the value of the DISPLAY variable<br /></font>异常<br /><br />启动参数&nbsp; -Djava.awt.headless=true<br /><br />在websphere上的配置情况：<br /><br />在 </p>
<p id="title-bread-crumb"><font color="#0000ff">应用程序服务器</font> &gt; <font color="#0000ff">server1</font> &gt; <font color="#0000ff">进程定义</font> &gt; Java 虚拟机 下配置：<br /><img border="0" alt="" src="http://www.blogjava.net/images/blogjava_net/freeman1984/2.png" width="320" height="53" /><br /></p>
<p><br />&nbsp;</p><img src ="http://www.blogjava.net/freeman1984/aggbug/370850.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2012-02-27 15:59 <a href="http://www.blogjava.net/freeman1984/archive/2012/02/27/370850.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>dom4j通过xpath查询xml (转)</title><link>http://www.blogjava.net/freeman1984/archive/2011/11/09/363271.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Wed, 09 Nov 2011 02:45:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/11/09/363271.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/363271.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/11/09/363271.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/363271.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/363271.html</trackback:ping><description><![CDATA[<ol><li>获取Document</li>
<ul><li>SAXReader saxReader = new SAXReader();</li><li>Document document = saxReader.read(FileUtil.getFileInputStream(fileName));<br /></li></ul></li><li>查询Element</li>
<ul><li>String xpath ="/composites/composite[@type='onDelete']";//查询属性type='ondDelete'的composite</li><li>List&lt;Element&gt; composites = document.selectNodes(xpath);<br /></li></ul></li><li>xpath语法</li></ol>
<div style="margin-left: 40px">
<div>
<h2>选取节点</h2>
<p>XPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。</p>
<h3>下面列出了最有用的路径表达式：</h3>
<table>
<tbody>
<tr>
<th>表达式</th>
<th>描述</th></tr>
<tr>
<td>nodename</td>
<td>选取此节点的所有子节点</td></tr>
<tr>
<td>/</td>
<td>从根节点选取</td></tr>
<tr>
<td>//</td>
<td>从匹配选择的当前节点选择文档中的节点，而不考虑它们的位置</td></tr>
<tr>
<td>.</td>
<td>选取当前节点</td></tr>
<tr>
<td>..</td>
<td>选取当前节点的父节点</td></tr>
<tr>
<td>@</td>
<td>选取属性</td></tr></tbody></table>
<h3>实例</h3>
<p>在下面的表格中，我们已列出了一些路径表达式以及表达式的结果：</p>
<table>
<tbody>
<tr>
<th>路径表达式</th>
<th>结果</th></tr>
<tr>
<td>bookstore</td>
<td>选取 bookstore 元素的所有子节点</td></tr>
<tr>
<td>/bookstore</td>
<td>
<p>选取根元素 bookstore</p>
<p>注释：假如路径起始于正斜杠( / )，则此路径始终代表到某元素的绝对路径！</p></td></tr>
<tr>
<td>bookstore/book</td>
<td>选取所有属于 bookstore 的子元素的 book 元素。</td></tr>
<tr>
<td>//book</td>
<td>选取所有 book 子元素，而不管它们在文档中的位置。</td></tr>
<tr>
<td>bookstore//book</td>
<td>选择所有属于 bookstore 元素的后代的 book 元素，而不管它们位于 bookstore 之下的什么位置。</td></tr>
<tr>
<td>//@lang</td>
<td>选取所有名为 lang 的属性。</td></tr></tbody></table></div>
<div>
<h2>谓语（Predicates）</h2>
<p>谓语用来查找某个特定的节点或者包含某个指定的值的节点。</p>
<p>谓语被嵌在方括号中。</p>
<h3>实例</h3>
<p>在下面的表格中，我们列出了带有谓语的一些路径表达式，以及表达式的结果：</p>
<table>
<tbody>
<tr>
<th>路径表达式</th>
<th>结果</th></tr>
<tr>
<td>/bookstore/book[1]</td>
<td>选取属于 bookstore 子元素的第一个 book 元素。</td></tr>
<tr>
<td>/bookstore/book[last()]</td>
<td>选取属于 bookstore 子元素的最后一个 book 元素。</td></tr>
<tr>
<td>/bookstore/book[last()-1]</td>
<td>选取属于 bookstore 子元素的倒数第二个 book 元素。</td></tr>
<tr>
<td>/bookstore/book[position()&lt;3]</td>
<td>选取最前面的两个属于 bookstore 元素的子元素的 book 元素。</td></tr>
<tr>
<td>//title[@lang]</td>
<td>选取所有拥有名为 lang 的属性的 title 元素。</td></tr>
<tr>
<td>//title[@lang='eng']</td>
<td>选取所有 title 元素，且这些元素拥有值为 eng 的 lang 属性。</td></tr>
<tr>
<td>/bookstore/book[price&gt;35.00]</td>
<td>选取所有 bookstore 元素的 book 元素，且其中的 price 元素的值须大于 35.00。</td></tr>
<tr>
<td>/bookstore/book[price&gt;35.00]/title</td>
<td>选取所有 bookstore 元素中的 book 元素的 title 元素，且其中的 price 元素的值须大于 35.00。</td></tr></tbody></table></div>
<div>
<h2>选取未知节点</h2>
<p>XPath 通配符可用来选取未知的 XML 元素。</p>
<table>
<tbody>
<tr>
<th>通配符</th>
<th>描述</th></tr>
<tr>
<td>*</td>
<td>匹配任何元素节点</td></tr>
<tr>
<td>@*</td>
<td>匹配任何属性节点</td></tr>
<tr>
<td>node()</td>
<td>匹配任何类型的节点</td></tr></tbody></table>
<h3>实例</h3>
<p>在下面的表格中，我们列出了一些路径表达式，以及这些表达式的结果：</p>
<table>
<tbody>
<tr>
<th>路径表达式</th>
<th>结果</th></tr>
<tr>
<td>/bookstore/*</td>
<td>选取 bookstore 元素的所有子节点</td></tr>
<tr>
<td>//*</td>
<td>选取文档中的所有元素</td></tr>
<tr>
<td>//title[@*]</td>
<td>选取所有带有属性的 title 元素。</td></tr></tbody></table></div>
<div>
<h2>选取若干路径</h2>
<p>通过在路径表达式中使用&#8220;|&#8221;运算符，您可以选取若干个路径。</p>
<h3>实例</h3>
<p>在下面的表格中，我们列出了一些路径表达式，以及这些表达式的结果：</p>
<table>
<tbody>
<tr>
<th>路径表达式</th>
<th>结果</th></tr>
<tr>
<td>//book/title | //book/price</td>
<td>选取所有 book 元素的 title 和 price 元素。</td></tr>
<tr>
<td>//title | //price</td>
<td>选取所有文档中的 title 和 price 元素。</td></tr>
<tr>
<td>/bookstore/book/title | //price</td>
<td>选取所有属于 bookstore 元素的 book 元素的 title 元素，以及文档中所有的 price 元素。</td></tr></tbody></table></div><br /><br />
<div>
<h2>XPath 轴</h2>
<p>轴可定义某个相对于当前节点的节点集。</p>
<table>
<tbody>
<tr>
<th>轴名称</th>
<th>结果</th></tr>
<tr>
<td>ancestor</td>
<td>选取当前节点的所有先辈（父、祖父等）</td></tr>
<tr>
<td>ancestor-or-self</td>
<td>选取当前节点的所有先辈（父、祖父等）以及当前节点本身</td></tr>
<tr>
<td>attribute</td>
<td>选取当前节点的所有属性</td></tr>
<tr>
<td>child</td>
<td>选取当前节点的所有子元素。</td></tr>
<tr>
<td>descendant</td>
<td>选取当前节点的所有后代元素（子、孙等）。</td></tr>
<tr>
<td>descendant-or-self</td>
<td>选取当前节点的所有后代元素（子、孙等）以及当前节点本身。</td></tr>
<tr>
<td>following</td>
<td>选取文档中当前节点的结束标签之后的所有节点。</td></tr>
<tr>
<td>namespace</td>
<td>选取当前节点的所有命名空间节点</td></tr>
<tr>
<td>parent</td>
<td>选取当前节点的父节点。</td></tr>
<tr>
<td>preceding</td>
<td>选取文档中当前节点的开始标签之前的所有节点。</td></tr>
<tr>
<td>preceding-sibling</td>
<td>选取当前节点之前的所有同级节点。</td></tr>
<tr>
<td>self</td>
<td>选取当前节点。</td></tr></tbody></table></div>
<div>
<h2>位置路径表达式</h2>
<p>位置路径可以是绝对的，也可以是相对的。</p>
<p>绝对路径起始于正斜杠( / )，而相对路径不会这样。在两种情况中，位置路径均包括一个或多个步，每个步均被斜杠分割：</p>
<h3>绝对位置路径：</h3><pre>/step/step/...</pre>
<h3>相对位置路径：</h3><pre>step/step/...</pre>
<p>每个步均根据当前节点集之中的节点来进行计算。</p>
<h3>步（step）包括：</h3>
<dl>
<dt>轴（axis）</dt>
<dd>定义所选节点与当前节点之间的树关系</dd>
<dt>节点测试（node-test）</dt>
<dd>识别某个轴内部的节点</dd>
<dt>零个或者更多谓语（predicate）</dt>
<dd>更深入地提炼所选的节点集</dd></dl>
<h3>步的语法：</h3><pre>轴名称::节点测试[谓语]</pre>
<h3>实例</h3>
<table>
<tbody>
<tr>
<th>例子</th>
<th>结果</th></tr>
<tr>
<td>child::book</td>
<td>选取所有属于当前节点的子元素的 book 节点</td></tr>
<tr>
<td>attribute::lang</td>
<td>选取当前节点的 lang 属性</td></tr>
<tr>
<td>child::*</td>
<td>选取当前节点的所有子元素</td></tr>
<tr>
<td>attribute::*</td>
<td>选取当前节点的所有属性</td></tr>
<tr>
<td>child::text()</td>
<td>选取当前节点的所有文本子节点</td></tr>
<tr>
<td>child::node()</td>
<td>选取当前节点的所有子节点</td></tr>
<tr>
<td>descendant::book</td>
<td>选取当前节点的所有 book 后代</td></tr>
<tr>
<td>ancestor::book</td>
<td>选择当前节点的所有 book 先辈</td></tr>
<tr>
<td>ancestor-or-self::book</td>
<td>选取当前节点的所有book先辈以及当前节点（假如此节点是book节点的话）</td></tr>
<tr>
<td>child::*/child::price</td>
<td>选取当前节点的所有 price 孙。</td></tr></tbody></table></div><br />
<div>
<h2>XPath 运算符</h2>
<p>下面列出了可用在 XPath 表达式中的运算符：</p>
<table>
<tbody>
<tr>
<th>运算符</th>
<th>描述</th>
<th>实例</th>
<th>返回值</th></tr>
<tr>
<td>|</td>
<td>计算两个节点集</td>
<td>//book | //cd</td>
<td>返回所有带有 book 和 ck 元素的节点集</td></tr>
<tr>
<td>+</td>
<td>加法</td>
<td>6 + 4</td>
<td>10</td></tr>
<tr>
<td>-</td>
<td>减法</td>
<td>6 - 4</td>
<td>2</td></tr>
<tr>
<td>*</td>
<td>乘法</td>
<td>6 * 4</td>
<td>24</td></tr>
<tr>
<td>div</td>
<td>除法</td>
<td>8 div 4</td>
<td>2</td></tr>
<tr>
<td>=</td>
<td>等于</td>
<td>price=9.80</td>
<td>
<p>如果 price 是 9.80，则返回 true。</p>
<p>如果 price 是 9.90，则返回 fasle。</p></td></tr>
<tr>
<td>!=</td>
<td>不等于</td>
<td>price!=9.80</td>
<td>
<p>如果 price 是 9.90，则返回 true。</p>
<p>如果 price 是 9.80，则返回 fasle。</p></td></tr>
<tr>
<td>&lt;</td>
<td>小于</td>
<td>price&lt;9.80</td>
<td>
<p>如果 price 是 9.00，则返回 true。</p>
<p>如果 price 是 9.90，则返回 fasle。</p></td></tr>
<tr>
<td>&lt;=</td>
<td>小于或等于</td>
<td>price&lt;=9.80</td>
<td>
<p>如果 price 是 9.00，则返回 true。</p>
<p>如果 price 是 9.90，则返回 fasle。</p></td></tr>
<tr>
<td>&gt;</td>
<td>大于</td>
<td>price&gt;9.80</td>
<td>
<p>如果 price 是 9.90，则返回 true。</p>
<p>如果 price 是 9.80，则返回 fasle。</p></td></tr>
<tr>
<td>&gt;=</td>
<td>大于或等于</td>
<td>price&gt;=9.80</td>
<td>
<p>如果 price 是 9.90，则返回 true。</p>
<p>如果 price 是 9.70，则返回 fasle。</p></td></tr>
<tr>
<td>or</td>
<td>或</td>
<td>price=9.80 or price=9.70</td>
<td>
<p>如果 price 是 9.80，则返回 true。</p>
<p>如果 price 是 9.50，则返回 fasle。</p></td></tr>
<tr>
<td>and</td>
<td>与</td>
<td>price&gt;9.00 and price&lt;9.90</td>
<td>
<p>如果 price 是 9.80，则返回 true。</p>
<p>如果 price 是 8.50，则返回 fasle。</p></td></tr>
<tr>
<td>mod</td>
<td>计算除法的余数</td>
<td>5 mod 2</td>
<td>1</td></tr></tbody></table></div></div>转自：<a href="http://txy920.blog.163.com/blog/static/1494427820095922212262/">http://txy920.blog.163.com/blog/static/1494427820095922212262/</a><img src ="http://www.blogjava.net/freeman1984/aggbug/363271.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-11-09 10:45 <a href="http://www.blogjava.net/freeman1984/archive/2011/11/09/363271.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入探讨 Java 类加载器</title><link>http://www.blogjava.net/freeman1984/archive/2011/10/20/361655.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Thu, 20 Oct 2011 06:57:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/10/20/361655.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/361655.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/10/20/361655.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/361655.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/361655.html</trackback:ping><description><![CDATA[<p><strong>简介：</strong>&nbsp;类加载器（class loader）是 Java&#8482; 中的一个很重要的概念。类加载器负责加载 Java 类的字节代码到 Java 虚拟机中。本文首先详细介绍了 Java 类加载器的基本概念，包括代理模式、加载类的具体过程和线程上下文类加载器等，接着介绍如何开发自己的类加载器，最后介绍了类加载器在 Web 容器和 OSGi&#8482; 中的应用。</p><!-- <p class="ibm-no-print"><div id="dw-tag-this" class="ibm-no-print"></div><div id="interestShow" class="ibm-no-print"></div></p> -->

<div id="dw-tag-content" class="ibm-no-print"></div>
<div id="dw-moretags-access" class="ibm-access"></div>
<p class="ibm-no-print">
<div id="dw-tag-this" class="ibm-no-print">
<div id="art-rating-summary"></div><!-- Rating_Area_End --><br /></div>
<p>&nbsp;</p><!-- dW_Summary_Area_END --><!-- CONTENT_BODY -->

<div id="ibm-content-body"><!-- MAIN_COLUMN_BEGIN -->

<div id="ibm-content-main"><!-- Related_Searches_Area_And_Overlays_Begin --><!-- MAIN_COLUMN_CONTAINER_BEGIN -->

<div class="ibm-container"><!-- MAIN_COLUMN_CONTENT_BEGIN -->

<p>类加载器是 Java 语言的一个创新，也是 Java 语言流行的重要原因之一。它使得 Java 类可以被动态加载到 Java 虚拟机中并执行。类加载器从 JDK 1.0 就出现了，最初是为了满足 Java Applet 的需要而开发出来的。Java Applet 需要从远程下载 Java 类文件到浏览器中并执行。现在类加载器在 Web 容器和 OSGi 中得到了广泛的使用。一般来说，Java 应用的开发人员不需要直接同类加载器进行交互。Java 虚拟机默认的行为就已经足够满足大多数情况的需求了。不过如果遇到了需要与类加载器进行交互的情况，而对类加载器的机制又不是很了解的话，就很容易花大量的时间去调试 <code>ClassNotFoundException</code> 和 <code>NoClassDefFoundError</code> 等异常。本文将详细介绍 Java 的类加载器，帮助读者深刻理解 Java 语言中的这个重要概念。下面首先介绍一些相关的基本概念。</p>
<p><span class="atitle">类加载器基本概念</span></p>
<p>顾名思义，类加载器（class loader）用来加载 Java 类到 Java 虚拟机中。一般来说，Java 虚拟机使用 Java 类的方式如下：Java 源程序（.java 文件）在经过 Java 编译器编译之后就被转换成 Java 字节代码（.class 文件）。类加载器负责读取 Java 字节代码，并转换成 <code>java.lang.Class</code> 类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 <code>newInstance()</code>方法就可以创建出该类的一个对象。实际的情况可能更加复杂，比如 Java 字节代码可能是通过工具动态生成的，也可能是通过网络下载的。</p>
<p>基本上所有的类加载器都是 <code>java.lang.ClassLoader</code> 类的一个实例。下面详细介绍这个 Java 类。</p>
<p><span class="smalltitle"><code>java.lang.ClassLoader</code> 类介绍</span></p>
<p><code>java.lang.ClassLoader</code> 类的基本职责就是根据一个指定的类的名称，找到或者生成其对应的字节代码，然后从这些字节代码中定义出一个 Java 类，即 <code>java.lang.Class</code> 类的一个实例。除此之外，<code>ClassLoader</code> 还负责加载 Java 应用所需的资源，如图像文件和配置文件等。不过本文只讨论其加载类的功能。为了完成加载类的这个职责，<code>ClassLoader</code> 提供了一系列的方法，比较重要的方法如 <font color="#4c6e94">表 1</font> 所示。关于这些方法的细节会在下面进行介绍。</p><br /><strong>表 1. ClassLoader 中与加载类相关的方法</strong><br />
<table class="data-table-1" border="0" cellspacing="0" summary="ClassLoader 中与加载类相关的方法" cellpadding="0" width="100%">
<tbody>
<tr>
<th scope="col">方法</th>
<th scope="col">说明</th></tr>
<tr>
<td><code>getParent()</code> </td>
<td>返回该类加载器的父类加载器。</td></tr>
<tr>
<td><code>loadClass(String name)</code> </td>
<td>加载名称为 <code>name</code> 的类，返回的结果是 <code>java.lang.Class</code> 类的实例。</td></tr>
<tr>
<td><code>findClass(String name)</code> </td>
<td>查找名称为 <code>name</code> 的类，返回的结果是 <code>java.lang.Class</code> 类的实例。</td></tr>
<tr>
<td><code>findLoadedClass(String name)</code> </td>
<td>查找名称为 <code>name</code> 的已经被加载过的类，返回的结果是 <code>java.lang.Class</code> 类的实例。</td></tr>
<tr>
<td><code>defineClass(String name, byte[] b, int off, int len)</code> </td>
<td>把字节数组 <code>b</code> 中的内容转换成 Java 类，返回的结果是 <code>java.lang.Class</code> 类的实例。这个方法被声明为 <code>final</code> 的。</td></tr>
<tr>
<td><code>resolveClass(Class&lt;?&gt; c)</code> </td>
<td>链接指定的 Java 类。</td></tr></tbody></table>
<p>对于 <font color="#4c6e94">表 1</font> 中给出的方法，表示类名称的 <code>name</code> 参数的值是类的二进制名称。需要注意的是内部类的表示，如 <code>com.example.Sample$1</code> 和 <code>com.example.Sample$Inner</code> 等表示方式。这些方法会在下面介绍类加载器的工作机制时，做进一步的说明。下面介绍类加载器的树状组织结构。</p>
<p><span class="smalltitle">类加载器的树状组织结构</span></p>
<p>Java 中的类加载器大致可以分成两类，一类是系统提供的，另外一类则是由 Java 应用开发人员编写的。系统提供的类加载器主要有下面三个：</p>
<ul><li>引导类加载器（bootstrap class loader）：它用来加载 Java 的核心库，是用原生代码来实现的，并不继承自 <code>java.lang.ClassLoader</code>。</li><li>扩展类加载器（extensions class loader）：它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。</li><li>系统类加载器（system class loader）：它根据 Java 应用的类路径（CLASSPATH）来加载 Java 类。一般来说，Java 应用的类都是由它来完成加载的。可以通过 <code>ClassLoader.getSystemClassLoader()</code> 来获取它。</li></ul>
<p>除了系统提供的类加载器以外，开发人员可以通过继承 <code>java.lang.ClassLoader</code> 类的方式实现自己的类加载器，以满足一些特殊的需求。</p>
<p>除了引导类加载器之外，所有的类加载器都有一个父类加载器。通过 <font color="#4c6e94">表 1</font> 中给出的 <code>getParent()</code> 方法可以得到。对于系统提供的类加载器来说，系统类加载器的父类加载器是扩展类加载器，而扩展类加载器的父类加载器是引导类加载器；对于开发人员编写的类加载器来说，其父类加载器是加载此类加载器 Java 类的类加载器。因为类加载器 Java 类如同其它的 Java 类一样，也是要由类加载器来加载的。一般来说，开发人员编写的类加载器的父类加载器是系统类加载器。类加载器通过这种方式组织起来，形成树状结构。树的根节点就是引导类加载器。<font color="#4c6e94">图 1</font> 中给出了一个典型的类加载器树状组织结构示意图，其中的箭头指向的是父类加载器。</p><br /><strong>图 1. 类加载器树状组织结构示意图</strong><br /><img alt="类加载器树状组织结构示意图" src="http://www.ibm.com/developerworks/cn/java/j-lo-classloader/image001.jpg" width="564" height="446" /> <br />
<p><font color="#4c6e94">代码清单 1</font> 演示了类加载器的树状组织结构。</p><br /><strong>清单 1. 演示类加载器的树状组织结构</strong><br />
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline"><pre class="displaycode">public class ClassLoaderTree { 

    public static void main(String[] args) { 
        ClassLoader loader = ClassLoaderTree.class.getClassLoader(); 
        while (loader != null) { 
            System.out.println(loader.toString()); 
            loader = loader.getParent(); 
        } 
    } 
}</pre></td></tr></tbody></table><br />
<p>每个 Java 类都维护着一个指向定义它的类加载器的引用，通过 <code>getClassLoader()</code> 方法就可以获取到此引用。<font color="#4c6e94">代码清单 1</font> 中通过递归调用 <code>getParent()</code> 方法来输出全部的父类加载器。<font color="#4c6e94">代码清单 1</font> 的运行结果如 <font color="#4c6e94">代码清单 2</font> 所示。</p><br /><strong>清单 2. 演示类加载器的树状组织结构的运行结果</strong><br />
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline"><pre class="displaycode">sun.misc.Launcher$AppClassLoader@9304b1 
sun.misc.Launcher$ExtClassLoader@190d11</pre></td></tr></tbody></table><br />
<p>如 <font color="#4c6e94">代码清单 2</font> 所示，第一个输出的是 <code>ClassLoaderTree</code> 类的类加载器，即系统类加载器。它是 <code>sun.misc.Launcher$AppClassLoader</code> 类的实例；第二个输出的是扩展类加载器，是 <code>sun.misc.Launcher$ExtClassLoader</code> 类的实例。需要注意的是这里并没有输出引导类加载器，这是由于有些 JDK 的实现对于父类加载器是引导类加载器的情况，<code>getParent()</code> 方法返回 <code>null</code>。</p>
<p>在了解了类加载器的树状组织结构之后，下面介绍类加载器的代理模式。</p>
<p><span class="smalltitle">类加载器的代理模式</span></p>
<p>类加载器在尝试自己去查找某个类的字节代码并定义它时，会先代理给其父类加载器，由父类加载器先去尝试加载这个类，依次类推。在介绍代理模式背后的动机之前，首先需要说明一下 Java 虚拟机是如何判定两个 Java 类是相同的。Java 虚拟机不仅要看类的全名是否相同，还要看加载此类的类加载器是否一样。只有两者都相同的情况，才认为两个类是相同的。即便是同样的字节代码，被不同的类加载器加载之后所得到的类，也是不同的。比如一个 Java 类 <code>com.example.Sample</code>，编译之后生成了字节代码文件 <code>Sample.class</code>。两个不同的类加载器 <code>ClassLoaderA</code> 和 <code>ClassLoaderB</code> 分别读取了这个 <code>Sample.class</code> 文件，并定义出两个 <code>java.lang.Class</code> 类的实例来表示这个类。这两个实例是不相同的。对于 Java 虚拟机来说，它们是不同的类。试图对这两个类的对象进行相互赋值，会抛出运行时异常 <code>ClassCastException</code>。下面通过示例来具体说明。<font color="#4c6e94">代码清单 3</font> 中给出了 Java 类 <code>com.example.Sample</code>。</p><br /><strong>清单 3. com.example.Sample 类</strong><br />
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline"><pre class="displaycode">package com.example; 

public class Sample { 
    private Sample instance; 

    public void setSample(Object instance) { 
        this.instance = (Sample) instance; 
    } 
}</pre></td></tr></tbody></table><br />
<p>如 <font color="#4c6e94">代码清单 3</font> 所示，<code>com.example.Sample</code> 类的方法 <code>setSample</code> 接受一个 <code>java.lang.Object</code> 类型的参数，并且会把该参数强制转换成 <code>com.example.Sample</code> 类型。测试 Java 类是否相同的代码如 <font color="#4c6e94">代码清单 4</font> 所示。</p><br /><strong>清单 4. 测试 Java 类是否相同</strong><br />
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline"><pre class="displaycode">public void testClassIdentity() { 
    String classDataRootPath = "C:\\workspace\\Classloader\\classData"; 
    FileSystemClassLoader fscl1 = new FileSystemClassLoader(classDataRootPath); 
    FileSystemClassLoader fscl2 = new FileSystemClassLoader(classDataRootPath); 
    String className = "com.example.Sample"; 	
    try { 
        Class&lt;?&gt; class1 = fscl1.loadClass(className); 
        Object obj1 = class1.newInstance(); 
        Class&lt;?&gt; class2 = fscl2.loadClass(className); 
        Object obj2 = class2.newInstance(); 
        Method setSampleMethod = class1.getMethod("setSample", java.lang.Object.class); 
        setSampleMethod.invoke(obj1, obj2); 
    } catch (Exception e) { 
        e.printStackTrace(); 
    } 
}</pre></td></tr></tbody></table><br />
<p><font color="#4c6e94">代码清单 4</font> 中使用了类 <code>FileSystemClassLoader</code> 的两个不同实例来分别加载类 <code>com.example.Sample</code>，得到了两个不同的 <code>java.lang.Class</code> 的实例，接着通过 <code>newInstance()</code> 方法分别生成了两个类的对象 <code>obj1</code> 和 <code>obj2</code>，最后通过 Java 的反射 API 在对象 <code>obj1</code> 上调用方法 <code>setSample</code>，试图把对象 <code>obj2</code> 赋值给 <code>obj1</code> 内部的 <code>instance</code> 对象。<font color="#4c6e94">代码清单 4</font> 的运行结果如 <font color="#4c6e94">代码清单 5</font> 所示。</p><br /><strong>清单 5. 测试 Java 类是否相同的运行结果</strong><br />
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline"><pre class="displaycode">java.lang.reflect.InvocationTargetException 
	 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
	 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
	 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
	 at java.lang.reflect.Method.invoke(Method.java:597) 
	 at classloader.ClassIdentity.testClassIdentity(ClassIdentity.java:26) 
	 at classloader.ClassIdentity.main(ClassIdentity.java:9) 
Caused by: java.lang.ClassCastException: com.example.Sample 
    cannot be cast to com.example.Sample 
	 at com.example.Sample.setSample(Sample.java:7) 
	 ... 6 more 
</pre></td></tr></tbody></table><br />
<p>从 <font color="#4c6e94">代码清单 5</font> 给出的运行结果可以看到，运行时抛出了 <code>java.lang.ClassCastException</code> 异常。虽然两个对象 <code>obj1</code> 和 <code>obj2</code> 的类的名字相同，但是这两个类是由不同的类加载器实例来加载的，因此不被 Java 虚拟机认为是相同的。</p>
<p>了解了这一点之后，就可以理解代理模式的设计动机了。代理模式是为了保证 Java 核心库的类型安全。所有 Java 应用都至少需要引用 <code>java.lang.Object</code> 类，也就是说在运行的时候，<code>java.lang.Object</code> 这个类需要被加载到 Java 虚拟机中。如果这个加载过程由 Java 应用自己的类加载器来完成的话，很可能就存在多个版本的 <code>java.lang.Object</code> 类，而且这些类之间是不兼容的。通过代理模式，对于 Java 核心库的类的加载工作由引导类加载器来统一完成，保证了 Java 应用所使用的都是同一个版本的 Java 核心库的类，是互相兼容的。</p>
<p>不同的类加载器为相同名称的类创建了额外的名称空间。相同名称的类可以并存在 Java 虚拟机中，只需要用不同的类加载器来加载它们即可。不同类加载器加载的类之间是不兼容的，这就相当于在 Java 虚拟机内部创建了一个个相互隔离的 Java 类空间。这种技术在许多框架中都被用到，后面会详细介绍。</p>
<p>下面具体介绍类加载器加载类的详细过程。</p>
<p><span class="smalltitle">加载类的过程</span></p>
<p>在前面介绍类加载器的代理模式的时候，提到过类加载器会首先代理给其它类加载器来尝试加载某个类。这就意味着真正完成类的加载工作的类加载器和启动这个加载过程的类加载器，有可能不是同一个。真正完成类的加载工作是通过调用 <code>defineClass</code> 来实现的；而启动类的加载过程是通过调用 <code>loadClass</code> 来实现的。前者称为一个类的定义加载器（defining loader），后者称为初始加载器（initiating loader）。在 Java 虚拟机判断两个类是否相同的时候，使用的是类的定义加载器。也就是说，哪个类加载器启动类的加载过程并不重要，重要的是最终定义这个类的加载器。两种类加载器的关联之处在于：一个类的定义加载器是它引用的其它类的初始加载器。如类 <code>com.example.Outer</code> 引用了类 <code>com.example.Inner</code>，则由类 <code>com.example.Outer</code> 的定义加载器负责启动类 <code>com.example.Inner</code> 的加载过程。</p>
<p>方法 <code>loadClass()</code> 抛出的是 <code>java.lang.ClassNotFoundException</code> 异常；方法 <code>defineClass()</code> 抛出的是 <code>java.lang.NoClassDefFoundError</code> 异常。</p>
<p>类加载器在成功加载某个类之后，会把得到的 <code>java.lang.Class</code> 类的实例缓存起来。下次再请求加载该类的时候，类加载器会直接使用缓存的类的实例，而不会尝试再次加载。也就是说，对于一个类加载器实例来说，相同全名的类只加载一次，即 <code>loadClass</code> 方法不会被重复调用。</p>
<p>下面讨论另外一种类加载器：线程上下文类加载器。</p>
<p><span class="smalltitle">线程上下文类加载器</span></p>
<p>线程上下文类加载器（context class loader）是从 JDK 1.2 开始引入的。类 <code>java.lang.Thread</code> 中的方法 <code>getContextClassLoader()</code> 和 <code>setContextClassLoader(ClassLoader cl)</code> 用来获取和设置线程的上下文类加载器。如果没有通过 <code>setContextClassLoader(ClassLoader cl)</code> 方法进行设置的话，线程将继承其父线程的上下文类加载器。Java 应用运行的初始线程的上下文类加载器是系统类加载器。在线程中运行的代码可以通过此类加载器来加载类和资源。</p>
<p>前面提到的类加载器的代理模式并不能解决 Java 应用开发中会遇到的类加载器的全部问题。Java 提供了很多服务提供者接口（Service Provider Interface，SPI），允许第三方为这些接口提供实现。常见的 SPI 有 JDBC、JCE、JNDI、JAXP 和 JBI 等。这些 SPI 的接口由 Java 核心库来提供，如 JAXP 的 SPI 接口定义包含在 <code>javax.xml.parsers</code> 包中。这些 SPI 的实现代码很可能是作为 Java 应用所依赖的 jar 包被包含进来，可以通过类路径（CLASSPATH）来找到，如实现了 JAXP SPI 的 <font color="#4c6e94">Apache Xerces</font> 所包含的 jar 包。SPI 接口中的代码经常需要加载具体的实现类。如 JAXP 中的 <code>javax.xml.parsers.DocumentBuilderFactory</code> 类中的 <code>newInstance()</code> 方法用来生成一个新的 <code>DocumentBuilderFactory</code> 的实例。这里的实例的真正的类是继承自 <code>javax.xml.parsers.DocumentBuilderFactory</code>，由 SPI 的实现所提供的。如在 Apache Xerces 中，实现的类是 <code>org.apache.xerces.jaxp.DocumentBuilderFactoryImpl</code>。而问题在于，SPI 的接口是 Java 核心库的一部分，是由引导类加载器来加载的；SPI 实现的 Java 类一般是由系统类加载器来加载的。引导类加载器是无法找到 SPI 的实现类的，因为它只加载 Java 的核心库。它也不能代理给系统类加载器，因为它是系统类加载器的祖先类加载器。也就是说，类加载器的代理模式无法解决这个问题。</p>
<p>线程上下文类加载器正好解决了这个问题。如果不做任何的设置，Java 应用的线程的上下文类加载器默认就是系统上下文类加载器。在 SPI 接口的代码中使用线程上下文类加载器，就可以成功的加载到 SPI 实现的类。线程上下文类加载器在很多 SPI 的实现中都会用到。</p>
<p>下面介绍另外一种加载类的方法：<code>Class.forName</code>。</p>
<p><span class="smalltitle">Class.forName</span></p>
<p><code>Class.forName</code> 是一个静态方法，同样可以用来加载类。该方法有两种形式：<code>Class.forName(String name, boolean initialize, ClassLoader loader)</code> 和 <code>Class.forName(String className)</code>。第一种形式的参数 <code>name</code> 表示的是类的全名；<code>initialize</code> 表示是否初始化类；<code>loader</code> 表示加载时使用的类加载器。第二种形式则相当于设置了参数 <code>initialize</code> 的值为 <code>true</code>，<code>loader</code> 的值为当前类的类加载器。<code>Class.forName</code> 的一个很常见的用法是在加载数据库驱动的时候。如 <code>Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance()</code> 用来加载 Apache Derby 数据库的驱动。</p>
<p>在介绍完类加载器相关的基本概念之后，下面介绍如何开发自己的类加载器。</p>
<div class="ibm-alternate-rule">
<hr />
</div>
<p class="ibm-ind-link ibm-back-to-top">回页首</p>
<p><span class="atitle">开发自己的类加载器</span></p>
<p>虽然在绝大多数情况下，系统默认提供的类加载器实现已经可以满足需求。但是在某些情况下，您还是需要为应用开发出自己的类加载器。比如您的应用通过网络来传输 Java 类的字节代码，为了保证安全性，这些字节代码经过了加密处理。这个时候您就需要自己的类加载器来从某个网络地址上读取加密后的字节代码，接着进行解密和验证，最后定义出要在 Java 虚拟机中运行的类来。下面将通过两个具体的实例来说明类加载器的开发。</p>
<p><span class="smalltitle">文件系统类加载器</span></p>
<p>第一个类加载器用来加载存储在文件系统上的 Java 字节代码。完整的实现如 <font color="#4c6e94">代码清单 6</font> 所示。</p><br /><strong>清单 6. 文件系统类加载器</strong><br />
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td class="code-outline"><pre class="displaycode">public class FileSystemClassLoader extends ClassLoader { 

    private String rootDir; 

    public FileSystemClassLoader(String rootDir) { 
        this.rootDir = rootDir; 
    } 

    protected Class&lt;?&gt; findClass(String name) throws ClassNotFoundException { 
        byte[] classData = getClassData(name); 
        if (classData == null) { 
            throw new ClassNotFoundException(); 
        } 
        else { 
            return defineClass(name, classData, 0, classData.length); 
        } 
    } 

    private byte[] getClassData(String className) { 
        String path = classNameToPath(className); 
        try { 
            InputStream ins = new FileInputStream(path); 
            ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
            int bufferSize = 4096; 
            byte[] buffer = new byte[bufferSize]; 
            int bytesNumRead = 0; 
            while ((bytesNumRead = ins.read(buffer)) != -1) { 
                baos.write(buffer, 0, bytesNumRead); 
            } 
            return baos.toByteArray(); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } 
        return null; 
    } 

    private String classNameToPath(String className) { 
        return rootDir + File.separatorChar 
                + className.replace('.', File.separatorChar) + ".class"; 
    } 
}</pre></td></tr></tbody></table><br />
<p>如 <font color="#4c6e94">代码清单 6</font> 所示，类 <code>FileSystemClassLoader</code> 继承自类 <code>java.lang.ClassLoader</code>。在 <font color="#4c6e94">表 1</font> 中列出的 <code>java.lang.ClassLoader</code> 类的常用方法中，一般来说，自己开发的类加载器只需要覆写 <code>findClass(String name)</code> 方法即可。<code>java.lang.ClassLoader</code> 类的方法 <code>loadClass()</code> 封装了前面提到的代理模式的实现。该方法会首先调用 <code>findLoadedClass()</code> 方法来检查该类是否已经被加载过；如果没有加载过的话，会调用父类加载器的 <code>loadClass()</code> 方法来尝试加载该类；如果父类加载器无法加载该类的话，就调用 <code>findClass()</code> 方法来查找该类。因此，为了保证类加载器都正确实现代理模式，在开发自己的类加载器时，最好不要覆写 <code>loadClass()</code> 方法，而是覆写 <code>findClass()</code> 方法。</p>
<p>类 <code>FileSystemClassLoader</code> 的 <code>findClass()</code> 方法首先根据类的全名在硬盘上查找类的字节代码文件（.class 文件），然后读取该文件内容，最后通过 <code>defineClass()</code> 方法来把这些字节代码转换成 <code>java.lang.Class</code> 类的实例。</p>
<p><span class="smalltitle">网络类加载器</span></p>
<p>下面将通过一个网络类加载器来说明如何通过类加载器来实现组件的动态更新。即基本的场景是：Java 字节代码（.class）文件存放在服务器上，客户端通过网络的方式获取字节代码并执行。当有版本更新的时候，只需要替换掉服务器上保存的文件即可。通过类加载器可以比较简单的实现这种需求。</p>
<p>类 <code>NetworkClassLoader</code> 负责通过网络下载 Java 类字节代码并定义出 Java 类。它的实现与 <code>FileSystemClassLoader</code> 类似。在通过 <code>NetworkClassLoader</code> 加载了某个版本的类之后，一般有两种做法来使用它。第一种做法是使用 Java 反射 API。另外一种做法是使用接口。需要注意的是，并不能直接在客户端代码中引用从服务器上下载的类，因为客户端代码的类加载器找不到这些类。使用 Java 反射 API 可以直接调用 Java 类的方法。而使用接口的做法则是把接口的类放在客户端中，从服务器上加载实现此接口的不同版本的类。在客户端通过相同的接口来使用这些实现类。网络类加载器的具体代码见 <font color="#4c6e94">下载</font>。</p>
<p>在介绍完如何开发自己的类加载器之后，下面说明类加载器和 Web 容器的关系。</p>
<div class="ibm-alternate-rule">
<hr />
</div>
<p class="ibm-ind-link ibm-back-to-top">回页首</p>
<p><span class="atitle">类加载器与 Web 容器</span></p>
<p>对于运行在 Java EE&#8482; 容器中的 Web 应用来说，类加载器的实现方式与一般的 Java 应用有所不同。不同的 Web 容器的实现方式也会有所不同。以 Apache Tomcat 来说，每个 Web 应用都有一个对应的类加载器实例。该类加载器也使用代理模式，所不同的是它是首先尝试去加载某个类，如果找不到再代理给父类加载器。这与一般类加载器的顺序是相反的。这是 Java Servlet 规范中的推荐做法，其目的是使得 Web 应用自己的类的优先级高于 Web 容器提供的类。这种代理模式的一个例外是：Java 核心库的类是不在查找范围之内的。这也是为了保证 Java 核心库的类型安全。</p>
<p>绝大多数情况下，Web 应用的开发人员不需要考虑与类加载器相关的细节。下面给出几条简单的原则： 
<ul><li>每个 Web 应用自己的 Java 类文件和使用的库的 jar 包，分别放在 <code>WEB-INF/classes</code> 和 <code>WEB-INF/lib</code> 目录下面。</li><li>多个应用共享的 Java 类文件和 jar 包，分别放在 Web 容器指定的由所有 Web 应用共享的目录下面。</li><li>当出现找不到类的错误时，检查当前类的类加载器和当前线程的上下文类加载器是否正确。</li></ul>
<p>&nbsp;</p>
<p>在介绍完类加载器与 Web 容器的关系之后，下面介绍它与 OSGi 的关系。</p>
<div class="ibm-alternate-rule">
<hr />
</div>
<p class="ibm-ind-link ibm-back-to-top">回页首</p>
<p><span class="atitle">类加载器与 OSGi</span></p>
<p>OSGi&#8482; 是 Java 上的动态模块系统。它为开发人员提供了面向服务和基于组件的运行环境，并提供标准的方式用来管理软件的生命周期。OSGi 已经被实现和部署在很多产品上，在开源社区也得到了广泛的支持。Eclipse 就是基于 OSGi 技术来构建的。</p>
<p>OSGi 中的每个模块（bundle）都包含 Java 包和类。模块可以声明它所依赖的需要导入（import）的其它模块的 Java 包和类（通过 <code>Import-Package</code>），也可以声明导出（export）自己的包和类，供其它模块使用（通过 <code>Export-Package</code>）。也就是说需要能够隐藏和共享一个模块中的某些 Java 包和类。这是通过 OSGi 特有的类加载器机制来实现的。OSGi 中的每个模块都有对应的一个类加载器。它负责加载模块自己包含的 Java 包和类。当它需要加载 Java 核心库的类时（以 <code>java</code> 开头的包和类），它会代理给父类加载器（通常是启动类加载器）来完成。当它需要加载所导入的 Java 类时，它会代理给导出此 Java 类的模块来完成加载。模块也可以显式的声明某些 Java 包和类，必须由父类加载器来加载。只需要设置系统属性 <code>org.osgi.framework.bootdelegation</code> 的值即可。</p>
<p>假设有两个模块 bundleA 和 bundleB，它们都有自己对应的类加载器 classLoaderA 和 classLoaderB。在 bundleA 中包含类 <code>com.bundleA.Sample</code>，并且该类被声明为导出的，也就是说可以被其它模块所使用的。bundleB 声明了导入 bundleA 提供的类 <code>com.bundleA.Sample</code>，并包含一个类 <code>com.bundleB.NewSample</code> 继承自 <code>com.bundleA.Sample</code>。在 bundleB 启动的时候，其类加载器 classLoaderB 需要加载类 <code>com.bundleB.NewSample</code>，进而需要加载类 <code>com.bundleA.Sample</code>。由于 bundleB 声明了类 <code>com.bundleA.Sample</code> 是导入的，classLoaderB 把加载类 <code>com.bundleA.Sample</code> 的工作代理给导出该类的 bundleA 的类加载器 classLoaderA。classLoaderA 在其模块内部查找类 <code>com.bundleA.Sample</code> 并定义它，所得到的类 <code>com.bundleA.Sample</code> 实例就可以被所有声明导入了此类的模块使用。对于以 <code>java</code> 开头的类，都是由父类加载器来加载的。如果声明了系统属性 <code>org.osgi.framework.bootdelegation=com.example.core.*</code>，那么对于包 <code>com.example.core</code> 中的类，都是由父类加载器来完成的。</p>
<p>OSGi 模块的这种类加载器结构，使得一个类的不同版本可以共存在 Java 虚拟机中，带来了很大的灵活性。不过它的这种不同，也会给开发人员带来一些麻烦，尤其当模块需要使用第三方提供的库的时候。下面提供几条比较好的建议： 
<ul><li>如果一个类库只有一个模块使用，把该类库的 jar 包放在模块中，在 <code>Bundle-ClassPath</code> 中指明即可。</li><li>如果一个类库被多个模块共用，可以为这个类库单独的创建一个模块，把其它模块需要用到的 Java 包声明为导出的。其它模块声明导入这些类。</li><li>如果类库提供了 SPI 接口，并且利用线程上下文类加载器来加载 SPI 实现的 Java 类，有可能会找不到 Java 类。如果出现了 <code>NoClassDefFoundError</code> 异常，首先检查当前线程的上下文类加载器是否正确。通过 <code>Thread.currentThread().getContextClassLoader()</code> 就可以得到该类加载器。该类加载器应该是该模块对应的类加载器。如果不是的话，可以首先通过 <code>class.getClassLoader()</code> 来得到模块对应的类加载器，再通过 <code>Thread.currentThread().setContextClassLoader()</code> 来设置当前线程的上下文类加载器。</li></ul>
<p>&nbsp;</p>
<div class="ibm-alternate-rule">
<hr />
</div>
<p><span class="atitle">总结</span></p>
<p>类加载器是 Java 语言的一个创新。它使得动态安装和更新软件组件成为可能。本文详细介绍了类加载器的相关话题，包括基本概念、代理模式、线程上下文类加载器、与 Web 容器和 OSGi 的关系等。开发人员在遇到 <code>ClassNotFoundException</code> 和 <code>NoClassDefFoundError</code> 等异常的时候，应该检查抛出异常的类的类加载器和当前线程的上下文类加载器，从中可以发现问题的所在。在开发自己的类加载器的时候，需要注意与已有的类加载器组织结构的协调。<br />转载自：<a href="http://www.ibm.com/developerworks/cn/java/j-lo-classloader/index.html">http://www.ibm.com/developerworks/cn/java/j-lo-classloader/index.html</a></p></div></div></div><img src ="http://www.blogjava.net/freeman1984/aggbug/361655.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-10-20 14:57 <a href="http://www.blogjava.net/freeman1984/archive/2011/10/20/361655.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java ClassLoader基础知识</title><link>http://www.blogjava.net/freeman1984/archive/2011/10/20/361641.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Thu, 20 Oct 2011 03:27:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/10/20/361641.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/361641.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/10/20/361641.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/361641.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/361641.html</trackback:ping><description><![CDATA[Java中一共有四个类加载器，之所以叫类加载器，是程序要用到某个类的时候，要用类加载器载入内存。<br />&nbsp;&nbsp;&nbsp; 这四个类加载器分别为：<strong>Bootstrap ClassLoader</strong>、<strong>Extension ClassLoader</strong>、<strong>AppClassLoader</strong><br />和<strong>URLClassLoader</strong>，他们的作用其实从名字就可以大概推测出来了。其中AppClassLoader在很多地方被叫做<strong>System ClassLoader<br /><br /></strong><strong>Bootstrap ClassLoader</strong>是在JVM开始运行的时候加载java的核心类，是用C++编写的，它用来加载核心类库，在JVM源代码中这样写道：<br />static const char classpathFormat[] =<br />"%/lib/rt.jar:"<br />"%/lib/i18n.jar:"<br />"%/lib/sunrsasign.jar:"<br />"%/lib/jsse.jar:"<br />"%/lib/jce.jar:"<br />"%/lib/charsets.jar:"<br />"%/classes";<br /><strong>Extension ClassLoader</strong>是用来加载扩展类，即<strong>/lib/ext</strong>中的类。<br /><strong>AppClassLoader</strong>用来加载<strong>Classpath</strong>的类，是和我们关系最密切的类。<br /><strong>URLClassLoader</strong>用来加载网络上远程的类，暂且不讨论。<br /><br /><strong><span style="color: #5b10ff"><span style="font-size: 18pt">它们之间的关系:<br /><br /></span></span></strong>1.<strong>Parent-Child</strong>，按顺序从大到小。不是简单的继承关系。<br /><br />2.ClassLoader有个<strong>getParent</strong>的方法，但是Ext ClassLoader调用后得到的是<strong>null</strong>，bootstrap是JVM自己的，用户看不到。<br /><br />3.classloader的<strong>委托机制</strong>：当等级比较低的ClassLoader要加载某个类的时候，它首先会请求Parent加载器来加载，Parent再请求它的Parent<br />比如现在Ext要加载了，它往上请求。如果最大的Bootstrap找不到，那么Boot会叫Ext自己找找，Ext找不到，是<strong><span style="color: #ff0000">不会</span></strong>让下一级的App去找的，此时就报出ClassNotFoundException<br /><br />4.类A调用类B，B会要求调用它的类的类加载器来加载它，也就是B会要求加载A的加载器来加载B。这就会有个问题，如果他们在一起，那没关系，肯定某个classloader会把它们俩都加载好。但是如果A在/lib/ext文件夹中，而B在Classpath中呢？过程是这样的首先加载A，那么一层层上到Bootstrap Classloader，boot没找到所以ext自己找，找到了，没问题；加载B，因为A调用了B，所以也从bootstrap来找，没找到，然后A的ext classloader来找还是没找到，但是再也不会往下调用了，于是报出ClassNotFoundException。<br />但是现实生活中有很多应用，比如JDBC核心方法在核心库而驱动在扩展库，是必定在两个地方的，那怎么办呢？要用到Context ClassLoader我们在建立一个线程Thread的时候，可以为这个线程通过setContextClassLoader方法来指定一个合适的classloader作为这个线程的context classloader，当此线程运行的时候，我们可以通过getContextClassLoader方法来获得此context classloader，就可以用它来载入我们所需要的Class。默认的是system classloader。利用这个特性，我们可以&#8220;打破&#8221;classloader委托机制了，父classloader可以获得当前线程的context classloader，而这个context classloader可以是它的子classloader或者其他的classloader，那么父classloader就可以从其获得所需的 Class，这就打破了只能向父classloader请求的限制了。这个机制可以满足当我们的classpath是在运行时才确定,并由定制的 classloader加载的时候,由system classloader(即在jvm classpath中)加载的class可以通过context classloader获得定制的classloader并加载入特定的class(通常是抽象类和接口,定制的classloader中是其实现),例如web应用中的servlet就是用这种机制加载的. <br />转载自：<a href="http://www.blogjava.net/clraychen/archive/2008/02/20/180868.html">http://www.blogjava.net/clraychen/archive/2008/02/20/180868.html</a><img src ="http://www.blogjava.net/freeman1984/aggbug/361641.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-10-20 11:27 <a href="http://www.blogjava.net/freeman1984/archive/2011/10/20/361641.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>synchronized 要注意的地方</title><link>http://www.blogjava.net/freeman1984/archive/2011/10/17/361403.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 17 Oct 2011 02:56:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/10/17/361403.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/361403.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/10/17/361403.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/361403.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/361403.html</trackback:ping><description><![CDATA[<p>在Java1.5之前，synchronized应该是最常用的java支持并发手段。那synchronized是怎么做到的了，从java1.0开始，java中的每个对象就一个内部锁。如果一个类的方法被synchronized关键字所修饰，那么这个对象的锁将保护整个方法。</p>
<p>举例来说：</p>
<p>public synchronized void method(){</p>
<p>&nbsp;&nbsp;&nbsp; method body</p>
<p>}</p>
<p>等价于</p>
<p>public void method(){</p>
<p>&nbsp;&nbsp;&nbsp; this.intrinsicLock.lock();</p>
<p>&nbsp;&nbsp;&nbsp; try{</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; method body;</p>
<p>&nbsp;&nbsp;&nbsp; }finally(){</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.intrinsicLock.unlock();</p>
<p>&nbsp;&nbsp;&nbsp; }</p>
<p>}</p>
<p>&nbsp;</p>
<p>从上面的代码示例可以看出，synchronized的使用方式是比较简单的。这也导致了大量的初学者在碰到java编程的时候落入陷阱里，认为既然synhronized可以搞定一切，那么不管三七二十一，只要有并发可能性的地方，就加上synchronized的关键字，这显然是不对的。在java对象中，这个java对象只有这一个内部锁，其中一个synchronized方法获取到了这个锁，另外一个synchronized方法的调用将被阻塞。</p>
<p>即</p>
<p>class sync{</p>
<p>&nbsp;&nbsp;&nbsp; public synchronized void methodA(){};</p>
<p>&nbsp;&nbsp;&nbsp; public synchronized void methodB(){};</p>
<p>&nbsp;&nbsp;&nbsp; ... ...</p>
<p>&nbsp;</p>
<p>}</p>
<p>methodA 和methodB在初始就是互斥的，如果methodA和methodB进入互相等待，就很容易出现死锁的情况。那如果碰到这种情况，应该怎么做了？常用的方式是在方法内部新建一个无意义的对象，然后对这个无意义的对象加锅。</p>
<p>&nbsp;</p>
<div class="dp-highlighter bg_java">
<div class="bar">
<div class="tools"><a class="ViewSource" title="view plain" href="http://blog.csdn.net/sunnydogzhou/article/details/6553960#">view plain</a><a class="CopyToClipboard" title="copy to clipboard" href="http://blog.csdn.net/sunnydogzhou/article/details/6553960#">copy to clipboard</a><a class="PrintSource" title="print" href="http://blog.csdn.net/sunnydogzhou/article/details/6553960#">print</a><a class="About" title="?" href="http://blog.csdn.net/sunnydogzhou/article/details/6553960#">?</a></div></div>
<ol class="dp-j"><li class="alt"><span class="keyword">package</span><span>&nbsp;zl.study.concurrency.synchronize;&nbsp;&nbsp;</span></li><li><span></span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;Sync&nbsp;{&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;i;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;plus(){&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;dummy&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;Object();&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">synchronized</span><span>(dummy){&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i++;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;minus(){&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;dummy&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;Object();&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">synchronized</span><span>(dummy){&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i--;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div>&nbsp;
<p>另外需要注意的是将静态类声明为synchronized方法也是合法的。举例来说，如果Sync有一个static synchronized方法，那么这个方法被调用时,bank.class这个类对象本身在jvm中将被锁住</p><img src ="http://www.blogjava.net/freeman1984/aggbug/361403.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-10-17 10:56 <a href="http://www.blogjava.net/freeman1984/archive/2011/10/17/361403.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于java.lang.IllegalMonitorStateException </title><link>http://www.blogjava.net/freeman1984/archive/2011/10/14/361306.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 14 Oct 2011 10:03:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/10/14/361306.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/361306.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/10/14/361306.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/361306.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/361306.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 关于java.lang.IllegalMonitorStateException 异常说明&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2011/10/14/361306.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/361306.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-10-14 18:03 <a href="http://www.blogjava.net/freeman1984/archive/2011/10/14/361306.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ThreadPoolExecutor运转机制详解 .</title><link>http://www.blogjava.net/freeman1984/archive/2011/10/12/361083.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Wed, 12 Oct 2011 10:05:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/10/12/361083.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/361083.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/10/12/361083.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/361083.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/361083.html</trackback:ping><description><![CDATA[<p>最近发现几起对ThreadPoolExecutor的误用，其中包括自己，发现都是因为没有仔细看注释和内部运转机制，想当然的揣测参数导致，先看一下新建一个ThreadPoolExecutor的构建参数：</p>
<p>&nbsp;</p>
<div class="dp-highlighter nogutter bg_java:nogutter:nocontrols">
<div class="bar"></div>
<ol class="dp-j"><li class="alt"><span class="keyword">public</span><span>&nbsp;ThreadPoolExecutor(</span><span class="keyword">int</span><span>&nbsp;corePoolSize,&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;</span><span class="keyword">int</span><span>&nbsp;maximumPoolSize,&nbsp;&nbsp;</span></span></li><li class="alt"><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;</span><span class="keyword">long</span><span>&nbsp;keepAliveTime,&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;TimeUnit&nbsp;unit,&nbsp;&nbsp;</span></li><li class="alt"><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;BlockingQueue&lt;Runnable&gt;&nbsp;workQueue,&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;ThreadFactory&nbsp;threadFactory,&nbsp;&nbsp;</span></li><li class="alt"><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;RejectedExecutionHandler&nbsp;handler)&nbsp;&nbsp;</span></li></ol></div><textarea style="display: none" class="java:nogutter:nocontrols" rows="15" cols="50" name="code">public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue&lt;Runnable&gt; workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)</textarea> 
<p>&nbsp;</p>
<p>看这个参数很容易让人以为是线程池里保持corePoolSize个线程，如果不够用，就加线程入池直至maximumPoolSize大小，如果还不够就往workQueue里加，如果workQueue也不够就用RejectedExecutionHandler来做拒绝处理。</p>
<p>但实际情况不是这样，具体流程如下：</p>
<p>&nbsp;</p>
<p>1)线程池的大小&gt;活动的线程 就放入queue，由于有空闲的线程，就不创建线程直接用空闲的线程处理<br />2)线程池的大小&lt;活动的线程&amp;&amp; 线程池的大小&gt;=最大限制数，没有空闲的线程，但不能创建线程，事件入queue等待有空闲的线程，如果超时，使RejectedExecutionHandler处理<br />3)线程池的大小&lt;活动的线程&amp;&amp; 线程池的大小&lt;最大限制数,没有空闲线程，可以创建线程，直接创建新线程处理新事件</p>
<p>内部结构如下所示：</p>
<p><img alt="" src="http://hi.csdn.net/attachment/201012/7/0_12917139691L3R.gif" /> </p>
<p>从中可以发现ThreadPoolExecutor就是依靠BlockingQueue的阻塞机制来维持线程池，当池子里的线程无事可干的时候就通过workQueue.take()阻塞住。</p>
<p>其实可以通过Executes来学学几种特殊的ThreadPoolExecutor是如何构建的。</p>
<p>&nbsp;</p>
<div class="dp-highlighter nogutter bg_java:nogutter:nocontrols">
<div class="bar"></div>
<ol class="dp-j"><li class="alt"><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;ExecutorService&nbsp;newFixedThreadPool(</span><span class="keyword">int</span><span>&nbsp;nThreads)&nbsp;{&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;</span><span class="keyword">new</span><span>&nbsp;ThreadPoolExecutor(nThreads,&nbsp;nThreads,&nbsp;&nbsp;</span></span></li><li class="alt"><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;&nbsp;&nbsp;0L,&nbsp;TimeUnit.MILLISECONDS,&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;&nbsp;&nbsp;</span><span class="keyword">new</span><span>&nbsp;LinkedBlockingQueue&lt;Runnable&gt;());&nbsp;&nbsp;</span></span></li><li class="alt"><span>}&nbsp;&nbsp;</span></li></ol></div><textarea style="display: none" class="java:nogutter:nocontrols" rows="15" cols="50" name="code">public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue&lt;Runnable&gt;());
}</textarea> 
<p>&nbsp;</p>
<p>newFixedThreadPool就是一个固定大小的ThreadPool</p>
<p>&nbsp;</p>
<div class="dp-highlighter nogutter bg_java:nogutter:nocontrols">
<div class="bar"></div>
<ol class="dp-j"><li class="alt"><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;ExecutorService&nbsp;newCachedThreadPool()&nbsp;{&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;</span><span class="keyword">new</span><span>&nbsp;ThreadPoolExecutor(</span><span class="number">0</span><span>,&nbsp;Integer.MAX_VALUE,&nbsp;&nbsp;</span></span></li><li class="alt"><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;&nbsp;&nbsp;60L,&nbsp;TimeUnit.SECONDS,&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;&nbsp;&nbsp;</span><span class="keyword">new</span><span>&nbsp;SynchronousQueue&lt;Runnable&gt;());&nbsp;&nbsp;</span></span></li><li class="alt"><span>}&nbsp;&nbsp;</span></li></ol></div><textarea style="display: none" class="java:nogutter:nocontrols" rows="15" cols="50" name="code">public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue&lt;Runnable&gt;());
}</textarea> 
<p>&nbsp;</p>
<p>newCachedThreadPool比较适合没有固定大小并且比较快速就能完成的小任务，没必要维持一个Pool，这比直接new Thread来处理的好处是能在60秒内重用已创建的线程。</p>
<p>其他类型的ThreadPool看看构建参数再结合上面所说的特性就大致知道它的特性<br />转载自：http://blog.csdn.net/cutesource/article/details/6061229</p><img src ="http://www.blogjava.net/freeman1984/aggbug/361083.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-10-12 18:05 <a href="http://www.blogjava.net/freeman1984/archive/2011/10/12/361083.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>javafx2.0可以试用了.</title><link>http://www.blogjava.net/freeman1984/archive/2011/10/10/360370.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 10 Oct 2011 03:57:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/10/10/360370.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/360370.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/10/10/360370.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/360370.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/360370.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 可以和netbeans7.1 beta结合使用，方法如下...&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2011/10/10/360370.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/360370.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-10-10 11:57 <a href="http://www.blogjava.net/freeman1984/archive/2011/10/10/360370.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MAP排序 (转)</title><link>http://www.blogjava.net/freeman1984/archive/2011/08/23/357121.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Tue, 23 Aug 2011 07:49:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/08/23/357121.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/357121.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/08/23/357121.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/357121.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/357121.html</trackback:ping><description><![CDATA[可能会遇到这样的情况，我可能要对Map&lt;key,value&gt;的集合进行排序，而这种排序又分为两种情况，你可能按key值排序；另外你也可能会遇到按value值进行排序的情况。 
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 大家都知道，默认的情况下，TreeMap：是按key升序,进行排序的；LinkedHashMap：是按加入顺序进行排序的；HashMap：内部数值的顺序并不是以存放的先后顺序为主，而是以hash值的顺序为主，其次才是存放的先后顺序。在这里我们只讨论如何实现HashMap的排序。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.我们先讨论按key值进行排序<br />我们先看一下这个Sorter类：</p>
<p>public class Sorter {</p>
<p>&nbsp;&nbsp;&nbsp; public static Map sort(Map map) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Map&lt;Object, Object&gt; mapVK = new TreeMap&lt;Object, Object&gt;(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new Comparator&lt;Object&gt;() {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public int compare(Object obj1, Object obj2) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String v1 = (String)obj1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String v2 = (String)obj2;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int s = v2.compareTo(v1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return s;<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; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; );</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set col = map.keySet();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Iterator iter = col.iterator();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (iter.hasNext()) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String key = (String) iter.next();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Integer value = (Integer) map.get(key);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mapVK.put(key, value);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return mapVK;<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; <br />}</p>
<p>最后给出一个例子：<br />public class SortHashMap {</p>
<p>&nbsp;&nbsp;&nbsp; public SortHashMap() {</p>
<p>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; public static void main(String[] args) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Map&lt;String, Integer&gt; maps = new HashMap&lt;String, Integer&gt;();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; maps.put("boy", 8);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; maps.put("cat", 7);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; maps.put("dog", 1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; maps.put("apple", 5);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //排序前的输出<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set set = maps.entrySet();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Iterator i = set.iterator();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(i.hasNext()){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Map.Entry&lt;String, Integer&gt; entry1=(Map.Entry&lt;String, Integer&gt;)i.next();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(entry1.getKey() + "--------&gt;" + entry1.getValue());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("----------------");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //排序后的输出<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Map&lt;String, Integer&gt; sortMaps = Sorter.sort(maps);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set sortSet = sortMaps.entrySet();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Iterator ii = sortSet.iterator();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(ii.hasNext()){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Map.Entry&lt;String, Integer&gt; entry1=(Map.Entry&lt;String, Integer&gt;)ii.next();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(entry1.getKey() + "--------&gt;" + entry1.getValue());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; }<br />}</p>
<p>排序前的输出结果是：<br />cat--------&gt;7<br />apple--------&gt;5<br />dog--------&gt;1<br />boy--------&gt;8</p>
<p>排序后的输出结果是：<br />dog--------&gt;1<br />cat--------&gt;7<br />boy--------&gt;8<br />apple--------&gt;5<br />经过排序后的Map有序了，是按照字母的逆序排列的。</p>
<p>2、我们再讨论如何按value值进行排序。<br />还是上面的那个例子，我们想要按照各类对象的数量打印出类别的名称。<br />我们再来修改一下这个SortHashMap类：</p>
<p>public class SortHashMap {</p>
<p>&nbsp;&nbsp;&nbsp; public SortHashMap() {</p>
<p>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; public static void main(String[] args) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Map&lt;String, Integer&gt; maps = new HashMap&lt;String, Integer&gt;();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; maps.put("boy", 8);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; maps.put("cat", 7);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; maps.put("dog", 1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; maps.put("apple", 5);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //排序前的输出<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set set = maps.entrySet();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Iterator i = set.iterator();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(i.hasNext()){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Map.Entry&lt;String, Integer&gt; entry1=(Map.Entry&lt;String, Integer&gt;)i.next();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(entry1.getKey() + "--------&gt;" + entry1.getValue());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("----------------");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //排序后的输出<br />&nbsp;&nbsp;&nbsp;&nbsp; List&lt;Map.Entry&lt;String, Integer&gt;&gt; info = new ArrayList&lt;Map.Entry&lt;String, Integer&gt;&gt;(maps.entrySet());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Collections.sort(info, new Comparator&lt;Map.Entry&lt;String, Integer&gt;&gt;() {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public int compare(Map.Entry&lt;String, Integer&gt; obj1, Map.Entry&lt;String, Integer&gt; obj2) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return obj2.getValue() - obj1.getValue();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int j = 0; j&lt;info.size();j++) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(info.get(j).getKey() + "-------&gt;" + info.get(j).getValue());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }<br />}</p>
<p>排序前的输出结果是：<br />cat--------&gt;7<br />apple--------&gt;5<br />dog--------&gt;1<br />boy--------&gt;8</p>
<p>排序后的输出结果是：<br />boy-------&gt;8<br />cat-------&gt;7<br />apple-------&gt;5<br />dog-------&gt;1</p>
<p>程序运行的结果，达到了我们的要求，实现了Map的排序。该方法主要是利用了ArrayList的排序实现了Map的排序输出，并没有影响到Map的存放结构。</p><img src ="http://www.blogjava.net/freeman1984/aggbug/357121.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-08-23 15:49 <a href="http://www.blogjava.net/freeman1984/archive/2011/08/23/357121.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>统计指标和术语汇总</title><link>http://www.blogjava.net/freeman1984/archive/2011/08/04/355820.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Thu, 04 Aug 2011 09:36:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/08/04/355820.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/355820.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/08/04/355820.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/355820.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/355820.html</trackback:ping><description><![CDATA[<strong>页面浏览量 </strong>PV(page view)，即页面浏览数，或点击量，通常是衡量一个频道或网站甚至一个网页的主要指标。 用户刷新页面不记录到页面浏览量中。 
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>独立访客数 </strong>UV(unique visitor)：独立访客，将每台独立上网电脑(以cookie为依据)视为一位访客，一天之内(00:00-24:00)，访问您网站的访客数量。一天之内相同cookie的访问只被计算1次。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>平均访问页数</strong><strong> </strong>这是一个平均数，即在一定时间内全部页面浏览量与所有独立访客数相除的结果，即一个用户浏览的网页数量。这一指标表明了访问者对网站内容或者产品信息感兴趣的程度，也就是常说的网站&#8220;粘性&#8221;。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>访问次数 </strong>也称为登陆数，一个登陆是指客户开始访问网站到离开网站的过程。其中：相邻两次点击页面时间间隔在30分钟以内为一次登陆，大于30分钟为两次登陆。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>平均网站访问时间 </strong>同一个访问过程中最后一个页面的访问时间减去第一个页面的访问时间，得到此访问在网站上的停留时间。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>页面停留时间 </strong>显示访问者在某个特定页面或某组页面上花费的时间。&#8721;(时间戳(N+1)-时间戳(N))/(页面访问量-退出数)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>新访客数 </strong>独立访客中，历史首次访问您网站的访客数。<strong></strong></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>重复访客者数 </strong>重复访问者。是指在一定时期内(两年)不止一次访问一个网站的独立用户。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>新访客率 </strong>某段时间内某个页面或多个页面新访客数占所有唯一身份访问者的比例。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>回访率 </strong>重复访客占所有唯一身份访问者的比例。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>独立IP数 </strong>指访问某个站点或点击某个页面的不同IP地址的人数。 在同一天内，只记录第一次进入网站的具有独立IP的访问者，在同一天内再次访问该网站则不计数。独立IP访问者提供了一定时间内不同观众数量的统计指标，而没有反应出网站的全面活动。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>访问频度 </strong>是指您网站上访问者每日访问的频度，用于揭示您网站内容对访问者的吸引程度。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>跳出率 </strong>某个时间段内，只浏览了一页即离开网站的访问次数占总访问次数的比例。对于某页面的跳出率算法：从这个页面进入网站没有再点击其他页即离开的次数/所有进入这个页面的次数对于整个网站跳出率的算法：只浏览一个页面即离开的访问次数/进入网站的总次数<strong></strong></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>退出率 </strong>某个时间段内，离开网页的次数占该网页总浏览次数的比例。从本页退出网站的次数/本页的综合浏览量。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>页面打开时间 </strong>页面顶部JS代码与页面底部JS代码执行时间的差值。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; <strong>唯一身份浏览量 </strong>唯一浏览量(如最常见内容报告中所示)会汇总由同一用户在同一会话期间生成的综合浏览量。唯一浏览量表示该页被浏览(一次或多次)期间的会话次数。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>页面价值 </strong>页面价值是指用户在到达目标页面或完成电子商务交易(或两者都有)前访问页面的平均价值。其计算公式如下：页面价值 =(总目标价值+电子商务收入)/指定页面的唯一身份浏览量</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>投放词ROI </strong>订单佣金/点击单价*点击量</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>登陆页面 </strong>即访问入口：每次访问过程中，用户进入的第一个页面，此页面可以显示网站对外或搜索引擎的一些链接入口。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>访问路径 </strong>每个访问者从进入您的网站开始访问，一直到最后离开您的网站，整个过程中先后浏览的页面称为访问路径。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>离开页面 </strong>是指某个访客本次访问您网站时所访问的最后一个页面。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>目标完成数 </strong>到达目标页面的会话数目。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>目标转化率 </strong>目标完成的会话占总会话的比例。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>路径进入数 </strong>进入用户预定义的浏览路径的会话数。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>路径完成数 </strong>完成预定义的浏览路径的会话数。即设置的浏览路径每个步骤(页面)都覆盖到的会话的数目。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>路径转化率 </strong>完成浏览路径的会话占进入浏览路径的会话的比例。如100个人(准确的说应该是100个会话，这里假设每个人只访问了一次会话)开始了注册流程，但是最终只有20个人注册成功了(到达注册成功页面)，则转化率为20%。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>搜索深度 </strong>同一用户一次会话的搜索次数。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>搜索次数 </strong>用户使用搜索功能的次数</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>搜索退出率 </strong>搜索后退出数站总搜索者的比例。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>网站 </strong>主要单个域名或多个域名的站点集合。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>频道</strong><strong>/</strong><strong>栏目 </strong>将网站中的各种内容根据功能归类，划分出若干逻辑上的频道或栏目。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>过滤页面 </strong>网站中的某些页面并不是独立的页面，而是附属于某个页面，如滚动条页面就是附属于首页的页面，用户可以将这些附属页面设置为过滤页面。过滤后的浏览数方能真正反映网站的访问情况。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>特定页面 </strong>对于需要特殊分析的页面，通过设置，从众多页面中独立出来，进行特定分析的页面。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>定义页面 </strong>页面功能没有定义的页面，即没有归类到任何频道的页面。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>热门 </strong>最受欢迎的页面或频道，即浏览数排名前若干位(可由用户自行定义)的页面或频道。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>冷门 </strong>最不受欢迎的页面或频道，即浏览数排名后若干位(可由用户自行定义)的页面或频道。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>热点 </strong>将一个网页中包含的各个链接根据功能归类划分出若干板块，比如机票板块、酒店板块、广告板块等，每个板块成为一个热点。进而分析出该页面上的各个热点板块被点击的情况。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>沉默时间 </strong>注册用户最后一次访问网站到分析日的天数。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>沉默用户 </strong>在沉默时间内未访问网站的注册用户。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>重度访问用户 </strong>按每次访问的停留时间划分，把停留时间超过20分钟的用户归为重度访问用户；按每次访问产生的浏览数划分，把一次访问浏览超过10个页面的用户归为重度访问用户。对于重度访问用户，包括以下四个指标，每个指标值越大，表明用户品质越高。</p><li>重度用户比例(次数)=(浏览数&#8805;11页面的访问数)/ 总访问数</li><li>重度用户比例(时长)=(&gt;20分钟的访问数)/ 总访问数</li><li>重度用户指数=(&gt;20分钟的浏览数)/(&gt;20分钟的访问数)</li><li>重度访问量比列=(&gt;20分钟的浏览数)/ 总浏览数</li>
<p>&nbsp;&nbsp;&nbsp;&nbsp; <strong>轻度访问用户 </strong>按每次访问的停留时间划分，把停留时间不超过1分钟的用户归为轻度访问用户。对于轻度访问用户，包括以下三个指标，每个指标值越小，表明用户品质越高。</p></li><li>轻度用户比例=(0-1分钟的访问数)/ 总访问数</li><li>轻度用户指数=(0-1分钟的浏览数)/(0-1分钟的访问数)</li><li>轻度访问量比例=(0-1分钟的浏览数)/ 总浏览</li>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>拒绝率 </strong>一次访问只访问一个页面的访问次数占总访问数的比例，比例越小，表明用户品质越高。</p></li><li>拒绝率(一个页面)= 只访问1个页面的访问数 / 总访问数</li><li>拒绝率(首页)= 只访问首页的访问数 / 总访问数</li>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>访客 </strong>所有访问网站的用户。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>会员 </strong>所有注册过的访客。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong><strong>客户 </strong></strong>所有消费过的会员。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>时段 </strong>按照一天24个小时自然时间段进行划分。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>地区 </strong>访问客户的来源地区，是根据IP地区对照表，查询访问客户的IP地址落在哪个IP区段内，而得到其对应的地区。地区包括国内地区和国外地区，国内地区以省为单位，国外地区以国家为单位。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>IP</strong><strong>地址 </strong>IP地址由4个数组成，每个数可取值0～255， 各数之间用一个点号&#8221;.&#8221;分开，例如： 202.103.8.46。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>运营商 </strong>客户端接入互联网的服务提供商，比如中国电信、中国网通、教育网等。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>接入方式 </strong>客户端接入互联网的方式，比如拨号、专线、ISDN、ADSL等。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>广告 </strong>通过在别的网站上放置网站链接或弹出窗口等方式介绍本网站的一种商业活动。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>邮件 </strong>通过发送电子邮件，邮件中包含链接地址，吸引用户通过点击邮件中包含的链接地址访问本网站，实际上也是广告的一种。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>搜索引擎 </strong>在互联网上为您提供信息&#8221;检索&#8221;服务的网站。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>关键字 </strong>用户通过搜索引擎&#8220;检索&#8221;的内容。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>投放词 </strong>在百度竞价系统后台设置的关键词。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>曝光数 </strong>广告的展示次数。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>广告点击数 </strong>用户点击弹出广告的次数，即Click数。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>趋势 </strong>趋势分为两种，第一种是以时段为单位的一天24小时发展趋势。第二种是以日为单位的周、月、以及指定区间发展趋势。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>汇总 </strong>对多网站的分析进行汇总。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>同期比较 </strong>对任意两个日、周、月、以及指定区间的浏览数(或访问数、或用户数、停留时间)进行比较。比较对象可以是页面、频道、栏目、广告、地区等。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>聚合 </strong>对日期的聚合，比如周聚合就是将7天的数据合在一起为一个分析项，聚合目的就是以聚合项为单位分析网站发展的趋势。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>环比 </strong>在趋势分析中，当前日期数据与上一日期数据的比成为环比。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>Excel</strong><strong>导出 </strong>将分析结果以Excel表格形式输出。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>网站拓扑结构 </strong>网站的拓扑结构是由网站汇总、网站分析和频道分析三类节点构成。其中，网站汇总下可以有部门汇总，网站分析下可以有子网站，频道分析下可以有子频道。用户根据网站拓扑结构，来查询所需要的分析结果。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>日志文件 </strong>日志文件是指被分析网站的工作日志。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<strong>状态代码 </strong>也称作错误代码，是为服务器所接收每个请求(网页点击)分配的 3 位数代码。</p><br />转自:<a href="http://blogread.cn/it/article.php?id=4073&amp;f=sinat">http://blogread.cn/it/article.php?id=4073&amp;f=sinat</a><img src ="http://www.blogjava.net/freeman1984/aggbug/355820.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-08-04 17:36 <a href="http://www.blogjava.net/freeman1984/archive/2011/08/04/355820.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>OAuth简介</title><link>http://www.blogjava.net/freeman1984/archive/2011/07/29/355312.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 29 Jul 2011 03:19:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/07/29/355312.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/355312.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/07/29/355312.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/355312.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/355312.html</trackback:ping><description><![CDATA[<h1 id="firstHeading" class="firstHeading"><!-- /jumpto --><!-- bodytext -->
</h1>
<div class="floatright"></div>
<p><strong>OAuth</strong>（开放授权）是一个<font color="#ba0000">开放标准</font>，允许用户让第三方应用访问该用户在某一网站上存储的私密的资源（如照片，视频，联系人列表），而无需将用户名和密码提供给第三方应用。</p>
<p>OAuth允许用户提供一个令牌，而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌授权一个特定的网站（例如，视频编辑网站)在特定的时段（例如，接下来的2小时内）内访问特定的资源（例如仅仅是某一相册中的视频）。这样，OAuth允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息，而不需要分享他们的访问许可或他们数据的所有内容。</p>
<p>OAuth是OpenID的一个补充，但是完全不同的服务。</p>
<h2><span id=".E8.AE.A4.E8.AF.81.E5.92.8C.E6.8E.88.E6.9D.83.E8.BF.87.E7.A8.8B" class="mw-headline">认证和授权过程</span></h2>
<p>在认证和授权的过程中涉及的三方包括：</p>
<div>
<ul><li><strong>服务提供方</strong>，用户使用服务提供方来存储受保护的资源，如照片，视频，联系人列表。</li><li><strong>用户</strong>，存放在服务提供方的受保护的资源的拥有者。</li><li><strong>客户端</strong>，要访问服务提供方资源的第三方应用，通常是网站，如提供照片打印服务的网站。在认证过程之前，客户端要向服务提供者申请客户端标识。</li></ul></div>
<p>使用OAuth进行认证和授权的过程如下所示:</p>
<ol><li><strong>用户</strong>访问<strong>客户端</strong>的网站，想操作用户存放在<strong>服务提供方</strong>的资源。</li><li><strong>客户端</strong>向<strong>服务提供方</strong>请求一个临时令牌。</li><li><strong>服务提供方</strong>验证<strong>客户端</strong>的身份后，授予一个临时令牌。</li><li><strong>客户端</strong>获得临时令牌后，将用户引导至<strong>服务提供方</strong>的授权页面请求用户授权。在这个过程中将临时令牌和客户端的回调连接发送给<strong>服务提供方</strong>。</li><li><strong>用户</strong>在<strong>服务提供方</strong>的网页上输入用户名和密码，然后授权该<strong>客户端</strong>访问所请求的资源。</li><li>授权成功后，<strong>服务提供方</strong>引导<strong>用户</strong>返回<strong>客户端</strong>的网页。</li><li><strong>客户端</strong>根据临时令牌从<strong>服务提供方</strong>那里获取访问令牌。</li><li><strong>服务提供方</strong>根据临时令牌和<strong>用户</strong>的授权情况授予<strong>客户端</strong>访问令牌。</li><li><strong>客户端</strong>使用获取的访问令牌访问存放在<strong>服务提供方</strong>上的受保护的资源。</li></ol>
<p>新浪oauth认证说明：<br /><a href="http://open.weibo.com/wiki/Oauth">http://open.weibo.com/wiki/Oauth</a><br />豆瓣oauth认证：<br /><a href="http://www.douban.com/service/apidoc/auth">http://www.douban.com/service/apidoc/auth</a></p><img src ="http://www.blogjava.net/freeman1984/aggbug/355312.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-07-29 11:19 <a href="http://www.blogjava.net/freeman1984/archive/2011/07/29/355312.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>RunTime.getRunTime().addShutdownHook用法 </title><link>http://www.blogjava.net/freeman1984/archive/2011/07/04/353659.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 04 Jul 2011 09:36:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/07/04/353659.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/353659.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/07/04/353659.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/353659.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/353659.html</trackback:ping><description><![CDATA[<p><span style="font-size: small"><font size="2">今天在阅读Tomcat源码的时候，catalina这个类中使用了下边的代码，不是很了解，所以google了一下，然后测试下方法，Tomcat中的相关代码如下：</font></span></p>
<p><span style="font-size: small"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<span style="color: #ff0000">Runtime.getRuntime().addShutdownHook(shutdownHook);</span></font></span></p>
<p><span style="font-size: small"><span style="color: #ff0000"><font size="2">&nbsp;&nbsp; 这个方法的含义说明：</font></span></span></p>
<p><span style="font-size: small"><span style="color: #ff0000"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #000000"> 这个方法的意思就是在jvm中增加一个关闭的钩子，当jvm关闭的时候，会执行系统中已经设置的所有通过方法addShutdownHook添加的钩子，当系统执行完这些钩子后，jvm才会关闭。所以这些钩子可以在jvm关闭的时候进行内存清理、对象销毁等操作。</span></font></span></span></p>
<p>&nbsp;</p>
<p><span style="color: #ff0000"><span style="font-size: small"><span style="color: #000000"><font size="2">一、编写个测试类</font></span></span></span></p>
<p><span style="color: #ff0000"><span style="font-size: small"><span style="color: #000000"><font size="2">&nbsp; package com.test.hook;</font></span></span></span></p>
<p><span style="color: #ff0000"><span style="font-size: small"><span style="color: #000000"><font size="2">public class TestShutdownHook {</font></span></span></span></p>
<p><span style="color: #ff0000"><span style="font-size: small"><span style="color: #000000"><font size="2">&nbsp;/**<br />&nbsp; * @param args<br />&nbsp; */<br />&nbsp;public static void main(String[] args) {<br />&nbsp;&nbsp;// 定义线程1<br />&nbsp;&nbsp;Thread thread1 = new Thread() {<br />&nbsp;&nbsp;&nbsp;public void run() {<br />&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("thread1...");<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;};</font></span></span></span></p>
<p><span style="color: #ff0000"><span style="font-size: small"><span style="color: #000000"><font size="2">&nbsp;&nbsp;// 定义线程2<br />&nbsp;&nbsp;Thread thread2 = new Thread() {<br />&nbsp;&nbsp;&nbsp;public void run() {<br />&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("thread2...");<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;};</font></span></span></span></p>
<p><span style="color: #ff0000"><span style="font-size: small"><span style="color: #000000"><font size="2">&nbsp;&nbsp;// 定义关闭线程<br />&nbsp;&nbsp;Thread shutdownThread = new Thread() {<br />&nbsp;&nbsp;&nbsp;public void run() {<br />&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("shutdownThread...");<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;};</font></span></span></span></p>
<p><span style="color: #ff0000"><span style="font-size: small"><span style="color: #000000"><font size="2">&nbsp;&nbsp;// jvm关闭的时候先执行该线程钩子<br />&nbsp;&nbsp;Runtime.getRuntime().addShutdownHook(shutdownThread);</font></span></span></span></p>
<p><span style="color: #ff0000"><span style="font-size: small"><span style="color: #000000"><font size="2">&nbsp;&nbsp;thread1.start();<br />&nbsp;&nbsp;thread2.start();<br />&nbsp;}<br />}</font></span></span></span></p>
<p><span style="color: #ff0000"><span style="font-size: small"><font size="2"></font></span></span></p>
<p><span style="color: #ff0000"><span style="font-size: small"><span style="color: #ff0000"><font size="2">打印结果：</font></span></span></span></p>
<p><span style="color: #ff0000"><span style="font-size: small"><span style="color: #000000"><font size="2">thread2...<br />thread1...<br />shutdownThread...</font></span></span></span></p>
<p><span style="color: #ff0000"><font size="2"></font></span></p>
<p><span style="color: #ff0000"><span style="font-size: small"><span style="color: #000000"><font size="2">或者：</font></span></span></span></p>
<p><span style="color: #ff0000"><span style="font-size: small"><span style="color: #000000"><font size="2">thread2...<br />thread1...<br />shutdownThread...</font></span></span></span></p>
<p><span style="color: #ff0000"><font size="2"></font></span></p>
<p><span style="color: #ff0000"><span style="font-size: small"><span style="color: #000000"><span style="color: #ff0000"><font size="2">结论：</font></span></span></span></span></p>
<p>&nbsp;</p>
<p>无论是先打印thread1还是thread2，shutdownThread 线程都是最后执行的（因为这个线程是在jvm执行关闭前才会执行）。</p><br />转载自:http://blog.csdn.net/wgw335363240/article/details/5854402<img src ="http://www.blogjava.net/freeman1984/aggbug/353659.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-07-04 17:36 <a href="http://www.blogjava.net/freeman1984/archive/2011/07/04/353659.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CountDownLatch 简介和例子</title><link>http://www.blogjava.net/freeman1984/archive/2011/07/04/353654.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 04 Jul 2011 09:14:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/07/04/353654.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/353654.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/07/04/353654.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/353654.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/353654.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 在一些应用场合中，某段程序需要等待某个条件达到要求后才能执行，或者等待一定长的时间后此行，从jdk1.5开始就可以使用CountDownLatch实现，&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp; CountDownLatch类是一个同步倒数计数器,构造时传入int参数,该参数就是计数器的初始值，每调用一次countDown()方法，计数器减1,计数器大于0 时，await()方法会阻塞后面程序执行，直到计数器为0，await(long timeout, TimeUnit unit)，是等待一定时间，然后执行，不管计数器是否到0了。<br />下面举一个等车的例子：<br />10个同学上车，车等待同学上车，如果有等待时间限制，到时间就开走，不管学生上没上完。如果没有等待时间，学生上完了再开：
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img id="Codehighlighter1_32_823_Open_Image" onclick="this.style.display='none'; Codehighlighter1_32_823_Open_Text.style.display='none'; Codehighlighter1_32_823_Closed_Image.style.display='inline'; Codehighlighter1_32_823_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_32_823_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_32_823_Closed_Text.style.display='none'; Codehighlighter1_32_823_Open_Image.style.display='inline'; Codehighlighter1_32_823_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif"><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;CountDownLatchTest&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_32_823_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_32_823_Open_Text"><span style="color: #000000">{<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;numberOfPeople&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">10</span><span style="color: #000000">;</span><span style="color: #008000">//</span><span style="color: #008000">等车的学生数</span><span style="color: #008000"><br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">boolean</span><span style="color: #000000">&nbsp;isGone&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">false</span><span style="color: #000000">;</span><span style="color: #008000">//</span><span style="color: #008000">车开的标志</span><span style="color: #008000"><br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;carWaitTime&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">3</span><span style="color: #000000">;</span><span style="color: #008000">//</span><span style="color: #008000">车等的时间</span><span style="color: #008000"><br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<br /><img id="Codehighlighter1_241_453_Open_Image" onclick="this.style.display='none'; Codehighlighter1_241_453_Open_Text.style.display='none'; Codehighlighter1_241_453_Closed_Image.style.display='inline'; Codehighlighter1_241_453_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_241_453_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_241_453_Closed_Text.style.display='none'; Codehighlighter1_241_453_Open_Image.style.display='inline'; Codehighlighter1_241_453_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;main(String[]&nbsp;args)&nbsp;</span><span style="color: #0000ff">throws</span><span style="color: #000000">&nbsp;InterruptedException&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_241_453_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_241_453_Open_Text"><span style="color: #000000">{<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CountDownLatch&nbsp;waitStudentsGetOn&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;CountDownLatch(numberOfPeople);<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Thread(</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;GetOn(waitStudentsGetOn)).start();<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;waitStudentGetOn(waitStudentsGetOn);</span><span style="color: #008000">//</span><span style="color: #008000">等所有的学生上车</span><span style="color: #008000"><br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;driveHome();</span><span style="color: #008000">//</span><span style="color: #008000">开车走</span><span style="color: #008000"><br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;<br /><img id="Codehighlighter1_557_675_Open_Image" onclick="this.style.display='none'; Codehighlighter1_557_675_Open_Text.style.display='none'; Codehighlighter1_557_675_Closed_Image.style.display='inline'; Codehighlighter1_557_675_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_557_675_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_557_675_Closed_Text.style.display='none'; Codehighlighter1_557_675_Open_Image.style.display='inline'; Codehighlighter1_557_675_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;waitStudentGetOn(CountDownLatch&nbsp;waitStudentsGetOn)&nbsp;</span><span style="color: #0000ff">throws</span><span style="color: #000000">&nbsp;InterruptedException&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_557_675_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_557_675_Open_Text"><span style="color: #000000">{<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">赶紧的,抓紧时间上车..</span><span style="color: #000000">"</span><span style="color: #000000">);<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;waitStudentsGetOn.await(carWaitTime,&nbsp;TimeUnit.SECONDS);</span><span style="color: #008000">//</span><span style="color: #008000">等5秒，还没上车，就开走。。</span><span style="color: #008000"><br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" /><br /><img id="Codehighlighter1_739_819_Open_Image" onclick="this.style.display='none'; Codehighlighter1_739_819_Open_Text.style.display='none'; Codehighlighter1_739_819_Closed_Image.style.display='inline'; Codehighlighter1_739_819_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_739_819_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_739_819_Closed_Text.style.display='none'; Codehighlighter1_739_819_Open_Image.style.display='inline'; Codehighlighter1_739_819_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;driveHome()&nbsp;</span><span style="color: #0000ff">throws</span><span style="color: #000000">&nbsp;InterruptedException&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_739_819_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_739_819_Open_Text"><span style="color: #000000">{<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">开车，鞋儿破&nbsp;帽儿破&nbsp;身上的袈裟破&nbsp;你笑我&nbsp;他笑我&nbsp;一把扇儿破</span><span style="color: #000000">"</span><span style="color: #000000">);<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isGone&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">true</span><span style="color: #000000">;<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif"  alt="" />}</span></span><span style="color: #000000"><br /><img id="Codehighlighter1_856_1934_Open_Image" onclick="this.style.display='none'; Codehighlighter1_856_1934_Open_Text.style.display='none'; Codehighlighter1_856_1934_Closed_Image.style.display='inline'; Codehighlighter1_856_1934_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_856_1934_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_856_1934_Closed_Text.style.display='none'; Codehighlighter1_856_1934_Open_Image.style.display='inline'; Codehighlighter1_856_1934_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif"></span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;GetOn&nbsp;</span><span style="color: #0000ff">implements</span><span style="color: #000000">&nbsp;Runnable</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_856_1934_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_856_1934_Open_Text"><span style="color: #000000">{<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;CountDownLatch&nbsp;waitStudentsGetOn;<br /><img id="Codehighlighter1_943_992_Open_Image" onclick="this.style.display='none'; Codehighlighter1_943_992_Open_Text.style.display='none'; Codehighlighter1_943_992_Closed_Image.style.display='inline'; Codehighlighter1_943_992_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_943_992_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_943_992_Closed_Text.style.display='none'; Codehighlighter1_943_992_Open_Image.style.display='inline'; Codehighlighter1_943_992_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;GetOn(CountDownLatch&nbsp;waitStudentsGetOn)</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_943_992_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_943_992_Open_Text"><span style="color: #000000">{<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">this</span><span style="color: #000000">.waitStudentsGetOn&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;waitStudentsGetOn;<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img id="Codehighlighter1_1013_1548_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1013_1548_Open_Text.style.display='none'; Codehighlighter1_1013_1548_Closed_Image.style.display='inline'; Codehighlighter1_1013_1548_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_1013_1548_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_1013_1548_Closed_Text.style.display='none'; Codehighlighter1_1013_1548_Open_Image.style.display='inline'; Codehighlighter1_1013_1548_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;run()&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_1013_1548_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_1013_1548_Open_Text"><span style="color: #000000">{<br /><img id="Codehighlighter1_1077_1539_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1077_1539_Open_Text.style.display='none'; Codehighlighter1_1077_1539_Closed_Image.style.display='inline'; Codehighlighter1_1077_1539_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_1077_1539_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_1077_1539_Closed_Text.style.display='none'; Codehighlighter1_1077_1539_Open_Image.style.display='inline'; Codehighlighter1_1077_1539_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;&nbsp;i&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">&nbsp;CountDownLatchTest.numberOfPeople;&nbsp;i</span><span style="color: #000000">++</span><span style="color: #000000">)&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_1077_1539_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_1077_1539_Open_Text"><span style="color: #000000">{<br /><img id="Codehighlighter1_1086_1332_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1086_1332_Open_Text.style.display='none'; Codehighlighter1_1086_1332_Closed_Image.style.display='inline'; Codehighlighter1_1086_1332_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_1086_1332_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_1086_1332_Closed_Text.style.display='none'; Codehighlighter1_1086_1332_Open_Image.style.display='inline'; Codehighlighter1_1086_1332_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">try</span><span style="color: #000000">&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_1086_1332_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_1086_1332_Open_Text"><span style="color: #000000">{<br /><img id="Codehighlighter1_1121_1219_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1121_1219_Open_Text.style.display='none'; Codehighlighter1_1121_1219_Closed_Image.style.display='inline'; Codehighlighter1_1121_1219_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_1121_1219_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_1121_1219_Closed_Text.style.display='none'; Codehighlighter1_1121_1219_Open_Image.style.display='inline'; Codehighlighter1_1121_1219_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">(CountDownLatchTest.isGone)</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_1121_1219_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_1121_1219_Open_Text"><span style="color: #000000">{<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">妈的，还差：</span><span style="color: #000000">"</span><span style="color: #000000">+</span><span style="color: #000000">waitStudentsGetOn.getCount()</span><span style="color: #000000">+</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;个没娃上车呢.怎么车走了</span><span style="color: #000000">"</span><span style="color: #000000">);<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">break</span><span style="color: #000000">;<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">boolean</span><span style="color: #000000">&nbsp;goonSuccess&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Student(i</span><span style="color: #000000">+</span><span style="color: #000000">1</span><span style="color: #000000">).getOn();</span><span style="color: #008000">//</span><span style="color: #008000">顺序上车</span><span style="color: #008000"><br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">(goonSuccess)waitStudentsGetOn.countDown();<br /><img id="Codehighlighter1_1365_1366_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1365_1366_Open_Text.style.display='none'; Codehighlighter1_1365_1366_Closed_Image.style.display='inline'; Codehighlighter1_1365_1366_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_1365_1366_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_1365_1366_Closed_Text.style.display='none'; Codehighlighter1_1365_1366_Open_Image.style.display='inline'; Codehighlighter1_1365_1366_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">catch</span><span style="color: #000000">&nbsp;(InterruptedException&nbsp;e)&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_1365_1366_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_1365_1366_Open_Text"><span style="color: #000000">{}</span></span><span style="color: #000000"><br /><img id="Codehighlighter1_1408_1488_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1408_1488_Open_Text.style.display='none'; Codehighlighter1_1408_1488_Closed_Image.style.display='inline'; Codehighlighter1_1408_1488_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_1408_1488_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_1408_1488_Closed_Text.style.display='none'; Codehighlighter1_1408_1488_Open_Image.style.display='inline'; Codehighlighter1_1408_1488_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">(waitStudentsGetOn.getCount()</span><span style="color: #000000">!=</span><span style="color: #000000">0l</span><span style="color: #000000">)</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_1408_1488_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_1408_1488_Open_Text"><span style="color: #000000">{<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">还差：</span><span style="color: #000000">"</span><span style="color: #000000">+</span><span style="color: #000000">(waitStudentsGetOn.getCount())</span><span style="color: #000000">+</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;个没上车<img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span style="color: #000000">"</span><span style="color: #000000">);<br /><img id="Codehighlighter1_1493_1535_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1493_1535_Open_Text.style.display='none'; Codehighlighter1_1493_1535_Closed_Image.style.display='inline'; Codehighlighter1_1493_1535_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_1493_1535_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_1493_1535_Closed_Text.style.display='none'; Codehighlighter1_1493_1535_Open_Image.style.display='inline'; Codehighlighter1_1493_1535_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #0000ff">else</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_1493_1535_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_1493_1535_Open_Text"><span style="color: #000000">{<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">都上车了<img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span style="color: #000000">"</span><span style="color: #000000">);<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img id="Codehighlighter1_1564_1932_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1564_1932_Open_Text.style.display='none'; Codehighlighter1_1564_1932_Closed_Image.style.display='inline'; Codehighlighter1_1564_1932_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_1564_1932_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_1564_1932_Closed_Text.style.display='none'; Codehighlighter1_1564_1932_Open_Image.style.display='inline'; Codehighlighter1_1564_1932_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Student</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_1564_1932_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_1564_1932_Open_Text"><span style="color: #000000">{<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;myNum;</span><span style="color: #008000">//</span><span style="color: #008000">学生编号</span><span style="color: #008000"><br /><img id="Codehighlighter1_1619_1650_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1619_1650_Open_Text.style.display='none'; Codehighlighter1_1619_1650_Closed_Image.style.display='inline'; Codehighlighter1_1619_1650_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_1619_1650_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_1619_1650_Closed_Text.style.display='none'; Codehighlighter1_1619_1650_Open_Image.style.display='inline'; Codehighlighter1_1619_1650_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif"></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;Student(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;num)</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_1619_1650_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_1619_1650_Open_Text"><span style="color: #000000">{<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">this</span><span style="color: #000000">.myNum&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;num;<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">上车</span><span style="color: #008000"><br /><img id="Codehighlighter1_1713_1929_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1713_1929_Open_Text.style.display='none'; Codehighlighter1_1713_1929_Closed_Image.style.display='inline'; Codehighlighter1_1713_1929_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_1713_1929_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_1713_1929_Closed_Text.style.display='none'; Codehighlighter1_1713_1929_Open_Image.style.display='inline'; Codehighlighter1_1713_1929_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif"></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">boolean</span><span style="color: #000000">&nbsp;getOn()&nbsp;</span><span style="color: #0000ff">throws</span><span style="color: #000000">&nbsp;InterruptedException</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_1713_1929_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_1713_1929_Open_Text"><span style="color: #000000">{<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.currentThread().sleep(</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Random().nextInt(</span><span style="color: #000000">2</span><span style="color: #000000">)</span><span style="color: #000000">*</span><span style="color: #000000">1000</span><span style="color: #000000">);</span><span style="color: #008000">//</span><span style="color: #008000">上车使用的时间，随机</span><span style="color: #008000"><br /><img id="Codehighlighter1_1824_1860_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1824_1860_Open_Text.style.display='none'; Codehighlighter1_1824_1860_Closed_Image.style.display='inline'; Codehighlighter1_1824_1860_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_1824_1860_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_1824_1860_Closed_Text.style.display='none'; Codehighlighter1_1824_1860_Open_Image.style.display='inline'; Codehighlighter1_1824_1860_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif"></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">(CountDownLatchTest.isGone)</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_1824_1860_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_1824_1860_Open_Text"><span style="color: #000000">{<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">false</span><span style="color: #000000">;</span><span style="color: #008000">//</span><span style="color: #008000">不能上了，上车失败</span><span style="color: #008000"><br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.print(</span><span style="color: #000000">"</span><span style="color: #000000">编号为:</span><span style="color: #000000">"</span><span style="color: #000000">+</span><span style="color: #000000">myNum</span><span style="color: #000000">+</span><span style="color: #000000">"</span><span style="color: #000000">的同学上车了..</span><span style="color: #000000">"</span><span style="color: #000000">);<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">true</span><span style="color: #000000">;<br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif"  alt="" />}</span></span></div><br /> <img src ="http://www.blogjava.net/freeman1984/aggbug/353654.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-07-04 17:14 <a href="http://www.blogjava.net/freeman1984/archive/2011/07/04/353654.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>tomcat https</title><link>http://www.blogjava.net/freeman1984/archive/2011/06/25/353006.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Sat, 25 Jun 2011 15:06:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/06/25/353006.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/353006.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/06/25/353006.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/353006.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/353006.html</trackback:ping><description><![CDATA[<p>HTTPS（全称：Hypertext Transfer Protocol over Secure Socket Layer），是以安全为目标的HTTP通道，简单讲是HTTP的安全版。即HTTP下加入SSL层，HTTPS的安全基础是SSL，因此加密</p>
<p>的详细内容就需要SSL<br />　　SSL协议的握手过程<br />SSL 协议既用到了公钥加密技术又用到了对称加密技术，对称加密技术虽然比公钥加密技术的速度快，可是公钥加密技术提供了更好的身份认证技术。SSL 的握手协议非常有效的让客户和服</p>
<p>务器之间完成相互之间的身份认证，其主要过程如下： 　　<br />&#9312;客户端的浏览器向服务器传送客户端 SSL 协议的版本号，加密算法的种类，产生的随机数，以及其他服务器和客户端之间通讯所需要的各种信息。 　　<br />&#9313;服务器向客户端传送 SSL 协议的版本号，加密算法的种类，随机数以及其他相关信息，同时服务器还将向客户端传送自己的证书。 　　<br />&#9314;客户利用服务器传过来的信息验证服务器的合法性，服务器的合法性包括：证书是否过期，发行服务器证书的 CA 是否可靠，发行者证书的公钥能否正确解开服务器证书的&#8220;发行者的数字</p>
<p>签名&#8221;，服务器证书上的域名是否和服务器的实际域名相匹配。如果合法性验证没有通过，通讯将断开；如果合法性验证通过，将继续进行第四步。 　　<br />&#9315;用户端随机产生一个用于后面通讯的&#8220;对称密码&#8221;，然后用服务器的公钥（服务器的公钥从步骤&#9313;中的服务器的证书中获得）对其加密，然后将加密后的&#8220;预主密码&#8221;传给服务器。 　　<br />&#9316;如果服务器要求客户的身份认证（在握手过程中为可选），用户可以建立一个随机数然后对其进行数据签名，将这个含有签名的随机数和客户自己的证书以及加密过的&#8220;预主密码&#8221;一起传</p>
<p>给服务器。 　　<br />&#9317;如果服务器要求客户的身份认证，服务器必须检验客户证书和签名随机数的合法性，具体的合法性验证过程包括：客户的证书使用日期是否有效，为客户提供证书的CA 是否可靠，发行CA </p>
<p>的公钥能否正确解开客户证书的发行 CA 的数字签名，检查客户的证书是否在证书废止列表（CRL）中。检验如果没有通过，通讯立刻中断；如果验证通过，服务器将用自己的私钥解开加密的</p>
<p>&#8220;预主密码&#8221;，然后执行一系列步骤来产生主通讯密码（客户端也将通过同样的方法产生相同的主通讯密码）。 　　<br />&#9318;服务器和客户端用相同的主密码即&#8220;通话密码&#8221;，一个对称密钥用于 SSL 协议的安全数据通讯的加解密通讯。同时在 SSL 通讯过程中还要完成数据通讯的完整性，防止数据通讯中的任何</p>
<p>变化。 　　<br />&#9319;客户端向服务器端发出信息，指明后面的数据通讯将使用的步骤&#9318;中的主密码为对称密钥，同时通知服务器客户端的握手过程结束。 　　<br />&#9320;服务器向客户端发出信息，指明后面的数据通讯将使用的步骤&#9318;中的主密码为对称密钥，同时通知客户端服务器端的握手过程结束。 　　<br />&#9321;SSL 的握手部分结束，SSL 安全通道的数据通讯开始，客户和服务器开始使用相同的对称密钥进行数据通讯，同时进行通讯完整性的检验。</p>
<p>&nbsp;</p>
<p><br />下面是在tomcat下实现https，使用jdk自带的keytool工具生成自签名证书。</p>
<p>1 生成keystore文件，keystore文件用来存储密钥和证书<br />&nbsp;&nbsp; keystore的详细参数可使用 可使用keystore命令查看。<br />&nbsp;&nbsp; <br />keytool -genkeypair -keyalg rsa -keysize 2048 -sigalg sha1withrsa -validity 3600 -alias <a href="http://www.joe.com">www.joe.com</a> -keystore e:\ssl\joe.keystore<br />输入keystore密码：<br />再次输入新密码:<br />您的名字与姓氏是什么？<br />&nbsp; [Unknown]：&nbsp; <a href="http://www.joe.com">www.joe.com</a><br />您的组织单位名称是什么？<br />&nbsp; [Unknown]：&nbsp; joe<br />您的组织名称是什么？<br />&nbsp; [Unknown]：&nbsp; joe<br />您所在的城市或区域名称是什么？<br />&nbsp; [Unknown]：&nbsp; bj<br />您所在的州或省份名称是什么？<br />&nbsp; [Unknown]：&nbsp; bj<br />该单位的两字母国家代码是什么<br />&nbsp; [Unknown]：&nbsp; cn<br />CN=www.joe.com, OU=joe, O=joe, L=bj, ST=bj, C=cn 正确吗？<br />&nbsp; [否]：&nbsp; y</p>
<p>输入&lt;<a href="http://www.joe.com">www.joe.com</a>&gt;的主密码<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （如果和 keystore 密码相同，按回车）：<br />2 导出自签名证书。正是平台需要导出csr文件并去权威的ca认证机构获取受信任证书，一般是收费的。<br />&nbsp;&nbsp; keytool -exportcert -alias <a href="http://www.joe.com">www.joe.com</a> -keystore e:\ssl\joe.keystore -file e:\ssl\joe.cer -rfc<br />输入keystore密码：<br />保存在文件中的认证 &lt;e:\ssl\joe.cer&gt;<br />下面配置tomcat(server.xml)使其支持https.<br />&lt;Connector port="443" protocol="HTTP/1.1" SSLEnabled="true"<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; maxThreads="150" scheme="https" secure="true"<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clientAuth="false" sslProtocol="TLS"&nbsp; keystoreFile="conf/joe.keystore" keystorePass="123456"/&gt;<br />&nbsp;&nbsp;&nbsp; </p>
<p>3 修改操作系统host文件，添加127.0.0.1 <a href="http://www.joe.com">www.joe.com</a></p>
<p>4 新建web应用httpstest<br />并添加indexjsp:<br />&nbsp;&lt;body&gt;<br />&nbsp;&nbsp;&nbsp; &lt;%<br />&nbsp;&nbsp;&nbsp;&nbsp; for(Enumeration en = request.getAttributeNames();en.hasMoreElements();){<br />&nbsp;&nbsp;&nbsp; &nbsp;String name = (String)en.nextElement();<br />&nbsp;&nbsp;&nbsp; &nbsp;out.println(name);<br />&nbsp;&nbsp;&nbsp; &nbsp;out.println("="+request.getAttribute(name));<br />&nbsp;&nbsp;&nbsp; &nbsp;out.println();<br />&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; %&gt;<br />&nbsp; &lt;/body&gt;</p>
<p>5 为了让浏览器信任我们的证书，需要在浏览器导入我们的证书为信任根证书。<br />6 访问：<a href="https://www.joe.com/httpstest">https://www.joe.com/httpstest</a><br />输出：<br />javax.servlet.request.ssl_session =4e05eb849ac41a45b56725488b68c28cc8c2ea94e2ec599852e1665297b2822b <br />javax.servlet.request.key_size =128 <br />javax.servlet.request.cipher_suite =SSL_RSA_WITH_RC4_128_MD5 (通讯的加密信息，由浏览器和服务器协商确定)。</p>
<p>&nbsp;</p><img src ="http://www.blogjava.net/freeman1984/aggbug/353006.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-06-25 23:06 <a href="http://www.blogjava.net/freeman1984/archive/2011/06/25/353006.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>网络编码</title><link>http://www.blogjava.net/freeman1984/archive/2011/06/24/352939.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 24 Jun 2011 03:22:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/06/24/352939.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/352939.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/06/24/352939.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/352939.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/352939.html</trackback:ping><description><![CDATA[<strong>网络编码（Network Coding</strong>）: 
<div class="spctrl"></div>　　传统的通信网络传送数据的方式是存储转发，即除了数据的发送节点和接收节点以外的节点只负责路由，而不对数据内容做任何处理，中间节点扮演着转发器的角色。长期以来，人们普遍认为在中间节点上对传输的数据进行加工不会有任何收益，然而R Ahlswede等人[1]于2000年提出的网络编码理论彻底推翻了这种传统观点。 
<div class="spctrl"></div>　　网络编码是一种融合了路由和编码的信息交换技术，它的核心思想是在网络中的各个节点上对各条信道上收到的信息进行线性或者非线性的处理，然后转发给下游节点，中间节点扮演着编码器或信号处理器的角色。根据图论中的最大流-最小割定理[2]，数据的发送方和接收方通信的最大速率不能超过双方之间的最大流值(或最小割值)，如果采用传统多播路由的方法，一般不能达到该上界。R Ahlswede等人以蝴蝶网络的研究为例，指出通过网络编码，可以达到多播路由传输的最大流界，提高了信息的传输效率，从而奠定了网络编码在现代网络通信研究领域的重要地位。 
<div class="spctrl"></div>　　网络编码技术自七年前诞生以来，可以说基本上藏身于各大学和实验室中而鲜为人知。这是一种编码算法，支持者们声称它可以将现有的网络吞吐量提高一倍，同时还能改善网络的可靠性和防范攻击的能力。网络编码技术最热心的支持者们说，该技术将会引发网络的下一代革命；其他人则认为，网络编码技术更有可能会潜移默化地改变目前基于路由的网络架构。 
<div class="bpctrl"></div>
<h2 class="headline-1 bk-sidecatalog-title"><span class="headline-content">工作原理</span></h2>　　网络编码的工作原理是把不同的信息转化成位数更小的&#8220;痕迹&#8221;，然后在目标节点进行演绎还原，这样就不必反复传输或者复制全部信息了。痕迹可以在多个中间节点间的多条路径上反复传递，然后再被送往最终的目的端点。它不需要额外的容量和路由&#8212;只需把信息的痕迹转换成位流即可，而这种转换现有的网络基础设施是可以支持的。 
<div class="bpctrl"></div>
<h2 class="headline-1 bk-sidecatalog-title"><span class="headline-content">安全问题</span></h2>　　研究人员承认，窃听方式与xor位流概念的混合可能会引发对安全性的担忧。 
<div class="spctrl"></div>　　但是麻省理工学院的Medard却认为，网络编码在执行过程中伪装了数据，并且能有效地承载数据，所以实际上增强了信息的安全性，要比在网络上传输不可破译的算法流的传统加密技术更安全。 
<div class="spctrl"></div>　　&#8220;在你做这种数据包的混合时，其本身就具备了数据隐藏的性能。&#8221;Medard说。&#8220;比如有两个位组A和B，对两个位组执行xor操作，从得出的结果中哪个位组的数据你都看不到。你可能知道其中的某些位的值，但你却不可能还原出A位组的数据，除非你完全知道B位组的数据。&#8221; 
<div class="spctrl"></div>　　她说，网络编码技术还能在P2P传输中检测恶意&#8220;污染&#8221;攻击，并纠正错误。 
<div class="spctrl"></div>　　当然，还需要做大量的工作，以便确定网络编码对于安全的影响。至于网络编码能否在互联网这种共享基础设施中最终取代路由器，也同样还需要解决很多问题才行。比如说，客户必须知道，当信息在共享网络中不能够进行混合的时候该如何实施网络编码；他们还需要注意网络编码在有线和无线基础设施中的细微差别；而业界必须能够找出某种办法，当运营商把不同客户的不同流量相互混合时，客户到底应该如何付费。 
<div class="spctrl"></div>　　Medard说，她和其他研究人员一起正在考虑解决这些问题的办法，继续探索改进网络的各种途径，以便让网络成为人类社会不可或缺的组成部分。 
<div class="bpctrl"></div>
<h2 class="headline-1 bk-sidecatalog-title"><span class="headline-content">实际应用</span></h2>　　网络编码（Network Number），就是在路由器配置中所说的&#8220;网域&#8221;、"网段"的概念。 
<div class="spctrl"></div>　　网络编码是融合了路由和编码的信息交换技术。在搭建网络的过程中，路由器正是实现网络编码的设备。即有路由器的地方就需要网络编码。 
<div class="spctrl"></div>　　网络编码（Network Number )=IP地址（IP Address）and 子网掩码（Subnet Mask）。通过划分子网，即设置子网掩码，获得不同的网络编码，分配给计算机和路由器。 
<div class="spctrl"></div>　　网络编码通常是使用在跨地域的网络互联之中。两者之间使用路由器连线，同时也上Internet。如果只申请到一组C 类IP地址，过路由器又需不同的网络,所以此时就必须使用到网络编码。<img src ="http://www.blogjava.net/freeman1984/aggbug/352939.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-06-24 11:22 <a href="http://www.blogjava.net/freeman1984/archive/2011/06/24/352939.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java对象序列化与RMI(转)</title><link>http://www.blogjava.net/freeman1984/archive/2011/06/24/352925.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 24 Jun 2011 02:15:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/06/24/352925.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/352925.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/06/24/352925.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/352925.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/352925.html</trackback:ping><description><![CDATA[<p>对于一个存在于Java虚拟机中的对象来说，其内部的状态只保持在内存中。JVM停止之后，这些状态就丢失了。在很多情况下，对象的内部状态是需要被持久化下来的。提到持久化，最直接的做法是保存到文件系统或是数据库之中。这种做法一般涉及到自定义存储格式以及繁琐的数据转换。<a href="http://en.wikipedia.org/wiki/Object-relational_mapping"><font color="#0b59b2">对象关系映射</font></a>（Object-relational mapping）是一种典型的用关系数据库来持久化对象的方式，也存在很多直接存储对象的<a href="http://en.wikipedia.org/wiki/Object_database"><font color="#0b59b2">对象数据库</font></a>。对象序列化机制（object serialization）是Java语言内建的一种对象持久化方式，可以很容易的在JVM中的活动对象和字节数组（流）之间进行转换。除了可以很简单的实现持久化之外，序列化机制的另外一个重要用途是在远程方法调用中，用来对开发人员屏蔽底层实现细节。</p>
<div class="vendor-content-box-float">基本的对象序列化</div>
<p>由于Java提供了良好的默认支持，实现基本的对象序列化是件比较简单的事。待序列化的Java类只需要实现<a href="http://download.oracle.com/javase/6/docs/api/java/io/Serializable.html"><font color="#0b59b2">Serializable</font></a>接口即可。Serializable仅是一个标记接口，并不包含任何需要实现的具体方法。实现该接口只是为了声明该Java类的对象是可以被序列化的。实际的序列化和反序列化工作是通过<a href="http://download.oracle.com/javase/6/docs/api/java/io/ObjectOutputStream.html"><font color="#0b59b2">ObjectOuputStream</font></a>和<a href="http://download.oracle.com/javase/6/docs/api/java/io/ObjectInputStream.html"><font color="#0b59b2">ObjectInputStream</font></a>来完成的。ObjectOutputStream的<a href="http://download.oracle.com/javase/6/docs/api/java/io/ObjectOutputStream.html#writeObject%28java.lang.Object%29"><font color="#0b59b2">writeObject</font></a>方法可以把一个Java对象写入到流中，ObjectInputStream的<a href="http://download.oracle.com/javase/6/docs/api/java/io/ObjectInputStream.html#readObject%28%29"><font color="#0b59b2">readObject</font></a>方法可以从流中读取一个Java对象。在写入和读取的时候，虽然用的参数或返回值是单个对象，但实际上操纵的是一个对象图，包括该对象所引用的其它对象，以及这些对象所引用的另外的对象。Java会自动帮你遍历对象图并逐个序列化。除了对象之外，Java中的基本类型和数组也是可以通过 ObjectOutputStream和ObjectInputStream来序列化的。</p><pre>try {
    User user = new User("Alex", "Cheng");
    ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("user.bin"));
    output.writeObject(user);
    output.close();
} catch (IOException e) {
    e.printStackTrace();
}
 
try {
    ObjectInputStream input = new ObjectInputStream(new FileInputStream("user.bin"));
    User user = (User) input.readObject();
    System.out.println(user);
} catch (Exception e) {
    e.printStackTrace();
} 
 </pre>
<p>上面的代码给出了典型的把Java对象序列化之后保存到磁盘上，以及从磁盘上读取的基本方式。 User类只是声明了实现Serializable接口。</p>
<p>在默认的序列化实现中，Java对象中的非静态和非瞬时域都会被包括进来，而与域的可见性声明没有关系。这可能会导致某些不应该出现的域被包含在序列化之后的字节数组中，比如密码等隐私信息。由于Java对象序列化之后的格式是固定的，其它人可以很容易的从中分析出其中的各种信息。对于这种情况，一种解决办法是把域声明为瞬时的，即使用<a href="http://en.wikibooks.org/wiki/Java_Programming/Keywords/transient"><font color="#0b59b2">transient</font></a>关键词。另外一种做法是添加一个serialPersistentFields? 域来声明序列化时要包含的域。从这里可以看到在Java序列化机制中的这种仅在书面层次上定义的契约。声明序列化的域必须使用固定的名称和类型。在后面还可以看到其它类似这样的契约。虽然Serializable只是一个标记接口，但它其实是包含有不少隐含的要求。下面的代码给出了 serialPersistentFields的声明示例，即只有firstName这个域是要被序列化的。</p><pre>private static final ObjectStreamField[] serialPersistentFields = { 
    new ObjectStreamField("firstName", String.class) 
};&nbsp; </pre>
<h2>自定义对象序列化</h2>
<p>基本的对象序列化机制让开发人员可以在包含哪些域上进行定制。如果想对序列化的过程进行更加细粒度的控制，就需要在类中添加writeObject和对应的 readObject方法。这两个方法属于前面提到的序列化机制的隐含契约的一部分。在通过ObjectOutputStream的 writeObject方法写入对象的时候，如果这个对象的类中定义了writeObject方法，就会调用该方法，并把当前 ObjectOutputStream对象作为参数传递进去。writeObject方法中一般会包含自定义的序列化逻辑，比如在写入之前修改域的值，或是写入额外的数据等。对于writeObject中添加的逻辑，在对应的readObject中都需要反转过来，与之对应。</p>
<p>在添加自己的逻辑之前，推荐的做法是先调用Java的默认实现。在writeObject方法中通过ObjectOutputStream的<a href="http://download.oracle.com/javase/6/docs/api/java/io/ObjectOutputStream.html#defaultWriteObject%28%29"><font color="#0b59b2">defaultWriteObject</font></a>来完成，在readObject方法则通过ObjectInputStream的<a href="http://download.oracle.com/javase/6/docs/api/java/io/ObjectInputStream.html#defaultReadObject%28%29"><font color="#0b59b2">defaultReadObject</font></a>来实现。下面的代码在对象的序列化流中写入了一个额外的字符串。</p><pre>private void writeObject(ObjectOutputStream output) throws IOException {
    output.defaultWriteObject();
    output.writeUTF("Hello World");
}
private void readObject(ObjectInputStream input) throws IOException, ClassNotFoundException {
    input.defaultReadObject();
    String value = input.readUTF();
    System.out.println(value);
}  
</pre>
<h2>序列化时的对象替换</h2>
<p>在有些情况下，可能会希望在序列化的时候使用另外一个对象来代替当前对象。其中的动机可能是当前对象中包含了一些不希望被序列化的域，比如这些域都是从另外一个域派生而来的；也可能是希望隐藏实际的类层次结构；还有可能是添加自定义的对象管理逻辑，如保证某个类在JVM中只有一个实例。相对于把无关的域都设成transient来说，使用对象替换是一个更好的选择，提供了更多的灵活性。替换对象的作用类似于Java EE中会使用到的<a href="http://java.sun.com/blueprints/patterns/TransferObject.html"><font color="#0b59b2">传输对象</font></a>（Transfer Object）。</p>
<p>考虑下面的例子，一个订单系统中需要把订单的相关信息序列化之后，通过网络来传输。订单类Order引用了客户类Customer。在默认序列化的情况下，Order类对象被序列化的时候，其引用的Customer类对象也会被序列化，这可能会造成用户信息的泄露。对于这种情况，可以创建一个另外的对象来在序列化的时候替换当前的Order类的对象，并把用户信息隐藏起来。</p><pre>private static class OrderReplace implements Serializable {
    private static final long serialVersionUID = 4654546423735192613L;
    private String orderId;
    public OrderReplace(Order order) {
        this.orderId = order.getId();
    }
    private Object readResolve() throws ObjectStreamException {
        //根据orderId查找Order对象并返回
    }
}    </pre>
<p>这个替换对象类OrderReplace只保存了Order的ID。在Order类的writeReplace方法中返回了一个OrderReplace对象。这个对象会被作为替代写入到流中。同样的，需要在OrderReplace类中定义一个readResolve方法，用来在读取的时候再转换回 Order类对象。这样对调用者来说，替换对象的存在就是透明的。</p><pre>private Object writeReplace() throws ObjectStreamException {
    return new OrderReplace(this);
} 
</pre>
<h2>序列化与对象创建</h2>
<p>在通过ObjectInputStream的readObject方法读取到一个对象之后，这个对象是一个新的实例，但是其构造方法是没有被调用的，其中的域的初始化代码也没有被执行。对于那些没有被序列化的域，在新创建出来的对象中的值都是默认的。也就是说，这个对象从某种角度上来说是不完备的。这有可能会造成一些隐含的错误。调用者并不知道对象是通过一般的new操作符来创建的，还是通过反序列化所得到的。解决的办法就是在类的readObject方法里面，再执行所需的对象初始化逻辑。对于一般的Java类来说，构造方法中包含了初始化的逻辑。可以把这些逻辑提取到一个方法中，在readObject方法中调用此方法。</p>
<h2>版本更新</h2>
<p>把一个Java对象序列化之后，所得到的字节数组一般会保存在磁盘或数据库之中。在保存完成之后，有可能原来的Java类有了更新，比如添加了额外的域。这个时候从兼容性的角度出发，要求仍然能够读取旧版本的序列化数据。在读取的过程中，当ObjectInputStream发现一个对象的定义的时候，会尝试在当前JVM中查找其Java类定义。这个查找过程不能仅根据Java类的全名来判断，因为当前JVM中可能存在名称相同，但是含义完全不同的Java 类。这个对应关系是通过一个全局惟一标识符serialVersionUID来实现的。通过在实现了Serializable接口的类中定义该域，就声明了该Java类的一个惟一的序列化版本号。JVM会比对从字节数组中得出的类的版本号，与JVM中查找到的类的版本号是否一致，来决定两个类是否是兼容的。对于开发人员来说，需要记得的就是在实现了Serializable接口的类中定义这样的一个域，并在版本更新过程中保持该值不变。当然，如果不希望维持这种向后兼容性，换一个版本号即可。该域的值一般是综合Java类的各个特性而计算出来的一个哈希值，可以通过Java提供的<a href="http://download.oracle.com/javase/1.4.2/docs/tooldocs/solaris/serialver.html"><font color="#0b59b2">serialver</font></a>命令来生成。在Eclipse中，如果Java类实现了Serializable接口，Eclipse会提示并帮你生成这个serialVersionUID。</p>
<p>在类版本更新的过程中，某些操作会破坏向后兼容性。如果希望维持这种向后兼容性，就需要格外的注意。一般来说，在新的版本中添加东西不会产生什么问题，而去掉一些域则是不行的。</p>
<h2>序列化安全性</h2>
<p>前面提到，Java对象序列化之后的内容格式是<a href="http://download.oracle.com/javase/6/docs/platform/serialization/spec/protocol.html"><font color="#0b59b2">公开的</font></a>。所以可以很容易的从中提取出各种信息。从实现的角度来说，可以从不同的层次来加强序列化的安全性。</p>
<ul><li>对序列化之后的流进行加密。这可以通过<a href="http://download.oracle.com/javase/6/docs/api/javax/crypto/CipherOutputStream.html"><font color="#0b59b2">CipherOutputStream</font></a>来实现。</li><li>实现自己的writeObject和readObject方法，在调用defaultWriteObject之前，先对要序列化的域的值进行加密处理。</li><li>使用一个<a href="http://download.oracle.com/javase/6/docs/api/java/security/SignedObject.html"><font color="#0b59b2">SignedObject</font></a>或<a href="http://download.oracle.com/javase/6/docs/api/javax/crypto/SealedObject.html"><font color="#0b59b2">SealedObject</font></a>来封装当前对象，用SignedObject或SealedObject进行序列化。</li><li>在从流中进行反序列化的时候，可以通过ObjectInputStream的<a href="http://download.oracle.com/javase/6/docs/api/java/io/ObjectInputStream.html#registerValidation%28java.io.ObjectInputValidation,%20int%29"><font color="#0b59b2">registerValidation</font></a>方法添加<a href="http://download.oracle.com/javase/6/docs/api/java/io/ObjectInputValidation.html"><font color="#0b59b2">ObjectInputValidation</font></a>接口的实现，用来验证反序列化之后得到的对象是否合法。</li></ul>
<h2>RMI</h2>
<p>RMI（Remote Method Invocation）是Java中的<a href="http://baike.baidu.com/view/32726.htm"><font color="#0b59b2">远程过程调用</font></a>（Remote Procedure Call，RPC）实现，是一种分布式Java应用的实现方式。它的目的在于对开发人员屏蔽横跨不同JVM和网络连接等细节，使得分布在不同JVM上的对象像是存在于一个统一的JVM中一样，可以很方便的互相通讯。之所以在介绍对象序列化之后来介绍RMI，主要是因为对象序列化机制使得RMI非常简单。调用一个远程服务器上的方法并不是一件困难的事情。开发人员可以基于<a href="http://mina.apache.org/"><font color="#0b59b2">Apache MINA</font></a>或是<a href="http://www.jboss.org/netty"><font color="#0b59b2">Netty</font></a>这样的框架来写自己的网络服务器，亦或是可以采用<a href="http://baike.baidu.com/view/1077487.htm"><font color="#0b59b2">REST架构风格</font></a>来编写HTTP服务。但这些解决方案中，不可回避的一个部分就是数据的编排和解排（marshal/unmarshal）。需要在Java对象和传输格式之间进行互相转换，而且这一部分逻辑是开发人员无法回避的。RMI的优势在于依靠Java序列化机制，对开发人员屏蔽了数据编排和解排的细节，要做的事情非常少。JDK 5之后，RMI通过动态代理机制去掉了早期版本中需要通过工具进行代码生成的繁琐方式，使用起来更加简单。</p>
<p>RMI采用的是典型的客户端-服务器端架构。首先需要定义的是服务器端的远程接口，这一步是设计好服务器端需要提供什么样的服务。对远程接口的要求很简单，只需要继承自RMI中的<a href="http://download.oracle.com/javase/6/docs/api/java/rmi/Remote.html"><font color="#0b59b2">Remote</font></a>接口即可。Remote和Serializable一样，也是标记接口。远程接口中的方法需要抛出<a href="http://download.oracle.com/javase/6/docs/api/java/rmi/RemoteException.html"><font color="#0b59b2">RemoteException</font></a>。定义好远程接口之后，实现该接口即可。如下面的Calculator是一个简单的远程接口。</p><pre>public interface Calculator extends Remote {
    String calculate(String expr) throws RemoteException;
}  </pre>
<p>实现了远程接口的类的实例称为远程对象。创建出远程对象之后，需要把它注册到一个注册表之中。这是为了客户端能够找到该远程对象并调用。</p><pre>public class CalculatorServer implements Calculator {
    public String calculate(String expr) throws RemoteException {
        return expr;
    }
    public void start() throws RemoteException, AlreadyBoundException {
        Calculator stub = (Calculator) UnicastRemoteObject.exportObject(this, 0);
        Registry registry = LocateRegistry.getRegistry();
        registry.rebind("Calculator", stub);
    }
}
</pre>
<p>CalculatorServer是远程对象的Java类。在它的start方法中通过<a href="http://download.oracle.com/javase/6/docs/api/java/rmi/server/UnicastRemoteObject.html"><font color="#0b59b2">UnicastRemoteObject</font></a>的<a href="http://download.oracle.com/javase/6/docs/api/java/rmi/server/UnicastRemoteObject.html#exportObject%28java.rmi.Remote,%20int%29"><font color="#0b59b2">exportObject</font></a>把当前对象暴露出来，使得它可以接收来自客户端的调用请求。再通过<a href="http://download.oracle.com/javase/6/docs/api/java/rmi/registry/Registry.html"><font color="#0b59b2">Registry</font></a>的<a href="http://download.oracle.com/javase/6/docs/api/java/rmi/registry/Registry.html#rebind%28java.lang.String,%20java.rmi.Remote%29"><font color="#0b59b2">rebind</font></a>方法进行注册，使得客户端可以查找到。</p>
<p>客户端的实现就是首先从注册表中查找到远程接口的实现对象，再调用相应的方法即可。实际的调用虽然是在服务器端完成的，但是在客户端看来，这个接口中的方法就好像是在当前JVM中一样。这就是RMI的强大之处。</p><pre>public class CalculatorClient {
    public void calculate(String expr) {
        try {
            Registry registry = LocateRegistry.getRegistry("localhost");
            Calculator calculator = (Calculator) registry.lookup("Calculator");
            String result = calculator.calculate(expr);
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
} 
</pre>
<p>在运行的时候，需要首先通过rmiregistry命令来启动RMI中用到的注册表服务器。</p>
<p>为了通过Java的序列化机制来进行传输，远程接口中的方法的参数和返回值，要么是Java的基本类型，要么是远程对象，要么是实现了 Serializable接口的Java类。当客户端通过RMI注册表找到一个远程接口的时候，所得到的其实是远程接口的一个动态代理对象。当客户端调用其中的方法的时候，方法的参数对象会在序列化之后，传输到服务器端。服务器端接收到之后，进行反序列化得到参数对象。并使用这些参数对象，在服务器端调用实际的方法。调用的返回值Java对象经过序列化之后，再发送回客户端。客户端再经过反序列化之后得到Java对象，返回给调用者。这中间的序列化过程对于使用者来说是透明的，由动态代理对象自动完成。除了序列化之外，RMI还使用了<a href="http://download.oracle.com/javase/6/docs/technotes/guides/rmi/codebase.html"><font color="#0b59b2">动态类加载</font></a>技术。当需要进行反序列化的时候，如果该对象的类定义在当前JVM中没有找到，RMI会尝试从远端下载所需的类文件定义。可以在RMI程序启动的时候，通过JVM参数java.rmi.server.codebase来指定动态下载Java类文件的URL。&nbsp;&nbsp;</p>
<h2>参考资料</h2>
<ul><li><a href="http://download.oracle.com/javase/6/docs/platform/serialization/spec/serialTOC.html"><font color="#0b59b2">Java对象序列化规范</font></a></li><li><a href="http://download.oracle.com/javase/6/docs/platform/rmi/spec/rmiTOC.html"><font color="#0b59b2">RMI规范</font></a></li></ul>
<p><br />转载自：infoq</p><img src ="http://www.blogjava.net/freeman1984/aggbug/352925.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-06-24 10:15 <a href="http://www.blogjava.net/freeman1984/archive/2011/06/24/352925.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>大家都用什么bug管理软件？</title><link>http://www.blogjava.net/freeman1984/archive/2011/06/20/352649.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 20 Jun 2011 03:38:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/06/20/352649.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/352649.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/06/20/352649.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/352649.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/352649.html</trackback:ping><description><![CDATA[&nbsp; 公司以前用的mantis，冒失功能太简单了，二次开发比较困难。现在想和公司的项目管理软件平台（java语言）集成，不知道大家有什么经验分享一下？？，或者介绍几个二次开发容易一点的！<img src ="http://www.blogjava.net/freeman1984/aggbug/352649.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-06-20 11:38 <a href="http://www.blogjava.net/freeman1984/archive/2011/06/20/352649.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>让tomcat运行php的几种方式(linux,aix和windows环境)</title><link>http://www.blogjava.net/freeman1984/archive/2011/06/16/352427.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Thu, 16 Jun 2011 07:04:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/06/16/352427.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/352427.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/06/16/352427.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/352427.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/352427.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: tomcat运行php的几种方式&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2011/06/16/352427.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/352427.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-06-16 15:04 <a href="http://www.blogjava.net/freeman1984/archive/2011/06/16/352427.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TCP/IP协议</title><link>http://www.blogjava.net/freeman1984/archive/2011/05/26/351043.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Thu, 26 May 2011 01:59:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/05/26/351043.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/351043.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/05/26/351043.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/351043.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/351043.html</trackback:ping><description><![CDATA[<p>TCP/IP（Transmission Control Protocol/Internet Protocol)的简写，中文译名为传输控制协议/<a href="http://baike.baidu.com/view/1706.htm" target="_blank">因特网</a>互联协议，又叫网络<a href="http://baike.baidu.com/view/278358.htm" target="_blank">通讯协议</a>，这个协议是Internet最基本的协议、Internet国际<a href="http://baike.baidu.com/view/6825.htm" target="_blank">互联网</a>络的基础，简单地说，就是由网络层的IP协议和传输层的TCP协议组成的。TCP/IP 定义了电子设备（比如计算机）如何连入因特网，以及数据如何在它们之间传输的标准。TCP/IP是一个四层的分层体系结构。高层为传输控制协议，它负责聚集信息或把文件拆分成更小的包。低层是网际协议，它处理每个包的地址部分，使这些包正确的到达目的地。<br /><br /></p>
<h3 class="headline-2 bk-sidecatalog-title"><a name="1_1"></a><span class="headline-content">概念</span></h3>
<p>　　<a href="http://baike.baidu.com/view/7729.htm" target="_blank"><strong><font color="#136ec2">TCP/IP</font></strong></a>（传输控制协议/网际协议）是异构网络互连的通信协议，通过它可以实现各种异构网络或异种机之间的互联通信。 </p>
<div class="spctrl"></div>
<p>　　TCP/IP已成为当今计算机网络最成熟、应用最广的互联协议。Internet采用的就是TCP/IP协议，网络上各种各样的计算机上只要安装了TCP/IP协议，它们之间就能相互通信。运行TCP/IP协议的网络是一种采用包（分组）交换网络。TCP/IP协议是由100多个协议组成的协议集，TCP和IP是其中两个最重要的协议。TCP和IP两个协议分别属于传输层和网络层，在Internet中起着不同的作用。 </p>
<h3 class="headline-2 bk-sidecatalog-title"><a name="1_2"></a><span class="headline-content">层次概述</span></h3>
<p>　　 
<table class="table-view">
<tbody>
<tr>
<td>﻿TCP/IP</td>
<td>﻿</td>
<td>OSI﻿</td></tr>
<tr>
<td>﻿应用层</td>
<td>﻿</td>
<td>﻿应用层 <br />表示层 <br />会话层</td></tr>
<tr>
<td>﻿传输层（TCP）</td>
<td>﻿</td>
<td>﻿传输层</td></tr>
<tr>
<td>﻿网络层（IP）</td>
<td>﻿</td>
<td>﻿网络层</td></tr>
<tr>
<td>﻿网络接口层</td>
<td>﻿</td>
<td>﻿数据链路层</td></tr></tbody></table>（TCP/IP结构对应OSI结构） </p>
<div class="spctrl"></div>
<p>　　TCP/IP是一个四层的分层体系结构。 </p>
<div class="spctrl"></div>
<p>　　最高层：应用层为协议的最高层，在该层应用程序与协议相配合，发送或接收数据。TCP/IP协议集在应用层上有远程登录协议（Telnet）、文件传输协议（FTP）、电子邮箱协议（SMTP）、域名系统（DNS）等，它们构成了TCP/IP的基本应用程序。 </p>
<div class="spctrl"></div>
<p>　　高层：即传输层，其主要协议有<a href="http://baike.baidu.com/view/30509.htm" target="_blank"><font color="#136ec2">UDP</font></a>（user data protocol）和<a href="http://baike.baidu.com/view/544903.htm" target="_blank"><font color="#136ec2">传输控制协议</font></a>（TCP,Transmission Control Protocol）。TCP协议是在IP协议提供的服务基础上，支持面向连接的、可靠地传输服务，是负责聚集信息或把文件拆分成更小的包。这些包通过网络传送到接收端的TCP层，接收端的TCP层把包还原为原始文件；UDP协议时直接利用IP协议进行UDP<a href="http://baike.baidu.com/view/121589.htm" target="_blank"><font color="#136ec2">数据报</font></a>的传输，因此UDP协议提供的是无连接、不保证数据完整到达目的地的传输服务。由于UDP不使用很繁琐的流控制或错误恢复机制，只充当数据报的发送者和接收者，因此，UDP比TCP简单得多。 </p>
<div class="spctrl"></div>
<p>　　低层：是<a href="http://baike.baidu.com/view/229604.htm" target="_blank"><font color="#136ec2">网际协议</font></a>(IP,Internet Protocol)，它处理每个包的地址部分，使这些包正确的到达目的地。网络上的网关计算机根据信息的地址来进行路由选择。即使来自同一文件的分包路由也有可能不同，但最后会在目的地汇合。 TCP/IP使用客户端/服务器模式进行通信。TCP/IP通信是点对点的，意思是通信是网络中的一台主机与另一台主机之间的。TCP/IP与上层应用程序之间可以说是&#8220;没有国籍的&#8221;，因为每个客户请求都被看做是与上一个请求无关的。正是它们之间的&#8220;无国籍的&#8221;释放了网络路径，才使每个人都可以连续不断的使用网络。 许多用户熟悉使用TCP/IP协议的高层应用协议。包括<a href="http://baike.baidu.com/view/7833.htm" target="_blank"><strong><font color="#136ec2">万维网</font></strong></a>（www，world wide web）的超文本传输协议（HTTP），文件传输协议（FTP），远程网络访问协议(<a href="http://baike.baidu.com/view/44255.htm" target="_blank"><strong><font color="#136ec2">Telnet</font></strong></a>)和简单邮件传输协议（SMTP）。这些协议通常和TCP/IP协议打包在一起。 使用模拟电话调制解调器连接网络的个人电脑通常是使用串行线路接口协议（SLIP）和点对点协议（<a href="http://baike.baidu.com/view/3280.htm" target="_blank"><strong><font color="#136ec2">P2P</font></strong></a>）。这些协议压缩IP包后通过拨号电话线发送到对方的调制解调器中。 与TCP/IP协议相关的协议还包括用户数据报协议（<strong>UDP</strong>），它代替TCP/IP协议来达到特殊的目的。其他协议是网络主机用来交换路由信息的，包括<a href="http://baike.baidu.com/view/11165.htm" target="_blank"><strong><font color="#136ec2">Internet</font></strong></a>控制信息协议（<a href="http://baike.baidu.com/view/30564.htm" target="_blank"><strong><font color="#136ec2">ICMP</font></strong></a>），内部网关协议（<a href="http://baike.baidu.com/view/448271.htm" target="_blank"><strong><font color="#136ec2">IGP</font></strong></a>），外部网关协议（EGP），边界网关协议（<a href="http://baike.baidu.com/view/360.htm" target="_blank"><strong><font color="#136ec2">BGP</font></strong></a>）。 </p>
<div class="bpctrl"></div>
<h2 class="headline-1 bk-sidecatalog-title"><span class="text_edit editable-title" data-edit-id="7649:7649:2"><a class="nslog:1019" href="http://baike.baidu.com/view/7729.htm#">编辑本段</a></span><a name="2"></a><span class="headline-content">产生背景</span></h2>
<p>　　众所周知，如今电脑上因特网都要作TCP/IP协议设置，显然该协议成了当今地球村&#8220;人与人&#8221;之间的&#8220;牵手协议&#8221;。 </p>
<div class="spctrl"></div>
<p>　　1997年，为了褒奖对因特网发展作出突出贡献的科学家，并对TCP/IP协议作出充分肯定，美国授予为因特网发明和定义TCP/IP协议的文顿&#183;瑟夫和卡恩&#8220;国家技术金奖&#8221;。这无疑使人们认识到TCP/IP协议的重要性。 </p>
<div class="spctrl"></div>
<p>　　在阿帕网（ARPR）产生运作之初，通过接口信号处理机实现互联的电脑并不多，大部分电脑相互之间不兼容，在一台电脑上完成的工作，很难拿到另一台电脑上去用，想让硬件和软件都不一样的电脑联网，也有很多困难。当时美国的状况是，陆军用的电脑是DEC系列产品，海军用的电脑是Honeywell中标机器，空军用的是IBM公司中标的电脑，每一个军种的电脑在各自的系里都运行良好，但却有一个大弊病：不能共享资源。 </p>
<div class="spctrl"></div>
<p>　　当时科学家们提出这样一个理念：&#8220;所有电脑生来都是平等的。&#8221;为了让这些&#8220;生来平等&#8221;的电脑能够实现&#8220;资源共享&#8221;就得在这些系统的标准之上，建立一种大家共同都必须遵守的标准，这样才能让不同的电脑按照一定的规则进行&#8220;谈判&#8221;，并且在谈判之后能&#8220;握手&#8221;。 </p>
<div class="spctrl"></div>
<p>　　在确定今天因特网各个电脑之间&#8220;谈判规则&#8221;过程中，最重要的人物当数瑟夫（Vinton G.Cerf）。正是他的努力，才使今天各种不同的电脑能按照协议上网互联。瑟夫也因此获得了与克莱因罗克（&#8220;因特网之父&#8221;）一样的美称&#8220;互联网之父&#8221;。 </p>
<div class="spctrl"></div>
<p>　　瑟夫从小喜欢标新立异，坚强而又热情。中学读书时，就被允许使用加州大学洛杉矶分校的电脑，他认为&#8220;为电脑编程序是个非常激动人心的事，&#8230;只要把程序编好，就可以让电脑做任何事情。&#8221;1965年，瑟夫从斯坦福大学毕业到IBM的一家公司当系统工程师，工作没多久，瑟夫就觉得知识不够用，于是到加州大学洛杉矶分校攻读博士，那时，正逢阿帕网的建立，&#8220;接口信号处理机&#8221;（IMP）的研试及网络测评中心的建立，瑟夫也成了著名科学家克莱因罗克手下的一位学生。瑟夫与另外三位年轻人（温菲尔德、克罗克、布雷登）参与了阿帕网的第一个节点的联接。此后不久，BBN公司对工作中各种情况发展有很强判断能力、被公认阿帕网建成作出巨大贡献的鲍伯&#183;卡恩（Bob Kahn）也来到了加州大学洛杉矶分校。 在那段日子里，往往是卡恩提出需要什么软件，而瑟夫则通宵达旦地把符合要求的软件给编出来，然后他们一起测试这些软件，直至能正常运行。 </p>
<div class="spctrl"></div>
<p>　　当时的主要格局是这样的，罗伯茨提出网络思想设计网络布局，卡恩设计阿帕网总体结构，克莱因罗克负责网络测评系统，还有众多的科学家、研究生参与研究、试验。69年9月阿帕网诞生、运行后，才发现各个IMP连接的时候，需要考虑用各种电脑都认可的信号来打开通信管道，数据通过后还要关闭通道。否则这些IMP不会知道什么时候应该接收信号，什么时候该结束，这就是我们现在所说的通信&#8220;协议&#8221;的概念。70年12月制定出来了最初的通信协议由卡恩开发、瑟夫参与的&#8220;网络控制协议&#8221;（NCP），但要真正建立一个共同的标准很不容易，72年10月国际电脑通信大会结束后，科学家们都在为此而努力。 </p>
<div class="spctrl"></div>
<p>　　&#8220;包切换&#8221;理论为网络之间的联接方式提供了理论基础。卡恩在自己研究的基础上，认识到只有深入理解各种操作系统的细节才能建立一种对各种操作系统普适的协议，73年卡恩请瑟夫一起考虑这个协议的各个细节，他们这次合作的结果产生了目前在开放系统下的所有网民和网管人员都在使用的&#8220;传输控制协议&#8221;（TCP，Transmission-Control Protocol）和&#8220;因特网协议&#8221;（IP，Internet Protocol）即TCP/IP协议。 </p>
<div class="spctrl"></div>
<p>　　通俗而言：TCP负责发现传输的问题，一有问题就发出信号，要求重新传输，直到所有数据安全正确地传输到目的地。而IP是给因特网的每一台电脑规定一个地址。1974年12月，卡恩、瑟夫的第一份TCP协议详细说明正式发表。当时美国国防部与三个科学家小组签定了完成TCP/IP的协议，结果由瑟夫领衔的小组捷足先登，首先制定出了通过详细定义的TCP/IP协议标准。当时作了一个试验，将信息包通过点对点的卫星网络，再通过陆地电缆，再通过卫星网络，再由地面传输，贯串欧洲和美国，经过各种电脑系统，全程9.4万公里竟然没有丢失一个数据位，远距离的可靠数据传输证明了TCP/IP协议的成功。 </p>
<div class="spctrl"></div>
<p>　　1983年1月1日，运行较长时期曾被人们习惯了的NCP被停止使用，TCP/IP协议作为因特网上所有主机间的共同协议，从此以后被作为一种必须遵守的规则被肯定和应用。正是由于TCP/IP协议，才有今天&#8220;地球村&#8221;因特网的巨大发展。 </p>
<div class="bpctrl"></div>
<h2 class="headline-1 bk-sidecatalog-title"><span class="text_edit editable-title" data-edit-id="7649:7649:3"><a class="nslog:1019" href="http://baike.baidu.com/view/7729.htm#">编辑本段</a></span><a name="3"></a><span class="headline-content">开发过程</span></h2>
<p>　　在构建了<a href="http://baike.baidu.com/view/108095.htm" target="_blank"><font color="#136ec2">阿帕网</font></a>先驱之后，DARPA开始了其他数据传输技术的研究。NCP诞生后两年，1972年，<a href="http://baike.baidu.com/view/2020429.htm" target="_blank"><font color="#136ec2">罗伯特&#183;卡恩</font></a>（Robert E. Kahn）被DARPA的信息技术处理办公室雇佣，在那里他研究卫星数据包网络和地面无线数据包网络，并且意识到能够在它们之间沟通的价值。在1973年春天，已有的ARPANET网络控制程序（NCP）协议的开发者<a href="http://baike.baidu.com/view/5129002.htm" target="_blank"><font color="#136ec2">文顿&#183;瑟夫</font></a>（Vinton Cerf）加入到卡恩为ARPANET设计下一代协议而开发开放互连模型的工作中。 </p>
<div class="spctrl"></div>
<p>　　到了<a href="http://baike.baidu.com/view/286653.htm" target="_blank"><font color="#136ec2">1973年</font></a>夏天，卡恩和瑟夫很快就开发出了一个基本的改进形式，其中网络协议之间的不同通过使用一个公用互联网络协议而隐藏起来，并且可靠性由主机保证而不是像ARPANET那样由网络保证。（瑟夫称赞Hubert Zimmerman和Louis Pouzin（CYCLADES网络的设计者）在这个设计上发挥了重要影响。） </p>
<div class="spctrl"></div>
<p>　　由于网络的作用减少到最小的程度，就有可能将任何网络连接到一起，而不用管它们不同的特点，这样就解决了卡恩最初的问题。（一个流行的说法提到瑟夫和卡恩工作的最终产品TCP/IP将在运行&#8220;两个罐子和一根弦&#8221;上，实际上它已经用在信鸽上。一个称为<em>网关</em>（后来改为<em><a href="http://baike.baidu.com/view/1360.htm" target="_blank"><font color="#136ec2">路由器</font></a></em>以免与<em><a href="http://baike.baidu.com/view/807.htm" target="_blank"><font color="#136ec2">网关</font></a></em>混淆）的计算机为每个网络提供一个接口并且在它们之间来回传输<a href="http://baike.baidu.com/view/25880.htm" target="_blank"><font color="#136ec2">数据包</font></a>。 </p>
<div class="spctrl"></div>
<p>　　这个设计思想更细的形式由瑟夫在斯坦福的网络研究组的1973年&#8211;<a href="http://baike.baidu.com/view/286308.htm" target="_blank"><font color="#136ec2">1974年</font></a>期间开发出来。（处于同一时期的诞生了PARC通用包协议组的施乐PARC早期网络研究工作也有重要的技术影响；人们在两者之间摇摆不定。） </p>
<div class="spctrl"></div>
<p>　　DARPA于是与BBN、斯坦福和伦敦大学签署了协议开发不同硬件平台上协议的运行版本。有四个版本被开发出来&#8212;&#8212;TCP v1、TCP v2、在1978年春天分成TCP v3和IP v3的版本，后来就是稳定的TCP/IP v4&#8212;&#8212;目前因特网仍然使用的标准协议。 </p>
<div class="spctrl"></div>
<p>　　<a href="http://baike.baidu.com/view/286651.htm" target="_blank"><font color="#136ec2">1975年</font></a>，两个网络之间的TCP/IP通信在斯坦福和伦敦大学（UCL）之间进行了测试。<a href="http://baike.baidu.com/view/286649.htm" target="_blank"><font color="#136ec2">1977年</font></a>11月，三个网络之间的TCP/IP测试在美国、英国和挪威之间进行。在<a href="http://baike.baidu.com/view/286309.htm" target="_blank"><font color="#136ec2">1978年</font></a>到1983年间，其他一些TCP/IP原型在多个研究中心之间开发出来。ARPANET完全转换到TCP/IP在1983年1月1日发生。[1] </p>
<div class="spctrl"></div>
<p>　　1984年，美国国防部将TCP/IP作为所有计算机网络的标准。1985年，因特网架构理事会举行了一个三天有250家厂商代表参加的关于计算产业使用TCP/IP的工作会议，帮助协议的推广并且引领它日渐增长的商业应用。 </p>
<div class="spctrl"></div>
<p>　　<a href="http://baike.baidu.com/view/286352.htm" target="_blank"><font color="#136ec2">2005年</font></a><a href="http://baike.baidu.com/view/477852.htm" target="_blank"><font color="#136ec2">9月9日</font></a>卡恩和瑟夫由于他们对于美国文化做出的卓越贡献被授予<a href="http://baike.baidu.com/view/1984059.htm" target="_blank"><font color="#136ec2">总统自由勋章</font></a>。 </p>
<div class="bpctrl"></div>
<h2 class="headline-1 bk-sidecatalog-title"><span class="text_edit editable-title" data-edit-id="7649:7649:4"><a class="nslog:1019" href="http://baike.baidu.com/view/7729.htm#">编辑本段</a></span><a name="4"></a><span class="headline-content">主要协议</span></h2>
<p>　　之所以说TCP/IP是一个协议族，是因为TCP/IP协议包括TCP、IP、UDP、ICMP、RIP、TELNET、FTP、SMTP、ARP、TFTP等许多协议，这些协议一起称为TCP/IP协议。以下是协议族中一些常用协议英文名称和用途： </p>
<div class="spctrl"></div>
<p>　　TCP(Transport Control Protocol)传输控制协议 </p>
<div class="spctrl"></div>
<p>　　IP(Internet Protocol)因特网协议 </p>
<div class="spctrl"></div>
<p>　　UDP(User Datagram Protocol)用户数据报协议 </p>
<div class="spctrl"></div>
<p>　　ICMP(Internet Control Message Protocol)互联网控制信息协议 </p>
<div class="spctrl"></div>
<p>　　SMTP(Simple Mail Transfer Protocol)简单邮件传输协议 </p>
<div class="spctrl"></div>
<p>　　SNMP(Simple Network manage Protocol)简单网络管理协议 </p>
<div class="spctrl"></div>
<p>　　FTP(File Transfer Protocol)文件传输协议 </p>
<div class="spctrl"></div>
<p>　　ARP(Address Resolution Protocol)地址解析协议 </p>
<div class="spctrl"></div>
<p>　　TCP/IP协议簇分为四层，IP位于协议簇的第二层(对应OSI的第三层)，TCP位于协议簇的第三层(对应OSI的第四层)。 </p>
<div class="spctrl"></div>
<p>　　TCP和IP是TCP/IP协议簇的中间两层，是整个协议簇的核心，起到了承上启下的作用。 </p>
<h3 class="headline-2 bk-sidecatalog-title"><a name="4_1"></a><span class="headline-content">1.IP</span></h3>
<p>　　网际协议IP是TCP/IP的心脏，也是网络层中最重要的协议。 </p>
<div class="spctrl"></div>
<p>　　IP层接收由更低层（网络接口层例如以太网设备驱动程序）发来的数据包，并把该数据包发送到更高层---TCP或UDP层；相反，IP层也把从TCP或UDP层接收来的数据包传送到更低层。IP数据包是不可靠的，因为IP并没有做任何事情来确认数据包是按顺序发送的或者没有被破坏。IP数据包中含有发送它的主机的地址（源地址）和接收它的主机的地址（目的地址）。 </p>
<div class="spctrl"></div>
<p>　　高层的TCP和UDP服务在接收数据包时，通常假设包中的源地址是有效的。也可以这样说，<a href="http://baike.baidu.com/view/3930.htm" target="_blank"><font color="#136ec2">IP地址</font></a>形成了许多服务的认证基础，这些服务相信数据包是从一个有效的主机发送来的。IP确认包含一个选项，叫作IP source routing，可以用来指定一条源地址和目的地址之间的直接路径。对于一些TCP和UDP的服务来说，使用了该选项的IP包好像是从路径上的最后一个系统传递过来的，而不是来自于它的真实地点。这个选项是为了测试而存在的，说明了它可以被用来欺骗系统来进行平常是被禁止的连接。那么，许多依靠IP源地址做确认的服务将产生问题并且会被非法入侵。 </p>
<h3 class="headline-2 bk-sidecatalog-title"><a name="4_2"></a><span class="headline-content">2.TCP</span></h3>
<p>　　如果IP数据包中有已经封好的TCP数据包，那么IP将把它们向&#8216;上&#8217;传送到TCP层。TCP将包排序并进行错误检查，同时实现虚电路间的连接。TCP数据包中包括序号和确认，所以未按照顺序收到的包可以被排序，而损坏的包可以被重传。 </p>
<div class="spctrl"></div>
<p>　　TCP将它的信息送到更高层的应用程序，例如Telnet的服务程序和客户程序。应用程序轮流将信息送回TCP层，TCP层便将它们向下传送到IP层，设备驱动程序和物理介质，最后到接收方。 </p>
<div class="spctrl"></div>
<p>　　面向连接的服务（例如Telnet、FTP、rlogin、X Windows和SMTP）需要高度的可靠性，所以它们使用了TCP。DNS在某些情况下使用TCP（发送和接收<a href="http://baike.baidu.com/view/43.htm" target="_blank"><font color="#136ec2">域名</font></a>数据库），但使用UDP传送有关单个主机的信息。 </p>
<h3 class="headline-2 bk-sidecatalog-title"><a name="4_3"></a><span class="headline-content">3.UDP</span></h3>
<p>　　UDP与TCP位于同一层，但它不管数据包的顺序、错误或重发。因此，UDP不被应用于那些使用虚电路的面向连接的服务，UDP主要用于那些面向查询---应答的服务，例如NFS。相对于FTP或Telnet，这些服务需要交换的信息量较小。使用UDP的服务包括NTP（网络时间协议）和DNS（DNS也使用TCP）。 </p>
<div class="spctrl"></div>
<p>　　欺骗UDP包比欺骗TCP包更容易，因为UDP没有建立初始化连接（也可以称为握手）（因为在两个系统间没有虚电路），也就是说，与UDP相关的服务面临着更大的危险。 </p>
<h3 class="headline-2 bk-sidecatalog-title"><a name="4_4"></a><span class="headline-content">4.ICMP</span></h3>
<p>　　ICMP与IP位于同一层，它被用来传送IP的的控制信息。它主要是用来提供有关通向目的地址的路径信息。ICMP的&#8216;Redirect&#8217;信息通知主机通向其他系统的更准确的路径，而&#8216;Unreachable&#8217;信息则指出路径有问题。另外，如果路径不可用了，ICMP可以使TCP连接&#8216;体面地&#8217;终止。PING是最常用的基于ICMP的服务。 </p>
<h3 class="headline-2 bk-sidecatalog-title"><a name="4_5"></a><span class="headline-content">5. TCP和UDP的端口结构</span></h3>
<p>　　TCP和UDP服务通常有一个客户/服务器的关系，例如，一个Telnet服务进程开始在系统上处于空闲状态，等待着连接。用户使用Telnet客户程序与服务进程建立一个连接。客户程序向服务进程写入信息，服务进程读出信息并发出响应，客户程序读出响应并向用户报告。因而，这个连接是双工的，可以用来进行读写。 </p>
<div class="spctrl"></div>
<p>　　两个系统间的多重Telnet连接是如何相互确认并协调一致呢？TCP或UDP连接唯一地使用每个信息中的如下四项进行确认： </p>
<div class="spctrl"></div>
<p>　　源IP地址 发送包的IP地址。 </p>
<div class="spctrl"></div>
<p>　　目的IP地址 接收包的IP地址。 </p>
<div class="spctrl"></div>
<p>　　源端口 源系统上的连接的端口。 </p>
<div class="spctrl"></div>
<p>　　目的端口 目的系统上的连接的端口。 </p>
<div class="spctrl"></div>
<p>　　端口是一个软件结构，被客户程序或服务进程用来发送和接收信息。一个端口对应一个16比特的数。服务进程通常使用一个固定的端口，例如，SMTP使用25、Xwindows使用6000。这些<a href="http://baike.baidu.com/view/642103.htm" target="_blank"><font color="#136ec2">端口号</font></a>是&#8216;广为人知&#8217;的，因为在建立与特定的主机或服务的连接时，需要这些地址和目的地址进行通讯。 </p>
<div class="bpctrl"></div>
<h2 class="headline-1 bk-sidecatalog-title"><span class="text_edit editable-title" data-edit-id="7649:7649:5"><a class="nslog:1019" href="http://baike.baidu.com/view/7729.htm#">编辑本段</a></span><a name="5"></a><span class="headline-content">IP地址</span></h2>
<p>　　在Internet上连接的所有计算机，从大型机到微型计算机都是以独立的身份出现，我们称它为主机。为了实现各主机间的通信，每台主机都必须有一个唯一的网络地址。就好像每一个住宅都有唯一的门牌一样，才不至于在传输资料时出现混乱。 </p>
<div class="spctrl"></div>
<p>　　Internet的网络地址是指连入Internet网络的计算机的地址编号。所以，在Internet网络中，网络地址唯一地标识一台计算机。 </p>
<div class="spctrl"></div>
<p>　　我们都已经知道，Internet是由几千万台计算机互相连接而成的。而我们要确认网络上的每一台计算机，靠的就是能唯一标识该计算机的网络地址，这个地址就叫做IP（Internet Protocol的简写）地址，即用Internet协议语言表示的地址。 </p>
<div class="spctrl"></div>
<p>　　目前，在Internet里，IP地址是一个32位的二进制地址，为了便于记忆，将它们分为4组，每组8位，由小数点分开，用四个字节来表示，而且，用点分开的每个字节的数值范围是0~255，如202.116.0.1，这种书写方法叫做点数表示法。 </p>
<h3 class="headline-2 bk-sidecatalog-title"><a name="5_1"></a><span class="headline-content">地址分类</span></h3>
<p>　　IP地址可确认网络中的任何一个网络和计算机，而要识别其它网络或其中的计算机，则是根据这些IP地址的分类来确定的。一般将IP地址按节点计算机所在网络规模的大小分为A，B，C三类，默认的网络屏蔽是根据IP地址中的第一个字段确定的。 </p>
<div class="spctrl"></div>
<p>　　1. A类地址 </p>
<div class="spctrl"></div>
<p>　　A类地址的表示范围为：1.0.0.1~126.255.255.255，默认网络屏蔽为：255.0.0.0；A类地址分配给规模特别大的网络使用。A类网络用第一组数字表示网络本身的地址，后面三组数字作为连接于网络上的主机的地址。分配给具有大量主机（直接个人用户）而局域网络个数较少的大型网络。例如IBM公司的网络。 </p>
<div class="spctrl"></div>
<p>　　127.0.0.0到127.255.255.255是保留地址，用做循环测试用的。 </p>
<div class="spctrl"></div>
<p>　　0.0.0.0到0.255.255.255也是保留地址，用做表示所有的IP地址。 </p>
<div class="spctrl"></div>
<p>　　一个<a href="http://baike.baidu.com/view/15408.htm" target="_blank"><font color="#136ec2">A类IP地址</font></a>由1字节（每个字节是8位）的网络地址和3个字节主机地址组成，网络地址的最高位必须是&#8220;0&#8221;,即第一段数字范围为1～127。每个A类地址理论上可连接16777214&lt;256*256*256-2&gt;台主机（-2是因为主机中要用去一个网络号和一个广播号），Internet有126个可用的A类地址。A类地址适用于有大量主机的大型网络。 </p>
<div class="spctrl"></div>
<p>　　2. B类地址 </p>
<div class="spctrl"></div>
<p>　　B类地址的表示范围为：128.0.0.1~191.255.255.255，默认网络屏蔽为：255.255.0.0；B类地址分配给一般的中型网络。B类网络用第一、二组数字表示网络的地址，后面两组数字代表网络上的主机地址。 </p>
<div class="spctrl"></div>
<p>　　169.254.0.0到169.254.255.255是保留地址。如果你的IP地址是自动获取IP地址，而你在网络上又没有找到可用的DHCP服务器，这时你将会从169.254.0.0到169.254.255.255中临时获得一个IP地址。 </p>
<div class="spctrl"></div>
<p>　　一个B类IP地址由2个字节的网络地址和2个字节的主机地址组成，网络地址的最高位必须是&#8220;10&#8221;，即第一段数字范围为128～191。每个B类地址可连接65534(2^16-2, 因为主机号的各位不能同时为0,1)台主机，Internet有16383(2^14-1)个B类地址(因为B类网络地址128.0.0.0是不指派的，而可以指派的最小地址为128.1.0.0[COME06]）。 </p>
<div class="spctrl"></div>
<p>　　3. C类地址 </p>
<div class="spctrl"></div>
<p>　　C类地址的表示范围为：192.0.0.1~223.255.255.255，默认网络屏蔽为：255.255.255.0；C类地址分配给小型网络，如一般的局域网，它可连接的主机数量是最少的，采用把所属的用户分为若干的网段进行管理。C类网络用前三组数字表示网络的地址，最后一组数字作为网络上的主机地址。 </p>
<div class="spctrl"></div>
<p>　　一个C类地址是由3个字节的网络地址和1个字节的主机地址组成，网络地址的最高位必须是&#8220;110&#8221;，即第一段数字范围为192～223。每个C类地址可连接254台主机，Internet有2097152个C类地址段（32*256*256），有532676608个地址（32*256*256*254）。 </p>
<div class="spctrl"></div>
<p>　　RFC 1918留出了3块IP地址空间（1个A类地址段，16个B类地址段，256个C类地址段）作为私有的内部使用的地址。在这个范围内的IP地址不能被路由到Internet骨干网上；Internet路由器将丢弃该私有地址。 </p>
<div class="spctrl"></div>
<p>　　IP地址类别　RFC 1918内部地址范围 </p>
<div class="spctrl"></div>
<p>　　A类　10.0.0.0到10.255.255.255 </p>
<div class="spctrl"></div>
<p>　　B类　172.16.0.0到172.31.255.255 </p>
<div class="spctrl"></div>
<p>　　C类　192.168.0.0到192.168.255.255 </p>
<div class="spctrl"></div>
<p>　　使用私有地址将网络连至Internet，需要将私有地址转换为公有地址。这个转换过程称为网络地址转换（Network Address Translation，NAT），通常使用路由器来执行NAT转换。 </p>
<div class="spctrl"></div>
<p>　　实际上，还存在着D类地址和E类地址。但这两类地址用途比较特殊，在这里只是简单介绍一下： </p>
<div class="spctrl"></div>
<p>　　D类地址不分网络地址和主机地址，它的第1个字节的前四位固定为1110。 D类地址范围：224.0.0.1到239.255.255.254 。 D类地址用于多点播送。D类地址称为<a href="http://baike.baidu.com/view/473043.htm" target="_blank"><font color="#136ec2">广播地址</font></a>，供特殊协议向选定的节点发送信息时用。 </p>
<div class="spctrl"></div>
<p>　　E类地址保留给将来使用。 </p>
<div class="spctrl"></div>
<p>　　连接到Internet上的每台计算机，不论其IP地址属于哪类都与网络中的其它计算机处于平等地位，因为只有IP地址才是区别计算机的唯一标识。所以，以上IP地址的分类只适用于网络分类。 </p>
<div class="spctrl"></div>
<p>　　在Internet中，一台计算机可以有一个或多个IP地址，就像一个人可以有多个通信地址一样，但两台或多台计算机却不能共享一个IP地址。如果有两台计算机的IP地址相同，则会引起异常现象，无论哪台计算机都将无法正常工作。 </p>
<div class="spctrl"></div>
<p>　　顺便提一下几类特殊的IP地址： </p>
<div class="spctrl"></div>
<p>　　1. 广播地址 目的端为给定网络上的所有主机，一般主机段为全1 </p>
<div class="spctrl"></div>
<p>　　2. 单播地址 目的端为指定网络上的单个主机地址 </p>
<div class="spctrl"></div>
<p>　　3. 组播地址 目的端为同一组内的所有主机地址 </p>
<div class="spctrl"></div>
<p>　　4. 环回地址 <a href="http://baike.baidu.com/view/971216.htm" target="_blank"><font color="#136ec2">127.0.0.1</font></a> 在环回测试和广播测试时会使用 </p>
<h3 class="headline-2 bk-sidecatalog-title"><a name="5_2"></a><span class="headline-content">网关地址</span></h3>
<p>　　若要使两个完全不同的网络（异构网）连接在一起，一般使用网关，在Internet中两个网络也要通过一台称为网关的计算机实现互联。这台计算机能根据用户通信目标计算机的IP地址，决定是否将用户发出的信息送出本地网络，同时，它还将外界发送给属于本地网络计算机的信息接收过来，它是一个网络与另一个网络相联的通道。为了使TCP/IP协议能够寻址，该通道被赋予一个IP地址，这个IP地址称为网关地址。 </p>
<div class="bpctrl"></div>
<h2 class="headline-1 bk-sidecatalog-title"><span class="text_edit editable-title" data-edit-id="7649:7649:6"><a class="nslog:1019" href="http://baike.baidu.com/view/7729.htm#">编辑本段</a></span><a name="6"></a><span class="headline-content">注意事项</span></h2>
<p>　　内部地址和外部地址在局域网的IP地址分配中，并没有区别，都可以使用。 </p>
<div class="spctrl"></div>
<p>　　在局域网的IP地址分配中，子网屏蔽的&#8220;1&#8221;部分只要和对应的IP地址分类规定的前几个二进制数一致即可。 </p>
<div class="bpctrl"></div>
<h2 class="headline-1 bk-sidecatalog-title"><span class="text_edit editable-title" data-edit-id="7649:7649:7"><a class="nslog:1019" href="http://baike.baidu.com/view/7729.htm#">编辑本段</a></span><a name="7"></a><span class="headline-content">子网划分</span></h2>
<p>　　若公司不上Internet,那一定不会烦恼IP地址的问题,因为可以任意使用所有的IP地址,不管是A类或是B类,这个时候不会想到要用子网,但若是上Internet那IP地址便弥足珍贵了,目前全球一阵Internet热,IP地址已经愈来愈少了,而所申请的IP地址目前也趋保守,而且只有经申请的IP地址能在Internet使用,但对某些公司只能申请到一个C类的IP地址,但又有多个点需要使用,那这时便需要使用到子网,这就需要考虑子网的划分，下面简介子网的原理及如何规划。 </p>
<h3 class="headline-2 bk-sidecatalog-title"><a name="7_1"></a><span class="headline-content">子网掩码（Subnet Mask）</span></h3>
<p>　　设定任何网络上的任何设备不管是主机、个人电脑、路由器等皆需要设定IP地址,而跟随着IP地址的是所谓的子网掩码（NetMask,Subnet Mask),这个子网掩码主要的目的是由IP地址中也能获得网络编码,也就是说IP地址和子网掩码合作而得到网络编码,如下所示： </p>
<div class="spctrl"></div>
<p>　　IP地址 </p>
<div class="spctrl"></div>
<p>　　192.10.10.6 11000000.00001010.00001010.00000110 </p>
<div class="spctrl"></div>
<p>　　子网掩码 </p>
<div class="spctrl"></div>
<p>　　255.255.255.0 11111111.11111111.11111111.00000000 </p>
<div class="spctrl"></div>
<p>　　AND </p>
<div class="spctrl"></div>
<p>　　------------------------------------------------------------------- </p>
<div class="spctrl"></div>
<p>　　Network Number </p>
<div class="spctrl"></div>
<p>　　192.10.10.0 11000000.00001010.00001010.00000000 </p>
<div class="spctrl"></div>
<p>　　子网掩码有所谓的默认值,如下所示 </p>
<div class="spctrl"></div>
<p>　　类 IP地址 范围 子网掩码 </p>
<div class="spctrl"></div>
<p>　　A　1.0.0.0-126.255.255.255 255.0.0.0 </p>
<div class="spctrl"></div>
<p>　　B　128.0.0.0-191.255.255.255 255.255.0.0 </p>
<div class="spctrl"></div>
<p>　　C　192.0.0.0-223.255.255.255 255.255.255.0 </p>
<div class="spctrl"></div>
<p>　　在预设的子网掩码（Net Mask）都只有255的值,在谈到子网掩码（Subnet Mask）时这个值便不一定是255了。在完整一组C类地址中如203.67.10.0-203.67.10.255 子网掩码255.255.255.0,203.67.10.0称之网络编码（Network Number，将IP 地址和子网掩码作和),而203.67.10.255是广播的IP地址,所以这两者皆不能使用,实际只能使用203.67.10.1--203.67.10.254等254个IP地址,这是以255.255.255.0作子网掩码的结果,而所谓Subnet Msk尚可将整组C类地址分成数组网络编码,这要在子网掩码上作手脚,若是要将整组C类地址分成2个网络编码那子网掩码设定为255.255.255.128,若是要将整组C类分成8组网络编码则子网掩码要为255.255.255.224,这是怎么来的,由以上知道网络编码是由IP地址和子网掩码作AND而来的,而且将子网掩码以二进制表示法知道是1的会保留,而为0的去掉 </p>
<div class="spctrl"></div>
<p>　　192.10.10.193--11000000.00001010.00001010.11000001 </p>
<div class="spctrl"></div>
<p>　　255.255.255.0--11111111.11111111.11111111.00000000 </p>
<div class="spctrl"></div>
<p>　　-------------------------------------------------------------- </p>
<div class="spctrl"></div>
<p>　　192.10.10.0--11000000.00001010.00001010.00000000 </p>
<div class="spctrl"></div>
<p>　　以上是以255.255.255.0为子网掩码的结果,网络编码是192.10.10.0,若是使用255.255.255.224作子网掩码结果便有所不同 </p>
<div class="spctrl"></div>
<p>　　192.10.10.193--11000000.00001010.00001010.11000001 </p>
<div class="spctrl"></div>
<p>　　255.255.255.224--11111111.11111111.11111111.11100000 </p>
<div class="spctrl"></div>
<p>　　-------------------------------------------------------------- </p>
<div class="spctrl"></div>
<p>　　192.10.10.192--11000000.00001010.00001010.11000000 </p>
<div class="spctrl"></div>
<p>　　此时网络编码变成了192.10.10.192,这便是子网。那要如何决定所使用的子网掩码,255.255.255.224以二进制表示法为11111111.11111111.11111111.11100000,变化是在最后一组,11100000便是224,以三个位（Bit）可表示2的3次方便是8个网络编码 </p>
<div class="spctrl"></div>
<p>　　子网掩码二进制表示法可分几个网络 </p>
<div class="spctrl"></div>
<p>　　255.255.255.011111111.11111111.11111111.00000000 1 </p>
<div class="spctrl"></div>
<p>　　255.255.255.128 </p>
<div class="spctrl"></div>
<p>　　11111111.11111111.11111111.10000000 2 </p>
<div class="spctrl"></div>
<p>　　255.255.255.192 </p>
<div class="spctrl"></div>
<p>　　11111111.11111111.11111111.11000000 4 </p>
<div class="spctrl"></div>
<p>　　255.255.255.224 </p>
<div class="spctrl"></div>
<p>　　11111111.11111111.11111111.11100000 8 </p>
<div class="spctrl"></div>
<p>　　255.255.255.240 </p>
<div class="spctrl"></div>
<p>　　11111111.11111111.11111111.11110000 16 </p>
<div class="spctrl"></div>
<p>　　255.255.255.248 </p>
<div class="spctrl"></div>
<p>　　11111111.11111111.11111111.11111000 32 </p>
<div class="spctrl"></div>
<p>　　255.255.255.252 </p>
<div class="spctrl"></div>
<p>　　11111111.11111111.11111111.11111100 64 </p>
<div class="spctrl"></div>
<p>　　以下使用255.255.255.224将C类地址203.67.10.0分成8组网络编码,各个网络编码及其广播IP地址及可使用之IP地址序号网络编码广播可使用之IP地址 </p>
<div class="spctrl"></div>
<p>　　（1）203.67.10.0--203.67.10.31 </p>
<div class="spctrl"></div>
<p>　　203.67.10.1--203.67.10.30 </p>
<div class="spctrl"></div>
<p>　　（2）203.67.10.32--203.67.10.63 </p>
<div class="spctrl"></div>
<p>　　203.67.10.33--203.67.10.62 </p>
<div class="spctrl"></div>
<p>　　（3）203.67.10.64--203.67.10.95 </p>
<div class="spctrl"></div>
<p>　　203.67.10.65--203.67.10.94 </p>
<div class="spctrl"></div>
<p>　　（4）203.67.10.96--203.67.10.127 </p>
<div class="spctrl"></div>
<p>　　203.67.10.97--203.67.10.126 </p>
<div class="spctrl"></div>
<p>　　（5）203.67.10.128--203.67.10.159 </p>
<div class="spctrl"></div>
<p>　　203.67.10.129--203.67.10.158 </p>
<div class="spctrl"></div>
<p>　　（6）203.67.10.160--203.67.10.191 </p>
<div class="spctrl"></div>
<p>　　203.67.10.161--203.67.10.190 </p>
<div class="spctrl"></div>
<p>　　（7）203.67.10.192--203.67.10.223 </p>
<div class="spctrl"></div>
<p>　　203.67.10.193--203.67.10.222 </p>
<div class="spctrl"></div>
<p>　　（8）203.67.10.224--203.67.10.255 </p>
<div class="spctrl"></div>
<p>　　203.67.10.225--203.67.10.254 </p>
<div class="spctrl"></div>
<p>　　可验证所使用的IP地址是否如上表所示 </p>
<div class="spctrl"></div>
<p>　　203.67.10.115--11001011.01000011.00001010.01110011 </p>
<div class="spctrl"></div>
<p>　　255.255.255.224--11111111.11111111.11111111.11100000 </p>
<div class="spctrl"></div>
<p>　　-------------------------------------------------------------- </p>
<div class="spctrl"></div>
<p>　　203.67.10.96--11001011.01000011.00001010.01100000 </p>
<div class="spctrl"></div>
<p>　　203.67.10.55--11001011.01000011.00001010.00110111 </p>
<div class="spctrl"></div>
<p>　　255.255.255.224--11111111.11111111.11111111.11100000 </p>
<div class="spctrl"></div>
<p>　　-------------------------------------------------------------- </p>
<div class="spctrl"></div>
<p>　　203.67.10.32--11001011.01000011.00001010.00100000 </p>
<div class="spctrl"></div>
<p>　　其它的子网掩码所分成的网络编码可自行以上述方法自行推演出来。 </p>
<h3 class="headline-2 bk-sidecatalog-title"><a name="7_2"></a><span class="headline-content">子网的应用</span></h3>
<p>　　使用子网是要解决只有一组C类地址但需要数个网络编码的问题,并不是解决IP地址不够用的问题,因为使用子网反而能使用的IP地址会变少,子网通常是使用在跨地域的网络互联之中,两者之间使用路由器连线,同时也上Internet,但只申请到一组C 类IP地址,过路由又需不同的网络,所以此时就必须使用到子网,当然二网络间也可以远程桥接（Remote Bridge，字面翻译）连接,那便没有使用子网的问题。 </p>
<div class="bpctrl"></div>
<h2 class="headline-1 bk-sidecatalog-title"><span class="text_edit editable-title" data-edit-id="7649:7649:8"><a class="nslog:1019" href="http://baike.baidu.com/view/7729.htm#">编辑本段</a></span><a name="8"></a><span class="headline-content">概念区分</span></h2>
<h3 class="headline-2 bk-sidecatalog-title"><a name="8_1"></a><span class="headline-content">协议阐述、IP申请的术语</span></h3>
<p>　　网络地址：在申请IP地址或是阐述TCP/IP协议的IP地址分类时，用到这个术语。它表示IP地址的代码序列中不可更加需要改变的部分。 </p>
<div class="spctrl"></div>
<p>　　主机地址：在申请IP地址或是阐述TCP/IP协议的IP地址分类时，用到这个术语。它表示IP地址的代码序列中能够更具需要改变的部分。 </p>
<div class="spctrl"></div>
<p>　　子网屏蔽：在阐述TCP/IP协议的IP地址分类时，用到这个术语。在申请IP地址时，由它表示所申请到的IP地址的网络地址和主机地址。 </p>
<h3 class="headline-2 bk-sidecatalog-title"><a name="8_2"></a><span class="headline-content">子网划分、内网搭建的术语</span></h3>
<p>　　网络编码（网络号）：经过子网划分后，子网掩码序列中&#8220;1&#8221;对应的IP地址部分。一个网络编码，对应一个网域（或网段）。包括申请到的网络地址的全部和主机地址的部分。 </p>
<div class="spctrl"></div>
<p>　　主机编码（主机号）：经过子网划分后，子网掩码序列中&#8220;0&#8221;对应的IP地址部分。一个主机编码，对应一个网域（或网段）的一台计算机。包括申请到主机地址的部分。 </p>
<div class="spctrl"></div>
<p>　　子网掩码：用于子网划分，它将能够改变的主机地址分为主机编码和网络编码的一部分。同时，它将网络地址全部确定为网络编码。 </p>
<div class="bpctrl"></div>
<h2 class="headline-1 bk-sidecatalog-title"><span class="text_edit editable-title" data-edit-id="7649:7649:9"><a class="nslog:1019" href="http://baike.baidu.com/view/7729.htm#">编辑本段</a></span><a name="9"></a><span class="headline-content">协议层级</span></h2>
<p>　　从协议分层模型方面来讲，TCP/IP由四个层次组成：网络接口层、网络层、传输层、应用层。 </p>
<h3 class="headline-2 bk-sidecatalog-title"><a name="9_1"></a><span class="headline-content">接口层</span></h3>
<p>　　这是TCP/IP软件的最低层，负责接收IP数据报并通过网络发送之，或者从网络上接收物理帧，抽出IP数据报，交给IP层。 </p>
<div class="spctrl"></div>
<p>　　常见的接口层协议有： </p>
<div class="spctrl"></div>
<p>　　Ethernet 802.3、Token Ring 802.5、X.25、Frame reley、HDLC、PPP ATM 等。 </p>
<h3 class="headline-2 bk-sidecatalog-title"><a name="9_2"></a><span class="headline-content">网络层</span></h3>
<p>　　负责相邻计算机之间的通信。其功能包括三方面。 </p>
<div class="spctrl"></div>
<p>　　一、处理来自传输层的分组发送请求，收到请求后，将分组装入IP数据报，填充报头，选择去往信宿机的路径，然后将数据报发往适当的网络接口。 </p>
<div class="spctrl"></div>
<p>　　二、处理输入数据报：首先检查其合法性，然后进行寻径--假如该数据报已到达信宿机，则去掉报头，将剩下部分交给适当的传输协议；假如该数据报尚未到达信宿，则转发该数据报。 </p>
<div class="spctrl"></div>
<p>　　三、处理路径、流控、拥塞等问题。 </p>
<div class="spctrl"></div>
<p>　　网络层包括：IP(Internet Protocol)协议、ICMP(Internet Control Message Protocol) </p>
<div class="spctrl"></div>
<p>　　控制报文协议、ARP(Address Resolution Protocol)地址转换协议、RARP(Reverse ARP)反向地址转换协议。 </p>
<div class="spctrl"></div>
<p>　　IP是网络层的核心，通过路由选择将下一跳IP封装后交给接口层。IP数据报是无连接服务。 </p>
<div class="spctrl"></div>
<p>　　ICMP是网络层的补充，可以回送报文。用来检测网络是否通畅。 </p>
<div class="spctrl"></div>
<p>　　Ping命令就是发送ICMP的echo包，通过回送的echo relay进行网络测试。 </p>
<div class="spctrl"></div>
<p>　　ARP是正向<a href="http://baike.baidu.com/view/149421.htm" target="_blank"><font color="#136ec2">地址解析协议</font></a>，通过已知的IP，寻找对应主机的<a href="http://baike.baidu.com/view/69334.htm" target="_blank"><font color="#136ec2">MAC地址</font></a>。 </p>
<div class="spctrl"></div>
<p>　　RARP是反向地址解析协议，通过MAC地址确定IP地址。比如无盘工作站和DHCP服务。 </p>
<h3 class="headline-2 bk-sidecatalog-title"><a name="9_3"></a><span class="headline-content">传输层</span></h3>
<p>　　提供应用程序间的通信。其功能包括：一、格式化信息流；二、提供可靠传输。为实现后者，传输层协议规定接收端必须发回确认，并且假如分组丢失，必须重新发送。 </p>
<div class="spctrl"></div>
<p>　　传输层协议主要是：传输控制协议TCP(Transmission Control Protocol)和用户数据报协议UDP(User Datagram rotocol)。 </p>
<div class="spctrl"></div>
<p>　　TCP是面向连接的通信协议，通过<a href="http://baike.baidu.com/view/1003841.htm" target="_blank"><font color="#136ec2">三次握手</font></a>建立连接，通讯时完成时要拆除连接，由于TCP是面向连接的所以只能用于点对点的通讯。 </p>
<div class="spctrl"></div>
<p>　　TCP提供的是一种可靠的数据流服务，采用&#8220;带重传的肯定确认&#8221;技术来实现传输的可靠性。TCP还采用一种称为&#8220;滑动窗口&#8221;的方式进行流量控制，所谓窗口实际表示接收能力，用以限制发送方的发送速度。 </p>
<div class="spctrl"></div>
<p>　　UDP是面向无连接的通讯协议，UDP数据包括目的端口号和源端口号信息，由于通讯不需要连接，所以可以实现广播发送。 </p>
<div class="spctrl"></div>
<p>　　UDP通讯时不需要接收方确认，属于不可靠的传输，可能会出丢包现象，实际应用中要求在程序员编程验证。 </p>
<h3 class="headline-2 bk-sidecatalog-title"><a name="9_4"></a><span class="headline-content">应用层</span></h3>
<p>　　向用户提供一组常用的应用程序，比如电子邮件、文件传输访问、远程登录等。远程登录TELNET使用TELNET协议提供在网络其它主机上注册的接口。TELNET会话提供了基于字符的虚拟终端。文件传输访问FTP使用<a href="http://baike.baidu.com/view/1157060.htm" target="_blank"><font color="#136ec2">FTP协议</font></a>来提供网络内机器间的文件拷贝功能。 </p>
<div class="spctrl"></div>
<p>　　应用层一般是面向用户的服务。如FTP、TELNET、DNS、SMTP、POP3。 </p>
<div class="spctrl"></div>
<p>　　FTP(File Transmision Protocol)是文件传输协议，一般上传下载用FTP服务，数据端口是20H，控制端口是21H。 </p>
<div class="spctrl"></div>
<p>　　Telnet服务是用户远程登录服务，使用23H端口，使用明码传送，保密性差、简单方便。 </p>
<div class="spctrl"></div>
<p>　　DNS(Domain Name Service)是域名解析服务，提供域名到IP地址之间的转换。 </p>
<div class="spctrl"></div>
<p>　　SMTP(Simple Mail Transfer Protocol)是简单邮件传输协议，用来控制信件的发送、中转。　 </p>
<div class="spctrl"></div>
<p>　　POP3(Post Office Protocol 3)是邮局协议第3版本，用于接收邮件。 </p>
<div class="spctrl"></div>
<p>　　数据格式： </p>
<div class="spctrl"></div>
<p>　　数据帧：帧头＋IP数据包＋帧尾 (帧头包括源和目标主机MAC地址及类型,帧尾是校验字) </p>
<div class="spctrl"></div>
<p>　　IP数据包：IP头部＋TCP数据信息 (IP头包括源和目标主机IP地址、类型、生存期等) </p>
<div class="spctrl"></div>
<p>　　TCP数据信息：TCP头部+实际数据 (TCP头包括源和目标主机端口号、顺序号、确认号、校验字等) </p>
<div class="bpctrl"></div>
<h2 class="headline-1 bk-sidecatalog-title"><span class="text_edit editable-title" data-edit-id="7649:7649:10"><a class="nslog:1019" href="http://baike.baidu.com/view/7729.htm#">编辑本段</a></span><a name="10"></a><span class="headline-content">网络模型</span></h2>
<p>　　TCP/IP协议并不完全符合OSI的七层参考模型。传统的<a href="http://baike.baidu.com/view/1171987.htm" target="_blank"><font color="#136ec2">开放式系统</font></a>互连参考模型，是一种通信协议的7层抽象的参考模型,其中每一层执行某一特定任务。该模型的目的是使各种硬件在相同的层次上相互通信。这7层是:物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。而TCP/IP通讯协议采用了4层的层级结构，每一层都呼叫它的下一层所提供的网络来完成自己的需求。 </p>
<div class="spctrl"></div>
<p>　　 
<table class="table-view">
<tbody>
<tr>
<td width="100">OSI中的层 </td>
<td width="100">功能 </td>
<td width="100">TCP/IP协议族 </td></tr>
<tr>
<td width="100">应用层 </td>
<td width="100">文件传输，电子邮件，文件服务，虚拟终端 </td>
<td width="100">TFTP，HTTP，SNMP，FTP，SMTP，DNS，RIP，Telnet </td></tr>
<tr>
<td width="100">表示层 </td>
<td width="100">数据格式化，代码转换，数据加密 </td>
<td width="100">没有协议 </td></tr>
<tr>
<td width="100">会话层 </td>
<td width="100">解除或建立与别的接点的联系 </td>
<td width="100">没有协议 </td></tr>
<tr>
<td width="100">传输层 </td>
<td width="100">提供端对端的接口 </td>
<td width="100">TCP，UDP </td></tr>
<tr>
<td width="100">网络层 </td>
<td width="100">为数据包选择路由 </td>
<td width="100">IP，ICMP，OSPF，BGP，IGMP ，ARP，RARP</td></tr>
<tr>
<td width="100">数据链路层 </td>
<td width="100">传输有地址的帧以及错误检测功能 </td>
<td width="100">SLIP，CSLIP，PPP，MTU </td></tr>
<tr>
<td width="100">物理层 </td>
<td width="100">以二进制数据形式在物理媒体上传输数据 </td>
<td width="100">ISO2110，IEEE802，IEEE802.2 </td></tr></tbody></table></p>
<div class="spctrl"></div>
<p>　　数据链路层包括了硬件接口和协议ARP，RARP，这两个协议主要是用来建立送到物理层上的信息和接收从物理层上传来的信息； </p>
<div class="spctrl"></div>
<p>　　网络层中的协议主要有IP，ICMP，IGMP等，由于它包含了IP协议模块，所以它是所有基于TCP/IP协议网络的核心。在网络层中，IP模块完成大部分功能。ICMP和IGMP以及其他支持IP的协议帮助IP完成特定的任务，如传输差错控制信息以及主机/路由器之间的控制电文等。网络层掌管着网络中主机间的信息传输。 </p>
<div class="spctrl"></div>
<p>　　传输层上的主要协议是TCP和UDP。正如网络层控制着主机之间的数据传递，传输层控制着那些将要进入网络层的数据。两个协议就是它管理这些数据的两种方式：TCP是一个基于连接的协议；UDP则是面向无连接服务的管理方式的协议。 </p>
<div class="spctrl"></div>
<p>　　TCP/IP模型的主要缺点有： </p>
<div class="spctrl"></div>
<p>　　首先，该模型没有清楚地区分哪些是规范、哪些是实现；其次，TCP/IP模型的主机&#8212;网络层定义了网络层与数据链路层的接口，并不是常规意义上的一层，和接口层的区别是非常重要的，TCP/IP模型没有将它们区分开来。 </p>
<div class="bpctrl"></div>
<h2 class="headline-1 bk-sidecatalog-title"><span class="text_edit editable-title" data-edit-id="7649:7649:11"><a class="nslog:1019" href="http://baike.baidu.com/view/7729.htm#">编辑本段</a></span><a name="11"></a><span class="headline-content">协议测试</span></h2>
<p>　　全面的测试应包括局域网和互联网两个方面，因此应从局域网和互联网两个方面测试，以下是在实际工作中利用命令行测试TCP/IP配置步骤： </p>
<div class="spctrl"></div>
<p>　　1、 单击&#8220;开始&#8221;/&#8220;运行&#8221;，输入CMD按回车，打开命令提示符窗口。 </p>
<div class="spctrl"></div>
<p>　　2、 首先检查IP地址、子网掩码、<a href="http://baike.baidu.com/view/119302.htm" target="_blank"><font color="#136ec2">默认网关</font></a>、DNS服务器地址是否正确，输入命令ipconfig /all,按回车。此时显示了你的网络配置，观查是否正确。 </p>
<div class="spctrl"></div>
<p>　　3、 输入ping 127.0.0.1，观查网卡是否能转发数据，如果出现&#8220;Request timed out&#8221;，表明配置差错或网络有问题。 </p>
<div class="spctrl"></div>
<p>　　4、 Ping一个互联网地址，如ping 202.102.128.68,看是否有数据包传回，以验证与互联网的连接性。 </p>
<div class="spctrl"></div>
<p>　　5、 Ping 一个局域网地址，观查与它的连通性。 </p>
<div class="spctrl"></div>
<p>　　6、 用nslookup测试DNS解析是否正确，输入如nslookup ，查看是否能解析。 </p>
<div class="spctrl"></div>
<p>　　如果你的计算机通过了全部测试，则说明网络正常，否则网络可能有不同程度的问题。在此不展开详述。不过，要注意，在使用 ping命令时，有些公司会在其主机设置丢弃ICMP数据包，造成你的ping命令无法正常返回数据包，不防换个网站试试。 </p>
<div class="bpctrl"></div>
<h2 class="headline-1 bk-sidecatalog-title"><span class="text_edit editable-title" data-edit-id="7649:7649:12"><a class="nslog:1019" href="http://baike.baidu.com/view/7729.htm#">编辑本段</a></span><a name="12"></a><span class="headline-content">主要特点</span></h2>
<p>　　（1）开放的协议标准，可以免费使用，并且独立于特定的计算机硬件与操作系统； </p>
<div class="spctrl"></div>
<p>　　（2）独立于特定的网络硬件，可以运行在局域网、广域网，更适用于互联网中； </p>
<div class="spctrl"></div>
<p>　　（3）统一的网络地址分配方案，使得整个TCP/IP设备在网中都具有惟一的地址； </p>
<div class="spctrl"></div>
<p>　　（4）标准化的高层协议，可以提供多种可靠的用户服务。 </p>
<div class="bpctrl"></div>
<h2 class="headline-1 bk-sidecatalog-title"><span class="text_edit editable-title" data-edit-id="7649:7649:13"><a class="nslog:1019" href="http://baike.baidu.com/view/7729.htm#">编辑本段</a></span><a name="13"></a><span class="headline-content">协议优势</span></h2>
<p>　　在长期的发展过程中，IP逐渐取代其他网络。这里是一个简单的解释。IP传输通用数据。数据能够用于任何目的，并且能够很轻易地取代以前由专有数据网络传输的数据。下面是一个普通的过程： </p>
<div class="spctrl"></div>
<p>　　一个专有的网络开发出来用于特定目的。如果它工作很好，用户将接受它。 </p>
<div class="spctrl"></div>
<p>　　为了便利提供IP服务，经常用于访问电子邮件或者聊天，通常以某种方式通过专有网络隧道实现。隧道方式最初可能非常没有效率，因为电子邮件和聊天只需要很低的带宽。 </p>
<div class="spctrl"></div>
<p>　　通过一点点的投资IP 基础设施逐渐在专有数据网络周边出现。 </p>
<div class="spctrl"></div>
<p>　　用IP取代专有服务的需求出现，经常是一个用户要求。 </p>
<div class="spctrl"></div>
<p>　　IP替代品过程遍布整个因特网，这使IP替代品比最初的专有网络更加有价值（由于网络效应）。 </p>
<div class="spctrl"></div>
<p>　　专有网络受到压制。许多用户开始维护使用IP替代品的复制品。 </p>
<div class="spctrl"></div>
<p>　　IP包的间接开销很小，少于1%，这样在成本上非常有竞争性。人们开发了一种能够将IP带到专有网络上的大部分用户的不昂贵的传输媒介。 </p>
<div class="spctrl"></div>
<p>　　大多数用户为了削减开销，专有网络被取消。 </p>
<div class="bpctrl"></div>
<h2 class="headline-1 bk-sidecatalog-title"><span class="text_edit editable-title" data-edit-id="7649:7649:14"><a class="nslog:1019" href="http://baike.baidu.com/view/7729.htm#">编辑本段</a></span><a name="14"></a><span class="headline-content">协议重置</span></h2>
<p>　　在Windows XP的网络组件列表里，Internet 协议 (TCP/IP)的"卸载"按钮是灰色不可选状态。这是因为传输控制协议/Internet 协议 (TCP/IP) 堆栈是 Microsoft XP/ 2003 的核心组件(TCP/IP协议是Windows XP的默认协议),不能删除。所以Windows XP不允许卸载TCP/IP协议。如果在特殊情况下需要重新安装TCP/IP协议，如何操作？ </p>
<div class="spctrl"></div>
<p>　　解决方法 </p>
<div class="spctrl"></div>
<p>　　在这种情况下，如果需要重新安装 TCP/IP 以使 TCP/<sup><font color="#3366cc">[1]</font></sup><a name="ref_[1]"></a>IP 堆栈恢复为原始状态。可以使用 NetShell 实用程序重置 TCP/IP 堆栈，使其恢复到初次安装操作系统时的状态。具体操作如下： </p>
<div class="spctrl"></div>
<p>　　1、单击 开始 --&gt; 运行，输入 "CMD" 后单击 "确定"; </p>
<div class="spctrl"></div>
<p>　　2、在命令行模式输入命令 </p>
<div class="spctrl"></div>
<p>　　netsh int ip reset C:\resetlog.txt </p>
<div class="spctrl"></div>
<p>　　(其中，Resetlog.txt记录命令结果的日志文件，一定要指定，这里指定了Resetlog.txt 日志文件及完整路径。) </p>
<div class="spctrl"></div>
<p>　　运行结果可以查看C:\resetlog.txt (咨询中可根据用户实际操作情况提供) </p>
<div class="spctrl"></div>
<p>　　运行此命令的结果与删除并重新安装 TCP/IP 协议的效果相同。 </p>
<div class="spctrl"></div>
<p>　　注意 </p>
<div class="spctrl"></div>
<p>　　本操作具有一定的风险性，请在操作前备份重要数据，并根据操作熟练度酌情使用。 </p>
<div class="bpctrl"></div>
<h2 class="headline-1 bk-sidecatalog-title"><span class="text_edit editable-title" data-edit-id="7649:7649:15"><a class="nslog:1019" href="http://baike.baidu.com/view/7729.htm#">编辑本段</a></span><a name="15"></a><span class="headline-content">协议缺陷</span></h2>
<h3 class="headline-2 bk-sidecatalog-title"><a name="15_1"></a><span class="headline-content">网络地址不足</span></h3>
<p>　　传统的TCP/IP协议基于<a href="http://baike.baidu.com/view/21992.htm" target="_blank"><font color="#136ec2">IPV4</font></a> 属于<a href="http://baike.baidu.com/view/533978.htm" target="_blank"><font color="#136ec2">第二代互联网</font></a>技术，核心技术属于美国。它的最大问题是<strong>网络地址资源有限</strong>，从理论上讲，编址1600万个网络、40亿台主机。但采用A、B、C三类编址方式后，可用的网络地址和主机地址的数目大打折扣，以至目前的IP地址已经枯竭。其中<a href="http://baike.baidu.com/view/595143.htm" target="_blank"><font color="#136ec2">北美</font></a>占有3/4，约30亿个，而人口最多的亚洲只有不到4亿个，<a href="http://baike.baidu.com/view/61891.htm" target="_blank"><font color="#136ec2">中国</font></a>截止2010年6月IPv4地址数量达到2.5亿，落后于4.2亿网民的需求。虽然用动态IP及Nat地址转换等技术实现了一些缓冲，但IPV4地址枯竭已经成为不争的事实。在此，专家提出IPV6的互联网技术，也正在推行，但IPV4的使用过度到IPV6需要很长的一段过度期。 </p>
<h3 class="headline-2 bk-sidecatalog-title"><a name="15_2"></a><span class="headline-content">传输能力不足</span></h3>
<p>　　传统的TCP/IP协议基于电话宽带 以及<a href="http://baike.baidu.com/view/848.htm" target="_blank"><font color="#136ec2">以太网</font></a>的电器特性而制定的，其分包原则与检验占用了数据包很大的一部分比例造成了传输效率低，现在网络正向着全<a href="http://baike.baidu.com/view/2058721.htm" target="_blank"><font color="#136ec2">光纤网络</font></a>和超高速以太网方向发展，TCP/IP协议不能满足其发展需要。</p><img src ="http://www.blogjava.net/freeman1984/aggbug/351043.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-05-26 09:59 <a href="http://www.blogjava.net/freeman1984/archive/2011/05/26/351043.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在java中使用TreeMap进行中文排序(转)</title><link>http://www.blogjava.net/freeman1984/archive/2011/05/20/350667.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 20 May 2011 03:36:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/05/20/350667.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/350667.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/05/20/350667.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/350667.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/350667.html</trackback:ping><description><![CDATA[<div>&nbsp;<wbr>最近工作遇到需要按一个model中不同的列进行排序的问题，查了一下JDK API文档，发现，java中可以排序的工具类和接口共有五个SortedMap 、SortedSet、TreeMap 、TreeSet和Collections，由于我要排序的是一系列model，所以，最后使用了TreeMap对象，而且TreeMap到最后的处理比较自由，可以直接返回TreeMap对象，也可以返回model的一个Collection对象。其它几个类的用法其实都是大同小异，如果java基础较好，看一下API文档很容易明白，只是Collection中需要显式调用sort()方法而已。 
<p>&nbsp;<wbr>&nbsp;<wbr> 写理论的东西或者深入的东西就会太多了，而且让人会看得比较烦，这里讲求实用，就不多说了，直接入正体，基本的排序代码如下：<br />&nbsp;<wbr> package ChineseSort;</p>
<p>import java.util.Collection;</p>
<p>import java.util.Iterator;</p>
<p>import java.util.SortedMap;</p>
<p>import java.util.TreeMap;</p>
<p>public class TestSort {</p>
<p>public static void main(String[] args) {</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> // TODO Auto-generated method stub&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr></p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> TreeMap map = new TreeMap();&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr></p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> for(int i=0; i&lt;10; i++) {</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> String&nbsp;<wbr> s = ""+(int)(Math.random()*1000);</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> map.put(s,s);</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> map.put("abcd","abcd");</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> map.put("Abc", "Abc");</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> map.put("bbb","bbb");</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> map.put("BBBB", "BBBB");</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> map.put("北京","北京");</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> map.put("中国","中国");</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> map.put("上海", "上海");</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> map.put("厦门", "厦门");</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> map.put("香港", "香港");</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> map.put("碑海", "碑海");</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> Collection col = map.values();</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> Iterator it = col.iterator();</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> while(it.hasNext()) {</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> System.out.println(it.next());</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> }</p>
<p>}</p>
<p>}</p>
<p>&nbsp;<wbr>&nbsp;<wbr> 代码就不多作解释了，一看就明白，开始放进去10个整数随机数，然后是英文，然后是中文。运行结果如下：</p>
<p>132</p>
<p>205</p>
<p>287</p>
<p>295</p>
<p>399</p>
<p>410</p>
<p>411</p>
<p>464</p>
<p>670</p>
<p>73</p>
<p>Abc</p>
<p>BBBB</p>
<p>abcd</p>
<p>bbb</p>
<p>上海</p>
<p>中国</p>
<p>北京</p>
<p>厦门</p>
<p>碑海</p>
<p>香港</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 注意，这里的数字排序正常，而英文排序是区分大小写的，这个也是正常的，因为ASCII码中小写字母比大写字母靠后，中文排序则明显的不正确，碑和北明显应该在一起的，而且应该在最前面。这个主要是java中使用中文编码GB2312或者JBK时，char型转换成int型得过程出现了比较大的偏差，很多文章介绍过了，大家可以去网上找一下，这里不多说了，直接寻找解决方案。</p>
<p>&nbsp;<wbr>&nbsp;<wbr> Java中之所以出现偏差，主要是compare方法的问题，所以这里自己实现Comparator接口，而国际化的问题，使用Collator类来解决。这里先解决中文问题,代码如下：</p>
<p>package ChineseSort;</p>
<p>import java.text.CollationKey;</p>
<p>import java.text.Collator;</p>
<p>import java.util.Comparator;</p>
<p>public class CollatorComparator implements Comparator {</p>
<p>Collator collator = Collator.getInstance();</p>
<p>public int compare(Object element1, Object element2) {</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> CollationKey key1 = collator.getCollationKey(element1.toString());</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> CollationKey key2 = collator.getCollationKey(element2.toString());</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> return key1.compareTo(key2);</p>
<p>}</p>
<p>}</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>同时修改我们前面完成的TestSort类，找到TreeMap map = new TreeMap();</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 修改为</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> CollatorComparator comparator = new CollatorComparator();</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> TreeMap map = new TreeMap();</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 再次运行该类，运行结果如下：</p>
<p>325</p>
<p>62</p>
<p>653</p>
<p>72</p>
<p>730</p>
<p>757</p>
<p>874</p>
<p>895</p>
<p>909</p>
<p>921</p>
<p>Abc</p>
<p>abcd</p>
<p>bbb</p>
<p>BBBB</p>
<p>碑海</p>
<p>北京</p>
<p>上海</p>
<p>厦门</p>
<p>香港</p>
<p>中国</p>
<p>&nbsp;<wbr>&nbsp;<wbr> 此时可以看到中文的排序已经完成正常。如果想不让英文区分大小写，则修改CollatorComparator类，找到</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> element1.toString()</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 修改为：</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> element1.toString().toLowerCase()</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 当然你改成转换成大写的也无所谓了，当然element2.toString()也要同时修改为element2.toString().toLowerCase()。再次运行结果如下：</p>
<p>207</p>
<p>353</p>
<p>656</p>
<p>659</p>
<p>770</p>
<p>789</p>
<p>857</p>
<p>861</p>
<p>931</p>
<p>984</p>
<p>Abc</p>
<p>abcd</p>
<p>bbb</p>
<p>BBBB</p>
<p>碑海</p>
<p>北京</p>
<p>上海</p>
<p>厦门</p>
<p>香港</p>
<p>中国</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 现在可以看到，排序已经完全符合我们的要求了。如果要反向排序也很容易，遍历的时候倒过来，或者你写两个Comparator的实现类，正向的排序就像我们前面所写的，反向排序就将return key1.compareTo(key2);修改成return -key1.compareTo(key2);，加了个负号，这里你可以直接加个符号看看效果，结果我就不写了，肯定中国是Number One。我还真没找到TreeMap里直接反向的方法，谁看到了告诉我。</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 最后一些要说明的，这里我就不再写实现的代码了，就是我们要实现的是根据model中的一个列进行排序，而我们测试代码只是简单的一些值，这个容易，遍历所有model，把要排序的列值取出来作为TreeMap的key，然后model放进去作为value就行了，这个很简单，如果想写成稍微通用点的，就使用反射机制，把取值方法封装一下就行了，然后把model对象和方法名扔进去就行了。至于value值重复的问题，也好办，只要value相同只要不是多列同时作为排序的键，那么他们之间的前后顺序无所谓，判断一下当前Map中是否含有该key值，存在，则新的key做成value+longtime就行了，就是加个时间戳（感觉用时间戳比较方便，其它的能区分的办法也行啦）。至于多列的排序，其实也容易，按照列的前后顺序firstvalue+secondvalue+......组成key放到TreeMap里照样OK J 方便吧。<br /></p></div><img src ="http://www.blogjava.net/freeman1984/aggbug/350667.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-05-20 11:36 <a href="http://www.blogjava.net/freeman1984/archive/2011/05/20/350667.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>el2</title><link>http://www.blogjava.net/freeman1984/archive/2011/04/09/347964.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Sat, 09 Apr 2011 11:06:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/04/09/347964.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/347964.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/04/09/347964.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/347964.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/347964.html</trackback:ping><description><![CDATA[<p>期待已久的日子即将到来: 最新版<a href="http://fatkun.com/goto/http://java.sun.com/products/jsp/" rel="nofollow" target="_blank">JavaServer Pages (JSP)</a>2.0 规范即将和其他的J2EE 1.4一同发布。新的JSP版本有一个新的飞跃，采用了新的方式：由于新的语言表达式（Expression Language，以下简称为EL）和JSP标准标签库（JSP Standard Tag Library ,以下简称为JSTL）这两种新的方式，在页面中不需要用java,对于开发一般的应用来说，重用代码变得更加容易。更具体来说，JSP 2.0带来了以下的优点：</p>
<ul>
    <li>首次被JSTL 1.0引入的EL现在被合并到JSP规范中，就像应用template text一样地使用所有的标准的和定制的组件。
    <li>新的EL已经被扩展，具备一个函数调用机制，JSTL1.1整合了一系列经常需要使用的函数。
    <li>新增加的变量和servlet 规范定义的错误处理机制被更好地组织起来。通过新增加的变量，JSP error pages 现在可以提供更多的错误信息。
    <li>容器因为更加严格的语法检查可以更容易地找出发生的错误。
    <li>所有的J2EE 1.4规范（包括JSP 2.0 和 Servlet 2.4），为了声明部署的规则描述而应用了XML schema。这样的好处之一是你现在可以通过任何顺序列出web.xml文件中的描述。JSP 2.0也增加了一些新的配置选项用于部署描述，允许通过全局的配置来代替基于每页的配置。
    <li>由于更具伸缩性的规则和新的自定义action element，现在就像编写XML文件一样，编写JSP页面变得更加容易。
    <li>定制的标签库现在可以开发成一系列的标签文件（具有JSP元素的文本文件），标签处理器可以使用新的、简化的标签处理器的API。与此同时，新规范加入了一些新的特性，比如：支持在jsp页面上显示动态属性列表和可执行片断属性。 </li>
</ul>
<p>在众多的书籍中，这是头一个讲解JSP 2.0新特性的文章。在这一部分，我们将看到和EL相关的信息，其他的新特性留到后面。在这里我假定读者已经熟悉JSP 1.2，而且至少听说过JSTL。</p>
<p>你可能对这本第三版的《JavaServer Pages》感兴趣。这本书中，我尽可能在细节上讲述所有的内容，而且并不认为你对JSP或者JSTL了解一切。这本书预计在2003年12月 出版，但是你现在可以在<a href="http://fatkun.com/goto/http://www.amazon.com/" rel="nofollow" target="_blank">http://www.amazon.com</a>、Barnes&amp;Noble，或者其他在线书店预订。</p>
<p>EL(The Expression Language)</p>
<p>如果过去使用过JSTL，那么你可能已经熟悉 了EL。EL在JSTL 1.0规范中被引入，用来在运行期间对Java表达式中action element属性赋值提供另一种选择。当JSTL EL已经非常迅速的流行起来情况下，还是存在一个问题： JSTL EL 表达式仅仅可以与JSTL和custom action一起使用，怎样才能使用非标准API对EL表达式求值？</p>
<p>JSP 2.0中,JSP容器自己可以理解EL表达式。这使你在所有过去只能应用Java表达式的地方应用EL表达式成为可能，比如：标准和定制action的属性值，模板文本。</p>
<p>在我们看具体的例子前，让我们更进一步的看看 什么是EL。EL是从JavaScript中获得启发的一种语言，XPath(一种用来访问XML文档的语言)，但是EL在对变量的null值和执行更多 数据类型的自动类型转换的处理上更加宽松。这些新特性对于web应用非常重要，在这些应用中输入通常通过html表单的request parameter来得到。这些参数可能仅仅在某些请求下才能体现出来，而且浏览器经常将request parameter作为文本发送，然而应用程序经常需要把他们作为数字类型、布尔类型（true 或者 false）来使用。通过EL，你根本就很少需要关心缺少某些参数的值或者类型转换。</p>
<p>一个EL表达式包含变量和操作符。任何存储在某个JSP作用范围(如：page、 request、session、application)的bean能被作为一个EL变量来使用。另外，EL支持以下预定义的变量：</p>
<table border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td>变量名称</td>
            <td>说明</td>
        </tr>
        <tr>
            <td valign="top">pageScope</td>
            <td>一个包含所有page scope范围的变量集合 (a java.util.Map)</td>
        </tr>
        <tr>
            <td valign="top">requestScope</td>
            <td>一个包含所有request scope范围的变量集合 (a java.util.Map)</td>
        </tr>
        <tr>
            <td valign="top">sessionScope</td>
            <td>一个包含所有session scope范围的变量集合 (a java.util.Map)</td>
        </tr>
        <tr>
            <td valign="top">applicationScope</td>
            <td>一个包含所有application scope范围的变量集合 (a java.util.Map)</td>
        </tr>
        <tr>
            <td valign="top">param</td>
            <td>一个包含所有请求参数的集合 (a java.util.Map)，通过每个参数对应一个String值的方式赋值</td>
        </tr>
        <tr>
            <td valign="top">paramValues</td>
            <td>一个包含所有请求参数的集合 (a java.util.Map)，通过每个参数对应一个String数组的方式赋值</td>
        </tr>
        <tr>
            <td valign="top">header</td>
            <td>一个包含所有请求的头信息的集合， (a java.util.Map) ,通过每个头信息对应一个String值的方式赋值</td>
        </tr>
        <tr>
            <td valign="top">headerValues</td>
            <td>一个包含所有请求的头信息的集合 (a java.util.Map) ，通过每个头信息的值都保存在一个String数组的方式赋值</td>
        </tr>
        <tr>
            <td valign="top">cookie</td>
            <td>一个包含所有请求的 cookie集合 (a java.util.Map)， &nbsp;&nbsp; 通过每一个cookie（javax.servlet.http.Cookie）对应一个cookie值的方式赋值</td>
        </tr>
        <tr>
            <td valign="top">initParam</td>
            <td>一个包含所有应用程序初始化参数的集合(a java.util.Map) ，通过每个参数分别对应一个String值的方式赋值</td>
        </tr>
        <tr>
            <td valign="top">pageContext</td>
            <td>一个javax.servlet.jsp.PageContext类的实例, 用来提供访问不同的请求数据</td>
        </tr>
    </tbody>
</table>
<p>操作符描述了你对变量所期望的操作。如果你之前曾经使用过任何编程语言的话，在EL表达式中所使用的操作符对你来说可能看起来很熟悉。因为它们和那些在大多数语言中所支持的操作符一样。</p>
<table border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td>Operator</td>
            <td>Description</td>
        </tr>
        <tr>
            <td valign="top">.</td>
            <td>访问一个bean属性或者 Map entry</td>
        </tr>
        <tr>
            <td valign="top">[]</td>
            <td>访问一个数组或者链表元素</td>
        </tr>
        <tr>
            <td valign="top">()</td>
            <td>对子表达式分组，用来改变赋值顺序</td>
        </tr>
        <tr>
            <td valign="top">? :</td>
            <td>条件语句，比如: 条件 ? ifTrue : ifFalse.如果条件为真，表达式值为前者，反之为后者</td>
        </tr>
        <tr>
            <td valign="top">+</td>
            <td>数学运算符，加操作</td>
        </tr>
        <tr>
            <td valign="top">-</td>
            <td>数学运算符，减操作或者对一个值取反</td>
        </tr>
        <tr>
            <td valign="top">*</td>
            <td>数学运算符，乘操作</td>
        </tr>
        <tr>
            <td valign="top">/ or div</td>
            <td>数学运算符，除操作</td>
        </tr>
        <tr>
            <td valign="top">% or mod</td>
            <td>数学运算符，模操作(取余)</td>
        </tr>
        <tr>
            <td valign="top">== or eq</td>
            <td>逻辑运算符，判断符号左右两端是否相等，如果相等返回true，否则返回false</td>
        </tr>
        <tr>
            <td valign="top">!= or ne</td>
            <td>逻辑运算符，判断符号左右两端是否不相等，如果不相等返回true，否则返回false</td>
        </tr>
        <tr>
            <td valign="top">&lt; or lt</td>
            <td>逻辑运算符，判断符号左边是否小于右边，如果小于返回true，否则返回false</td>
        </tr>
        <tr>
            <td valign="top">&gt; or gt</td>
            <td>逻辑运算符，判断符号左边是否大于右边，如果大于返回true，否则返回false</td>
        </tr>
        <tr>
            <td valign="top">&lt;= or le</td>
            <td>逻辑运算符，判断符号左边是否小于或者等于右边，如果小于或者等于返回true，否则返回false</td>
        </tr>
        <tr>
            <td valign="top">&gt;= or ge</td>
            <td>逻辑运算符，判断符号左边是否大于或者等于右边，如果大于或者等于返回true，否则返回false</td>
        </tr>
        <tr>
            <td valign="top">&amp;&amp; or and</td>
            <td>逻辑运算符，与操作赋。如果左右两边同为true返回true，否则返回false</td>
        </tr>
        <tr>
            <td valign="top">|| or or</td>
            <td>逻辑运算符，或操作赋。如果左右两边有任何一边为true返回true，否则返回false</td>
        </tr>
        <tr>
            <td valign="top">! or not</td>
            <td>逻辑运算符，非操作赋。如果对true取运算返回false，否则返回true</td>
        </tr>
        <tr>
            <td valign="top">empty</td>
            <td>用来对一个空变量值进行判断: null、一个空String、空数组、 空Map、没有条目的Collection集合</td>
        </tr>
        <tr>
            <td valign="top">func(args)</td>
            <td>调用方法, func是方法名，args是参数，可以没有，或者有一个、多个参数.参数间用逗号隔开</td>
        </tr>
    </tbody>
</table>
<p>一个EL表达式可以包含：数字、文本（在单引号或者双引号之间）、布尔值、null值。</p>
<p>因为一个EL表达式可以出现在静态文本出现的 地方，因此你必须告诉JSP容器它应该被当作一个EL表达式来处理。你可以通过使用定界符来做到这一点。一个EL表达式总是以&#8221;${ }&#8221;来标记（一个&#8220;$&#8221;符号和一个左花括号,右花括号）。这里有一个EL表达式，它将一个命名为amount的变量加5：</p>
<p>${amount + 5}</p>
<p>如果你想要将5加到一个bean的property上，可以使用property访问操作符：</p>
<p>${order.amount + 5}</p>
<p>在当前这个指定的bean或者collection集合中，Property访问操作符（一个&#8220;.&#8220;符号）告诉EL去寻找名字为amount的property。</p>
<p>${order['amount'] + 5}</p>
<p>在[]之间的值必须是一个property的名字（就像上面的例子中那样）或者是一个保存property名字的变量（或者是一个完整的EL子表达式）。</p>
<p>EL表达式可以被用来赋值给任何标准的或者定制的JSP行为属性（action attribute），这些行为属性被标记为可以接受动态值（或者请求期间的属性值，就象它被正式调用一样）：</p>
<p>&lt;c:out value=&#8221;${order.amount + 5}&#8221;/&gt;</p>
<p>在JSP 2.0之前，你不得不使用Java表达式去给一个属性动态赋值。在过去的很多年中，这已经成为语法混乱的一个普遍根源。</p>
<p>最后，EL表达式可以在页面中和模板直接混合使用。当你生成HTML并且需要设置一个动态值给一个属性的时候，这非常方便：</p>
<p>&lt;input name=&#8221;firstName&#8221; value=&#8221;${customer.firstName}&#8221;&gt;</p>
<p>JSP 1.2中，你不得不使用JSTL的&lt;c:out&gt;来实现同样的事情，最后把各种不同类型的元素混合起来，这导致程序理解起来非常的困难：</p>
<p>&lt;input name=&#8221;firstName&#8221;</p>
<p>value=&#8221;&lt;c:out value=&#8221;${customer.firstName}&#8221;/&gt;&#8221; &gt;</p>
<p>新JSTL 1.1 Tag Library 标识符</p>
<p>JSTL1.1发布的是一个初级的版本，主要 目的是用来整合JSTL和JSP2.0 。最明显的变化是JSTL1.0 &#8220;孪生函数库&#8221;（一组库用来接受EL表达式，另外一组用来接受JAVA表达式），而它们已经被一组既可以用于EL表达式也可以用于JAVA表达式的函数库 所代替。</p>
<p>在JSTL 1.1中使用以下标识符:</p>
<table border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td>库</td>
            <td>URI</td>
            <td>前缀</td>
        </tr>
        <tr>
            <td>Core</td>
            <td>http://java.sun.com/jsp/jstl/core</td>
            <td>c</td>
        </tr>
        <tr>
            <td>XML processing</td>
            <td>http://java.sun.com/jsp/jstl/xml</td>
            <td>x</td>
        </tr>
        <tr>
            <td>I18N formatting</td>
            <td>http://java.sun.com/jsp/jstl/fmt</td>
            <td>fmt</td>
        </tr>
        <tr>
            <td>Database access</td>
            <td>http://java.sun.com/jsp/jstl/sql</td>
            <td>sql</td>
        </tr>
        <tr>
            <td>Functions</td>
            <td>http://java.sun.com/jsp/jstl/functions</td>
            <td>fn</td>
        </tr>
    </tbody>
</table>
<p>如果你曾经使用过JSTL1.0，你可能会注意到新的标识符和旧的EL库标试符一模一样，除了加入了&#8220;/jsp path&#8221; element。你也可能注意到在JSTL1.1中有一个库，包含了EL的函数。我们稍后就会看到。</p>
<p>一个新的EL操作符</p>
<p>在JSP页面中一个非常普遍的需求就是：当某 个条件为真时，要在网页中包含一些文字。在JSP1.2和JSTL1.1中，用具有代表性的&lt;c:if&gt;来实现，但是这样做非常繁琐。 JSP2.0增加了一个新的条件操作符用于EL，以更加优雅的方式来处理这样的情况。这个条件操作符存在于很多编程语言中（比 如：Java,C,JavaScript）,因此你可能以前就见过它。它判断一个布尔的条件，当条件为真或者假时，分别取不同的结果。</p>
<p>一个能清楚说明它如何工作的例子：</p>
<p>&lt;select name=&#8221;artist&#8221;&gt;</p>
<p>&lt;option value=&#8221;1&#8243; ${param.artist == 1 ? &#8216;selected&#8217; : &#8221;}&gt;</p>
<p>Vesica Pisces</p>
<p>&lt;option value=&#8221;2&#8243; ${param.artist == 2 ? &#8216;selected&#8217; : &#8221;}&gt;</p>
<p>Cortical Control</p>
<p>&lt;option value=&#8221;3&#8243; ${param.artist == 3 ? &#8216;selected&#8217; : &#8221;}&gt;</p>
<p>Vida Vierra</p>
<p>&lt;/select&gt;</p>
<p>在这里，我使用了EL表达式和条件操作符来选 择是否包含 html 中的 &#8220;selected&#8221;属性，只有符合条件的 &#8220;option&#8221; 才被添加 &#8220;selected&#8221; 属性。如果条件（param.artist==1）为真时，前面的&#8220;selected&#8221; 才被添加到网页中；否则就添加后面的（在这里是空字符串 &#8216;&#8217;）到页面中。</p>
<p>EL函数</p>
<p>当EL从JSTL规范中移到JSP规范中，它使用了一个如何进行函数调用的技巧。这个EL函数语法非常简单：方法名，紧接着在圆括号中有一组参数：&lt;%@ taglib prefix=&#8221;fn&#8221;</p>
<p>uri=&#8221;http://java.sun.com/jsp/jstl/functions&#8221; %&gt;</p>
<p>${fn:length(myCollection)}</p>
<p>这是一个属于标签库中的函数,并且函数名字在页面中所包含的前缀要指定taglib库。在这个例子中，我使用了前缀fn,这是JSTL function库默认的前缀。</p>
<p>标签库描述符（Tag Library Descriptor,TLD）将函数名称映射到一个由JAVA实现的静态方法中：&lt;function&gt;</p>
<p>&lt;description&gt;</p>
<p>Returns the number of items in a collection or the number of characters in a string.</p>
<p>&lt;/description&gt;</p>
<p>&lt;name&gt;length&lt;/name&gt;</p>
<p>&lt;function-class&gt;</p>
<p>org.apache.taglibs.standard.functions.Functions</p>
<p>&lt;/function-class&gt;</p>
<p>&lt;function-signature&gt;</p>
<p>int length(java.lang.Object)</p>
<p>&lt;/function-signature&gt;</p>
<p>&lt;/function&gt;</p>
<p>在这里最有趣的element 是&lt;function-signature&gt;。它包含一个函数返回类型的声明，静态的方法的名字，在圆括号中声明该方法所有参数的类型（可以 没有参数或者有多个，参数间用逗号间隔开）。返回值类型和参数类型必须是java的原始类型（Object）或者是其他合法类型。</p>
<p>这个静态方法 length()在Jakarta Taglibs标准库中用类似于下面的代码实现的：</p>
<div class="wp_syntax">
<table>
    <tbody>
        <tr>
            <td class="line_numbers">
            <pre>1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            23
            24
            25
            26
            27
            28
            29
            30
            31
            32
            33
            34
            35
            36
            37
            38
            39
            40
            41
            42
            43
            44
            45
            46
            47
            48
            49
            50
            51
            52
            53
            54
            55
            56
            57
            58
            59
            60
            61
            62
            63
            64
            65
            66
            67
            68
            69
            </pre>
            </td>
            <td class="code">
            <pre style="font-family: monospace" class="java"><span style="color: #000000; font-weight: bold">public</span> <span style="color: #000000; font-weight: bold">static</span> <span style="color: #000066; font-weight: bold">int</span> length<span style="color: #009900">(</span><span style="color: #003399">Object</span> obj<span style="color: #009900">)</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">throws</span> JspTagException <span style="color: #009900">{</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">if</span> <span style="color: #009900">(</span>obj <span style="color: #339933">==</span> <span style="color: #000066; font-weight: bold">null</span><span style="color: #009900">)</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">return</span> <span style="color: #cc66cc">0</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">if</span> <span style="color: #009900">(</span>obj <span style="color: #000000; font-weight: bold">instanceof</span> <span style="color: #003399">String</span><span style="color: #009900">)</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">return</span> <span style="color: #009900">(</span><span style="color: #009900">(</span><span style="color: #003399">String</span><span style="color: #009900">)</span>obj<span style="color: #009900">)</span>.<span style="color: #006633">length</span><span style="color: #009900">(</span><span style="color: #009900">)</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">if</span> <span style="color: #009900">(</span>obj <span style="color: #000000; font-weight: bold">instanceof</span> <span style="color: #003399">Collection</span><span style="color: #009900">)</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">return</span> <span style="color: #009900">(</span><span style="color: #009900">(</span><span style="color: #003399">Collection</span><span style="color: #009900">)</span>obj<span style="color: #009900">)</span>.<span style="color: #006633">size</span><span style="color: #009900">(</span><span style="color: #009900">)</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">if</span> <span style="color: #009900">(</span>obj <span style="color: #000000; font-weight: bold">instanceof</span> <span style="color: #003399">Map</span><span style="color: #009900">)</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">return</span> <span style="color: #009900">(</span><span style="color: #009900">(</span><span style="color: #003399">Map</span><span style="color: #009900">)</span>obj<span style="color: #009900">)</span>.<span style="color: #006633">size</span><span style="color: #009900">(</span><span style="color: #009900">)</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #000066; font-weight: bold">int</span> count <span style="color: #339933">=</span> <span style="color: #cc66cc">0</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">if</span> <span style="color: #009900">(</span>obj <span style="color: #000000; font-weight: bold">instanceof</span> <span style="color: #003399">Iterator</span><span style="color: #009900">)</span> <span style="color: #009900">{</span>
            &nbsp;
            <span style="color: #003399">Iterator</span> iter <span style="color: #339933">=</span> <span style="color: #009900">(</span><span style="color: #003399">Iterator</span><span style="color: #009900">)</span> obj<span style="color: #339933">;</span>
            &nbsp;
            count <span style="color: #339933">=</span> <span style="color: #cc66cc">0</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">while</span> <span style="color: #009900">(</span>iter.<span style="color: #006633">hasNext</span><span style="color: #009900">(</span><span style="color: #009900">)</span><span style="color: #009900">)</span> <span style="color: #009900">{</span>
            &nbsp;
            count<span style="color: #339933">++;</span>
            &nbsp;
            iter.<span style="color: #006633">next</span><span style="color: #009900">(</span><span style="color: #009900">)</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #009900">}</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">return</span> count<span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #009900">}</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">if</span> <span style="color: #009900">(</span>obj <span style="color: #000000; font-weight: bold">instanceof</span> <span style="color: #003399">Enumeration</span><span style="color: #009900">)</span> <span style="color: #009900">{</span>
            &nbsp;
            <span style="color: #003399">Enumeration</span> <span style="color: #000000; font-weight: bold">enum</span> <span style="color: #339933">=</span> <span style="color: #009900">(</span><span style="color: #003399">Enumeration</span><span style="color: #009900">)</span> obj<span style="color: #339933">;</span>
            &nbsp;
            count <span style="color: #339933">=</span> <span style="color: #cc66cc">0</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">while</span> <span style="color: #009900">(</span><span style="color: #000000; font-weight: bold">enum</span>.<span style="color: #006633">hasMoreElements</span><span style="color: #009900">(</span><span style="color: #009900">)</span><span style="color: #009900">)</span> <span style="color: #009900">{</span>
            &nbsp;
            count<span style="color: #339933">++;</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">enum</span>.<span style="color: #006633">nextElement</span><span style="color: #009900">(</span><span style="color: #009900">)</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #009900">}</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">return</span> count<span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #009900">}</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">try</span> <span style="color: #009900">{</span>
            &nbsp;
            count <span style="color: #339933">=</span> <span style="color: #003399">Array</span>.<span style="color: #006633">getLength</span><span style="color: #009900">(</span>obj<span style="color: #009900">)</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">return</span> count<span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #009900">}</span> <span style="color: #000000; font-weight: bold">catch</span> <span style="color: #009900">(</span><span style="color: #003399">IllegalArgumentException</span> ex<span style="color: #009900">)</span> <span style="color: #009900">{</span><span style="color: #009900">}</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">throw</span> <span style="color: #000000; font-weight: bold">new</span> JspTagException<span style="color: #009900">(</span><span style="color: #0000ff">"Unsupported type"</span><span style="color: #009900">)</span><span style="color: #009900">)</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #009900">}</span></pre>
            </td>
        </tr>
    </tbody>
</table>
</div>
<p>就像你所看到的，在那里没有什么出奇的地方。它是一个常规的静态方法，这个函数中通过对运行期中的参数类别的判断，找出参数的长度。</p>
<p>除了在这个方法中使用的length()方法，JSTL1.1标签库还包含了许多其它经常使用的函数：</p>
<table border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td>函数</td>
            <td>描述</td>
        </tr>
        <tr>
            <td valign="top">fn:contains(string, substring)</td>
            <td>如果参数string中包含参数substring，返回true</td>
        </tr>
        <tr>
            <td valign="top">fn:containsIgnoreCase(string, substring)</td>
            <td>如果参数string中包含参数substring（忽略大小写），返回true</td>
        </tr>
        <tr>
            <td valign="top">fn:endsWith(string, suffix)</td>
            <td>如果参数 string 以参数suffix结尾，返回true</td>
        </tr>
        <tr>
            <td valign="top">fn:escapeXml(string)</td>
            <td>将有特殊意义的XML (和HTML)转换为对应的XML character entity code，并返回</td>
        </tr>
        <tr>
            <td valign="top">fn:indexOf(string, substring)</td>
            <td>返回参数substring在参数string中第一次出现的位置</td>
        </tr>
        <tr>
            <td valign="top">fn:join(array, separator)</td>
            <td>将一个给定的数组array用给定的间隔符separator串在一起，组成一个新的字符串并返回。</td>
        </tr>
        <tr>
            <td valign="top">fn:length(item)</td>
            <td>返回参数item中包含元素的数量。参数Item类型是数组、collection或者String。如果是String类型,返回值是String中的字符数。</td>
        </tr>
        <tr>
            <td valign="top">fn:replace(string, before, after)</td>
            <td valign="top">返回一个String对象。用参数after字符串替换参数string中所有出现参数before字符串的地方，并返回替换后的结果</td>
        </tr>
        <tr>
            <td valign="top">fn:split(string, separator)</td>
            <td>返回一个数组，以参数separator 为分割符分割参数string，分割后的每一部分就是数组的一个元素</td>
        </tr>
        <tr>
            <td valign="top">fn:startsWith(string, prefix)</td>
            <td>如果参数string以参数prefix开头，返回true</td>
        </tr>
        <tr>
            <td valign="top">fn:substring(string, begin, end)</td>
            <td>返回参数string部分字符串, 从参数begin开始到参数end位置，包括end位置的字符</td>
        </tr>
        <tr>
            <td valign="top">fn:substringAfter(string, substring)</td>
            <td>返回参数substring在参数string中后面的那一部分字符串</td>
        </tr>
        <tr>
            <td valign="top">fn:substringBefore(string, substring)</td>
            <td>返回参数substring在参数string中前面的那一部分字符串</td>
        </tr>
        <tr>
            <td valign="top">fn:toLowerCase(string)</td>
            <td>将参数string所有的字符变为小写，并将其返回</td>
        </tr>
        <tr>
            <td valign="top">fn:toUpperCase(string)</td>
            <td>将参数string所有的字符变为大写，并将其返回</td>
        </tr>
        <tr>
            <td valign="top">fn:trim(string)</td>
            <td>去除参数string 首尾的空格，并将其返回</td>
        </tr>
    </tbody>
</table>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/freeman1984/aggbug/347964.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-04-09 19:06 <a href="http://www.blogjava.net/freeman1984/archive/2011/04/09/347964.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>web和jstl</title><link>http://www.blogjava.net/freeman1984/archive/2011/04/09/347931.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Sat, 09 Apr 2011 02:26:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/04/09/347931.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/347931.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/04/09/347931.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/347931.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/347931.html</trackback:ping><description><![CDATA[<p>关于taglib中tld定义的说明</p>
<p>在JSP中使用标签是很平常的事情，在制作自定义变迁时，通常都需要写tld文件来定义变迁的各种属性，对应的java类，前缀等等。标签与tld文件紧紧相连，那么，到底应该怎么放置tld文件？在web.xml中怎么定义tld文件的位置？</p>
<p>以下是具体的分析</p>
<p>&#216;&nbsp; Taglib的使用：</p>
<p>首先是在头部申明taglib, uri必须是web.xml定义的，或者是原始tld文件定义的。</p>
<p>&lt;%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %&gt;</p>
<p>&lt;%@ taglib prefix="ex" uri="/jstl-examples-taglib" %&gt;</p>
<p>&nbsp;</p>
<p>然后便可以在jsp页面中通过prefix使用相应的标签</p>
<p>&lt;c:import varReader="reader" url="${filepath}"&gt;</p>
<p>&nbsp; &lt;ex:escapeHtml reader="${reader}"/&gt;</p>
<p>&lt;/c:import&gt;</p>
<p>&nbsp;</p>
<p>&#216;&nbsp; Uri与tld文件的映射关系</p>
<p>JSP文件中使用的标签通常都有一个tld定义文件(标签库定义文件，主要定义标签对应的java类，标签的属性等等信息)与之对应的,web容器需要找到相应的tld文件，以tld文件中定义的内容判断标签的使用是否正确。</p>
<p>Web做【使用正确性】判断处理，当遇到类似【&lt;c:import】这样的标签时，会通过prefix定位到uri，再根据uri定位到相应的tld文件，对tld文件进行解析。其中uri&#223;&#224;tld文件的映射关系如下：</p>
<p>Key</p>
<p>（Uri）<br />
&nbsp;Value</p>
<p>（String[] taglib_tld_location）<br />
&nbsp;<br />
Taglib-URI：</p>
<p>(如/jstl-examples-taglib、http://java.sun.com/jstl/core等)<br />
&nbsp;taglib_tld_location[0]<br />
&nbsp;<br />
taglib_tld_location[1]<br />
&nbsp;</p>
<p>本文主要介绍的便是uri到tld的映射</p>
<p>&nbsp;</p>
<p>&#216;&nbsp; Tld文件路径定义方式</p>
<p>如下方式1和方式2只能在2.3版本使用，Servlet2.4开始便不能在web.xml中定义taglib了。</p>
<p>&lt;!DOCTYPE web-app</p>
<p>&nbsp;&nbsp;&nbsp; PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"</p>
<p>&nbsp;&nbsp;&nbsp; "http://java.sun.com/dtd/web-app_2_3.dtd"&gt;</p>
<p>l&nbsp; 方式1：</p>
<p>如下所示，在web.xml中定义</p>
<p>&nbsp;&nbsp;&nbsp; &lt;taglib&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;taglib-uri&gt;/jstl-examples-taglib&lt;/taglib-uri&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;taglib-location&gt;/WEB-INF/lib/jstl-examples.tld&lt;/taglib-location&gt;</p>
<p>&lt;/taglib&gt;</p>
<p>如果这样定义的话，映射关系便如下：</p>
<p>/jstl-examples-taglib&#223;&#224;{&#8220;/WEB-INF/lib/jstl-examples.tld&#8221;,&#8221;&#8221;} // taglib_tld_location[0]就足以表示tld路径，因此taglib_tld_location[1]为空。</p>
<p>&nbsp;</p>
<p>l&nbsp; 方式2：</p>
<p>如下所示，在web.xml中定义</p>
<p>&nbsp;&nbsp;&nbsp; &lt;taglib&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;taglib-uri&gt;/jstl-examples-taglib&lt;/taglib-uri&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;taglib-location&gt;/WEB-INF/lib/ jstl-examples.jar&lt;/taglib-location&gt;</p>
<p>&lt;/taglib&gt;</p>
<p>如果这样定义的话，映射关系便如下：</p>
<p>/jstl-examples-taglib&#223;&#224;{&#8220;/WEB-INF/lib/ jstl-examples.jar&#8221;,&#8221; META-INF/taglib.tld&#8221;}</p>
<p>&nbsp;// taglib_tld_location[0]表示jar路径，taglib_tld_location[1]固定为META-INF/taglib.tld(也就是说，tld在jar文件中的保存路径必须是META-INF/taglib.tld，名称必须是taglib.tld)。这就是说一个jar里只能有一个tld。如果代码中不固定为taglib.tld的话，也很难处理，因为如果tld的名称可以随便定义的话，出现多个tld在jar文件中时将会导致混乱。</p>
<p>&nbsp;</p>
<p>l&nbsp; 方式3：</p>
<p>不需要在web.xml中定义，只需要把tld保存在web应用能够使用的jar文件中的META-INF路径下便可。这种情况的机制是这样的：web容器会遍历当前web应用能够访问的jar文件，从jar文件中查找META-INF/xxx.tld文件，当找到一个tld文件之后，便会解析tld文件，取出&lt;taglib&gt;节点的&lt;uri&gt;值，把uri作为key值生成映射关系。</p>
<p>如下所示的jstl的core标签库的tld文件，便会有如下的映射关系</p>
<p>http://java.sun.com/jstl/core&#223;&#224;{&#8220;tld文件所在的jar文件的路径&#8221;,&#8221; META-INF/xxx.tld&#8221;}//taglib_tld_location[0]表示jar路径，taglib_tld_location[1]为所搜到的tld在jar文件中的相对路径</p>
<p>&#8230;&#8230;</p>
<p>&lt;taglib&gt;</p>
<p>&nbsp; &lt;tlib-version&gt;1.0&lt;/tlib-version&gt;</p>
<p>&nbsp; &lt;jsp-version&gt;1.2&lt;/jsp-version&gt;</p>
<p>&nbsp; &lt;short-name&gt;c&lt;/short-name&gt;</p>
<p>&nbsp; &lt;uri&gt;http://java.sun.com/jstl/core&lt;/uri&gt;</p>
<p>&nbsp; &lt;display-name&gt;JSTL core&lt;/display-name&gt;</p>
<p>&nbsp; &lt;description&gt;JSTL 1.0 core library&lt;/description&gt;</p>
<p>&#8230;&#8230;</p>
<p>&nbsp; &lt;tag&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;name&gt;catch&lt;/name&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;tag-class&gt;org.apache.taglibs.standard.tag.common.core.CatchTag&lt;/tag-class&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;body-content&gt;JSP&lt;/body-content&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;description&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Catches any Throwable that occurs in its body and optionally</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exposes it.</p>
<p>&nbsp;&nbsp;&nbsp; &lt;/description&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;attribute&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;name&gt;var&lt;/name&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;required&gt;false&lt;/required&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;rtexprvalue&gt;false&lt;/rtexprvalue&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;/attribute&gt;</p>
<p>&nbsp; &lt;/tag&gt;</p>
<p>&#8230;&#8230;</p>
<p>&nbsp;</p>
<p>&#216;&nbsp; Tld文件的解析逻辑</p>
<p>以jstl为例：</p>
<p>Web容器遇到类似【&lt;c:import】标签时，就会通过在头部中定义的&lt;%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %&gt;找到uri，再根据此uri便可以定位到taglib_tld_location。当taglib_tld_location[0]不是jar文件时，便直接使用java的FileInputStream读取tld文件；当taglib_tld_location[0]是jar文件时，则会</p>
<p>通过如下代码读取tld文件。</p>
<p>URL jarFileUrl = new URL("jar:" + location[0] + "!/");</p>
<p>ZipEntry jarEntry = jarFile.getEntry(location[1]);</p>
<p>&nbsp;</p>
<p>&#216;&nbsp; 总结：</p>
<p>Tld的定义可以不在web.xml中定义，这时需要保证tld在web应用能够访问的jar中，并且保存在jar的META-INF目录下。此时JSP直接使用tld中定义的&lt;uri&gt;便可；</p>
<p>如果在web.xml中定义tld的路径的话，可以直接指定tld文件路径，此时要保证tld不在jar包中(比如在WEB-INF目录下)；也可以指定为jar文件路径，此时要保证tld在jar中且路径为META-INF/taglib.tld。</p>
<p>&nbsp;</p>
<p>以前用WSAD wizard做的，都可以在JSP页面中解析到EL表达式，当然前提是JSP2.0的情况下。 <br />
今天遇到了一个莫名其妙的问题。刚下载Eclipse3.3+MyEclipse6.0体验的过程中，遇上了解析不到EL表达式的问题。经过好几个小时的琢磨终于发现了，给大家share一下： <br />
问题就出在建Web Project的时候web.xml声明上。 <br />
web.xml声明部分一般分为如下版本的xsd, <br />
web-app_2_2.xsd <br />
web-app_2_3.xsd <br />
web-app_2_4.xsd <br />
web-app_2_5.xsd <br />
<br />
更详细的列出各版本web.xml声明部分吧，如下： <br />
web-app_2_2.xsd <br />
<br />
&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />
&lt;!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/dtd/web-app_2_2.dtd"&gt;<br />
<br />
web-app_2_3.xsd <br />
<br />
&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />
&lt;!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"&gt;<br />
<br />
web-app_2_4.xsd <br />
<br />
&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />
&lt;web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee&nbsp; http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"&gt;<br />
<br />
web-app_2_5.xsd <br />
<br />
&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />
&lt;web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee&nbsp; http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"&gt;<br />
<br />
<br />
确定web.xml里的xsd版本之后一定要在JSP的声明(&lt;%@page %&gt;)部分加一行，如下： <br />
&lt;%@ page isELIgnored="false" %&gt; <br />
这样设为false才能解析EL表达式。 <br />
经过各版本的test之后.... <br />
注意!! 其中servlets 2.4(我没记错的话JSP 2.0出来之后的第一个版本)，这个版本的isELIgnored默认设置为false。所以使用web.xml里用web-app_2_4.xsd声明的时候在JSP页面不用特意声明。 <br />
<br />
下面是官方Documention中isELIgnored Attribute的详解： <br />
The isELIgnored Attribute <br />
&#8226; Format <br />
&#8211; &lt;%@ page isELIgnored="false" %&gt; <br />
&#8211; &lt;%@ page isELIgnored="true" %&gt; <br />
Purpose <br />
&#8211; To control whether the JSP 2.0 Expression Language <br />
(EL) is ignored (true) or evaluated normally (false). <br />
&#8226; Notes <br />
&#8211; If your web.xml specifies servlets 2.3 (corresponding to <br />
JSP 1.2) or earlier, the default is true <br />
&#8226; But it is still legal to change the default—you are permitted <br />
to use this attribute in a JSP-2.0-compliant server <br />
regardless of the web.xml version. <br />
&#8211; If your web.xml specifies servlets 2.4 (corresponding to <br />
JSP 2.0) or earlier, the default is false <br />
</p>
<p><br />
本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/qingkangxu/archive/2010/12/05/6057034.aspx</p>
 <img src ="http://www.blogjava.net/freeman1984/aggbug/347931.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-04-09 10:26 <a href="http://www.blogjava.net/freeman1984/archive/2011/04/09/347931.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WEB应用中的身份验证(1)--基本身份验证BASIC authorization method </title><link>http://www.blogjava.net/freeman1984/archive/2011/03/22/346772.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Tue, 22 Mar 2011 10:33:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/03/22/346772.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/346772.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/03/22/346772.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/346772.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/346772.html</trackback:ping><description><![CDATA[<p>在任何一种WEB应用开发中，不论大中小规模的，每个开发者都会遇到一些需要保护程序数据的问题，涉及到用户的LOGIN ID和PASSWORD。那么如何执行验证方式更好呢？实际上，有很多方式来实现。在本文里，我们不会把所有的验证方法都考虑到，我们的目的是让你学会如何以最简单最方便的验证方法来完成。下面将讨论基本验证方式之一（BASIC authorization method）</p>
<p>要搭建整个流程需要四个阶段：</p>
<p>一、建立测试用数据库<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们这里用Mysql进行测试，其他数据库完全一样。<br />
&nbsp;&nbsp;&nbsp;&nbsp;1、创建用户表<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;CREATE TABLE users (<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;id int(11) NOT NULL auto_increment,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;username varchar(20) NOT NULL,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;password varchar(20) NOT NULL,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;PRIMARY KEY&nbsp; (id)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;) </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;2、创建权限表（此事例中用不到）<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;CREATE TABLE roles(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;id int(11) NOT NULL auto_increment,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;rolename varchar(20) NOT NULL,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;PRIMARY KEY&nbsp; (id)<br />
&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;<br />
&nbsp;&nbsp;&nbsp;&nbsp;3、创建用户－权限对应表<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CREATE TABLE user_roles (<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; id int(11) NOT NULL auto_increment,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; username varchar(20) NOT NULL,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rolename varchar(20) NOT NULL,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PRIMARY KEY&nbsp; (id)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;4、插入数据<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;insert into users(username,password) values('zhangdongyu', 'loveyuanyuan')<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;insert into roles(rolename) values('manager')<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;insert into user_roles(username,rolename) values('zhangdongyu', 'manager')<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
二、修改${tomcat}\conf\server.xml<br />
&nbsp;&nbsp;找到<br />
&nbsp;&nbsp;&nbsp;&lt;!--<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Realm className="org.apache.catalina.realm.MemoryRealm" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 在上面这句话下面添加一下内容：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;Realm <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;className="org.apache.catalina.realm.JDBCRealm" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;debug="99"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;driverName="org.gjt.mm.mysql.Driver" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connectionURL="jdbc:mysql://localhost/weblogin" &lt;!--数据库连接地址--&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connectionName="root"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--数据库用户名--&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;connectionPassword="123"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--数据库密码--&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;userTable="users" &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--用户表--&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;userNameCol="username" &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--用户名列--&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;userCredCol="password"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--密码列--&gt;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;userRoleTable="user_roles" &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--用户权限对应表--&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;roleNameCol="rolename" &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--权限列--&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;/&gt;&nbsp;&nbsp;&nbsp;</p>
<p>三、创建工程<br />
&nbsp;&nbsp;在Eclipse创建一个web工程sercurityTest，在WebRoot下面创建一个文件夹admin(也可在里面建立几个文件)</p>
<p><br />
&nbsp;&nbsp;<img style="width: 222px; height: 137px" alt="Eclipse截图" src="http://p.blog.csdn.net/images/p_blog_csdn_net/swengineer/1.jpg" width="146" height="110" /></p>
<p><br />
&nbsp;&nbsp;在web.xml文件中添加以下片段：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;security-constraint&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;web-resource-collection&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;web-resource-name&gt;Web Demo&lt;/web-resource-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;url-pattern&gt;/admin/*&lt;/url-pattern&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/web-resource-collection&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;auth-constraint&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;role-name&gt;<font style="background-color: #33cccc">manager</font>&lt;/role-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/auth-constraint&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/security-constraint&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;login-config&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;auth-method&gt;BASIC&lt;/auth-method&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;realm-name&gt;Web Demo&lt;/realm-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/login-config&gt;</p>
<p>四、重启Tomcat，使设置生效</p>
<p>总结测试：<br />
&nbsp;&nbsp;通过上面的四部分配置，当你再次访问程序中受保护的地址，如:http://localhost/sercurityTest/admin时<br />
&nbsp;&nbsp;会弹出验证对话框，让你输入用户名和密码，只有输入库中的用户名密码并且该用户有manager权限时才能进<br />
&nbsp;&nbsp;入受保护目录。<img style="width: 322px; height: 235px" alt="弹出验证" src="http://p.blog.csdn.net/images/p_blog_csdn_net/swengineer/2.jpg" width="272" height="201" /><br />
</p>
<br />
转载自：http://blog.csdn.net/swengineer/archive/2006/12/01/1424020.aspx
<img src ="http://www.blogjava.net/freeman1984/aggbug/346772.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-03-22 18:33 <a href="http://www.blogjava.net/freeman1984/archive/2011/03/22/346772.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JVM内存模型以及垃圾回收</title><link>http://www.blogjava.net/freeman1984/archive/2011/03/08/345929.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Tue, 08 Mar 2011 05:16:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/03/08/345929.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/345929.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/03/08/345929.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/345929.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/345929.html</trackback:ping><description><![CDATA[<p>JVM内存模型以及垃圾回收<br />
内存由 Perm 和 Heap 组成. 其中</p>
<p>Heap = {Old + NEW = { Eden , from, to } }<br />
具体可查看javavisualvm<br />
<img border="0" alt="" src="http://www.blogjava.net/images/blogjava_net/freeman1984/vmvusual.JPG" /></p>
<p>JVM内存模型中分两大块，一块是 NEW Generation, 另一块是Old Generation. 在New Generation中，有一个叫Eden的空间，主要是用来存放新生的对象，还有两个Survivor Spaces（from,to）, 它们用来存放每次垃圾回收后存活下来的对象。在Old Generation中，主要存放应用程序中生命周期长的内存对象，还有个Permanent Generation，主要用来放JVM自己的反射对象，比如类对象和方法对象等。 <br />
&nbsp;</p>
<p>垃圾回收描述：</p>
<p><br />
在New Generation块中，垃圾回收一般用Copying的算法，速度快。每次GC的时候，存活下来的对象首先由Eden拷贝到某个Survivor Space, 当Survivor Space空间满了后, 剩下的live对象就被直接拷贝到Old Generation中去。因此，每次GC后，Eden内存块会被清空。在Old Generation块中，垃圾回收一般用mark-compact的算法，速度慢些，但减少内存要求.<br />
垃圾回收分多级，0级为全部(Full)的垃圾回收，会回收OLD段中的垃圾；1级或以上为部分垃圾回收，只会回收NEW中的垃圾，内存溢出通常发生于OLD段或Perm段垃圾回收后，仍然无内存空间容纳新的Java对象的情况。</p>
<p>当一个URL被访问时，内存申请过程如下：<br />
A. JVM会试图为相关Java对象在Eden中初始化一块内存区域<br />
B. 当Eden空间足够时，内存申请结束。否则到下一步<br />
C. JVM试图释放在Eden中所有不活跃的对象（这属于1或更高级的垃圾回收）, 释放后若Eden空间仍然不足以放入新对象，则试图将部分Eden中活跃对象放入Survivor区<br />
D. Survivor区被用来作为Eden及OLD的中间交换区域，当OLD区空间足够时，Survivor区的对象会被移到Old区，否则会被保留在Survivor区<br />
E. 当OLD区空间不够时，JVM会在OLD区进行完全的垃圾收集（0级）<br />
F. 完全垃圾收集后，若Survivor及OLD区仍然无法存放从Eden复制过来的部分对象，导致JVM无法在Eden区为新对象创建内存区域，则出现&#8221;out of memory错误&#8221;</p>
<p>JVM调优建议:</p>
<p>ms/mx：定义YOUNG+OLD段的总尺寸，ms为JVM启动时YOUNG+OLD的内存大小；mx为最大可占用的YOUNG+OLD内存大小。在用户生产环境上一般将这两个值设为相同，以减少运行期间系统在内存申请上所花的开销。<br />
NewSize/MaxNewSize：定义YOUNG段的尺寸，NewSize为JVM启动时YOUNG的内存大小；MaxNewSize为最大可占用的YOUNG内存大小。在用户生产环境上一般将这两个值设为相同，以减少运行期间系统在内存申请上所花的开销。<br />
PermSize/MaxPermSize：定义Perm段的尺寸，PermSize为JVM启动时Perm的内存大小；MaxPermSize为最大可占用的Perm内存大小。在用户生产环境上一般将这两个值设为相同，以减少运行期间系统在内存申请上所花的开销。<br />
SurvivorRatio：设置Survivor空间和Eden空间的比例</p>
<p>内存溢出的可能性</p>
<p>1. OLD段溢出<br />
这种内存溢出是最常见的情况之一，产生的原因可能是：<br />
1) 设置的内存参数过小(ms/mx, NewSize/MaxNewSize)<br />
2) 程序问题<br />
单个程序持续进行消耗内存的处理，如循环几千次的字符串处理，对字符串处理应建议使用StringBuffer。此时不会报内存溢出错，却会使系统持续垃圾收集，无法处理其它请求，相关问题程序可通过Thread Dump获取（见系统问题诊断一章）单个程序所申请内存过大，有的程序会申请几十乃至几百兆内存，此时JVM也会因无法申请到资源而出现内存溢出，对此首先要找到相关功能，然后交予程序员修改，要找到相关程序，必须在Apache日志中寻找。<br />
当Java对象使用完毕后，其所引用的对象却没有销毁，使得JVM认为他还是活跃的对象而不进行回收，这样累计占用了大量内存而无法释放。由于目前市面上还没有对系统影响小的内存分析工具，故此时只能和程序员一起定位。</p>
<p><br />
2. Perm段溢出<br />
通常由于Perm段装载了大量的Servlet类而导致溢出，目前的解决办法：<br />
1) 将PermSize扩大，一般256M能够满足要求<br />
2) 若别无选择，则只能将servlet的路径加到CLASSPATH中，但一般不建议这么处理</p>
<p>3. C Heap溢出<br />
系统对C Heap没有限制，故C Heap发生问题时，Java进程所占内存会持续增长，直到占用所有可用系统内存</p>
<p>其他：</p>
<p>JVM有2个GC线程。第一个线程负责回收Heap的Young区。第二个线程在Heap不足时，遍历Heap，将Young 区升级为Older区。Older区的大小等于-Xmx减去-Xmn，不能将-Xms的值设的过大，因为第二个线程被迫运行会降低JVM的性能。</p>
<p>为什么一些程序频繁发生GC？有如下原因：<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 程序内调用了System.gc()或Runtime.gc()。<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一些中间件软件调用自己的GC方法，此时需要设置参数禁止这些GC。<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Java的Heap太小，一般默认的Heap值都很小。<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 频繁实例化对象，Release对象。此时尽量保存并重用对象，例如使用StringBuffer()和String()。<br />
如果你发现每次GC后，Heap的剩余空间会是总空间的50%，这表示你的Heap处于健康状态。许多Server端的Java程序每次GC后最好能有65%的剩余空间。<br />
经验之谈：<br />
1．Server端JVM最好将-Xms和-Xmx设为相同值。为了优化GC，最好让-Xmn值约等于-Xmx的1/3[2]。 <br />
2．一个GUI程序最好是每10到20秒间运行一次GC，每次在半秒之内完成[2]。 <br />
注意：<br />
1．增加Heap的大小虽然会降低GC的频率，但也增加了每次GC的时间。并且GC运行时，所有的用户线程将暂停，也就是GC期间，Java应用程序不做任何工作。<br />
2．Heap大小并不决定进程的内存使用量。进程的内存使用量要大于-Xmx定义的值，因为Java为其他任务分配内存，例如每个线程的Stack等。<br />
2．Stack的设定<br />
每个线程都有他自己的Stack。</p>
<p>-Xss 每个线程的Stack大小 </p>
<p>Stack的大小限制着线程的数量。如果Stack过大就好导致内存溢漏。-Xss参数决定Stack大小，例如-Xss1024K。如果Stack太小，也会导致Stack溢漏。<br />
3．硬件环境<br />
硬件环境也影响GC的效率，例如机器的种类，内存，swap空间，和CPU的数量。<br />
如果你的程序需要频繁创建很多transient对象，会导致JVM频繁GC。这种情况你可以增加机器的内存，来减少Swap空间的使用[2]。<br />
4．4种GC<br />
第一种为单线程GC，也是默认的GC。，该GC适用于单CPU机器。<br />
第二种为Throughput GC，是多线程的GC，适用于多CPU，使用大量线程的程序。第二种GC与第一种GC相似，不同在于GC在收集Young区是多线程的，但在Old区和第一种一样，仍然采用单线程。-XX:+UseParallelGC参数启动该GC。<br />
第三种为Concurrent Low Pause GC，类似于第一种，适用于多CPU，并要求缩短因GC造成程序停滞的时间。这种GC可以在Old区的回收同时，运行应用程序。-XX:+UseConcMarkSweepGC参数启动该GC。<br />
第四种为Incremental Low Pause GC，适用于要求缩短因GC造成程序停滞的时间。这种GC可以在Young区回收的同时，回收一部分Old区对象。-Xincgc参数启动该GC。</p>
<img src ="http://www.blogjava.net/freeman1984/aggbug/345929.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-03-08 13:16 <a href="http://www.blogjava.net/freeman1984/archive/2011/03/08/345929.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>存储过程常用技巧，以及游标，自治事务</title><link>http://www.blogjava.net/freeman1984/archive/2011/03/04/345700.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 04 Mar 2011 06:35:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/03/04/345700.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/345700.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/03/04/345700.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/345700.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/345700.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 我们在进行pl/sql编程时打交道最多的就是存储过程了。存储过程的结构是非常的简单的，我们在这里除了学习存储过程的基本结构外，还会学习编写存储过程时相关的一些实用的知识。如：游标的处理，异常的处理，集合的选择等等 1.存储过程结构 1.1 第一个存储过程 Java代码 1.create or replace procedure proc1(&nbsp;&nbsp; 2.&nbs...&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2011/03/04/345700.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/345700.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-03-04 14:35 <a href="http://www.blogjava.net/freeman1984/archive/2011/03/04/345700.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对Lucene PhraseQuery的slop的理解(转载)</title><link>http://www.blogjava.net/freeman1984/archive/2011/02/25/345116.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 25 Feb 2011 05:51:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/02/25/345116.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/345116.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/02/25/345116.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/345116.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/345116.html</trackback:ping><description><![CDATA[文章来自：http://myzhangjl.blog.sohu.com/95911870.html<br />
这几天看Lucene,看到检索那块,被PhraseQuery折腾了一阵,那本《Lucene In Action》里的代码版本太旧了，也不知是翻译的问题还是我的理解问题，总之在看PhraseQuery的设置slop时费了半天劲，不过，总算是搞明白了，发个帖子来分享一下：
<p><font size="3">&nbsp;&nbsp;&nbsp; 所谓PhraseQuery，就是通过短语来检索，比如我想查&#8220;big car&#8221;这个短语，那么如果待匹配的document的指定项里包含了"big car"这个短语，这个document就算匹配成功。可如果待匹配的句子里包含的是&#8220;big black car&#8221;，那么就无法匹配成功了，如果也想让这个匹配，就需要设定slop，先给出slop的概念：slop是指两个项的位置之间允许的最大间隔距离，下面我举例来解释：</font></p>
<p><font size="3">&nbsp;&nbsp; 我的待匹配的句子是：<strong><em>the quick brown fox jumped over the lazy dog.</em></strong></font></p>
<p><font size="3">&nbsp; &nbsp;<strong>例1：</strong> 如果我想用&#8220;<em><strong>quick fox</strong></em>&#8221;来匹配出上面的句子，我发现原句里是<em><strong>quick [brown] fox</strong></em>，就是说和我的&#8220;<em><strong>quick fox</strong></em>&#8221;中间相差了一个单词的距离，所以，我这里把slop设为1，表示<strong><em>quick</em></strong>和<em><strong>fox</strong></em>这两项之间最大可以允许有一个单词的间隔，这样所有&#8220;<em><strong>quick [***] fox</strong></em>&#8221;就都可以被匹配出来了。</font></p>
<p><font size="3">&nbsp;&nbsp;<strong> 例2：</strong>如果我想用&#8220;<em><strong>fox quick</strong></em>&#8221;来匹配出上面的句子，这也是可以的，不过比例1要麻烦，我们需要看把&#8220;<em><strong>fox quick</strong></em>&#8221;怎么移动能形成&#8220;<em><strong>quick [***] fox</strong></em>&#8221;，如下表所示，把<strong><em>fox</em></strong>向右移动3次即可：</font></p>
<div align="center">
<table border="1" align="center">
    <tbody>
        <tr>
            <td>&nbsp;&nbsp;</td>
            <td>fox</td>
            <td>quick</td>
            <td>&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td>1</td>
            <td>&nbsp;&nbsp;</td>
            <td>fox|quick</td>
            <td>&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td>2</td>
            <td>&nbsp;&nbsp;</td>
            <td>quick</td>
            <td>fox</td>
            <td>&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td>3</td>
            <td>&nbsp;&nbsp;</td>
            <td>quick</td>
            <td>&nbsp;&nbsp;</td>
            <td>fox</td>
        </tr>
    </tbody>
</table>
</div>
<p>&nbsp;&nbsp;&nbsp;<font size="3"> <strong>例3：</strong>如果我想用&#8220;<strong><em>lazy jumped quick</em></strong>&#8221;该如何匹配上面的句子呢？这个比例2还要麻烦，我们要考虑3个单词，不管多少个单词，slop表示的是间隔的最大距离，详细起见，我们分别来看每种组合：(<font size="2">我的待匹配的句子是：<strong><em>the quick brown fox jumped over the lazy dog.</em></strong></font>)</font></p>
<ul>
    <li><font size="3"><strong><em>lazy jumped:</em></strong>原句是<strong><em>jumped [over] [the] lazy</em></strong>，就是说它们两个之间间隔了2个词,如下所示：需要把<em><strong>lazy</strong></em>向右移动4位</font></li>
</ul>
<p>&nbsp;</p>
<table border="1" align="center">
    <tbody>
        <tr>
            <td>&nbsp;&nbsp;</td>
            <td>lazy</td>
            <td>jumped</td>
            <td>&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td>1</td>
            <td>&nbsp;&nbsp;</td>
            <td>lazy|jumped</td>
            <td>&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td>2</td>
            <td>&nbsp;&nbsp;</td>
            <td>jumped</td>
            <td>lazy</td>
            <td>&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td>3</td>
            <td>&nbsp;&nbsp;</td>
            <td>jumped</td>
            <td>&nbsp;&nbsp;</td>
            <td>lazy</td>
            <td>&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td>4</td>
            <td>&nbsp;&nbsp;</td>
            <td>jumped</td>
            <td>&nbsp;&nbsp;</td>
            <td></td>
            <td>&nbsp;lazy&nbsp;</td>
        </tr>
    </tbody>
</table>
<p>&nbsp;</p>
<ul>
    <li>&nbsp; <font size="3"><strong><em>lazy jumped&nbsp;quick：</em></strong>我们主要看<em><strong>lazy</strong></em>和<strong><em>quick</em></strong>，但是由于<em><strong>jumped</strong></em>是在中间，所以移动的时候还是要把<strong><em>jumped</em></strong>考虑在内，原句里<em><strong>lazy</strong></em>和<strong><em>quick</em></strong>的关系是：<strong><em>quick [brown] [fox] [jumped] [over] [the] lazy ，quick lazy</em></strong>中间间隔了5个词，所以如下图所示，把lazy向右移动8次</font></li>
</ul>
<div align="center">
<table border="1" align="center">
    <tbody>
        <tr>
            <td>&nbsp;&nbsp;</td>
            <td>&nbsp;lazy</td>
            <td>
            <p align="center">jumped</p>
            </td>
            <td>quick</td>
            <td>&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;</td>
            <td></td>
        </tr>
        <tr>
            <td>
            <p align="center">1</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">lazy|jumped</p>
            </td>
            <td>
            <p align="center">quick</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align="center">2</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">jumped</p>
            </td>
            <td>
            <p align="center">lazy|quick</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align="center">&nbsp;3&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">jumped</p>
            </td>
            <td>
            <p align="center">quick</p>
            </td>
            <td>
            <p align="center">&nbsp;lazy&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align="center">4</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">jumped</p>
            </td>
            <td>
            <p align="center">quick</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">lazy&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align="center">&nbsp;5&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">jumped</p>
            </td>
            <td>
            <p align="center">quick</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">lazy&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align="center">6</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">jumped</p>
            </td>
            <td>
            <p align="center">quick</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">lazy&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align="center">7</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">jumped</p>
            </td>
            <td>
            <p align="center">quick</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;&nbsp;</p>
            </td>
            <td>
            <p align="center">lazy&nbsp;</p>
            </td>
            <td>
            <p align="center">&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align="center">8</p>
            </td>
            <td>&nbsp;&nbsp;</td>
            <td>
            <p align="center">jumped</p>
            </td>
            <td>
            <p align="center">quick</p>
            </td>
            <td>&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;</td>
            <td>lazy&nbsp;</td>
        </tr>
    </tbody>
</table>
</div>
<p>&nbsp;</p>
<ul>
    <li>&nbsp;<font size="3">最后是<strong><em>jumped qucik</em></strong>，这里不详细画表格了，大家可以自己试试，应该是把jumped向右移动4次。</font></li>
</ul>
<p><font size="3">&nbsp;&nbsp; 综合以上3种情况，所以我们需要把slop设为8才令&#8220;<font size="3"><strong><em>lazy jumped&nbsp;quick</em></strong></font>&#8221;可以匹配到原句。</font></p>
<img src ="http://www.blogjava.net/freeman1984/aggbug/345116.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-02-25 13:51 <a href="http://www.blogjava.net/freeman1984/archive/2011/02/25/345116.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用apache pdfbox读取pdf 实例</title><link>http://www.blogjava.net/freeman1984/archive/2011/02/24/345064.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Thu, 24 Feb 2011 06:55:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/02/24/345064.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/345064.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/02/24/345064.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/345064.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/345064.html</trackback:ping><description><![CDATA[<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><img id="Codehighlighter1_56_592_Open_Image" onclick="this.style.display='none'; Codehighlighter1_56_592_Open_Text.style.display='none'; Codehighlighter1_56_592_Closed_Image.style.display='inline'; Codehighlighter1_56_592_Closed_Text.style.display='inline';" alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" /><img style="display: none" id="Codehighlighter1_56_592_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_56_592_Closed_Text.style.display='none'; Codehighlighter1_56_592_Open_Image.style.display='inline'; Codehighlighter1_56_592_Open_Text.style.display='inline';" alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" /><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;main(String[]&nbsp;args)&nbsp;</span><span style="color: #0000ff">throws</span><span style="color: #000000">&nbsp;Exception&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_56_592_Closed_Text"><img alt="" src="http://www.blogjava.net/Images/dot.gif" /></span><span id="Codehighlighter1_56_592_Open_Text"><span style="color: #000000">{<br />
<img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;InputStream&nbsp;inputStream&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;BufferedInputStream(<br />
<img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;FileInputStream(</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;File(</span><span style="color: #000000">"</span><span style="color: #000000">d:\\work\\lt.pdf</span><span style="color: #000000">"</span><span style="color: #000000">)));<br />
<img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;PDDocument&nbsp;pdfDocument&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;PDDocument.load(inputStream);<br />
<img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;StringWriter&nbsp;writer&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;StringWriter();<br />
<img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;PDFTextStripper&nbsp;stripper&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;PDFTextStripper();<br />
<img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;stripper.writeText(pdfDocument,&nbsp;writer);<br />
<img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;contents&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;writer.getBuffer().toString();<br />
<img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">文档内容：</span><span style="color: #000000">"</span><span style="color: #000000">+</span><span style="color: #000000">contents);<br />
<img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;PDDocumentInformation&nbsp;documentInformation&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;pdfDocument.getDocumentInformation();<br />
<img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">标题：</span><span style="color: #000000">"</span><span style="color: #000000">+</span><span style="color: #000000">documentInformation.getTitle());<br />
<img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" />}</span></span><span style="color: #000000"><br />
<img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" />}</span></div>
需要jar包：<br />
pdfbox-1.4.0.jar<br />
fontbox-1.4.0.jar
<img src ="http://www.blogjava.net/freeman1984/aggbug/345064.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-02-24 14:55 <a href="http://www.blogjava.net/freeman1984/archive/2011/02/24/345064.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>