﻿<?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-hk2000c技术专栏-随笔分类-Java 技术</title><link>http://www.blogjava.net/hk2000c/category/12789.html</link><description>技术源于哲学，哲学来源于生活

关心生活，关注健康，关心他人

</description><language>zh-cn</language><lastBuildDate>Sat, 12 Apr 2008 04:21:08 GMT</lastBuildDate><pubDate>Sat, 12 Apr 2008 04:21:08 GMT</pubDate><ttl>60</ttl><item><title>ActiveMQ4.1 +Spring2.0的POJO JMS方案[整理版] </title><link>http://www.blogjava.net/hk2000c/archive/2008/04/12/192305.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Fri, 11 Apr 2008 17:37:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2008/04/12/192305.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/192305.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2008/04/12/192305.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/192305.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/192305.html</trackback:ping><description><![CDATA[.概述
<h3><a name="ActiveMQ-1.1JMS%E4%B8%8EActiveMQ%E7%89%B9%E6%80%A7%26nbsp%3B%26nbsp%3B"></a>1.1 JMS与ActiveMQ特性&nbsp;&nbsp;</h3>
<p>&nbsp;&nbsp;&nbsp;JMS始终在JavaEE五花八门的协议里，WebService满天飞的时候占一位置，是因为：</p>
<ul>
    <li>它可以把不影响用户执行结果又比较耗时的任务（比如发邮件通知管理员）<strong>异步</strong>的扔给JMS 服务端去做，而尽快的把屏幕返还给用户。
    <li>服务端能够多线程排队响应高并发的请求，并保证请求不丢失。
    <li>可以在Java世界里达到最高的解耦。客户端与服务端无需直连，甚至无需知晓对方是谁、在哪里、有多少人，只要对流过的信息作响应就行了，在企业应用环境复杂时作用明显。 </li>
</ul>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nobr"><a title="Visit page outside Confluence" href="http://www.activemq.org/" rel="nofollow">ActiveMQ<sup><img class="rendericon" height="7" alt="" src="http://wiki.springside.org.cn/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _counted="undefined" /></sup></a></span>的特性：</p>
<ul>
    <li>完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现，也是Apache Geronimo默认的JMS provider。
    <li>POJO withdout EJB Container，不需要实现EJB繁琐复杂的Message Bean接口和配置。
    <li>Spring Base，可以使用Spring的各种特性如IOC、AOP&nbsp;。
    <li>Effective，基于Jencks的JCA Container实现&nbsp;pool connection，control transactions and manage security。&nbsp; </li>
</ul>
<h3><a name="ActiveMQ-1.2SpringSide%E7%9A%84%E5%AE%8C%E5%85%A8POJO%E7%9A%84JMS%E6%96%B9%E6%A1%88%26nbsp%3B%26nbsp%3B%26nbsp%3B"></a>1.2 SpringSide 的完全POJO的JMS方案&nbsp;&nbsp;&nbsp;</h3>
<p>&nbsp; <span class="nobr"><a title="Visit page outside Confluence" href="http://www.springside.org.cn/" rel="nofollow">SpringSide 2.0<sup><img class="rendericon" height="7" alt="" src="http://wiki.springside.org.cn/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _counted="undefined" /></sup></a></span>在BookStore示例中，演示了用户下订单时，将发通知信到用户邮箱的动作，通过JMS交给JMS服务端异步完成，避免了邮件服务器的堵塞而影响用户的下订。</p>
<p>&nbsp; 全部代码于examples\bookstore\src\java\org\springside\bookstore\components\activemq 目录中。</p>
<p>&nbsp; 一个JMS场景通常需要三者参与：</p>
<ul>
    <li>一个POJO的的Message Producer，负责使用Spring的JMS Template发送消息。
    <li>一个Message Converter，负责把Java对象如订单(Order)转化为消息，使得Producer能够直接发送POJO。
    <li>一个MDP Message Consumer，负责接收并处理消息。 </li>
</ul>
<p>&nbsp;&nbsp;<span class="nobr"><a title="Visit page outside Confluence" href="http://www.springside.org.cn/" rel="nofollow">SpringSide 2.0<sup><img class="rendericon" height="7" alt="" src="http://wiki.springside.org.cn/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _counted="undefined" /></sup></a></span>采用了ActiveMQ 4.1-incubator 与Spring 2.0 集成，对比SS1.0M3，有三个值得留意的地方，使得代码中几乎不见一丝JMS的侵入代码：</p>
<ol>
    <li>采用Spring2.0的Schema式简化配置。
    <li>实现Message Converter转化消息与对象，使得Producer能够直接发送POJO而不是JMS Message。
    <li>使用了Spring2.0的DefaultMessageListenerContainer与MessageListenerAdapter，消息接收者不用实现MessageListener 接口。
    <li>同时，Spring 2.0 的DefaultMessageListenerContainer 代替了SS1.0M3中的<span class="nobr"><a title="Visit page outside Confluence" href="http://jencks.codehaus.org/" rel="nofollow">Jenck(JCA Container)<sup><img class="rendericon" height="7" alt="" src="http://wiki.springside.org.cn/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _counted="undefined" /></sup></a></span>，充当MDP Container的角色。 </li>
</ol>
<h2><a name="ActiveMQ-2.%E5%BC%95%E5%85%A5ActiveMQ%E7%9A%84XSD"></a>2.引入ActiveMQ的XSD</h2>
<p>&nbsp; ActiveMQ4.1 响应Spring 2.0号召，支持了引入XML Schema namespace的简单配置语法，简化了配置的语句。&nbsp;</p>
<p>&nbsp; 在ApplicationContext.xml(Spring的配置文件)中引入ActiveMQ的XML Scheam 配置文件),如下:</p>
<div class="code">
<div class="codeContent">
<pre class="code-java">&lt;beans
&nbsp;&nbsp;xmlns=<span class="code-quote">"http:<span class="code-comment">//www.springframework.org/schema/beans"</span>
</span>&nbsp;&nbsp;xmlns:amq=<span class="code-quote">"http:<span class="code-comment">//activemq.org/config/1.0"</span>
</span>&nbsp;&nbsp;xmlns:xsi=<span class="code-quote">"http:<span class="code-comment">//www.w3.org/2001/XMLSchema-instance"</span>
</span>&nbsp;&nbsp;xsi:schemaLocation="http:<span class="code-comment">//www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
</span>&nbsp; http:<span class="code-comment">//activemq.org/config/1.0 http://people.apache.org/repository/org.apache.activemq/xsds/activemq-core-4.1-incubator-SNAPSHOT.xsd"&gt;</span></pre>
</div>
</div>
<p>由于ActiveMQ4.1 SnapShot的那个XSD有部分错误，因此使用的是自行修改过的XSD。</p>
<p>先在ClassPath根目录放一个修改过的activemq-core-4.1-incubator-SNAPSHOT.xsd。</p>
<p>在ClassPath 下面建立META-INF\spring.schemas 内容如下。这个spring.schemas是spring自定义scheam的配置文件,请注意"http:\://"部分写法</p>
<div class="code">
<div class="codeContent">
<pre class="code-java">http\:<span class="code-comment">//people.apache.org/repository/org.apache.activemq/xsds/activemq-core-4.1-incubator-SNAPSHOT.xsd=/activemq-core-4.1-incubator-SNAPSHOT.xsd</span></pre>
</div>
</div>
<h2><a name="ActiveMQ-3.%E9%85%8D%E7%BD%AE%E6%96%B9%E6%A1%88"></a>3. 配置方案</h2>
<h3><a name="ActiveMQ-3.1%26nbsp%3B%E5%9F%BA%E7%A1%80%E9%9B%B6%E4%BB%B6%26nbsp%3B"></a>3.1&nbsp;基础零件&nbsp;</h3>
<p><strong>1.&nbsp;配置ActiveMQ Broker</strong>&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp; 暂时采用在JVM中嵌入这种最简单的模式，&nbsp; 当spring初始化时候，ActiveMQ embedded Broker 就会启动了。</p>
<div class="code">
<div class="codeContent">
<pre class="code-java">&lt;!--&nbsp; lets create an embedded ActiveMQ Broker --&gt;
&lt;amq:broker useJmx=<span class="code-quote">"<span class="code-keyword">false</span>"</span> persistent=<span class="code-quote">"<span class="code-keyword">false</span>"</span>&gt;
&nbsp;&nbsp;	&lt;amq:transportConnectors&gt;
　　　　		&lt;amq:transportConnector uri=<span class="code-quote">"tcp:<span class="code-comment">//localhost:0"</span>/&gt;
</span>　	&lt;/amq:transportConnectors&gt;
　&lt;/amq:broker&gt;</pre>
</div>
</div>
<p><strong>2. 配置(A)ConnectionFactory</strong></p>
<p>&nbsp; 由于前面配置的Broker是JVM embedded 所以URL为:vm://localhost</p>
<div class="code">
<div class="codeContent">
<pre class="code-java">&lt;!--&nbsp; ActiveMQ connectionFactory to use&nbsp; --&gt;
&nbsp;&lt;amq:connectionFactory id=<span class="code-quote">"jmsConnectionFactory"</span> brokerURL=<span class="code-quote">"vm:<span class="code-comment">//localhost"</span>/&gt;</span></pre>
</div>
</div>
<p><strong>3 配置(B)Queue</strong></p>
<div class="code">
<div class="codeContent">
<pre class="code-java">&lt;!--&nbsp; ActiveMQ destinations to use&nbsp; --&gt;
&nbsp;&lt;amq:queue name=<span class="code-quote">"destination"</span> physicalName=<span class="code-quote">"org.apache.activemq.spring.Test.spring.embedded"</span>/&gt;</pre>
</div>
</div>
<p><strong>4.&nbsp;配置(C)Converter</strong></p>
<p><strong>&nbsp;&nbsp;</strong> 配置Conveter，使得Producer能够直接发送Order对象，而不是JMS的Message对象。</p>
<div class="code">
<div class="codeContent">
<pre class="code-java">&lt;!--&nbsp; OrderMessage converter&nbsp; --&gt;
&nbsp;&lt;bean id=<span class="code-quote">"orderMessageConverter"</span> class=<span class="code-quote">"org.springside.bookstore.components.activemq.OrderMessageConverter"</span>/&gt;&nbsp;&nbsp;</pre>
</div>
</div>
<h3><a name="ActiveMQ-3.2%26nbsp%3B%26nbsp%3B%E5%8F%91%E9%80%81%E7%AB%AF%26nbsp%3B"></a>3.2&nbsp;&nbsp;发送端&nbsp;</h3>
<p><strong>1 配置JmsTemplate</strong></p>
<p>&nbsp;&nbsp; Spring提供的Template，绑定了(A)ConnectionFactory与(C)Converter。</p>
<div class="code">
<div class="codeContent">
<pre class="code-java">&lt;!--&nbsp; Spring JmsTemplate config --&gt;
&nbsp;&lt;bean id=<span class="code-quote">"jmsTemplate"</span> class=<span class="code-quote">"org.springframework.jms.core.JmsTemplate"</span>&gt;
&nbsp;&nbsp;&lt;property name=<span class="code-quote">"connectionFactory"</span>&gt;
&nbsp;&nbsp;&nbsp;&lt;!--&nbsp; lets wrap in a pool to avoid creating a connection per send --&gt;
&nbsp;&nbsp;&nbsp;&lt;bean class=<span class="code-quote">"org.springframework.jms.connection.SingleConnectionFactory"</span>&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name=<span class="code-quote">"targetConnectionFactory"</span> ref=<span class="code-quote">"jmsConnectionFactory"</span>/&gt;
&nbsp;&nbsp;&nbsp;&lt;/bean&gt;
&nbsp;&nbsp;&lt;/property&gt;
&nbsp;&nbsp;&lt;!-- custom MessageConverter --&gt;
&nbsp;&nbsp;&lt;property name=<span class="code-quote">"messageConverter"</span> ref=<span class="code-quote">"orderMessageConverter"</span>/&gt;
&nbsp;&lt;/bean&gt;</pre>
</div>
</div>
<p><strong>2.Producer</strong></p>
<p>&nbsp;&nbsp; 消息发送者，使用JmsTemplate发送消息，绑定了JmsTemplate (含A、C)与(B)Queue。</p>
<div class="code">
<div class="codeContent">
<pre class="code-java">&lt;!-- POJO which send Message uses&nbsp; Spring JmsTemplate，绑定JMSTemplate 与Queue --&gt;
&nbsp;&lt;bean id=<span class="code-quote">"orderMessageProducer"</span> class=<span class="code-quote">"org.springside.bookstore.components.activemq.OrderMessageProducer"</span>&gt;
&nbsp;&nbsp;&lt;property name=<span class="code-quote">"template"</span> ref=<span class="code-quote">"jmsTemplate"</span>/&gt;
&nbsp;&nbsp;&lt;property name=<span class="code-quote">"destination"</span> ref=<span class="code-quote">"destination"</span>/&gt;
&nbsp;&lt;/bean&gt;</pre>
</div>
</div>
<h3><a name="ActiveMQ-3.3%E6%8E%A5%E6%94%B6%E7%AB%AF"></a>3.3 接收端</h3>
<p><strong>&nbsp;&nbsp;1.接收处理者(MDP)</strong></p>
<p>&nbsp;&nbsp;&nbsp; 使用Spring的MessageListenerAdapter，指定负责处理消息的POJO及其方法名，绑定(C)Converter。</p>
<div class="code">
<div class="codeContent">
<pre class="code-java">&nbsp;&nbsp;&lt;!--&nbsp; Message Driven POJO (MDP)，绑定Converter --&gt;
&nbsp;&lt;bean id=<span class="code-quote">"messageListener"</span> class=<span class="code-quote">"org.springframework.jms.listener.adapter.MessageListenerAdapter"</span>&gt;
&nbsp;&nbsp;&lt;constructor-arg&gt;
&nbsp;&nbsp;&nbsp;&lt;bean class=<span class="code-quote">"org.springside.bookstore.components.activemq.OrderMessageConsumer"</span>&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name=<span class="code-quote">"mailService"</span> ref=<span class="code-quote">"mailService"</span>/&gt;
&nbsp;&nbsp;&nbsp;&lt;/bean&gt;
&nbsp;&nbsp;&lt;/constructor-arg&gt;
&nbsp;&nbsp;&lt;!--&nbsp; may be other method --&gt;
&nbsp;&nbsp;&lt;property name=<span class="code-quote">"defaultListenerMethod"</span> value=<span class="code-quote">"sendEmail"</span>/&gt;
&nbsp;&nbsp;&lt;!-- custom MessageConverter define --&gt;
&nbsp;&nbsp;&lt;property name=<span class="code-quote">"messageConverter"</span> ref=<span class="code-quote">"orderMessageConverter"</span>/&gt;
&nbsp;&lt;/bean&gt;&nbsp;</pre>
</div>
</div>
<p><strong>2. listenerContainer</strong></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;负责调度MDP，&nbsp;绑定(A) connectionFactory, (B)Queue和MDP。</p>
<div class="code">
<div class="codeContent">
<pre class="code-java">&lt;!--&nbsp; <span class="code-keyword">this</span> is the attendant message listener container --&gt;
&nbsp;&lt;bean id=<span class="code-quote">"listenerContainer"</span> class=<span class="code-quote">"org.springframework.jms.listener.DefaultMessageListenerContainer"</span>&gt;
&nbsp;&nbsp;&lt;property name=<span class="code-quote">"connectionFactory"</span> ref=<span class="code-quote">"jmsConnectionFactory"</span>/&gt;
&nbsp;&nbsp;&lt;property name=<span class="code-quote">"destination"</span> ref=<span class="code-quote">"destination"</span>/&gt;
&nbsp;&nbsp;&lt;property name=<span class="code-quote">"messageListener"</span> ref=<span class="code-quote">"messageListener"</span>/&gt;
&nbsp;&lt;/bean&gt;</pre>
</div>
</div>
<p>&nbsp; 互相绑定的关系有点晕，发送端和接收端都以不同形式绑定了(A) connectionFactory, (B)Queue和 (C)Converter。</p>
<h2><a name="ActiveMQ-4.%E4%B8%8B%E7%AF%87"></a>4. 下篇</h2>
<br />
<h2><a name="ActiveMQ-part2-1.%E8%AF%B4%E6%98%8E"></a>1. 说明</h2>
<p>&nbsp;&nbsp; 请先阅读<a title="ActiveMQ" href="http://wiki.springside.org.cn/display/springside/ActiveMQ">ActiveMQ4.1 +Spring2.0的POJO JMS方案(上)</a></p>
<p>&nbsp;&nbsp; 本篇将补充说明了：</p>
<p>&nbsp;&nbsp; 1) 使用数据库持久化消息，保证服务器重启时消息不会丢失<br />
&nbsp;&nbsp; 2) 使用Jencks作正宗的JCA Container。</p>
<h2><a name="ActiveMQ-part2-2.%E6%8C%81%E4%B9%85%E5%8C%96%E6%B6%88%E6%81%AF"></a>2.持久化消息</h2>
<h3><a name="ActiveMQ-part2-2.1%E7%BB%99Broker%E5%8A%A0%E5%85%A5%E9%85%8D%E7%BD%AE"></a>2.1 给Broker加入<font color="#800000">Persistence</font> 配置</h3>
<p>在配置文件applicationContext-activemq-embedded-persitence.xml中的&lt;amq:broker&gt;节点加入&nbsp;&nbsp;</p>
<div class="code">
<div class="codeContent">
<pre class="code-java">&lt;amq:persistenceAdapter&gt;
&lt;amq:jdbcPersistenceAdapter id=<span class="code-quote">"jdbcAdapter"</span> dataSource=<span class="code-quote">"#hsql-ds"</span> createTablesOnStartup=<span class="code-quote">"<span class="code-keyword">true</span>"</span> useDatabaseLock=<span class="code-quote">"<span class="code-keyword">false</span>"</span>/&gt;
&lt;/amq:persistenceAdapter&gt;</pre>
</div>
</div>
<p>请注意MSSQL(2000/2005)和HSQL由于不支持[SELECT&nbsp; * ACTIVEMQ_LOCK FOR UPDATE ]语法,因此不能使用默认的userDatabaseLock="true",只能设置成useDatabaseLock="false"</p>
<h3><a name="ActiveMQ-part2-2.2%E9%85%8D%E7%BD%AE%E5%A4%9A%E7%A7%8D%E6%95%B0%E6%8D%AE%E6%BA%90"></a>2.2 配置多种数据源</h3>
<p>配置多种数据源,给jdbcPersistenceAdapter使用，SpringSide 中使用的内嵌HSQL</p>
<div class="code">
<div class="codeContent">
<pre class="code-java">&nbsp;&lt;!-- The HSQL Datasource that will be used by the Broker --&gt;
&lt;bean id=<span class="code-quote">"hsql-ds"</span> class=<span class="code-quote">"org.apache.commons.dbcp.BasicDataSource"</span> destroy-method=<span class="code-quote">"close"</span>&gt;
&lt;property name=<span class="code-quote">"driverClassName"</span> value=<span class="code-quote">"org.hsqldb.jdbcDriver"</span>/&gt;
&lt;property name=<span class="code-quote">"url"</span> value=<span class="code-quote">"jdbc:hsqldb:res:hsql/activemq"</span>/&gt;
&lt;property name=<span class="code-quote">"username"</span> value=<span class="code-quote">"sa"</span>/&gt;
&lt;property name=<span class="code-quote">"password"</span> value=""/&gt;
&lt;property name=<span class="code-quote">"poolPreparedStatements"</span> value=<span class="code-quote">"<span class="code-keyword">true</span>"</span>/&gt;
&lt;/bean&gt;</pre>
</div>
</div>
<h3><a name="ActiveMQ-part2-2.3%E8%AF%B4%E6%98%8E"></a>2. 3 说明</h3>
<p>&nbsp;&nbsp; 笔者仅仅使用了jdbcPersistenceAdapter,其实在ActiveMQ的XSD已经描述了多种PersistenceAdapter,可以参考对应的XSD文件.</p>
<p>&nbsp;&nbsp;另外对于数据库的差异主要表现在设置了userDatabaseLock="true"之后，ActiveMQ使用的[SELECT * ACTIVEMQ_LOCK&nbsp;FOR UPDATE] 上面，会导致一些数据库出错(测试中MSSQL2000/2005,HSQL都会导致出错)。另外HSQL的脚本请参见activemq.script。</p>
<h2><a name="ActiveMQ-part2-3.Jenck%28JCAContainer%29%26nbsp%3B%26nbsp%3B"></a>3. Jenck(JCA Container)&nbsp;&nbsp;</h2>
<p>&nbsp;&nbsp; Spring 2.0本身使用DefaultMessageListenerContainer 可以充当MDP中的Container角色，但是鉴于Jencks是JCA标准的，它不仅仅能够提供jms的jca整合,包括其他资源比如jdbc都可以做到jca管理</p>
<p>所以,同时完成了这个ActiveMQ+Spring+Jencks 配置演示,更多的针对生产系统的JCA特性展示,会在稍后的开发计划讨论中确定。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 此文档适用于说明使用 Jecncks 和 使用Spring 2.0(DefaultMessageListenerContainer)&nbsp; 充当MDP Container时的区别，同时演示Jecnks 的Spring 2.0 新配置实例。</p>
<h3><a name="ActiveMQ-part2-3.1%E5%BC%95%E5%85%A5ActiveMQResourceAdapter%E5%92%8CJencks%E7%9A%84XSD"></a>3.1 引入ActiveMQ ResourceAdapter 和Jencks 的XSD</h3>
<p>&nbsp; 在ApplicationContext.xml(Spring的配置文件)中引入ActiveMQ ResourceAdapter 和Jencks 的XML Scheam 配置文件),如下:</p>
<p>&nbsp;&nbsp; ActiveMQ4.1 响应Spring 2.0号召，支持了引入XML Schema namespace的简单配置语法，简化了配置的语句。&nbsp;</p>
<p>&nbsp; 在ApplicationContext.xml(Spring的配置文件)中引入ActiveMQ的XML Scheam 配置文件),如下:</p>
<div class="code">
<div class="codeContent">
<pre class="code-java">&lt;beans
xmlns=<span class="code-quote">"http:<span class="code-comment">//www.springframework.org/schema/beans"</span>   xmlns:amq=<span class="code-quote">"http://activemq.org/config/1.0"</span>   xmlns:ampra=<span class="code-quote">"http://activemq.org/ra/1.0"</span>   xmlns:jencks=<span class="code-quote">"http://jencks.org/1.3"</span>   xmlns:xsi=<span class="code-quote">"http://www.w3.org/2001/XMLSchema-instance"</span>
</span>&nbsp; xsi:schemaLocation="http:<span class="code-comment">//www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
</span>&nbsp; http:<span class="code-comment">//activemq.org/config/1.0 http://people.apache.org/repository/org.apache.activemq/xsds/activemq-core-4.1-incubator-SNAPSHOT.xsd
</span>&nbsp; http:<span class="code-comment">//activemq.org/ra/1.0 http://people.apache.org/repository/org.apache.activemq/xsds/activemq-ra-4.1-incubator-SNAPSHOT.xsd
</span>&nbsp; http:<span class="code-comment">//jencks.org/1.3 http://repository.codehaus.org/org/jencks/jencks/1.3/jencks-1.3.xsd"&gt;</span></pre>
</div>
</div>
<p>由于ActiveMQ RA和Jencks&nbsp;那个XSD 仍然有部分错误，因此使用的是自行修改过的XSD。(是xs:any元素引起的错误)</p>
<p>先在ClassPath根目录放一个修改过的activemq-ra-4.1-incubator-SNAPSHOT.xsd和jencks-1.3.xsd。</p>
<p>同样修改 ClassPath 下面META-INF\spring.schemas <font color="#990000">增加</font>内容如下。这个spring.schemas是spring自定义scheam的配置文件,请注意"http:\://"部分写法</p>
<div class="code">
<div class="codeContent">
<pre class="code-java">http\:<span class="code-comment">//people.apache.org/repository/org.apache.activemq/xsds/activemq-ra-4.1-incubator-SNAPSHOT.xsd=/activemq-ra-4.1-incubator-SNAPSHOT.xsd
</span>http\:<span class="code-comment">//repository.codehaus.org/org/jencks/jencks/1.3/jencks-1.3.xsd=/jencks-1.3.xsd</span></pre>
</div>
</div>
<h3><a name="ActiveMQ-part2-3.2%26nbsp%3B%E9%85%8D%E7%BD%AE%E6%96%B9%E6%A1%88"></a>3.2 &nbsp;配置方案</h3>
<h3><a name="ActiveMQ-part2-3.2.1%26nbsp%3B%E5%9F%BA%E7%A1%80%E9%9B%B6%E4%BB%B6%26nbsp%3B"></a>3.2.1&nbsp;基础零件&nbsp;</h3>
<p><strong>1.&nbsp;配置ActiveMQ Broker</strong>&nbsp; 参见 <span class="nobr"><a title="Visit page outside Confluence" href="http://wiki.springside.org.cn/display/springside/ActiveMQ+Spring" rel="nofollow">ActiveMQ+Spring<sup><img class="rendericon" height="7" alt="" src="http://wiki.springside.org.cn/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _counted="undefined" /></sup></a></span></p>
<p><strong>2.&nbsp;配置ActiveMQ Resource Adapter</strong></p>
<div class="code">
<div class="codeContent">
<pre class="code-java">&lt;amqra:managedConnectionFactory id=<span class="code-quote">"jmsManagedConnectionFactory"</span> resourceAdapter=<span class="code-quote">"#resourceAdapter"</span>/&gt;&lt;amqra:resourceAdapter id=<span class="code-quote">"resourceAdapter"</span> serverUrl=<span class="code-quote">"vm:<span class="code-comment">//localhost"</span> /&gt;</span></pre>
</div>
</div>
<p><strong>3.&nbsp;配置Jencks 基础配置</strong></p>
<p><strong>&nbsp;&nbsp;</strong> 具体的配置可以参见Jencks的XSD</p>
<div class="code">
<div class="codeContent">
<pre class="code-java">&lt;!-- jencks PoolFactory config--&gt;
&lt;jencks:singlePoolFactory id=<span class="code-quote">"poolingSupport"</span> maxSize=<span class="code-quote">"16"</span> minSize=<span class="code-quote">"5"</span> blockingTimeoutMilliseconds=<span class="code-quote">"60"</span> idleTimeoutMinutes=<span class="code-quote">"60"</span> matchOne=<span class="code-quote">"<span class="code-keyword">true</span>"</span> matchAll=<span class="code-quote">"<span class="code-keyword">true</span>"</span> selectOneAssumeMatch=<span class="code-quote">"<span class="code-keyword">true</span>"</span> /&gt;&nbsp;&lt;!-- jencks XATransactionFactory --&gt;
&lt;jencks:xATransactionFactory id=<span class="code-quote">"transactionSupport"</span> useTransactionCaching=<span class="code-quote">"<span class="code-keyword">true</span>"</span> useThreadCaching=<span class="code-quote">"<span class="code-keyword">true</span>"</span> /&gt;&nbsp;&nbsp;
&lt;!-- jencks ConnectionManagerFactory --&gt;
&lt;jencks:connectionManagerFactory id=<span class="code-quote">"connectionManager"</span> containerManagedSecurity=<span class="code-quote">"<span class="code-keyword">false</span>"</span>&nbsp; poolingSupport=<span class="code-quote">"#poolingSupport"</span> transactionSupport=<span class="code-quote">"#transactionSupport"</span> /&gt;&nbsp;&lt;!-- jencks TransactionContextManagerFactory --&gt;
&lt;jencks:transactionContextManagerFactory id=<span class="code-quote">"transactionContextManagerFactory"</span>/&gt;
&nbsp;&nbsp;</pre>
</div>
</div>
<p><strong>4.&nbsp;配置给JmsTemplate使用的connectionFactory (主要是生成者/发送者 使用)</strong></p>
<p>&nbsp;&nbsp; 这里注意下,在配置jmsTemplate的使用的targetConnectionFactory就是使用jencks配置的connectionManager</p>
<div class="code">
<div class="codeContent">
<pre class="code-java">&lt;!-- spring config jms with jca--&gt;
&nbsp;&lt;bean id=<span class="code-quote">"jmsManagerConnectionFactory"</span> class=<span class="code-quote">"org.springframework.jca.support.LocalConnectionFactoryBean"</span>&gt;
&nbsp;&nbsp;&lt;property name=<span class="code-quote">"managedConnectionFactory"</span>&gt;
&nbsp;&nbsp;&nbsp;&lt;ref local=<span class="code-quote">"jmsManagedConnectionFactory"</span> /&gt;
&nbsp;&nbsp;&lt;/property&gt;
&nbsp;&nbsp;&lt;property name=<span class="code-quote">"connectionManager"</span>&gt;
&nbsp;&nbsp;&nbsp;&lt;ref local=<span class="code-quote">"connectionManager"</span> /&gt;
&nbsp;&nbsp;&lt;/property&gt;
&nbsp;&lt;/bean&gt;
&nbsp;
&nbsp;&lt;!--&nbsp; Spring JmsTemplate config --&gt;
&nbsp;&lt;bean id=<span class="code-quote">"jmsTemplate"</span> class=<span class="code-quote">"org.springframework.jms.core.JmsTemplate"</span>&gt;
&nbsp;&nbsp;&lt;property name=<span class="code-quote">"connectionFactory"</span>&gt;
&nbsp;&nbsp;&nbsp;&lt;!--&nbsp; lets wrap in a pool to avoid creating a connection per send --&gt;
&nbsp;&nbsp;&nbsp;&lt;bean class=<span class="code-quote">"org.springframework.jms.connection.SingleConnectionFactory"</span>&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name=<span class="code-quote">"targetConnectionFactory"</span> ref=<span class="code-quote">"jmsManagerConnectionFactory"</span> /&gt;
&nbsp;&nbsp;&nbsp;&lt;/bean&gt;
&nbsp;&nbsp;&lt;/property&gt;
&nbsp;&nbsp;&lt;!-- custom MessageConverter --&gt;
&nbsp;&nbsp;&lt;property name=<span class="code-quote">"messageConverter"</span> ref=<span class="code-quote">"orderMessageConverter"</span> /&gt;
&nbsp;&lt;/bean&gt;&nbsp;&nbsp;</pre>
</div>
</div>
<p><strong>5.&nbsp;配置Spring 2.0的MessageListenerAdapter,保证不需要用户实现MessageListener</strong></p>
<p><strong>&nbsp;&nbsp;</strong> 见<span class="nobr"><a title="Visit page outside Confluence" href="http://wiki.springside.org.cn/display/springside/ActiveMQ+Spring" rel="nofollow">ActiveMQ+Spring<sup><img class="rendericon" height="7" alt="" src="http://wiki.springside.org.cn/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" _counted="undefined" /></sup></a></span></p>
<p>&nbsp;6.<strong>配置Jecnks 充当MDP的Container</strong></p>
<p><strong>&nbsp;</strong> 就是把上面的MessageListenerAdapter配置到Jencks里面,完成整个MDP的配置</p>
<div class="code">
<div class="codeContent">
<pre class="code-java">&nbsp;&lt;!-- Jencks Container--&gt;
&nbsp;&lt;jencks:jcaContainer&gt;&nbsp;&nbsp;	&lt;jencks:bootstrapContext&gt;
&nbsp;&nbsp;&nbsp;		&lt;jencks:bootstrapContextFactory threadPoolSize=<span class="code-quote">"25"</span> /&gt;
&nbsp;&nbsp;	&lt;/jencks:bootstrapContext&gt;
&nbsp;&nbsp;		&lt;jencks:connectors&gt;
&nbsp;&nbsp;&nbsp;	&nbsp;&nbsp;&nbsp;&lt;!-- use jencks container (use spring MessageListenerAdapter)--&gt;
&nbsp;&nbsp;&nbsp;		&lt;jencks:connector ref=<span class="code-quote">"messageListener"</span>&gt;
&nbsp;&nbsp;&nbsp;&nbsp;			&lt;jencks:activationSpec&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;				&lt;amqra:activationSpec destination=<span class="code-quote">"org.apache.activemq.spring.Test.spring.embedded"</span> destinationType=<span class="code-quote">"javax.jms.Queue"</span> /&gt;
&nbsp;&nbsp;&nbsp;&nbsp;			&lt;/jencks:activationSpec&gt;
&nbsp;&nbsp;&nbsp;		&lt;/jencks:connector&gt;&nbsp;&nbsp;	&lt;/jencks:connectors&gt;&nbsp;		&nbsp;&lt;jencks:resourceAdapter&gt;
&nbsp;&nbsp;&nbsp;		&lt;amqra:resourceAdapter serverUrl=<span class="code-quote">"vm:<span class="code-comment">//localhost"</span> /&gt;
</span>&nbsp;&nbsp;	&lt;/jencks:resourceAdapter&gt;
&nbsp;&lt;/jencks:jcaContainer&gt;</pre>
</div>
</div>
<br />
<img src ="http://www.blogjava.net/hk2000c/aggbug/192305.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2008-04-12 01:37 <a href="http://www.blogjava.net/hk2000c/archive/2008/04/12/192305.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Servlet API 和 NIO: 最终组合在一起</title><link>http://www.blogjava.net/hk2000c/archive/2008/01/03/172595.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Thu, 03 Jan 2008 14:58:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2008/01/03/172595.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/172595.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2008/01/03/172595.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/172595.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/172595.html</trackback:ping><description><![CDATA[<blockquote>您认为把 NIO 和 Servlet API 组合在一起是不可能的？请再好好想一下。在本文中，Java 开发人员 Taylor Cowan 向您展示了如何把生产者/消费者模型应用到消费者非阻塞 I/O，从而轻松地让 Servlet API 全新地兼容 NIO。在这个过程中，您将会看到采用了什么来创建实际的基于 Servlet 并实现了 NIO 的 Web 服务器；您也将发现在企业环境中，那个服务器是如何以标准的 Java I/O 服务器（Tomcat 5.0）为基础而创建的。</blockquote><!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--end RESERVED FOR FUTURE USE INCLUDE FILES-->
<p>NIO 是带有 JDK 1.4 的 Java 平台的最有名（如果不是最出色的）的添加部分之一。下面的许多文章阐述了 NIO 的基本知识及如何利用非阻塞通道的好处。但它们所遗漏的一件事正是，没有充分地展示 NIO 如何可以提高 J2EE Web 层的可伸缩性。对于企业开发人员来说，这些信息特别密切相关，因为实现 NIO 不像把少数几个 import 语句改变成一个新的 I/O 包那样简单。首先，Servlet API 采用阻塞 I/O 语义，因此默认情况下，它不能利用非阻塞 I/O。其次，不像 JDK 1.0 中那样，线程不再是&#8220;资源独占&#8221;（resource hog），因此使用较少的线程不一定表明服务器可以处理更多的客户机。</p>
<p>在本文中，为了创建基于 Servlet 并实现了 NIO 的 Web 服务器，您将学习如何解决 Servlet API 与非阻塞 I/O 的不配合问题。我们将会看到在多元的 Web 服务器环境中，这个服务器是如何针对标准 I/O 服务器（Tomcat 5.0）进行伸缩的。为符合企业中生存期的事实，我们将重点放在当保持 socket 连接的客户机数量以指数级增长时，NIO 与标准 I/O 相比较的情况如何。</p>
<p>注意，本文针对某些 Java 开发人员，他们已经熟悉了 Java 平台上 I/O 编程的基础知识。有关非阻塞 I/O 的介绍，请参阅 <a href="http://www.ibm.com/developerworks/cn/java/j-nioserver/index.html#resources">参考资料</a> 部分。 </p>
<p><a name="IDAYBGLB"><span class="atitle">线程不再昂贵</span></a></p>
<p>大家都知道，线程是比较昂贵的。在 Java 平台的早期（JDK 1.0），线程的开销是一个很大负担，因此强制开发人员自定义生成解决方案。一个常见的解决方案是使用 VM 启动时创建的线程池，而不是按需创建每个新线程。尽管最近在 VM 层上提高了线程的性能，但标准 I/O 仍然要求分配惟一的线程来处理每个新打开的 socket。就短期而言，这工作得相当不错，但当线程的数量增加超过了 1K，标准 I/O 的不足就表现出来了。由于要在线程间进行上下文切换，因此 CPU 简直变成了超载。</p>
<p>由于 JDK 1.4 中引入了 NIO，企业开发人员最终有了&#8220;单线程&#8221;模型的一个内置解决方案：多元 I/O 使得固定数量的线程可以服务不断增长的用户数量。</p>
<p><em>多路复用（Multiplexing）</em>指的是通过一个载波来同时发送多个信号或流。当使用手机时，日常的多路复用例子就发生了。无线频率是稀有的资源，因此无线频率提供商使用多路复用技术通过一个频率发送多个呼叫。在一个例子中，把呼叫分成一些段，然后给这些段很短的持续时间，并在接收端重新装配。这就叫做 <em>时分多路复用（time-division multiplexing）</em>，即 TDM。 </p>
<p>在 NIO 中，接收端相当于&#8220;选择器&#8221;（参阅 <code>java.nio.channels.Selector</code> ）。不是处理呼叫，选择器是处理多个打开的 socket。就像在 TDM 中那样，选择器重新装配从多个客户机写入的数据段。这使得服务器可以用单个线程管理多个客户机。 </p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-nioserver/index.html#main"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="IDALCGLB"><span class="atitle">Servlet API 和 NIO</span></a></p>
<p>对于 NIO，非阻塞读写是必要的，但它们并不是完全没有麻烦。除了不会阻塞之外，非阻塞读不能给呼叫方任何保证。客户机或服务器应用程序可能读取完整信息、部分消息或者根本读取不到消息。另外，非阻塞读可能读取到太多的消息，从而强制为下一个呼叫准备一个额外的缓冲区。最后，不像流那样，读取了零字节并不表明已经完全接收了消息。</p>
<p>这些因素使得没有轮询就不可能实现甚至是简单的 <code>readline</code> 方法。所有的 servlet 容器必须在它们的输入流上提供 <code>readline</code> 方法。因此，许多开发人员放弃了创建基于 Servlet 并实现了 NIO 的 Web 应用程序服务器。不过这里有一个解决方案，它组合了 Servlet API 和 NIO 的多元 I/O 的能力。 </p>
<p>在下面的几节中，您将学习如何使用 <code>java.io.PipedInput</code> 和 <code>PipedOutputStream</code> 类来把生产者/消费者模型应用到消费者非阻塞 I/O。当读取非阻塞通道时，把它写到正由第二个线程消费的管道。注意，这种分解映射线程不同于大多数基于 Java 的客户机/服务器应用程序。这里，我们让一个线程单独负责处理非阻塞通道（生产者），让另一个线程单独负责把数据作为流消费（消费者）。管道也为应用程序服务器解决了非阻塞 I/O 问题，因为 servlet 在消费 I/O 时将采用阻塞语义。 </p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-nioserver/index.html#main"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="IDAFDGLB"><span class="atitle">示例服务器</span></a></p>
<p>示例服务器展示了 Servlet API 和 NIO 不兼容的生产者/消费者解决方案。该服务器与 Servlet API 非常相似，可以为成熟的基于 NIO 应用程序服务器提供 POC (proof of concept)，是专门编写来衡量 NIO 相对于标准 Java I/O 的性能的。它处理简单的 HTTP <code>get</code> 请求，并支持来自客户机的 Keep-Alive 连接。这是重要的，因为多路复用 I/O 只证明在要求服务器处理大量打开的 scoket 连接时是有意的。 </p>
<p>该服务器被分成两个包： <code>org.sse.server</code> 和 <code>org.sse.http</code> 包中有提供主要 <code>服务器</code> 功能的类，比如如下的一些功能：接收新客户机连接、阅读消息和生成工作线程以处理请求。 <code>http</code> 包支持 HTTP 协议的一个子集。详细阐述 HTTP 超出了本文的范围。有关实现细节，请从 <a href="http://www.ibm.com/developerworks/cn/java/j-nioserver/index.html#resources">参考资料</a> 部分下载代码示例。 </p>
<p>现在让我们来看一下 <code>org.sse.server</code> 包中一些最重要的类。 </p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-nioserver/index.html#main"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="IDALEGLB"><span class="atitle">Server 类</span></a></p>
<p><code>Server</code> 类拥有多路复用循环 —— 任何基于 NIO 服务器的核心。在清单 1 中，在服务器接收新客户机或检测到正把可用的字节写到打开的 socket 前， <code>select()</code> 的调用阻塞了。这与标准 Java I/O 的主要区别是，所有的数据都是在这个循环中读取的。通常会把从特定 socket 中读取字节的任务分配给一个新线程。使用 NIO 选择器事件驱动方法，实际上可以用单个线程处理成千上万的客户机，不过，我们还会在后面看到线程仍有一个角色要扮演。 </p>
<p>每个 <code>select()</code> 调用返回一组事件，指出新客户机可用；新数据准备就绪，可以读取；或者客户机准备就绪，可以接收响应。server 的 <code>handleKey()</code> 方法只对新客户机（ <code>key.isAcceptable()</code> ）和传入数据 ( <code>key.isReadable()</code> ) 感兴趣。到这里，工作就结束了，转入 <code>ServerEventHandler</code> 类。 </p>
<br />
<a name="IDAQFGLB"><strong>清单 1. Server.java 选择器循环</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">public void listen() {
            SelectionKey key = null;
            try {
            while (true) {
            selector.select();
            Iterator it = selector.selectedKeys().iterator();
            while (it.hasNext()) {
            key = (SelectionKey) it.next();
            handleKey(key);
            it.remove();
            }
            }
            } catch (IOException e) {
            key.cancel();
            } catch (NullPointerException e) {
            // NullPointer at sun.nio.ch.WindowsSelectorImpl, Bug: 4729342
            e.printStackTrace();
            }
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-nioserver/index.html#main"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="IDA0FGLB"><span class="atitle">ServerEventHandler 类</span></a></p>
<p><code>ServerEventHandler</code> 类响应服务器事件。当新客户机变为可用时，它就实例化一个新的 <code>Client</code> 对象，该对象代表了那个客户机的状态。数据是以非阻塞方式从通道中读取的，并被写到 <code>Client</code> 对象中。 <code>ServerEventHandler</code> 对象也维护请求队列。为了处理（消费）队列中的请求，生成了不定数量的工作线程。在传统的生产者/消费者方式下，为了在队列变为空时线程会阻塞，并在新请求可用时线程会得到通知，需要写 <code>Queue</code> 。 </p>
<p>为了支持等待的线程，在清单 2 中已经重写了 <code>remove()</code> 方法。如果列表为空，就会增加等待线程的数量，并阻塞当前线程。它实质上提供了非常简单的线程池。 </p>
<br />
<a name="IDA1GGLB"><strong>清单 2. Queue.java</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">public class Queue extends LinkedList
            {
            private int waitingThreads = 0;
            public synchronized void insert(Object obj)
            {
            addLast(obj);
            notify();
            }
            public synchronized Object remove()
            {
            if ( isEmpty() ) {
            try	{ waitingThreads++; wait();}
            catch (InterruptedException e)  {Thread.interrupted();}
            waitingThreads--;
            }
            return removeFirst();
            }
            public boolean isEmpty() {
            return 	(size() - waitingThreads &lt;= 0);
            }
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>工作线程的数量与 Web 客户机的数量无关。不是为每个打开的 socket 分配一个线程，相反，我们把所有请求放到一个由一组 <code>RequestHandlerThread</code> 实例所服务的通用队列中。理想情况下，线程的数量应该根据处理器的数量和请求的长度或持续时间进行调整。如果请求通过资源或处理需求花了很长时间，那么通过添加更多的线程，可以提高感知到的服务质量。 </p>
<p>注意，这不一定提高整体的吞吐量，但确实改善了用户体验。即使在超载的情况下，也会给每个线程一个处理时间片。这一原则同样适用于基于标准 Java I/O 的服务器；不过这些服务器是受到限制的，因为会 <em>要求</em> 它们为每个打开的 socket 连接分配一个线程。NIO 服务器完全不用担心这一点，因此它们可以扩展到大量用户。最后的结果是 NIO 服务器仍然需要线程，只是不需要那么多。 </p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-nioserver/index.html#main"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="IDANHGLB"><span class="atitle">请求处理</span></a></p>
<p><code>Client</code> 类有两个用途。首先，通过把传入的非阻塞 I/O 转换成可由 Servlet API 消费的阻塞 <code>InputStream</code> ，它解决了阻塞/非阻塞问题。其次，它管理特定客户机的请求状态。因为当全部读取消息时，非阻塞通道没有给出任何提示，所以强制我们在协议层处理这一情况。 <code>Client</code> 类在任意指定的时刻都指出了它是否正在参与进行中的请求。如果它准备处理新请求， <code>write()</code> 方法就会为请求处理而将该客户机排到队列中。如果它已经参与了请求，它就只是使用 <code>PipedInputStream</code> 和 <code>PipedOutputStream</code> 类把传入的字节转换成一个 <code>InputStream</code> 。 </p>
<p>图 1 展示了两个线程围绕管道进行交互。主线程把从通道读取的数据写到管道中。管道把相同的数据作为 <code>InputStream</code> 提供给消费者。管道的另一个重要特性是：它是进行缓冲处理的。如果没有进行缓冲处理，主线程在尝试写到管道时就会阻塞。因为主线程单独负责所有客户机间的多路复用，因此我们不能让它阻塞。 </p>
<br />
<a name="IDA0YGLB"><strong>图 1. PipedInput/OutputStream</strong></a><br />
<img height="111" alt="关系的图形表示" src="http://www.ibm.com/developerworks/cn/java/j-nioserver/figure1.gif" width="454" /> <br />
<p>在 <code>Client</code> 自己排队后，工作线程就可以消费它了。 <code>RequestHandlerThread</code> 类承担了这个角色。至此，我们已经看到主线程是如何连续地循环的，它要么接受新客户机，要么读取新的 I/O。工作线程循环等待新请求。当客户机在请求队列上变为可用时，它就马上被 <code>remove()</code> 方法中阻塞的第一个等待线程所消费。 </p>
<br />
<a name="IDATZGLB"><strong>清单 3. RequestHandlerThread.java</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">public void run() {
            while (true) {
            Client client = (Client) myQueue.remove();
            try {
            for (; ; ) {
            HttpRequest req = new HttpRequest(client.clientInputStream,
            myServletContext);
            HttpResponse res = new HttpResponse(client.key);
            defaultServlet.service(req, res);
            if (client.notifyRequestDone())
            break;
            }
            } catch (Exception e) {
            client.key.cancel();
            client.key.selector().wakeup();
            }
            }
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>然后该线程创建新的 <code>HttpRequest</code> 和 <code>HttpResponse</code> 实例，并调用 <code>defaultServlet</code> 的 service 方法。注意， <code>HttpRequest</code> 是用 <code>Client</code> 对象的 <code>clientInputStream</code> 属性构造的。 <code>PipedInputStream</code> 就是负责把非阻塞 I/O 转换成阻塞流。 </p>
<p>从现在开始，请求处理就与您在 J2EE Servlet API 中期望的相似。当对 servlet 的调用返回时，工作线程在返回到池中之前，会检查是否有来自相同客户机的另一个请求可用。注意，这里用到了单词 <em>池 (pool)</em>。事实上，线程会对队列尝试另一个 <code>remove()</code> 调用，并变成阻塞，直到下一个请求可用。 </p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-nioserver/index.html#main"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="IDA30GLB"><span class="atitle">运行示例</span></a></p>
<p>示例服务器实现了 HTTP 1.1 协议的一个子集。它处理普通的 HTTP <code>get</code> 请求。它带有两个命令行参数。第一个指定端口号，第二个指定 HTML 文件所驻留的目录。在解压文件后， <em>切换</em>到项目目录，然后执行下面的命令，注意要把下面的 webroot 目录替换为您自己的目录： </p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">java -cp bin org.sse.server.Start 8080
            "C:\mywebroot"
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>还请注意，服务器并没有实现目录清单，因此必须指定有效的 URL 来指向您的 webroot 目录下的文件。</p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-nioserver/index.html#main"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="IDAP1GLB"><span class="atitle">性能结果</span></a></p>
<p>示例 NIO 服务器是在重负载下与 Tomcat 5.0 进行比较的。选择 Tomcat 是因为它是基于标准 Java I/O 的纯 Java 解决方案。为了提高可伸缩性，一些高级的应用程序服务器是用 JNI 本机代码优化的，因此它们没有提供标准 I/O 和 NIO 之间的很好比较。目标是要确定 NIO 是否给出了大量的性能优势，以及是在什么条件下给出的。</p>
<p>如下是一些说明：</p>
<ul>
    <li>Tomcat 是用最大的线程数量 2000 来配置的，而示例服务器只允许用 4 个工作线程运行。 <br />
    <li>每个服务器是针对相同的一组简单 HTTP <code>get</code> 测试的，这些 HTTP <code>get</code> 基本上由文本内容组成。 <br />
    <br />
    <li>把加载工具（Microsoft Web Application Stress Tool）设置为使用&#8220;Keep-Alive&#8221;会话，导致了大约要为每个用户分配一个 socket。然后它导致了在 Tomcat 上为每个用户分配一个线程，而 NIO 服务器用固定数量的线程来处理相同的负载。 </li>
</ul>
<p>图 2 展示了在不断增加负载下的&#8220;请求/秒&#8221;率。在 200 个用户时，性能是相似的。但当用户数量超过 600 时，Tomcat 的性能开始急剧下降。这最有可能是由于在这么多的线程间切换上下文的开销而导致的。相反，基于 NIO 的服务器的性能则以线性方式下降。记住，Tomcat 必须为每个用户分配一个线程，而 NIO 服务器只配置有 4 个工作线程。</p>
<br />
<a name="IDAG2GLB"><strong>图 2. 请求/秒</strong></a><br />
<img height="292" alt="关系的图形表示" src="http://www.ibm.com/developerworks/cn/java/j-nioserver/graph1.gif" width="468" /> <br />
<p>图 3 进一步显示了 NIO 的性能。它展示了操作的 Socket 连接错误数/分钟。同样，在大约 600 个用户时，Tomcat 的性能急剧下降，而基于 NIO 的服务器的错误率保持相对较低。</p>
<br />
<a name="IDAU2GLB"><strong>图 3. Socket 连接错误数/分钟</strong></a><br />
<img height="282" alt="关系的图形表式" src="http://www.ibm.com/developerworks/cn/java/j-nioserver/graph2.gif" width="531" /> <br />
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-nioserver/index.html#main"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<br />
<p><a name="IDAA3GLB"><span class="atitle">结束语</span></a></p>
<p>在本文中您已经学习了，实际上可以使用 NIO 编写基于 Servlet 的 Web 服务器，甚至可以启用它的非阻塞特性。对于企业开发人员来说，这是好消息，因为在企业环境中，NIO 比标准 Java I/O 更能够进行伸缩。不像标准的 Java I/O，NIO 可以用固定数量的线程处理许多客户机。当基于 Servlet 的 NIO Web 服务器用来处理保持和拥有 socket 连接的客户机时，会获得更好的性能。</p>
<br />
<br />
<p><a name="resources"><span class="atitle">参考资料 </span></a></p>
<ul>
    <li>您可以参阅本文在 developerWorks 全球站点上的 <a href="http://www.ibm.com/developerworks/library/j-nioserver/index.html?S_TACT=105AGX52&amp;S_CMP=cn-a-j">英文原文</a>. <br />
    <br />
    <li>下载本文中使用的 <a href="http://download.boulder.ibm.com/ibmdl/pub/software/dw/library/j-nioserver-source.zip">源代码</a>。 <br />
    <br />
    <br />
    <br />
    <li>看看&#8220; <a href="http://www.ibm.com/developerworks/cn/java/j-javaio/">Merlin 给 Java 平台带来了非阻塞 I/O</a>&#8221;（ <em>developerWorks</em>，2002 年 3 月），获得 NIO 语义的进一步知识。 <br />
    <br />
    <br />
    <br />
    <li>综合的 developerWorks 教程&#8220; <a href="http://www.ibm.com/developerworks/cn/views/java/tutorials.jsp?cv_doc_id=85062">NIO 入门</a>&#8221;（ <em>developerWorks</em>，2003 年 11 月）从高级的概念到底层的编程细节，详细论及了 NIO 库。 <br />
    <br />
    <br />
    <br />
    <li>Merlin Hughes 的由两部分组成的文章&#8220; <a href="http://www.ibm.com/developerworks/cn/java/j-io1/">Turning streams inside out</a>&#8221;（ <em>developerWorks</em>，2002 年 9 月）为 Java I/O（标准版和 NIO 版）的一些普遍的挑战提供了制作精巧的设计解决方案。 <br />
    <br />
    <br />
    <br />
    <li>为获取有关 Java I/O 问题的一些背景知识，请参阅 Allen Holub 的&#8220; <a href="http://www.ibm.com/developerworks/cn/java/j-king/">关于解决 Java 编程语言线程问题的建议 </a>&#8221;（ <em>developerWorks</em>，2000 年 10 月）。 <br />
    <br />
    <br />
    <br />
    <li>访问 <a href="http://java.sun.com/j2se/1.4.2/docs/guide/nio/">NIO 主页</a>，从资源中学习非阻塞 I/O。 <br />
    <br />
    <br />
    <br />
    <li><a href="http://www.javanio.info/">JavaNIO.info</a> 是查找有关 NIO 的资源的理想地方。 <br />
    <br />
    <br />
    <br />
    <li>为从书本系统学习 NIO，请参阅该领域的经典著作：Ron Hitchens 的 <a href="http://www.oreilly.com/catalog/javanio/">Java NIO</a>（O'Reilly &amp; Associates，2002 年）。 <br />
    <br />
    <br />
    <br />
    <li>在 developerWorks <a href="http://www.ibm.com/developerworks/cn/java/">Java 技术专区</a>可以找到有关 Java 编程各个方面的文章。 <br />
    <br />
    <br />
    <br />
    <li>访问 <a href="http://devworks.krcinfo.com/">Developer Bookstore</a>，获取技术书籍的完整列表，其中包括数百本 <a href="http://devworks.krcinfo.com/WebForms/ProductList.aspx?Search=Category&amp;id=200&amp;parent=Java">Java 相关的图书</a>。 <br />
    <br />
    <br />
    <br />
    <li>也请参阅 <a href="http://www.ibm.com/developerworks/cn/views/java/tutorials.jsp">Java 技术专区教程页</a>，从 <em>developerWorks</em> 获取免费的 Java 专门教程的完整列表。 <br />
    <br />
    <br />
    </li>
</ul>
<br />
<br />
<p><a name="author"><span class="atitle">关于作者</span></a></p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td colspan="3"><img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /></td>
        </tr>
        <tr valign="top" align="left">
            <td>
            <p>&nbsp;</p>
            </td>
            <td><img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="4" /></td>
            <td width="100%">
            <p>Taylor Cowan 是一位软件工程师，也是一位专攻 J2EE 的自由撰稿人。他从 North Texas 大学的计算机科学专业获得了硕士学位，另外，他还从 Jazz Arranging 获得了音乐学士学位。</p>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/hk2000c/aggbug/172595.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2008-01-03 22:58 <a href="http://www.blogjava.net/hk2000c/archive/2008/01/03/172595.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java 多线程入门大全</title><link>http://www.blogjava.net/hk2000c/archive/2008/01/02/172275.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Wed, 02 Jan 2008 10:14:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2008/01/02/172275.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/172275.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2008/01/02/172275.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/172275.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/172275.html</trackback:ping><description><![CDATA[<br />
&nbsp;&nbsp;&nbsp; 一种是继承自Thread类.Thread 类是一个具体的类，即不是抽象类，该类封装了线程的行为。要创建一个线程，程序员必须创建一个从 Thread 类导出的新类。程序员通过覆盖 Thread 的 run() 函数来完成有用的<a onclick="javascript:tagshow(event, '%B9%A4%D7%F7');" href="javascript:;" target="_self"><u><strong><font color="#333333">工作</font></strong></u></a>。<font color="#ff0000">用户并不直接调用此函数；而是通过调用 Thread 的 start() 函数，该函数再调用 run()。</font><br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 例如:
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; public class Test extends Thread{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Test(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String args[]){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Test t1 = new Test();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Test t2 = new Test();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t1.start();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t2.start();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //do thread's things<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;</p>
<hr />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; 另一种是实现Runnable接口,此接口只有一个函数，run()，此函数必须由实现了此接口的类实现。<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 例如:
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; public class Test implements Runnable{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread thread1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread thread2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Test(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thread1 = new Thread(this,"1");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thread2 = new Thread(this,"2");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String args[]){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Test t = new Test();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t.startThreads();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //do thread's things<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void startThreads(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thread1.start();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thread2.start();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; 两种创建方式看起来差别不大,但是弄不清楚的话，也许会将你的程序弄得一团糟。两者区别有以下几点：</p>
<p>1.当你想继承某一其它类时,你只能用后一种方式.</p>
<p>2.<font color="#ff0000">第一种因为继承自Thread,只创建了自身对象,但是在数量上，需要几个线程，就得创建几个自身对象；第二种只创建一个自身对象，却创建几个Thread对象.</font>而两种方法重大的区别就在于此，请你考虑：如果你在第一种里创建数个自身对象并且start()后，你会发现好像synchronized不起作用了，已经加锁的代码块或者方法居然同时可以有几个线程进去，而且同样一个变量，居然可以有好几个线程同时可以去更改它。（例如下面的代码）这是因为，在这个程序中，虽然你起了数个线程，可是你也创建了数个对象，而且，每个线程对应了每个对象也就是说，每个线程更改和占有的对象都不一样，所以就出现了同时有几个线程进入一个方法的现象，其实，那也不是一个方法，而是不同对象的相同的方法。所以，这时候你要加锁的话，只能将方法或者变量声明为静态，将static加上后，你就会发现，线程又能管住方法了，同时不可能有两个线程进入同样一个方法，那是因为，现在不是每个对象都拥有一个方法了，而是所有的对象共同拥有一个方法，这个方法就是静态方法。</p>
<p>&nbsp;&nbsp;&nbsp; 而你如果用第二种方法使用线程的话，就不会有上述的情况，因为此时，你只创建了一个自身对象，所以，自身对象的属性和方法对于线程来说是共有的。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;因此，我建议，最好用后一种方法来使用线程。</p>
<p>public class mainThread extends Thread{<br />
&nbsp; int i=0;<br />
&nbsp; public static void main(String args[]){<br />
&nbsp;&nbsp;&nbsp; mainThread m1 = new mainThread();<br />
&nbsp;&nbsp;&nbsp; mainThread m2 = new mainThread();<br />
&nbsp;&nbsp;&nbsp; mainThread m3 = new mainThread();<br />
&nbsp;&nbsp;&nbsp; mainThread m4 = new mainThread();<br />
&nbsp;&nbsp;&nbsp; mainThread m5 = new mainThread();<br />
&nbsp;&nbsp;&nbsp; mainThread m6 = new mainThread();<br />
&nbsp;&nbsp;&nbsp; m1.start();<br />
&nbsp;&nbsp;&nbsp; m2.start();<br />
&nbsp;&nbsp;&nbsp; m3.start();<br />
&nbsp;&nbsp;&nbsp; m4.start();<br />
&nbsp;&nbsp;&nbsp; m5.start();<br />
&nbsp;&nbsp;&nbsp; m6.start();<br />
&nbsp; }<br />
&nbsp; public synchronized void t1(){<br />
&nbsp;&nbsp;&nbsp; i=++i;<br />
&nbsp;&nbsp;&nbsp; try{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(500);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; catch(Exception e){}<br />
&nbsp;&nbsp;&nbsp; //每个线程都进入各自的t1()方法，分别打印各自的i<br />
&nbsp;&nbsp;&nbsp; System.out.println(Thread.currentThread().getName()+" "+i);<br />
&nbsp; }<br />
&nbsp; public void run(){<br />
&nbsp;&nbsp;&nbsp; synchronized(this){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (true) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t1();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; }<br />
}</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<hr />
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; 下面我们来讲synchronized的4种用法吧:</p>
<p>&nbsp;&nbsp;&nbsp; 1.方法声明时使用,放在范围操作符(public等)之后,返回类型声明(void等)之前.即一次只能有一个线程进入该方法,其他线程要想在此时调用该方法,只能排队等候,当前线程(就是在synchronized方法内部的线程)执行完该方法后,别的线程才能进入.<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例如:</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public synchronized void synMethod() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //方法体<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; 2.对某一代码块使用,synchronized后跟括号,括号里是变量,这样,一次只有一个线程进入该代码块.例如:</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public int synMethod(int a1){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronized(a1) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //一次只能有一个线程进入<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; 3.synchronized后面括号里是一对象,此时,线程获得的是对象锁.例如:</p>
<blockquote dir="ltr" style="margin-right: 0px">
<blockquote dir="ltr" style="margin-right: 0px">
<blockquote dir="ltr" style="margin-right: 0px">
<p>public class MyThread implements Runnable {<br />
&nbsp; public static void main(String args[]) {<br />
&nbsp;&nbsp;&nbsp; MyThread mt = new MyThread();<br />
&nbsp;&nbsp;&nbsp; Thread t1 = new Thread(mt, "t1");<br />
&nbsp;&nbsp;&nbsp; Thread t2 = new Thread(mt, "t2");<br />
&nbsp;&nbsp;&nbsp; Thread t3 = new Thread(mt, "t3");<br />
&nbsp;&nbsp;&nbsp; Thread t4 = new Thread(mt, "t4");<br />
&nbsp;&nbsp;&nbsp; Thread t5 = new Thread(mt, "t5");<br />
&nbsp;&nbsp;&nbsp; Thread t6 = new Thread(mt, "t6");<br />
&nbsp;&nbsp;&nbsp; t1.start();<br />
&nbsp;&nbsp;&nbsp; t2.start();<br />
&nbsp;&nbsp;&nbsp; t3.start();<br />
&nbsp;&nbsp;&nbsp; t4.start();<br />
&nbsp;&nbsp;&nbsp; t5.start();<br />
&nbsp;&nbsp;&nbsp; t6.start();<br />
&nbsp; }</p>
<p>&nbsp; public void run() {<br />
&nbsp;&nbsp;&nbsp; synchronized (this) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(Thread.currentThread().getName());<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; }<br />
} </p>
</blockquote></blockquote></blockquote>
<p><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp; 对于3,如果线程进入,则得到对象锁,那么别的线程在该类所有对象上的任何操作都不能进行.在对象级使用锁通常是一种比较粗糙的方法。为什么要将整个对象都上锁，而不允许<a onclick="javascript:tagshow(event, '%C6%E4%CB%FB');" href="javascript:;" target="_self"><u><strong><font color="#333333">其他</font></strong></u></a>线程短暂地使用对象中其他同步方法来访问共享资源？如果一个对象拥有多个资源，就不需要只为了让一个线程使用其中一部分资源，就将所有线程都锁在外面。由于每个对象都有锁，可以如下所示使用虚拟对象来上锁：</p>
<blockquote dir="ltr" style="margin-right: 0px">
<blockquote dir="ltr" style="margin-right: 0px">
<blockquote dir="ltr" style="margin-right: 0px">
<p>class FineGrainLock {</p>
<p>&nbsp;&nbsp; MyMemberClass x, y;<br />
&nbsp;&nbsp; Object xlock = new Object(), ylock = new Object();</p>
<p>&nbsp;&nbsp; public void foo() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronized(xlock) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //access x here<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //do something here - but don't use shared resources</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronized(ylock) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //access y here<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp; public void bar() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronized(this) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //access both x and y here<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //do something here - but don't use shared resources<br />
&nbsp;&nbsp; }<br />
}</p>
</blockquote></blockquote></blockquote>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; 4.synchronized后面括号里是类.例如:</p>
<blockquote dir="ltr" style="margin-right: 0px">
<blockquote dir="ltr" style="margin-right: 0px">
<blockquote dir="ltr" style="margin-right: 0px">
<p>class ArrayWithLockOrder{<br />
&nbsp; private static long num_locks = 0;<br />
&nbsp; private long lock_order;<br />
&nbsp; private int[] arr;</p>
<p>&nbsp; public ArrayWithLockOrder(int[] a)<br />
&nbsp; {<br />
&nbsp;&nbsp;&nbsp; arr = a;<br />
&nbsp;&nbsp;&nbsp; synchronized(ArrayWithLockOrder.class) {//-----------------------------------------这里<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; num_locks++;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 锁数加 1。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lock_order = num_locks;&nbsp; // 为此对象实例设置唯一的 lock_order。<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; }<br />
&nbsp; public long lockOrder()<br />
&nbsp; {<br />
&nbsp;&nbsp;&nbsp; return lock_order;<br />
&nbsp; }<br />
&nbsp; public int[] array()<br />
&nbsp; {<br />
&nbsp;&nbsp;&nbsp; return arr;<br />
&nbsp; }<br />
}</p>
<p>class SomeClass implements Runnable<br />
{<br />
&nbsp; public int sumArrays(ArrayWithLockOrder a1,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ArrayWithLockOrder a2)<br />
&nbsp; {<br />
&nbsp;&nbsp;&nbsp; int value = 0;<br />
&nbsp;&nbsp;&nbsp; ArrayWithLockOrder first = a1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 保留数组引用的一个<br />
&nbsp;&nbsp;&nbsp; ArrayWithLockOrder last = a2;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 本地副本。<br />
&nbsp;&nbsp;&nbsp; int size = a1.array().length;<br />
&nbsp;&nbsp;&nbsp; if (size == a2.array().length)<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (a1.lockOrder() &gt; a2.lockOrder())&nbsp; // 确定并设置对象的锁定<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 顺序。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; first = a2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; last = a1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronized(first) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 按正确的顺序锁定对象。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronized(last) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int[] arr1 = a1.array();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int[] arr2 = a2.array();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i=0; i&lt;size; i++)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value += arr1[i] + arr2[i];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; return value;<br />
&nbsp; }<br />
&nbsp; public void run() {<br />
&nbsp;&nbsp;&nbsp; //...<br />
&nbsp; }<br />
}</p>
</blockquote></blockquote></blockquote>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; 对于4,如果线程进入,则线程在该类中所有操作不能进行,包括静态变量和静态方法,实际上,对于含有静态方法和静态变量的代码块的同步,我们通常用4来加锁.</p>
<p>以上4种之间的关系：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;锁是和对象相关联的，每个对象有一把锁，为了执行synchronized语句，线程必须能够获得synchronized语句中表达式指定的对象的锁，一个对象只有一把锁，被一个线程获得之后它就不再拥有这把锁，线程在执行完synchronized语句后，将获得锁交还给对象。<br />
&nbsp;&nbsp;&nbsp; <font color="#ff0000"><strong>在方法前面加上synchronized修饰符即可以将一个方法声明为同步化方法。同步化方法在执行之前获得一个锁。如果这是一个类方法，那么获得的锁是和声明方法的类相关的Class类对象的锁。如果这是一个实例方法，那么此锁是this对象的锁。</strong></font><br />
</p>
<p>&nbsp;</p>
<hr />
<p>&nbsp;</p>
<p>&nbsp;&nbsp;下面谈一谈一些常用的方法:</p>
<p>&nbsp; wait(),wait(long),notify(),notifyAll()等方法是当前类的实例方法,<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wait()是使持有对象锁的线程释放锁;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wait(long)是使持有对象锁的线程释放锁时间为long(毫秒)后,再次获得锁,wait()和wait(0)等价;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; notify()是唤醒一个正在等待该对象锁的线程,如果等待的线程不止一个,那么被唤醒的线程由jvm确定;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; notifyAll是唤醒所有正在等待该对象锁的线程.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在这里我也重申一下,我们应该优先使用notifyAll()方法,因为唤醒所有线程比唤醒一个线程更容易让jvm找到最适合被唤醒的线程.</p>
<p>&nbsp;&nbsp;&nbsp; 对于上述方法,只有在当前线程中才能使用,否则报运行时错误<a onclick="javascript:tagshow(event, 'java');" href="javascript:;" target="_self"><u><strong><font color="#333333">java</font></strong></u></a>.lang.IllegalMonitorStateException: current thread not owner.</p>
<p>&nbsp;</p>
<hr />
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; 下面,我谈一下synchronized和wait()、notify()等的关系:</p>
<p>1.有synchronized的地方不一定有wait,notify</p>
<p>2.有wait,notify的地方必有synchronized.这是因为wait和notify不是属于线程类，而是每一个对象都具有的方法，而且，这两个方法都和对象锁有关，有锁的地方，必有synchronized。</p>
<p>另外，请注意一点：如果要把notify和wait方法放在一起用的话，必须先调用notify后调用wait，因为如果调用完wait，该线程就已经不是current thread了。如下例：</p>
<p>/**<br />
&nbsp;* Title:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Jdeveloper's Java Projdect<br />
&nbsp;* Description:&nbsp; n/a<br />
&nbsp;* Copyright:&nbsp;&nbsp;&nbsp; Copyright (c) 2001<br />
&nbsp;* Company:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; soho&nbsp; <a href="http://www.chinajavaworld.com/"><u><font color="#333333">http://www.ChinaJavaWorld.com</font></u></a><br />
&nbsp;* @author <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#106;&#100;&#101;&#118;&#101;&#108;&#111;&#112;&#101;&#114;&#64;&#50;&#49;&#99;&#110;&#46;&#99;&#111;&#109;"><u><font color="#333333">jdeveloper@21cn.com</font></u></a><br />
&nbsp;* @version 1.0<br />
&nbsp;*/<br />
import java.lang.Runnable;<br />
import java.lang.Thread;</p>
<p>public class DemoThread<br />
&nbsp;&nbsp;&nbsp; implements Runnable {</p>
<p>&nbsp; public DemoThread() {<br />
&nbsp;&nbsp;&nbsp; TestThread testthread1 = new TestThread(this, "1");<br />
&nbsp;&nbsp;&nbsp; TestThread testthread2 = new TestThread(this, "2");</p>
<p>&nbsp;&nbsp;&nbsp; testthread2.start();<br />
&nbsp;&nbsp;&nbsp; testthread1.start();</p>
<p>&nbsp; }</p>
<p>&nbsp; public static void main(String[] args) {<br />
&nbsp;&nbsp;&nbsp; DemoThread demoThread1 = new DemoThread();</p>
<p>&nbsp; }</p>
<p>&nbsp; public void run() {</p>
<p>&nbsp;&nbsp;&nbsp; TestThread t = (TestThread) Thread.currentThread();<br />
&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!t.getName().equalsIgnoreCase("1")) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronized (this) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wait();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (true) {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("@time in thread" + t.getName() + "=" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t.increaseTime());</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (t.getTime() % 10 == 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronized (this) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("****************************************");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; notify();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (t.getTime() == 100)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wait();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; catch (Exception e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; }</p>
<p>}</p>
<p>class TestThread<br />
&nbsp;&nbsp;&nbsp; extends Thread {<br />
&nbsp; private int time = 0;<br />
&nbsp; public TestThread(Runnable r, String name) {<br />
&nbsp;&nbsp;&nbsp; super(r, name);<br />
&nbsp; }</p>
<p>&nbsp; public int getTime() {<br />
&nbsp;&nbsp;&nbsp; return time;<br />
&nbsp; }</p>
<p>&nbsp; public int increaseTime() {<br />
&nbsp;&nbsp;&nbsp; return++time;<br />
&nbsp; }</p>
<p>}</p>
<p>&nbsp;&nbsp;&nbsp; 下面我们用生产者/消费者这个例子来说明他们之间的关系:</p>
<blockquote dir="ltr" style="margin-right: 0px">
<blockquote dir="ltr" style="margin-right: 0px">
<blockquote dir="ltr" style="margin-right: 0px">
<p>&nbsp;&nbsp;&nbsp; public class test {<br />
&nbsp; public static void main(String args[]) {<br />
&nbsp;&nbsp;&nbsp; Semaphore s = new Semaphore(1);<br />
&nbsp;&nbsp;&nbsp; Thread t1 = new Thread(s, "producer1");<br />
&nbsp;&nbsp;&nbsp; Thread t2 = new Thread(s, "producer2");<br />
&nbsp;&nbsp;&nbsp; Thread t3 = new Thread(s, "producer3");<br />
&nbsp;&nbsp;&nbsp; Thread t4 = new Thread(s, "consumer1");<br />
&nbsp;&nbsp;&nbsp; Thread t5 = new Thread(s, "consumer2");<br />
&nbsp;&nbsp;&nbsp; Thread t6 = new Thread(s, "consumer3");<br />
&nbsp;&nbsp;&nbsp; t1.start();<br />
&nbsp;&nbsp;&nbsp; t2.start();<br />
&nbsp;&nbsp;&nbsp; t3.start();<br />
&nbsp;&nbsp;&nbsp; t4.start();<br />
&nbsp;&nbsp;&nbsp; t5.start();<br />
&nbsp;&nbsp;&nbsp; t6.start();<br />
&nbsp; }<br />
}</p>
<p>class Semaphore<br />
&nbsp;&nbsp;&nbsp; implements Runnable {<br />
&nbsp; private int count;<br />
&nbsp; public Semaphore(int n) {<br />
&nbsp;&nbsp;&nbsp; this.count = n;<br />
&nbsp; }</p>
<p>&nbsp; public synchronized void acquire() {<br />
&nbsp;&nbsp;&nbsp; while (count == 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wait();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (InterruptedException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //keep trying<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; count--;<br />
&nbsp; }</p>
<p>&nbsp; public synchronized void release() {<br />
&nbsp;&nbsp;&nbsp; while (count == 10) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wait();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (InterruptedException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //keep trying<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; count++;<br />
&nbsp;&nbsp;&nbsp; notifyAll(); //alert a thread that's blocking on this semaphore<br />
&nbsp; }</p>
<p>&nbsp; public void run() {<br />
&nbsp;&nbsp;&nbsp; while (true) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (Thread.currentThread().getName().substring(0,8).equalsIgnoreCase("consumer")) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; acquire();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (Thread.currentThread().getName().substring(0,8).equalsIgnoreCase("producer")) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; release();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(Thread.currentThread().getName() + " " + count);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; }<br />
}</p>
</blockquote></blockquote></blockquote>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 生产者生产,消费者消费,一般没有冲突,但当库存为0时,消费者要消费是不行的,但当库存为上限(这里是10)时,生产者也不能生产.请好好研读上面的程序,你一定会比以前进步很多.</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 上面的代码说明了synchronized和wait,notify没有绝对的关系,在synchronized声明的方法、代码块中,你完全可以不用wait,notify等方法,但是,如果当线程对某一资源存在某种争用的情况下,你必须适时得将线程放入等待或者唤醒.</p>
&nbsp;<br />
<img src ="http://www.blogjava.net/hk2000c/aggbug/172275.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2008-01-02 18:14 <a href="http://www.blogjava.net/hk2000c/archive/2008/01/02/172275.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实现非阻塞套接字的一种简单方法</title><link>http://www.blogjava.net/hk2000c/archive/2007/12/31/171799.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Sun, 30 Dec 2007 21:07:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2007/12/31/171799.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/171799.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2007/12/31/171799.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/171799.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/171799.html</trackback:ping><description><![CDATA[<h1 style="color: #000000">
<p>2003 年 11 月 24 日</p>
<blockquote>尽管 SSL 阻塞操作――当读写数据的时候套接字的访问被阻塞――与对应的非阻塞方式相比提供了更好的 I/O 错误通知，但是非阻塞操作允许调用的线程继续运行。本文中，作者同时就客户端和服务器端描述了如何使用Java Secure Socket Extensions （JSSE） 和 Java NIO （新 I/O）库创建非阻塞的安全连接，并且介绍了创建非阻塞套接字的传统方法，以及使用JSSE 和 NIO 的一种可选的（必需的）方法。</blockquote><!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--end RESERVED FOR FUTURE USE INCLUDE FILES-->
<p>阻塞，还是非阻塞？这就是问题所在。无论在程序员的头脑中多么高贵&#8230;&#8230;当然这不是莎士比亚，本文提出了任何程序员在编写 Internet 客户程序时都应该考虑的一个重要问题。通信操作应该是阻塞的还是非阻塞的？ </p>
<p>许多程序员在使用 Java 语言编写 Internet 客户程序时并没有考虑这个问题，主要是因为在以前只有一种选择――阻塞通信。但是现在 Java 程序员有了新的选择，因此我们编写的每个客户程序也许都应该考虑一下。 </p>
<p>非阻塞通信在 Java 2 SDK 的 1.4 版被引入 Java 语言。如果您曾经使用该版本编过程序，可能会对新的 I/O 库（NIO）留下了印象。在引入它之前，非阻塞通信只有在实现第三方库的时候才能使用，而第三方库常常会给应用程序引入缺陷。 </p>
<p>NIO 库包含了文件、管道以及客户机和服务器套接字的非阻塞功能。库中缺少的一个特性是安全的非阻塞套接字连接。在 NIO 或者 JSSE 库中没有建立安全的非阻塞通道类，但这并不意味着不能使用安全的非阻塞通信。只不过稍微麻烦一点。 </p>
<p>要完全领会本文，您需要熟悉：</p>
<ul>
    <li>Java 套接字通信的概念。您也应该实际编写过应用程序。而且不只是打开连接、读取一行然后退出的简单应用程序，应该是实现 POP3 或 HTTP 之类协议的客户机或通信库这样的程序。
    <li>SSL 基本概念和加密之类的概念。基本上就是知道如何设置一个安全连接（但不必担心 JSSE ――这就是关于它的一个&#8220;紧急教程&#8221;）。
    <li>NIO 库。
    <li>在您选择的平台上安装 Java 2 SDK 1.4 或以后的版本。（我是在 Windows 98 上使用 1.4.1_01 版。） </li>
</ul>
<p>如果需要关于这些技术的介绍，请参阅 <a href="http://www.ibm.com/developerworks/cn/java/j-sslnb/index.html#resources">参考资料</a>部分。 </p>
<p>那么到底什么是阻塞和非阻塞通信呢？ </p>
<p><a name="1"><span class="atitle">阻塞和非阻塞通信</span></a></p>
<p>阻塞通信意味着通信方法在尝试访问套接字或者读写数据时阻塞了对套接字的访问。在 JDK 1.4 之前，绕过阻塞限制的方法是无限制地使用线程，但这样常常会造成大量的线程开销，对系统的性能和可伸缩性产生影响。java.nio 包改变了这种状况，允许服务器有效地使用 I/O 流，在合理的时间内处理所服务的客户请求。 </p>
<p>没有非阻塞通信，这个过程就像我所喜欢说的&#8220;为所欲为&#8221;那样。基本上，这个过程就是发送和读取任何能够发送/读取的东西。如果没有可以读取的东西，它就中止读操作，做其他的事情直到能够读取为止。当发送数据时，该过程将试图发送所有的数据，但返回实际发送出的内容。可能是全部数据、部分数据或者根本没有发送数据。 </p>
<p>阻塞与非阻塞相比确实有一些优点，特别是遇到错误控制问题的时候。在阻塞套接字通信中，如果出现错误，该访问会自动返回标志错误的代码。错误可能是由于网络超时、套接字关闭或者任何类型的 I/O 错误造成的。在非阻塞套接字通信中，该方法能够处理的唯一错误是网络超时。为了检测使用非阻塞通信的网络超时，需要编写稍微多一点的代码，以确定自从上一次收到数据以来已经多长时间了。 </p>
<p>哪种方式更好取决于应用程序。如果使用的是同步通信，如果数据不必在读取任何数据之前处理的话，阻塞通信更好一些，而非阻塞通信则提供了处理任何已经读取的数据的机会。而异步通信，如 IRC 和聊天客户机则要求非阻塞通信以避免冻结套接字。 </p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-sslnb/index.html#main"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="2"><span class="atitle">创建传统的非阻塞客户机套接字</span></a></p>
<p>Java NIO 库使用通道而非流。通道可同时用于阻塞和非阻塞通信，但创建时默认为非阻塞版本。但是所有的非阻塞通信都要通过一个名字中包含 <code>Channel</code> 的类完成。在套接字通信中使用的类是 <code>SocketChannel，</code> 而创建该类的对象的过程不同于典型的套接字所用的过程，如清单 1 所示。 </p>
<br />
<a name="listing1"><strong>清单 1. 创建并连接 SocketChannel 对象</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">SocketChannel sc = SocketChannel.open();
            sc.connect("www.ibm.com",80);
            sc.finishConnect();
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>必须声明一个 <code>SocketChannel</code> 类型的指针，但是不能使用 <code>new</code> 操作符创建对象。相反，必须调用 <code>SocketChannel</code> 类的一个静态方法打开通道。打开通道后，可以通过调用 <code>connect()</code> 方法与它连接。但是当该方法返回时，套接字不一定是连接的。为了确保套接字已经连接，必须接着调用 <code>finishConnect()</code> 。 </p>
<p>当套接字连接之后，非阻塞通信就可以开始使用 <code>SocketChannel</code> 类的 <code>read()</code> 和 <code>write()</code> 方法了。也可以把该对象强制转换成单独的 <code>ReadableByteChannel</code> 和 <code>WritableByteChannel</code> 对象。无论哪种方式，都要对数据使用 <code>Buffer</code> 对象。因为 NIO 库的使用超出了本文的范围，我们不再对此进一步讨论。 </p>
<p>当不再需要套接字时，可以使用 <code>close()</code> 方法将其关闭： </p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">sc.close();
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>这样就会同时关闭套接字连接和底层的通信通道。 </p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-sslnb/index.html#main"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="3"><span class="atitle">创建替代的非阻塞的客户机套接字</span></a></p>
<p>上述方法比传统的创建套接字连接的例程稍微麻烦一点。不过，传统的例程也能用于创建非阻塞套接字，不过需要增加几个步骤以支持非阻塞通信。 </p>
<p><code>SocketChannel</code> 对象中的底层通信包括两个 <code>Channel</code> 类： <code>ReadableByteChannel</code> 和 <code>WritableByteChannel。</code> 这两个类可以分别从现有的 <code>InputStream</code> 和 <code>OutputStream</code> <code>阻塞流中使用 <code>Channels</code> 类的 <code>newChannel()</code> 方法创建，如清单 2 所示： </p>
<br />
<a name="listing2"><strong>清单 2. 从流中派生通道</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">ReadableByteChannel rbc = Channels.newChannel(s.getInputStream());
            WriteableByteChannel wbc = Channels.newChannel(s.getOutputStream());
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p><code>Channels</code> 类也用于把通道转换成流或者 reader 和 writer。这似乎是把通信切换到阻塞模式，但并非如此。如果试图读取从通道派生的流，读方法将抛出 <code>IllegalBlockingModeException </code>异常。 </p>
<p>相反方向的转换也是如此。不能使用 <code>Channels</code> 类把流转换成通道而指望进行非阻塞通信。如果试图读从流派生的通道，读仍然是阻塞的。但是像编程中的许多事情一样，这一规则也有例外。 </p>
<p>这种例外适合于实现 <code>SelectableChannel</code> 抽象类的类。 <code>SelectableChannel</code> 和它的派生类能够选择使用阻塞或者非阻塞模式。 <code>SocketChannel</code> 就是这样的一个派生类。 </p>
<p>但是，为了能够在两者之间来回切换，接口必须作为 <code>SelectableChannel </code>实现。对于套接字而言，为了实现这种能力必须使用 <code>SocketChannel</code> 而不是 <code>Socket</code> 。 </p>
<p>回顾一下，要创建套接字，首先必须像通常使用 <code>Socket</code> 类那样创建一个套接字。套接字连接之后，使用 <a href="http://www.ibm.com/developerworks/cn/java/j-sslnb/index.html#listing2">清单 2</a>中的两行代码把流转换成通道。 </p>
<br />
<a name="listing3"><strong>清单 3. 创建套接字的另一种方法</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">Socket s = new Socket("www.ibm.com", 80);
            ReadableByteChannel rbc = Channels.newChannel(s.getInputStream());
            WriteableByteChannel wbc = Channels.newChannel(s.getOutputStream());
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>如前所述，这样并不能实现非阻塞套接字通信――所有的通信仍然在阻塞模式下。在这种情况下，非阻塞通信必须模拟实现。模拟层不需要多少代码。让我们来看一看。 </p>
<p><a name="N1015A"><span class="smalltitle">从模拟层读数据</span></a></p>
<p>模拟层在尝试读操作之前首先检查数据的可用性。如果数据可读则开始读。如果没有数据可用，可能是因为套接字被关闭，则返回表示这种情况的代码。在清单 4 中要注意仍然使用了 <code>ReadableByteChannel</code> 读，尽管 <code>InputStream</code> 完全可以执行这个动作。为什么这样做呢？为了造成是 NIO 而不是模拟层执行通信的假象。此外，还可以使模拟层与其他通道更容易结合，比如向文件通道内写入数据。 </p>
<br />
<a name="listing4"><strong>清单 4. 模拟非阻塞的读操作</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">/* The checkConnection method returns the character read when
            determining if a connection is open.
            */
            y = checkConnection();
            if(y &lt;= 0) return y;
            buffer.putChar((char ) y);
            return rbc.read(buffer);
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p><a name="N10175"><span class="smalltitle">向模拟层写入数据</span></a></p>
<p>对于非阻塞通信，写操作只写入能够写的数据。发送缓冲区的大小和一次可以写入的数据多少有很大关系。缓冲区的大小可以通过调用 <code>Socket</code> 对象的 <code>getSendBufferSize()</code> 方法确定。在尝试非阻塞写操作时必须考虑到这个大小。如果尝试写入比缓冲块更大的数据，必须拆开放到多个非阻塞写操作中。太大的单个写操作可能被阻塞。 </p>
<br />
<a name="listing5"><strong>清单 5. 模拟非阻塞的写操作</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">int x, y = s.getSendBufferSize(), z = 0;
            int expectedWrite;
            byte [] p = buffer.array();
            ByteBuffer buf = ByteBuffer.allocateDirect(y);
            /* If there isn't any data to write, return, otherwise flush the stream */
            if(buffer.remaining() == 0) return 0;
            os.flush()
            for(x = 0; x &lt; p.length; x += y)
            {
            if(p.length - x &lt; y)
            {
            buf.put(p, x, p.length - x);
            expectedWrite = p.length - x;
            }
            else
            {
            buf.put(p, x, y);
            expectedWrite = y;
            }
            /* Check the status of the socket to make sure it's still open */
            if(!s.isConnected()) break;
            /* Write the data to the stream, flushing immediately afterward */
            buf.flip();
            z = wbc.write(buf); os.flush();
            if(z &lt; expectedWrite) break;
            buf.clear();
            }
            if(x &gt; p.length) return p.length;
            else if(x == 0) return -1;
            else return x + z;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>与读操作类似，首先要检查套接字是否仍然连接。但是如果把数据写入 <code>WritableByteBuffer</code> 对象，就像清单 5 那样，该对象将自动进行检查并在没有连接时抛出必要的异常。在这个动作之后开始写数据之前，流必须立即被清空，以保证发送缓冲区中有发送数据的空间。任何写操作都要这样做。发送到块中的数据与发送缓冲区的大小相同。执行清除操作可以保证发送缓冲不会溢出而导致写操作被阻塞。 </p>
<p>因为假定写操作只能写入能够写的内容，这个过程还必须检查套接字保证它在每个数据块写入后仍然是打开的。如果在写入数据时套接字被关闭，则必须中止写操作并返回套接字关闭之前能够发送的数据量。 </p>
<p><code>BufferedOutputReader</code> 可用于模拟非阻塞写操作。如果试图写入超过缓冲区两倍长度的数据，则直接写入缓冲区整倍数长度的数据（缓冲余下的数据）。比如说，如果缓冲区的长度是 256 字节而需要写入 529 字节的数据，则该对象将清除当前缓冲区、发送 512 字节然后保存剩下的 17 字节。 </p>
<p>对于非阻塞写而言，这并非我们所期望的。我们希望分次把数据写入同样大小的缓冲区中，并最终把全部数据都写完。如果发送的大块数据留下一些数据被缓冲，那么在所有数据被发送的时候，写操作就会被阻塞。 </p>
<p><a name="N101A4"><span class="smalltitle">模拟层类模板</span></a></p>
<p>整个模拟层可以放到一个类中，以便更容易和应用程序集成。如果要这样做，我建议从 <code>ByteChannel </code>派生这个类。这个类可以强制转换成单独的 <code>ReadableByteChannel</code> 和 <code>WritableByteChannel</code> 类。 </p>
<p>清单 6 给出了从 <code>ByteChannel</code> 派生的模拟层类模板的一个例子。本文后面将一直使用这个类表示通过阻塞连接执行的非阻塞操作。 </p>
<br />
<a name="listing6"><strong>清单 6. 模拟层的类模板</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">public class nbChannel implements ByteChannel
            {
            Socket s;
            InputStream is; OutputStream os;
            ReadableByteChannel rbc;
            WritableByteChannel wbc;
            public nbChannel(Socket socket);
            public int read(ByteBuffer dest);
            public int write(ByteBuffer src);
            public void close();
            protected int checkConnection();
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p><a name="N101CA"><span class="smalltitle">使用模拟层创建套接字</span></a></p>
<p>使用新建的模拟层创建套接字非常简单。只要像通常那样创建 <code>Socket</code> 对象，然后创建 <code>nbChannel</code> 对象就可以了，如清单 7 所示： </p>
<br />
<a name="listing7"><strong>清单 7. 使用模拟层</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">Socket s = new Socket("www.ibm.com", 80);
            nbChannel socketChannel = new nbChannel(s);
            ReadableByteChannel rbc = (ReadableByteChannel)socketChannel;
            WritableByteChannel wbc = (WritableByteChannel)socketChannel;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-sslnb/index.html#main"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="4"><span class="atitle">创建传统的非阻塞服务器套接字</span></a></p>
<p>服务器端的非阻塞套接字和客户端上的没有很大差别。稍微麻烦一点的只是建立接受输入连接的套接字。套接字必须通过从服务器套接字通道派生一个阻塞的服务器套接字绑定到阻塞模式。清单 8 列出了需要做的步骤。 </p>
<br />
<a name="listing8"><strong>清单 8. 创建非阻塞的服务器套接字（SocketChannel）</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">ServerSocketChannel ssc = ServerSocketChannel.open();
            ServerSocket ss = ssc.socket();
            ss.bind(new InetSocketAddress(port));
            SocketChannel sc = ssc.accept();
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>与客户机套接字通道相似，服务器套接字通道也必须打开而不是使用 <code>new</code> 操作符或者构造函数。在打开之后，必须派生服务器套接字对象以便把套接字通道绑定到一个端口。一旦套接字被绑定，服务器套接字对象就可以丢弃了。 </p>
<p>通道使用 <code>accept()</code> 方法接收到来的连接并把它们转给套接字通道。一旦接收了到来的连接并转给套接字通道对象，通信就可以通过 <code>read()</code> 和 <code>write()</code> 方法开始进行了。 </p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-sslnb/index.html#main"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="5"><span class="atitle">创建替代的非阻塞服务器套接字</span></a></p>
<p>实际上，并非真正的替代。因为服务器套接字通道必须使用服务器套接字对象绑定，为何不完全绕开服务器套接字通道而仅使用服务器套接字对象呢？不过这里的通信不使用 <code>SocketChannel</code> ，而要使用模拟层 <code>nbChannel。</code> </p>
<br />
<a name="listing9"><strong>清单 9. 建立服务器套接字的另一种方法</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">ServerSocket ss = new ServerSocket(port);
            Socket s = ss.accept();
            nbChannel socketChannel = new nbChannel(s);
            ReadableByteChannel rbc = (ReadableByteChannel)socketChannel;
            WritableByteChannel wbc = (WritableByteChannel)socketChannel;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-sslnb/index.html#main"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="6"><span class="atitle">创建 SSL 连接</span></a></p>
<p>创建SSL连接，我们要分别从客户端和服务器端考察。 </p>
<p><a name="N10232"><span class="smalltitle">从客户端</span></a></p>
<p>创建 SS L连接的传统方法涉及到使用套接字工厂和其他一些东西。我将不会详细讨论如何创建SSL连接，不过有一本很好的教程，&#8220;Secure your sockets with JSSE&#8221;（请参阅 <a href="http://www.ibm.com/developerworks/cn/java/j-sslnb/index.html#resources">参考资料</a>），从中您可以了解到更多的信息。 </p>
<p>创建 SSL 套接字的默认方法非常简单，只包括几个很短的步骤：</p>
<ol>
    <li>创建套接字工厂。
    <li>创建连接的套接字。
    <li>开始握手。
    <li>派生流。
    <li>通信。 </li>
</ol>
<p>清单 10 说明了这些步骤：</p>
<br />
<a name="listing10"><strong>清单 10. 创建安全的客户机套接字</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">SSLSocketFactory sslFactory =
            (SSLSocketFactory)SSLSocketFactory.getDefault();
            SSLSocket ssl = (SSLSocket)sslFactory.createSocket(host, port);
            ssl.startHandshake();
            InputStream is = ssl.getInputStream();
            OutputStream os = ssl.getOutputStream();
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>默认方法不包括客户验证、用户证书和其他特定连接可能需要的东西。 </p>
<p><a name="N10264"><span class="smalltitle">从服务器端</span></a></p>
<p>建立SSL服务器连接的传统方法稍微麻烦一点，需要加上一些类型转换。因为这些超出了本文的范围，我将不再进一步介绍，而是说说支持SSL服务器连接的默认方法。 </p>
<p>创建默认的 SSL 服务器套接字也包括几个很短的步骤：</p>
<ol>
    <li>创建服务器套接字工厂。
    <li>创建并绑定服务器套接字。
    <li>接受传入的连接。
    <li>开始握手。
    <li>派生流。
    <li>通信。 </li>
</ol>
<p>尽管看起来似乎与客户端的步骤相似，要注意这里去掉了很多安全选项，比如客户验证。 </p>
<p>清单 11 说明这些步骤：</p>
<br />
<a name="listing11"><strong>清单 11. 创建安全的服务器套接字</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">SSLServerSocketFactory sslssf =
            (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
            SSLServerSocket sslss = (SSLServerSocket)sslssf.createServerSocket(port);
            SSLSocket ssls = (SSLSocket)sslss.accept();
            ssls.startHandshake();
            InputStream is = ssls.getInputStream();
            OutputStream os = ssls.getOutputStream();
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-sslnb/index.html#main"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="7"><span class="atitle">创建安全的非阻塞连接</span></a></p>
<p>要精心实现安全的非阻塞连接，也需要分别从客户端和服务器端来看。 </p>
<p><a name="N1029E"><span class="smalltitle">从客户端</span></a></p>
<p>在客户端建立安全的非阻塞连接非常简单： </p>
<ol>
    <li>创建并连接 <code>Socket</code> 对象。
    <li>把 <code>Socket</code> 对象添加到模拟层上。
    <li>通过模拟层通信。 </li>
</ol>
<p>清单 12 说明了这些步骤：</p>
<br />
<a name="listing12"><strong>清单 12. 创建安全的客户机连接</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">/* Create the factory, then the secure socket */
            SSLSocketFactory sslFactory =
            (SSLSocketFactory)SSLSocketFactory.getDefault();
            SSLSocket ssl = (SSLSocket)sslFactory.createSocket(host, port);
            /* Start the handshake.  Should be done before deriving channels */
            ssl.startHandshake();
            /* Put it into the emulation layer and create separate channels */
            nbChannel socketChannel = new nbChannel(ssl);
            ReadableByteChannel rbc = (ReadableByteChannel)socketChannel;
            WritableByteChannel wbc = (WritableByteChannel)socketChannel;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>利用前面给出的 <a href="http://www.ibm.com/developerworks/cn/java/j-sslnb/index.html#emulclass">模拟层类</a> 就可以实现非阻塞的安全连接。因为安全套接字通道不能使用 <code>SocketChannel</code> 类打开，而 Java API 中又没有完成这项工作的类，所以创建了一个模拟类。模拟类可以实现非阻塞通信，无论使用安全套接字连接还是非安全套接字连接。 </p>
<p>列出的步骤包括默认的安全设置。对于更高级的安全性，比如用户证书和客户验证， <a href="http://www.ibm.com/developerworks/cn/java/j-sslnb/index.html#resources">参考资料</a> 部分提供了说明如何实现的文章。 </p>
<p><a name="N102DA"><span class="smalltitle">从服务器端</span></a></p>
<p>在服务器端建立套接字需要对默认安全稍加设置。但是一旦套接字被接收和路由，设置必须与客户端的设置完全相同，如清单 13 所示： </p>
<br />
<a name="listing13"><strong>清单 13. 创建安全的非阻塞服务器套接字</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">/* Create the factory, then the socket, and put it into listening mode */
            SSLServerSocketFactory sslssf =
            (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
            SSLServerSocket sslss = (SSLServerSocket)sslssf.createServerSocket(port);
            SSLSocket ssls = (SSLSocket)sslss.accept();
            /* Start the handshake on the new socket */
            ssls.startHandshake();
            /* Put it into the emulation layer and create separate channels */
            nbChannel socketChannel = new nbChannel(ssls);
            ReadableByteChannel rbc = (ReadableByteChannel)socketChannel;
            WritableByteChannel wbc = (WritableByteChannel)socketChannel;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>同样，要记住这些步骤使用的是默认安全设置。 </p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br />
                        </td>
                        <td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-sslnb/index.html#main"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="8"><span class="atitle">集成安全的和非安全的客户机连接</span></a></p>
<p>多数 Internet 客户机应用程序，无论使用 Java 语言还是其他语言编写，都需要提供安全和非安全连接。Java Secure Socket Extensions 库使得这项工作非常容易，我最近在编写一个 HTTP 客户库时就使用了这种方法。 </p>
<p><code>SSLSocket</code> 类派生自 <code>Socket。</code> 您可能已经猜到我要怎么做了。所需要的只是该对象的一个 <code>Socket</code> 指针。如果套接字连接不使用SSL，则可以像通常那样创建套接字。如果要使用 SSL，就稍微麻烦一点，但此后的代码就很简单了。清单 14 给出了一个例子： </p>
<br />
<a name="listing14"><strong>清单 14. 集成安全的和非安全的客户机连接</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">Socket s;
            ReadableByteChannel rbc;
            WritableByteChannel wbc;
            nbChannel socketChannel;
            if(!useSSL) s = new Socket(host, port);
            else
            {
            SSLSocketFactory sslsf = SSLSocketFactory.getDefault();
            SSLSocket ssls = (SSLSocket)SSLSocketFactory.createSocket(host, port);
            ssls.startHandshake();
            s = ssls;
            }
            socketChannel = new nbChannel(s);
            rbc = (ReadableByteChannel)socketChannel;
            wbc = (WritableByteChannel)socketChannel;
            ...
            s.close();
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>创建通道之后，如果套接字使用了SSL，那么就是安全通信，否则就是普通通信。如果使用了 SSL，关闭套接字将导致握手中止。</p>
<p>这种设置的一种可能是使用两个单独的类。一个类负责处理通过套接字沿着与非安全套接字的连接进行的所有通信。一个单独的类应该负责创建安全的连接，包括安全连接的所有必要设置，无论是否是默认的。安全类应该直接插入通信类，只有在使用安全连接时被调用。 </p>
</code></h1>
<img src ="http://www.blogjava.net/hk2000c/aggbug/171799.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2007-12-31 05:07 <a href="http://www.blogjava.net/hk2000c/archive/2007/12/31/171799.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>J2SE API读取Properties文件六种方法 </title><link>http://www.blogjava.net/hk2000c/archive/2007/12/27/170763.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Wed, 26 Dec 2007 16:00:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2007/12/27/170763.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/170763.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2007/12/27/170763.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/170763.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/170763.html</trackback:ping><description><![CDATA[<span class="a14c" id="zoom">&nbsp;
<p style="text-indent: 2em">使用J2SEAPI读取Properties文件的六种方法<br />
<br />
<br />
<br />
　　1。使用java.util.Properties类的load()方法示例：InputStreamin=lnewBufferedInputStream(newFileInputStream(name));Propertiesp=newProperties();p.load(in);<br />
<br />
　　2。使用java.util.ResourceBundle类的getBundle()方法示例：ResourceBundlerb=ResourceBundle.getBundle(name,Locale.getDefault());<br />
<br />
　　3。使用java.util.PropertyResourceBundle类的构造函数示例：InputStreamin=newBufferedInputStream(newFileInputStream(name));ResourceBundlerb=newPropertyResourceBundle(in);<br />
<br />
　　4。使用class变量的getResourceAsStream()方法示例：InputStreamin=JProperties.class.getResourceAsStream(name);Propertiesp=newProperties();p.load(in);<br />
<br />
　　5。使用class.getClassLoader()所得到的java.lang.ClassLoader的getResourceAsStream()方法示例：InputStreamin=JProperties.class.getClassLoader().getResourceAsStream(name);Propertiesp=newProperties();p.load(in);<br />
<br />
　　6。使用java.lang.ClassLoader类的getSystemResourceAsStream()静态方法示例：InputStreamin=ClassLoader.getSystemResourceAsStream(name);Propertiesp=newProperties();p.load(in);<br />
<br />
　　补充<br />
<br />
　　Servlet中可以使用javax.servlet.ServletContext的getResourceAsStream()方法示例：InputStreamin=context.getResourceAsStream(path);Propertiesp=newProperties();p.load(in);
<p align="center"></p>
<p>&nbsp;</p>
<span>
<p align="center"><br />
</p>
</span></span>
<img src ="http://www.blogjava.net/hk2000c/aggbug/170763.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2007-12-27 00:00 <a href="http://www.blogjava.net/hk2000c/archive/2007/12/27/170763.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java 多线程 wait() 以及 notirfy() 简析</title><link>http://www.blogjava.net/hk2000c/archive/2007/12/19/168761.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Wed, 19 Dec 2007 07:20:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2007/12/19/168761.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/168761.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2007/12/19/168761.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/168761.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/168761.html</trackback:ping><description><![CDATA[<p>class ThreadA <br />
{<br />
&nbsp; public static void main(String[] args) <br />
&nbsp; {<br />
&nbsp;&nbsp;&nbsp; ThreadB b=new ThreadB();<br />
&nbsp;&nbsp;&nbsp; b.start();<br />
&nbsp;&nbsp;&nbsp; System.out.println("b is start....");<br />
&nbsp;&nbsp;&nbsp; synchronized(b)//括号里的b是什么意思,起什么作用?<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;System.out.println("Waiting for b to complete...");<br />
&nbsp;b.wait();//这一句是什么意思，究竟让谁wait?<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Completed.Now back to main thread");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }catch (InterruptedException e){}<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; System.out.println("Total is :"+b.total);<br />
&nbsp;&nbsp; }<br />
} </p>
<p><br />
class ThreadB extends Thread<br />
{<br />
&nbsp; int total;<br />
&nbsp; public void run()<br />
&nbsp; {<br />
&nbsp;&nbsp;&nbsp; synchronized(this)<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("ThreadB is running..");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i=0;i&lt;100;i++ )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; total +=i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("total is "+total);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; notify();<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; }<br />
}</p>
<p>要分析这个程序,首先要理解notify()和wait(),为什么在前几天纪录线程的时候没有纪录这两个方法呢,因为这两个方法本来就不属于Thread类,而是属于最底层的object基础类的,也就是说不光是Thread，每个对象都有notify和wait的功能，为什么？因为他们是用来操纵锁的,而每个对象都有锁,锁是每个对象的基础,既然锁是基础的,那么操纵锁的方法当然也是最基础了.</p>
<p>&nbsp;再往下看之前呢,首先最好复习一下Think in Java的14.3.1中第3部分内容：等待和通知,也就是wait()和notify了.</p>
<p>按照Think in Java中的解释:"wait()允许我们将线程置入&#8220;睡眠&#8221;状态，同时又&#8220;积极&#8221;地等待条件发生改变.而且只有在一个notify()或notifyAll()发生变化的时候，线程才会被唤醒，并检查条件是否有变."</p>
<p>&nbsp; 我们来解释一下这句话.<br />
&nbsp; "wait()允许我们将线程置入&#8220;睡眠&#8221;状态",也就是说,wait也是让当前线程阻塞的,这一点和sleep或者suspend是相同的.那和sleep,suspend有什么区别呢?</p>
<p>&nbsp;&nbsp; 区别在于"(wait)同时又&#8220;积极&#8221;地等待条件发生改变",这一点很关键,sleep和suspend无法做到.因为我们有时候需要通过同步（synchronized）的帮助来防止线程之间的冲突，而一旦使用同步,就要锁定对象，也就是获取对象锁,其它要使用该对象锁的线程都只能排队等着,等到同步方法或者同步块里的程序全部运行完才有机会.在同步方法和同步块中,无论sleep()还是suspend()都不可能自己被调用的时候解除锁定,他们都霸占着正在使用的对象锁不放.<br />
&nbsp;&nbsp; 而wait却可以,它可以让同步方法或者同步块暂时放弃对象锁,而将它暂时让给其它需要对象锁的人(这里应该是程序块,或线程)用,这意味着可在执行wait()期间调用线程对象中的其他同步方法!在其它情况下(sleep啊,suspend啊),这是不可能的.<br />
&nbsp;&nbsp; 但是注意我前面说的,只是暂时放弃对象锁,暂时给其它线程使用,我wait所在的线程还是要把这个对象锁收回来的呀.wait什么?就是wait别人用完了还给我啊！<br />
&nbsp;&nbsp; 好,那怎么把对象锁收回来呢?<br />
&nbsp;&nbsp; 第一种方法,限定借出去的时间.在wait()中设置参数,比如wait(1000),以毫秒为单位,就表明我只借出去1秒中,一秒钟之后,我自动收回.<br />
&nbsp;&nbsp; 第二种方法,让借出去的人通知我,他用完了,要还给我了.这时,我马上就收回来.哎,假如我设了1小时之后收回,别人只用了半小时就完了,那怎么办呢?靠!当然用完了就收回了,还管我设的是多长时间啊.</p>
<p>&nbsp;&nbsp; 那么别人怎么通知我呢?相信大家都可以想到了,notify(),这就是最后一句话"而且只有在一个notify()或notifyAll()发生变化的时候，线程才会被唤醒"的意思了.<br />
&nbsp;&nbsp; 因此,我们可将一个wait()和notify()置入任何同步方法或同步块内部，无论在那个类里是否准备进行涉及线程的处理。而且实际上,我们也只能在同步方法或者同步块里面调用wait()和notify().</p>
<p>&nbsp;&nbsp; 这个时候我们来解释上面的程序,简直是易如反掌了.</p>
<p>&nbsp;&nbsp; synchronized(b){...}；的意思是定义一个同步块,使用b作为资源锁。b.wait();的意思是临时释放锁，并阻塞当前线程,好让其他使用同一把锁的线程有机会执行,在这里要用同一把锁的就是b线程本身.这个线程在执行到一定地方后用notify()通知wait的线程,锁已经用完,待notify()所在的同步块运行完之后,wait所在的线程就可以继续执行.</p>
<img src ="http://www.blogjava.net/hk2000c/aggbug/168761.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2007-12-19 15:20 <a href="http://www.blogjava.net/hk2000c/archive/2007/12/19/168761.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java单例延迟加载</title><link>http://www.blogjava.net/hk2000c/archive/2007/12/18/168619.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Tue, 18 Dec 2007 15:58:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2007/12/18/168619.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/168619.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2007/12/18/168619.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/168619.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/168619.html</trackback:ping><description><![CDATA[public class Foo {<br />
&nbsp;&nbsp;&nbsp; // 似有静态内部类, 只有当有引用时, 该类才会被装载<br />
&nbsp;&nbsp;&nbsp; private static class LazyFoo {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; public static Foo foo = new Foo();<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; public static Foo getInstance() {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; return LazyFoo.foo;<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
<br />
<img src ="http://www.blogjava.net/hk2000c/aggbug/168619.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2007-12-18 23:58 <a href="http://www.blogjava.net/hk2000c/archive/2007/12/18/168619.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>how to debug with webshpere 5 6 in intellij</title><link>http://www.blogjava.net/hk2000c/archive/2007/11/20/161947.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Tue, 20 Nov 2007 13:56:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2007/11/20/161947.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/161947.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2007/11/20/161947.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/161947.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/161947.html</trackback:ping><description><![CDATA[<h2 class="blue">How to configure remote JSP debugging<br />
under WebSphere Application Servers</h2>
<h2>Introduction</h2>
<p>This article describes how you can create a run and debug configuration in IntelliJ IDEA 5.1 (or higher) to allow your Web modules with JSP files to be remotely debugged under WebSphere 5.1 and WebSphere 6.0 application servers. It also describes how to configure these application servers to enable integration with IntelliJ IDEA, and provides you with step-by-step instructions for application deployment.</p>
<h2>Requirements</h2>
<p>Before making any settings, make sure that the following requirements are met:</p>
<ol>
    <li>WebSphere 5.1 or 6.0 application server is installed (full or express version). IntelliJ IDEA does not have any bundled servers, so you need to install them yourself.
    <li>JDK (Sun Java2<sup>TM</sup> Standard Edition SDK) 1.4 or less is installed. Although IntelliJ IDEA supports JDK 5.0, WebSphere application servers require JDK 1.4 or less.
    <li>WebSphere application server is started. </li>
</ol>
<p>You can find the full documentation on how to install, start, and initially configure the server at <a href="http://http//www-306.ibm.com/software/websphere/" target="_blank">http://www-306.ibm.com/software/websphere/</a>.</p>
<h2>Configuring WebSphere Application Server</h2>
<p>To enable remote debugging on the server, perform the following steps:</p>
<ol>
    <li>Start the server's <strong>Administrative Console</strong>.
    <li>Expand <strong>Servers &gt; Application Servers</strong>.
    <div class="feature"><img class="screenshot" height="248" alt="screenshot" src="http://www.jetbrains.com/idea/documentation/screenshots/howto_10.gif" width="474" /> </div>
    <br class="clr" />
    <hr class="hide" />
    <strong>Note:</strong>
    <p class="comment">WebSphere Application Server V6.0: Administrative Console</p>
    <li>Click the server name and clic the <strong>Configuration</strong> tab
    <li>Navigate to the <strong>Additional Properties</strong> group and click the <strong>Debugging Service</strong> link.
    <li>Make sure that the debugging service is enabled at server startup.
    <ul class="starlist">
        <li>For the <strong>WebSphere 5.1</strong> application server, select the <strong>Startup</strong> check box.
        <div class="feature"><img class="screenshot" height="268" alt="screenshot" src="http://www.jetbrains.com/idea/documentation/screenshots/howto_11.gif" width="500" /> </div>
        <br class="clr" />
        <hr class="hide" />
        <strong>Note:</strong>
        <p class="comment">WebSphere Application Server - Express 5.1: enabling debugging</p>
        <li>For the <strong>WebSphere 6.0</strong> application server, select the <strong>Enable service at server</strong> startup check box.
        <p>To the <strong>JVM Debug arguments</strong> field add the following line before the existing set of arguments: <strong class="lib">-Dwas.debug.mode=true</strong></p>
        <div class="feature"><img class="screenshot" height="275" alt="screenshot" src="http://www.jetbrains.com/idea/documentation/screenshots/howto_12.gif" width="329" /> </div>
        <br class="clr" />
        <hr class="hide" />
        <strong>Note:</strong>
        <p class="comment">WebSphere Application Server 6.0: enabling debugging</p>
        </li>
    </ul>
    <li>Click the <strong>Apply</strong> button. Then save the settings (for example, using the notification message)
    <div class="feature"><img class="screenshot" height="101" alt="screenshot" src="http://www.jetbrains.com/idea/documentation/screenshots/howto_13.gif" width="369" /> </div>
    <br class="clr" />
    <hr class="hide" />
    <strong>Note:</strong>
    <p class="comment">WebSphere Application Server 6.0: notification message</p>
    <li>Restart the server using WebSphere's or operating system's administration tools. </li>
</ol>
<h2>Generating the Application Archive File</h2>
<p>IntelliJ IDEA can generate the WAR, EAR, or JAR file for your application automatically. For this purpose, you need to configure your module (Web, J2EE Application, or EJB).</p>
<ol>
    <li>In IntelliJ IDEA, click <strong>File &gt; Settings (Ctrl + Alt + S)</strong>, and then select <strong>Modules</strong>.
    <li>In the <strong>Modules</strong> list, click the module for which you need to generate the archive file.
    <li>Click the <strong>J2EE Build Settings</strong> tab.
    <li>Select the <strong>Create web module war/ear/jar file</strong> check box, and specify the location of the file. This path will be required later, on the application deployment stage. </li>
</ol>
<p>Apply the changes, and make the project (click the <strong>Build &gt; Make Project</strong> menu or press <strong>Ctrl + F9</strong>).</p>
<p>The application is now ready for deployment.</p>
<h2>Deploying Application</h2>
<p>You deploy the application using the WebSphere application server's tools.</p>
<ol>
    <li>Start the server's <strong>Administrative Console</strong>.
    <li>Click <strong>Applications &gt; Install New Application</strong>, and then click your server.
    <li>Select <strong>Local file system</strong> or <strong>Remote</strong> file system depending on your server installation, and then specify the path to your WAR, EAR, or JAR file (usually, it corresponds to the path you specified when generating the application archive file in IntelliJ IDEA).
    <li>In the <strong>Context Root</strong> text box, specify the context (e.g. "myContext").
    <div class="feature"><img class="screenshot" height="303" alt="screenshot" src="http://www.jetbrains.com/idea/documentation/screenshots/howto_14.gif" width="496" /> </div>
    <br class="clr" />
    <hr class="hide" />
    <strong>Note:</strong>
    <p class="comment">WebSphere Application Server 6.0: enabling debugging</p>
    <li>Click <strong>Next</strong>. Skip the next screen and click <strong>Next</strong> again. <strong>Note:</strong>
    <p class="comment">The Security Warning may appear. It displays the content of the <strong class="lib">was.policy file</strong>. You can simply click <strong>Continue</strong>.</p>
    <li>On the first step of the <strong>Install New Application</strong> wizard, select the <strong>Enable class reloading</strong> check box, and then click <strong>Next</strong>. This allows you to redeploy the application without reinstalling it
    <div class="feature"><img class="screenshot" height="460" alt="screenshot" src="http://www.jetbrains.com/idea/documentation/screenshots/howto_15.gif" width="416" /> </div>
    <br class="clr" />
    <hr class="hide" />
    <strong>Note:</strong>
    <p class="comment">WebSphere Application Server 6.0: selecting installation options.</p>
    <li>On the second step, select the check box next to your Web module to map it to the server. Then click <strong>Next</strong>.
    <li>On the third step, select the check box next to your Web module to map the virtual host to it, and then click <strong>Next</strong>.
    <li>On the last step, just click <strong>Finish</strong>. The deployment will start. <strong>Note:</strong>
    <p class="comment">The server may not always notify you when the deployment is complete. If the operation takes too long, click <strong>Enterprise Applications</strong>. If your application is present in the enterprise applications list with the �Stopped� status (red cross icon), the deployment is complete, and you can move to the next step.</p>
    <li>When the deployment is finished, the server console will show you the installation results page. Save the configuration, for example using the <strong>Save to Master Configuration</strong> link on this page.
    <li>Click <strong>Applications &gt; Enterprise Applications</strong>. In the list of applications your application should be displayed with the �Stopped� status (red cross icon).
    <li>Select the check box next to your application, and then click <strong>Start</strong>. </li>
</ol>
<div class="feature"><img class="screenshot" height="365" alt="screenshot" src="http://www.jetbrains.com/idea/documentation/screenshots/howto_16.gif" width="500" /> </div>
<br class="clr" />
<hr class="hide" />
<strong>Note:</strong>
<p class="comment">WebSphere Application Server 6.0: starting the application</p>
<h2>Creating Run/Debug Configuration</h2>
<p>WebSphere 5.1/6.0 application servers are supported by means of the general IntelliJ IDEA integration with the JSR compatible servers and do not have a server-specific type of Run/Debug configuration. You need to create a configuration for a JSR45 compatible server and then modify it according to WebSphere application server's needs.</p>
<ol>
    <li>In IntelliJ IDEA, click the <strong>Run &gt; Edit Configurations</strong> menu, and then click the <strong>JSR45 Compatible Server</strong> tab.
    <li>Click the plus sign or press Insert to add a new configuration, and then click <strong>Remote</strong>. Specify some configuration name.
    <li>Click the <strong>Configure</strong> button to add an application server.
    <li>In the <strong>Application Servers</strong> dialog box, click <strong>Add</strong>, and then specify some server name.
    <li>Click the <strong>Attach Classes</strong> button, and find the j2ee.jar file for your version of WebSphere Application server (<strong class="lib">&lt;installation folder&gt;\lib\j2ee.jar</strong>).
    <div class="feature"><img class="screenshot" height="240" alt="screenshot" src="http://www.jetbrains.com/idea/documentation/screenshots/howto_17.gif" width="520" /> </div>
    <br class="clr" />
    <hr class="hide" />
    <strong>Note:</strong>
    <p class="comment">IntelliJ IDEA 5.1: configuring application servers</p>
    <li>In the <strong>Application Servers</strong> dialog box, click <strong>Apply</strong> to save the changes, and then in the configuration, in the <strong>Application Server</strong> list, select the added server.
    <li>In the <strong>Startup</strong> page text box, specify the home page of your web application in the following format:
    <ul class="starlist">
        <li><strong>WebSphere Application Server 5.1</strong><br />
        <strong class="lib">http://localhost:7080/&lt;ContextRoot&gt;/&lt;home page&gt;</strong>
        <li><strong>WebSphere Application Server 6.0</strong><br />
        <strong class="lib">http://localhost:9080/&lt;ContextRoot&gt;/&lt;home page&gt;</strong> </li>
    </ul>
    <p>"7080" and "9080" are default ports for the WebSphere 5.1 and 6.0 servers, respectively. If you have changed the default port, specify the actual port number instead.</p>
    <p><strong class="lib">&lt;ContextRoot&gt;</strong> is name of web context used during application deployment, e.g. "myContext".<br />
    <strong class="lib">&lt;home page&gt;</strong> can be any page from your Web module.</p>
    <li>Optionally, you can configure the application server log to display its content in the IntelliJ IDEA's <strong>Run</strong> tool window, in the console.
    <p>Click the <strong>Add</strong> button, and then in the <strong>Edit Log Files Aliases</strong> dialog specify some alias name (e.g. "activity"). In the <strong>Log File Location</strong> text box, specify the location of the activity.log file. By default, this file is located in the &lt;home&gt;\logs folder.</p>
    <li>In the <strong>JSP package</strong> text box, enter one of the following:
    <ul class="starlist">
        <li><strong>WebSphere Application Server 5.1</strong><br />
        <strong class="lib">org.apache.jsp</strong>
        <li><strong>WebSphere Application Server 6.0</strong><br />
        <strong class="lib">com.ibm._jsp</strong> </li>
    </ul>
    <li>In the <strong>VM options variable</strong> text box, type DEBUG.
    <li>If you use <strong>WebSphere Application Server 5.1</strong>, select to use the specific JSP's line mapping model. For the <strong>WebSphere Application Server 6.0</strong> this check box is ignored, but it is recommended to clear it.
    <li>In the <strong>Port</strong> text box, specify the port number of the corresponding application server (it should be the same as specified for the startup page).
    <div class="feature"><img class="screenshot" height="414" alt="screenshot" src="http://www.jetbrains.com/idea/documentation/screenshots/howto_18.gif" width="512" /> </div>
    <br class="clr" />
    <hr class="hide" />
    <strong>Note:</strong>
    <p class="comment">IntelliJ IDEA 5.0: Run/Debug configuration for WebSphere Application Server 6.0</p>
    <li>Click the <strong>Startup/Connection</strong> tab, and then click <strong>Debug</strong>. Check that the <strong>Socket</strong> option is selected, and the <strong>Port</strong> number is 7777. </li>
</ol>
<h2>Debugging Application</h2>
<p>To start debugging the application in IntelliJ IDEA, just click <strong>Run &gt; Debug</strong> or press <strong>Shift + F9</strong>. You can use all the power of the IntelliJ IDEA debugger for the JSP files running on the WebSphere Application Server, including breakpoints, stepping commands, watches, etc.</p>
<strong>Note:</strong>
<p class="comment">To apply any changes in the web module, you will need to redeploy the application as described earlier in this article. The "Build on frame deactivation" feature is not supported for remote debugging.</p>
<h2>Troubleshooting</h2>
<p><strong>The server crashes during the debug session</strong></p>
<p>Such problems may appear if you use the IBM's virtual machine supplied with the WebSphere server. Possible solutions in this case are:</p>
<ul class="starlist">
    <li>Run IntelliJ IDEA with the command line option:<br />
    <strong class="lib">-Didea.debugger.keep.temp.objects=false</strong><br />
    In this case IntelliJ IDEA will avoid calling certain methods from debug API.
    <li>Use Sun's JDK 1.4 or less </li>
</ul>
<p><strong>IntelliJ IDEA is unable to open the debugger port</strong></p>
<p>In most cases, it is an internal WebSphere server error. Try to restart the WebSphere application server.</p>
<h2>Conclusion</h2>
<p>We hope that this article helped you to configure remote debugging successfully. If you have encountered any problems that are not described in the <strong>Troubleshooting</strong> section, don't hesitate to contact our technical support: <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#115;&#117;&#112;&#112;&#111;&#114;&#116;&#64;&#106;&#101;&#116;&#98;&#114;&#97;&#105;&#110;&#115;&#46;&#99;&#111;&#109;">support@jetbrains.com</a>.</p>
<img src ="http://www.blogjava.net/hk2000c/aggbug/161947.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2007-11-20 21:56 <a href="http://www.blogjava.net/hk2000c/archive/2007/11/20/161947.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>intellij 7 sn </title><link>http://www.blogjava.net/hk2000c/archive/2007/11/20/161920.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Tue, 20 Nov 2007 11:07:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2007/11/20/161920.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/161920.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2007/11/20/161920.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/161920.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/161920.html</trackback:ping><description><![CDATA[Enter your name: <font color="#ff0000"><strong>Daniel</strong></font><br />
Your key is: <font color="#009900"><strong>22457-MWPIW-INDLX-2PU2X-WBHSX-C4YK0</strong></font><br />
<br />
<img src ="http://www.blogjava.net/hk2000c/aggbug/161920.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2007-11-20 19:07 <a href="http://www.blogjava.net/hk2000c/archive/2007/11/20/161920.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用java调用oracle存储过程总结 </title><link>http://www.blogjava.net/hk2000c/archive/2007/11/16/161075.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Fri, 16 Nov 2007 09:15:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2007/11/16/161075.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/161075.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2007/11/16/161075.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/161075.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/161075.html</trackback:ping><description><![CDATA[<p style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体">这段时间开始学习写存储过程，主要原因还是因为工作需要吧，本来以为很简单的，但几经挫折，豪气消磨殆尽，但总算搞通了，为了避免后来者少走弯路，特记述与此，同时亦对自己进行鼓励。</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体">一：无返回值的存储过程</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体">存储过程为：</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">CREATE OR REPLACE PROCEDURE TESTA(PARA1 IN VARCHAR2,PARA2 IN VARCHAR2)&nbsp;AS</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">BEGIN </span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp; INSERT INTO HYQ.B_ID (I_ID,I_NAME) VALUES (PARA1, PARA2);</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">END TESTA;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体">然后呢，在</span><span style="font-family: ˎ̥">java</span><span style="font-family: 宋体">里调用时就用下面的代码：</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">package com.hyq.src;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">import java.sql.*;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">import java.sql.ResultSet;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">public class TestProcedureOne {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;public TestProcedureOne() {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;}</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;public static void main(String[] args ){</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; String driver = "oracle.jdbc.driver.OracleDriver";</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; String strUrl = "jdbc:oracle:thin:@127.0.0.1:1521: hyq ";</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; Statement stmt = null;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; ResultSet rs = null;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; Connection conn = null;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; CallableStatement cstmt = null;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; try {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Class.forName(driver);</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn =&nbsp;DriverManager.getConnection(strUrl, " hyq ", " hyq ");</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CallableStatement proc = null;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proc = conn.prepareCall("{ call HYQ.TESTA(?,?) }");</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proc.setString(1, "100");</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proc.setString(2, "TestOne");</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proc.execute();</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; catch (SQLException ex2) {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ex2.printStackTrace();</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; catch (Exception ex2) {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ex2.printStackTrace();</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; finally{</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(rs != null){</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rs.close();</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(stmt!=null){</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stmt.close();</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(conn!=null){</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.close();</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (SQLException ex1) {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;}</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">}</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体">当然了，这就先要求要建张表</span><span style="font-family: ˎ̥">TESTTB,</span><span style="font-family: 宋体">里面两个字段（</span><span style="font-family: ˎ̥">I_ID</span><span style="font-family: 宋体">，</span><span style="font-family: ˎ̥">I_NAME</span><span style="font-family: 宋体">）。</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体">二：有返回值的存储过程（非列表）</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体">存储过程为：</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">CREATE OR REPLACE PROCEDURE TESTB(PARA1 IN VARCHAR2,PARA2 OUT VARCHAR2)&nbsp;AS</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">BEGIN </span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp; SELECT INTO PARA2 FROM TESTTB WHERE I_ID= PARA1; </span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">END TESTB;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体">在</span><span style="font-family: ˎ̥">java</span><span style="font-family: 宋体">里调用时就用下面的代码：</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">package com.hyq.src;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">public class TestProcedureTWO {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;public TestProcedureTWO() {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;}</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;public static void main(String[] args ){</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; String driver = "oracle.jdbc.driver.OracleDriver";</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; String strUrl = "jdbc:oracle:thin:@127.0.0.1:1521:hyq";</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; Statement stmt = null;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; ResultSet rs = null;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; Connection conn = null;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; try {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Class.forName(driver);</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn =&nbsp;DriverManager.getConnection(strUrl, " hyq ", " hyq ");</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CallableStatement proc = null;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proc = conn.prepareCall("{ call HYQ.TESTB(?,?) }");</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proc.setString(1, "100");</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proc.registerOutParameter(2, Types.VARCHAR);</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proc.execute();</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String testPrint = proc.getString(2);</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("=testPrint=is="+testPrint);</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; catch (SQLException ex2) {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ex2.printStackTrace();</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; catch (Exception ex2) {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ex2.printStackTrace();</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; finally{</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(rs != null){</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rs.close();</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(stmt!=null){</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stmt.close();</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(conn!=null){</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.close();</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (SQLException ex1) {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;}</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">}</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">}</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体">注意，这里的</span><span style="font-family: ˎ̥">proc.getString(2)</span><span style="font-family: 宋体">中的数值</span><span style="font-family: ˎ̥">2</span><span style="font-family: 宋体">并非任意的，而是和存储过程中的</span><span style="font-family: ˎ̥">out</span><span style="font-family: 宋体">列对应的，如果</span><span style="font-family: ˎ̥">out</span><span style="font-family: 宋体">是在第一个位置，那就是</span><span style="font-family: ˎ̥">proc.getString(1)</span><span style="font-family: 宋体">，如果是第三个位置，就是</span><span style="font-family: ˎ̥">proc.getString(3)</span><span style="font-family: 宋体">，当然也可以同时有多个返回值，那就是再多加几个</span><span style="font-family: ˎ̥">out</span><span style="font-family: 宋体">参数了。</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体">三：返回列表</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体">由于</span><span style="font-family: ˎ̥">oracle</span><span style="font-family: 宋体">存储过程没有返回值，它的所有返回值都是通过</span>out<span style="font-family: 宋体">参数来替代的，列表同样也不例外，但由于是集合，所以不能用一般的参数，必须要用</span>pagkage<span style="font-family: 宋体">了</span>.<span style="font-family: 宋体">所以要分两部分，</span></p>
<p style="margin: 0cm 0cm 0pt 18pt; text-indent: -18pt; tab-stops: list 18.0pt">1，&nbsp;<span style="font-family: 宋体">建一个程序包。如下：</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">CREATE OR REPLACE PACKAGE TESTPACKAGE &nbsp;AS</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;TYPE Test_CURSOR IS REF CURSOR;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">end TESTPACKAGE;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">2</span><span style="font-family: 宋体">，建立</span><span style="font-family: 宋体">存储过程，存储过程为：</span></p>
<p style="margin: 0cm 0cm 0pt">CREATE OR REPLACE PROCEDURE TESTC<span style="font-family: ˎ̥">(p_CURSOR out TESTPACKAGE.Test_CURSOR) IS </span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">BEGIN</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; OPEN p_CURSOR FOR SELECT * FROM HYQ.TESTTB;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">END TESTC;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体">可以看到，它是把游标（可以理解为一个指针），作为一个</span><span style="font-family: ˎ̥">out </span><span style="font-family: 宋体">参数来返回值的。</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体">在</span><span style="font-family: ˎ̥">java</span><span style="font-family: 宋体">里调用时就用下面的代码：</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">package com.hyq.src;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">import java.sql.*;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">import java.io.OutputStream;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">import java.io.Writer;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">import java.sql.PreparedStatement;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">import java.sql.ResultSet;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">import oracle.jdbc.driver.*;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">public class TestProcedureTHREE {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;public TestProcedureTHREE() {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;}</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;public static void main(String[] args ){</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; String driver = "oracle.jdbc.driver.OracleDriver";</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; String strUrl = "jdbc:oracle:thin:@127.0.0.1:1521:hyq";</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; Statement stmt = null;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; ResultSet rs = null;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; Connection conn = null;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; try {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Class.forName(driver);</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn =&nbsp;DriverManager.getConnection(strUrl, "hyq", "hyq");</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CallableStatement proc = null;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proc = conn.prepareCall("{ call hyq.testc(?) }");</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proc.registerOutParameter(1,oracle.jdbc.OracleTypes.CURSOR);</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proc.execute();</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rs = (ResultSet)proc.getObject(1);</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(rs.next())</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("&lt;tr&gt;&lt;td&gt;" + rs.getString(1) + "&lt;/td&gt;&lt;td&gt;"+rs.getString(2)+"&lt;/td&gt;&lt;/tr&gt;");</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; catch (SQLException ex2) {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ex2.printStackTrace();</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; catch (Exception ex2) {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ex2.printStackTrace();</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; finally{</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(rs != null){</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rs.close();</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(stmt!=null){</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stmt.close();</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(conn!=null){</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.close();</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (SQLException ex1) {</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">&nbsp;}</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: ˎ̥">}</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体">在这里要注意，在执行前一定要先把</span><span style="font-family: ˎ̥">oracle</span><span style="font-family: 宋体">的驱动包放到</span><span style="font-family: ˎ̥">class</span><span style="font-family: 宋体">路径里，否则会报错的。</span></p>
<p style="margin: 0cm 0cm 0pt">&nbsp;</p>
<img src ="http://www.blogjava.net/hk2000c/aggbug/161075.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2007-11-16 17:15 <a href="http://www.blogjava.net/hk2000c/archive/2007/11/16/161075.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SSO(Single Sign-on) in Action(上篇) </title><link>http://www.blogjava.net/hk2000c/archive/2007/11/16/161048.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Fri, 16 Nov 2007 08:27:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2007/11/16/161048.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/161048.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2007/11/16/161048.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/161048.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/161048.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: [原创] SSO(Single Sign-on) in Action(上篇) 1. SSO 原理浅谈 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SSO 是一个非常大的主题，我对这个主题有着深深的感受，自从广州 UserGroup 的论坛成立以来，无数网友都在尝试使用开源的 CAS ， Kerberos 也提供另外一种方式的 SSO ，即基于 Windows ...&nbsp;&nbsp;<a href='http://www.blogjava.net/hk2000c/archive/2007/11/16/161048.html'>阅读全文</a><img src ="http://www.blogjava.net/hk2000c/aggbug/161048.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2007-11-16 16:27 <a href="http://www.blogjava.net/hk2000c/archive/2007/11/16/161048.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JA-SIG CAS 资料 </title><link>http://www.blogjava.net/hk2000c/archive/2007/11/16/161033.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Fri, 16 Nov 2007 07:50:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2007/11/16/161033.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/161033.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2007/11/16/161033.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/161033.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/161033.html</trackback:ping><description><![CDATA[<p>CAS (Central Authentication Service) 是 Yale 大学的 ITS 开发的一套 JAVA 实现的开源</p>
<p>的 SSO(single sign-on) 的服务(主要是2.0，到3.0为ja-sig)。</p>
<p>关键字</p>
<p>TGC(ticket-granting cookie)--------- 受权的票据证明</p>
<p>KDC( Key Distribution Center ) ---------- 密钥发放中心</p>
<p>Service ticket(ST) --------- 服务票据， 由 KDC 的 TGS 发放。 任何一台 Workstation 都需要拥有一张有效的 Service Ticket 才能访问域内部的应用 (Applications) 。 如果能正确接收 Service Ticket ，说明在 CASClient-CASServer 之间的信任关系已经被正确建立起来 , 通常为一张数字加密的证书</p>
<p>Ticket Granting tieckt(TGT) --------- 票据授权票据，由 KDC 的 AS 发放。即获取这样一张票据后，以后申请各种其他服务票据 (ST) 便不必再向 KDC 提交身份认证信息 ( 准确术语是 Credentials) 。</p>
<p>authentication service (AS) --------- 认证用服务，索取 Crendential ，发放 TGT</p>
<p>ticket-granting service (TGS) --------- 票据授权服务，索取 TGT ，发放 ST</p>
<p>CAS 单点服务器的认证过程，所有应用服务器收到应用请求后，检查 ST 和 TGT ，如果没有或不对，转到 CAS 认证服务器登陆页面，通过安全认证后得到 ST 和 TGT 再重定向到相关应用服务器，在会话生命周期之内如果再定向到别的应用，将出示</p>
<p>ST 和 TGT 进行认证 , 注意 , 取得 TGT 的过程是通过 SSL 安全协议的 ( 换句话说就是如果不用 ssl 协议 , 每访问一个应用服务，就得重新到认证服务中心认证一次 ) ，关于 SSL 的相关描述可以查看附录 .</p>
<p>白话描述 :</p>
<p>单点登陆 , 无非就是提供给用户一次登陆 , 多个系统共享用户信息的操作 .</p>
<p>这个是怎么操作的呢 ? 有简单的方法 , 当用户访问其他系统的时候 , 写个 URL 带上用户的 ID 和 PASS 提交到相应的系统就可以了 . 这也是一种方法</p>
<p>那 CAS 是怎么操作的呢 ? 或则是 KRB(Kerberos 是一个加密认证协议，允许网络用户不使用明文密码访问服务，一个普通 <br />
的协议实现包括 LOGIN 服务存在伪造欺骗对 Key Distribution Center 的响应 。</p>
<p>) 怎么操作的呢 ?</p>
<p>他并不是很复杂 , 他先是建立一个 专门认证用户的 服务 (SERVER) 这个服务只做一件事 , 负责验证用户的 ID 和 PASS 是否是正确 , 在正确的情况提供用户一个名为 TGT 的票据 ,</p>
<p>相当你要去游乐场玩 , 首先你要在门口检查你的身份 ( 即 CHECK 你的 ID 和 PASS), 如果你通过验证 , 游乐场的门卫 (AS) 即提供给你一张门卡 (TGT).</p>
<p>这张卡片的用处就是告诉 游乐场的各个场所 , 你是通过正门进来 , 而不是后门偷爬进来的 , 并且也是获取进入场所一把钥匙 .</p>
<p>好的 , 现在你有张卡 , 但是这对你来不重要 , 因为你来游乐场不是为了拿这张卡的 , 好的 , 我们向你的目的出发 , 恩 , 你来到一个摩天楼 , 你想进入玩玩 ,</p>
<p>这时摩天轮的服务员 (client) 拦下你 , 向你要求摩天轮的 (ST) 票据 , 你说你只有一个门卡 (TGT), 好的 , 那你只要把 TGT 放在一旁的票据授权机 (TGS) 上刷一下 ,</p>
<p>票据授权机 (TGS) 就根据你现在所在的摩天轮 , 给你一张摩天轮的票据 (ST), 哈 , 你有摩天轮的票据 , 现在你可以畅通无阻的进入摩天轮里游玩了 .</p>
<p>当然如果你玩完摩天轮后 , 想去游乐园的咖啡厅休息下 , 那你一样只要带着那张门卡 (TGT). 到相应的咖啡厅的票据授权机 (TGS) 刷一下 , 得到咖啡厅的票据 (ST) 就可以进入咖啡厅</p>
<p>当你离开游乐场后 , 想用这张 TGT 去刷打的回家的费用 , 呵呵 , 对不起 , 你的 TGT 已经过期了 , 在你离开游乐场那刻开始 , 你的 TGT 就已经销毁了 ~</p>
<p>Yale CAS Server 的配置过程</p>
<p>CAS (Central Authentication Service) 是 Yale 大学的 ITS 开发的一套 JAVA 实现的开源</p>
<p>的 SSO(single sign-on) 的服务。该服务是以一个 java web app(eg:cas.war) 来进行服务的，</p>
<p>使用时需要将 cas.war 发布到一个 servlet2.3 兼容的服务器上，并且服务器需要支持 SSL ，</p>
<p>在需要使用该服务的其他服务器（客户），只要进行简单的配置就可以实现 SSO 了。</p>
<p>CAS 的客户端可以有很多种，因为验证的结果是以 XML 的格式返回的， CAS 的客户端已</p>
<p>打包进去的有 java,perl,python,asp,apache module 等好几种客户端示例，你还可以根据</p>
<p>需要实现一个自己的客户端，非常简单 !~</p>
<p>下面我们以 tomcat 5.0 作为 CAS Server(server1) ，另外一台 tomcat5.0 为 client(client1)</p>
<p>为例进行说明。</p>
<p>1. 下载 cas-server 和 cas-client( 可选，建议使用）</p>
<p><a href="http://www.ja-sig.org/downloads/cas/cas-server-3.0.5.zip" target="blank">http://www.ja-sig.org/downloads/cas/cas-server-3.0.5.zip</a></p>
<p><a href="http://www.ja-sig.org/downloads/cas-clients/cas-client-java-2.1.1.zip" target="blank">http://www.ja-sig.org/downloads/cas-clients/cas-client-java-2.1.1.zip</a></p>
<p>2. 将 cas-server-3.0.5.zip 解压，并将 lib/cas.war 拷贝到 server1 的 webapps 下</p>
<p>3. 产生 SERVER 的证书</p>
<p>PS: 参数与各系统本身一致</p>
<p>%JAVA_HOME%\bin\keytool -delete -alias tomcat -keypass changeit</p>
<p>%JAVA_HOME%\bin\keytool -genkey -alias tomcat -keypass changeit -keyalg RSA</p>
<p>%JAVA_HOME%\bin\keytool -export -alias tomcat -keypass changeit -file %FILE_NAME%</p>
<p>%JAVA_HOME%\bin\keytool -import -file server.crt -keypass changeit -keystore %JAVA_HOME%/jre/lib/security/cacerts</p>
<p>%JAVA_HOME%\bin\keytool -import -file server.crt -keystore %JAVA_HOME%\jre\lib\security\cacerts</p>
<p>4. 在 server1 配置 tomcat 使用 HTTPS</p>
<p>$CATALINA_HOME/conf/server.xml 里</p>
<p>&lt;Connector className="org.apache.coyote.tomcat5.CoyoteConnector"</p>
<p>port="8443" minProcessors="5" maxProcessors="75"</p>
<p>enableLookups="true" disableUploadTimeout="true"</p>
<p>acceptCount="100" debug="0" scheme="https"</p>
<p>secure="true"&gt;</p>
<p>&lt;Factory className="org.apache.coyote.tomcat5.CoyoteServerSocketFactory"</p>
<p>keystoreFile="/path/to/your/keystore-file"</p>
<p>keystorePass="your-password" clientAuth="false" protocol="TLS" /&gt;</p>
<p>&lt;/Connector&gt;</p>
<p>5. 在要使用 CAS 的客户端 client1 里设置（以 servlets-examples 这个 APP 为例），我们使用</p>
<p>ServletFilter(CAS client 里提供的 ) 来实现 SSO 的检查。</p>
<p>修改 servlets-examples/WEB-INF/web.xml</p>
<p>&lt;filter&gt;</p>
<p>&lt;filter-name&gt;CASFilter&lt;/filter-name&gt;</p>
<p>&lt;filter-class&gt;edu.yale.its.tp.cas.client.filter.CASFilter&lt;/filter-class&gt;</p>
<p>&lt;init-param&gt;</p>
<p>&lt;param-name&gt;edu.yale.its.tp.cas.client.filter.loginUrl&lt;/param-name&gt;</p>
<p>&lt;param-value&gt;https://your.cas.server.name(eg:server1):port/cas/login&lt;/param-value&gt;</p>
<p>&lt;/init-param&gt;</p>
<p>&lt;init-param&gt;</p>
<p>&lt;param-name&gt;edu.yale.its.tp.cas.client.filter.validateUrl&lt;/param-name&gt;</p>
<p>&lt;param-value&gt;https://your.cas.server.name(eg:server1):port/cas/proxyValidate&lt;/param-value&gt;</p>
<p>&lt;/init-param&gt;</p>
<p>&lt;init-param&gt;</p>
<p>&lt;param-name&gt;edu.yale.its.tp.cas.client.filter.serviceUrl&lt;/param-name&gt;</p>
<p>&lt;param-value&gt;your.client.server.ip(eg:127.0.0.1):port&lt;/param-value&gt;</p>
<p>&lt;/init-param&gt;</p>
<p>&lt;/filter&gt;</p>
<p>&lt;filter-mapping&gt;</p>
<p>&lt;filter-name&gt;CASFilter&lt;/filter-name&gt;</p>
<p>&lt;url-pattern&gt;/servlet/*&lt;/url-pattern&gt;</p>
<p>&lt;/filter-mapping&gt;</p>
<p>PS: 在 client 端配置 filter 时 , 需要将 CAS 的 filter 放在 web.xml 最上端 ,. 如果在你的 web.xml 有类似 encodingFilter 的 filter 也需要将这个 filter 放在 CAS filter 下面 , 否则你会发现每次访问时都需要你进行验证 .</p>
<p>6. 将 cas-client-java-2.1.1.zip 解压，把 java/lib/casclient.jar 拷贝到 client1 服务器上的</p>
<p>webapps/servlets-examples/WEB-INF/lib 目录下（如果没有就建一个）</p>
<p>7. 导出 SERVER 的证书，用来给所有需要用到的客户端导入</p>
<p>keytool -export -file server.crt -alias my-alias-name -keystore keystore-file</p>
<p>8. 在客户端的 JVM 里导入信任的 SERVER 的证书 ( 根据情况有可能需要管理员权限 )</p>
<p>keytool -import -keystore $JAVA_HOME/jre/lib/security/cacerts -file server.crt -alias my-alias-name</p>
<p>9.test &amp; done.</p>
<p>把 server1 和 client1 分别起来，检查启动的 LOG 是否正常，如果一切 OK ，就访问</p>
<p><a href="http://client1:8080/servlets-examples/servlet/HelloWorldExample" target="blank">http://client1:8080/servlets-examples/servlet/HelloWorldExample</a></p>
<p>系统会自动跳转到一个验证页面，随便输入一个相同的账号 , 密码，严正通过之后就会访问</p>
<p>到真正的 HelloWorldExample 这个 servlet 了</p>
<p>实现自已的认证代码 (java 代码和相关注释 , 需要 cas-server-3.0.5.jar 包 )</p>
<p><br />
package com.mcm.sso; </p>
<p>&nbsp;</p>
<p>import org.jasig.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler; </p>
<p>import org.jasig.cas.authentication.principal.UsernamePasswordCredentials; </p>
<p>import org.springframework.util.StringUtils; </p>
<p>&nbsp;</p>
<p>public class MyUsernamePasswordAuthenticationHandler extends </p>
<p>AbstractUsernamePasswordAuthenticationHandler { </p>
<p>&nbsp;</p>
<p>public boolean authenticateUsernamePasswordInternal( </p>
<p>final UsernamePasswordCredentials credentials) { </p>
<p>final String username = credentials.getUsername(); </p>
<p>final String password = credentials.getPassword(); </p>
<p>&nbsp;</p>
<p>// 此处实现你的登陆验证代码 </p>
<p>if (StringUtils.hasText(username) &amp;&amp; StringUtils.hasText(password) ) { </p>
<p>getLog().debug( </p>
<p>" User [ " + username + " ] was successfully authenticated with ucix. " ); </p>
<p>return true ; </p>
<p>} </p>
<p>&nbsp;</p>
<p>getLog().debug( " User [ " + username + " ] failed authentication " ); </p>
<p>&nbsp;</p>
<p>return false ; </p>
<p>} </p>
<p>&nbsp;</p>
<p>protected void afterPropertiesSetInternal() throws Exception { </p>
<p>super .afterPropertiesSetInternal(); </p>
<p>} </p>
<p>} </p>
<p>&nbsp;</p>
<p>然后将这个类配置到 deployerConfigContext.xml 文件里 , 替代 &lt;bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler" /&gt;</p>
<p>可能要用到数据库连接之类的配置，具体可参照 spring framework 相关文档</p>
<p>在 client 端取到登陆相关信息及登出系统</p>
<p>1. 取得用用户 ID</p>
<p>以下两种方式都可以</p>
<p>session.getAttribute(CASFilter.CAS_FILTER_USER);</p>
<p>session.getAttribute("edu.yale.its.tp.cas.client.filter.user");</p>
<p>也可以直接取得认证 java 对象</p>
<p>session.getAttribute(CASFilter.CAS_FILTER_RECEIPT);</p>
<p>session.getAttribute("edu.yale.its.tp.cas.client.filter.receipt");</p>
<p>JSP2.0 标准写法</p>
<p>&lt;c:out value="${sessionScope['edu.yale.its.tp.cas.client.filter.user']}"/&gt;</p>
<p>在 jsp 中使用 CAS Tag Library 标签</p>
<p>除实现以上功能完还可以实现登出之类的相关功能，具体参照 cas 官方文档</p>
<p><a href="http://www.ja-sig.org/products/cas/client/jsp/index.html" target="blank">http://www.ja-sig.org/products/cas/client/jsp/index.html</a></p>
<p>附录</p>
<p>1 ． SSL(Server Socket Layer) 简介</p>
<p>在网络上信息在源 - 宿的传递过程中会经过其它的计算机。一般情况下，中间的计算机不会监听路过的信息。但在使用网上银行或者进行信用卡交易的时候有可能被监视，从而导致个人隐私的泄露。由于 Internet 和 Intranet 体系结构的原因，总有某些人能够读取并替换用户发出的信息。随着网上支付的不断发展，人们对信息安全的要求越来越高。因此 Netscape 公司提出了 SSL 协议，旨在达到在开放网络 (Internet) 上安全保密地传输信息的目的，这种协议在 WEB 上获得了广泛的应用。 之后 IETF(ietf.org) 对 SSL 作了标准化，即 RFC2246 ，并将其称为 TLS （ Transport Layer Security ），从技术上讲， TLS1.0 与 SSL3.0 的差别非常微小。</p>
<p>2 ． SSL 工作原理</p>
<p>SSL 协议使用不对称加密技术实现会话双方之间信息的安全传递。可以实现信息传递的保密性、完整性，并且会话双方能鉴别对方身份。不同于常用的 http 协议，我们在与网站建立 SSL 安全连接时使用 https 协议，即采用 https://ip:port/ 的方式来访问。当我们与一个网站建立 https 连接时，我们的浏览器与 Web Server 之间要经过一个握手的过程来完成身份鉴定与密钥交换，从而建立安全连接。具体过程如下：</p>
<p>用户浏览器将其 SSL 版本号、加密设置参数、与 session 有关的数据以及其它一些必要信息发送到服务器。</p>
<p>服务器将其 SSL 版本号、加密设置参数、与 session 有关的数据以及其它一些必要信息发送给浏览器，同时发给浏览器的还有服务器的证书。如果配置服务器的 SSL 需要验证用户身份，还要发出请求要求浏览器提供用户证书。</p>
<p>客户端检查服务器证书，如果检查失败，提示不能建立 SSL 连接。如果成功，那么继续。客户端浏览器为本次会话生成 pre-master secret ，并将其用服务器公钥加密后发送给服务器。如果服务器要求鉴别客户身份，客户端还要再对另外一些数据签名后并将其与客户端证书一起发送给服务器。</p>
<p>如果服务器要求鉴别客户身份，则检查签署客户证书的 CA 是否可信。如果不在信任列表中，结束本次会话。如果检查通过，服务器用自己的私钥解密收到的 pre-master secret ，并用它通过某些算法生成本次会话的 master secret 。</p>
<p>客户端与服务器均使用此 master secret 生成本次会话的会话密钥 ( 对称密钥 ) 。在双方 SSL 握手结束后传递任何消息均使用此会话密钥。这样做的主要原因是对称加密比非对称加密的运算量低一个数量级以上，能够显著提高双方会话时的运算速度。</p>
<p>客户端通知服务器此后发送的消息都使用这个会话密钥进行加密。并通知服务器客户端已经完成本次 SSL 握手。</p>
<p>服务器通知客户端此后发送的消息都使用这个会话密钥进行加密。并通知客户端服务器已经完成本次 SSL 握手。</p>
<p>本次握手过程结束，会话已经建立。双方使用同一个会话密钥分别对发送以及接受的信息进行加、解密。 </p>
<img src ="http://www.blogjava.net/hk2000c/aggbug/161033.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2007-11-16 15:50 <a href="http://www.blogjava.net/hk2000c/archive/2007/11/16/161033.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Request tomcat 包装类 org.apache.catalina.connector.Request 分析</title><link>http://www.blogjava.net/hk2000c/archive/2007/10/27/156388.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Sat, 27 Oct 2007 11:52:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2007/10/27/156388.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/156388.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2007/10/27/156388.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/156388.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/156388.html</trackback:ping><description><![CDATA[javax.servlet.http.Cookie<br />
<br />
JSESSIONID = 当前session 号码<br />
<br />
org/apache/coyote/Request.java<br />
<br />
基本封装类，包括基本request 信息 <br />
<br />
其源代码在此可以查看 <a href="http://www.docjar.com/html/api/org/apache/coyote/Request.java.html">http://www.docjar.com/html/api/org/apache/coyote/Request.java.html</a><br />
<br />
&nbsp;<font color="brown"><strong>public</strong></font> <a href="http://www.docjar.com/docs/api/org/apache/coyote/Request.html">Request</a>() {<br />
<strong><a name="x72">72</a></strong>&nbsp; <br />
<strong><a name="x73">73</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parameters.setQuery(queryMB);<br />
<strong><a name="x74">74</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parameters.setURLDecoder(urlDecoder);<br />
<strong><a name="x75">75</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parameters.setHeaders(headers);<br />
<strong><a name="x76">76</a></strong>&nbsp; <br />
<strong><a name="x77">77</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; methodMB.setString(<font color="red">"GET"</font>);<br />
<strong><a name="x78">78</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uriMB.setString(<font color="red">"/"</font>);<br />
<strong><a name="x79">79</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queryMB.setString("");<br />
<strong><a name="x80">80</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protoMB.setString(<font color="red">"HTTP/1.0"</font>);<br />
<strong><a name="x81">81</a></strong>&nbsp; <br />
<strong><a name="x82">82</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<strong><a name="x83">83</a></strong>&nbsp; <br />
<br />
开始初始化<br />
<br />
回收<br />
&nbsp;<font color="green">// -------------------- Recycling -------------------- </font><br />
<strong><a name="x459">459</a></strong> <br />
<strong><a name="x460">460</a></strong> <br />
<strong><a name="x461">461</a></strong>&nbsp;&nbsp;&nbsp;&nbsp; <font color="brown"><strong>public</strong></font> <font color="brown"><strong>void</strong></font> recycle() {<br />
<strong><a name="x462">462</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bytesRead=0;<br />
<strong><a name="x463">463</a></strong> <br />
<strong><a name="x464">464</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; contentLength = -1;<br />
<strong><a name="x465">465</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; contentTypeMB = <font color="brown"><strong>null</strong></font>;<br />
<strong><a name="x466">466</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; charEncoding = <font color="brown"><strong>null</strong></font>;<br />
<strong><a name="x467">467</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; headers.recycle();<br />
<strong><a name="x468">468</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; serverNameMB.recycle();<br />
<strong><a name="x469">469</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; serverPort=-1;<br />
<strong><a name="x470">470</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; localPort = -1;<br />
<strong><a name="x471">471</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; remotePort = -1;<br />
<strong><a name="x472">472</a></strong> <br />
<strong><a name="x473">473</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cookies.recycle();<br />
<strong><a name="x474">474</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parameters.recycle();<br />
<strong><a name="x475">475</a></strong> <br />
<strong><a name="x476">476</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unparsedURIMB.recycle();<br />
<strong><a name="x477">477</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uriMB.recycle(); <br />
<strong><a name="x478">478</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; decodedUriMB.recycle();<br />
<strong><a name="x479">479</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queryMB.recycle();<br />
<strong><a name="x480">480</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; methodMB.recycle();<br />
<strong><a name="x481">481</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protoMB.recycle();<br />
<strong><a name="x482">482</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="green">//remoteAddrMB.recycle();</font><br />
<strong><a name="x483">483</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="green">//remoteHostMB.recycle();</font><br />
<strong><a name="x484">484</a></strong> <br />
<strong><a name="x485">485</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="green">// XXX Do we need such defaults ?</font><br />
<strong><a name="x486">486</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; schemeMB.recycle();<br />
<strong><a name="x487">487</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; methodMB.setString(<font color="red">"GET"</font>);<br />
<strong><a name="x488">488</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uriMB.setString(<font color="red">"/"</font>);<br />
<strong><a name="x489">489</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queryMB.setString("");<br />
<strong><a name="x490">490</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protoMB.setString(<font color="red">"HTTP/1.0"</font>);<br />
<strong><a name="x491">491</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="green">//remoteAddrMB.setString(<font color="red">"127.0.0.1"</font>);</font><br />
<strong><a name="x492">492</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="green">//remoteHostMB.setString(<font color="red">"localhost"</font>);</font><br />
<strong><a name="x493">493</a></strong> <br />
<strong><a name="x494">494</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; instanceId.recycle();<br />
<strong><a name="x495">495</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; remoteUser.recycle();<br />
<strong><a name="x496">496</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; authType.recycle();<br />
<strong><a name="x497">497</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; attributes.clear();<br />
<strong><a name="x498">498</a></strong>&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
伟大的method() 方法<br />
<br />
<br />
&nbsp;<font color="brown"><strong>public</strong></font> MessageBytes method() {<br />
<strong><a name="x184">184</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="brown"><strong>return</strong></font> methodMB;<br />
<strong><a name="x185">185</a></strong>&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<strong><a name="x186">186</a></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;getMethod() 方法就是从这里搞来的。<br />
<br />
还有 org.apache.tomcat.util.http.MimeHeader 存放了所有的Header 信息 <br />
<br />
<br />
=== MimeHeaders ===<br />
accept = image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*<br />
referer = http://localhost/user/userRegister.html<br />
accept-language = zh-CN,en-US;q=0.5<br />
content-type = application/x-www-form-urlencoded<br />
ua-cpu = x86<br />
accept-encoding = gzip, deflate<br />
user-agent = Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.1; MAXTHON 2.0)<br />
host = localhost<br />
content-length = 70<br />
connection = Keep-Alive<br />
cache-control = no-cache<br />
cookie = JSESSIONID=06820B9CA579BF64CC89C5E041864459<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<img src ="http://www.blogjava.net/hk2000c/aggbug/156388.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2007-10-27 19:52 <a href="http://www.blogjava.net/hk2000c/archive/2007/10/27/156388.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Design an e-commerce system data diagram</title><link>http://www.blogjava.net/hk2000c/archive/2007/02/27/100976.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Tue, 27 Feb 2007 10:25:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2007/02/27/100976.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/100976.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2007/02/27/100976.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/100976.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/100976.html</trackback:ping><description><![CDATA[
		<p>Today, I design an e-commerce system data diagram. Beacause of I using hibernate and XDoclet, I use the Class diagram instead of Data structure and ERP diagram. My strategy in J2EE system design is to clear the bussiness logic first, and design POJOs and their relations, finally, implement it with mature 3 or more tier web architecture.<br /><br /><br /></p>
<img src ="http://www.blogjava.net/hk2000c/aggbug/100976.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2007-02-27 18:25 <a href="http://www.blogjava.net/hk2000c/archive/2007/02/27/100976.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> SOA 技术</title><link>http://www.blogjava.net/hk2000c/archive/2006/08/10/62806.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Thu, 10 Aug 2006 07:49:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2006/08/10/62806.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/62806.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2006/08/10/62806.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/62806.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/62806.html</trackback:ping><description><![CDATA[
		<p>听到SOA很久了，决定去看看 SOA 。<br />研究一下，毕竟是好的。<br /><br />资源<br /><br /><a href="http://www.umlchina.com/News/Content/39.htm">http://www.umlchina.com/News/Content/39.htm</a><br /><br /><br /><br />一些感想：<br /><br />旧酒换新瓶，就像Web2.0。SOA 感觉上就像WebService 技术的再包装。加入了一些面向业务分割的理念，使应用系统能够以SOA理念开发。<br /><br />还是一种实验中的东西。企业根本不关心什么SOA技术如何，企业只关心，SOA能给他们带来什么？SOA 并不是银弹，离成功还有很长的一段路要走。期待更有价值的SOA 2.0 出现。<br /><br /><br /><br /><br /><br /><br /><br /><br /></p>
<img src ="http://www.blogjava.net/hk2000c/aggbug/62806.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2006-08-10 15:49 <a href="http://www.blogjava.net/hk2000c/archive/2006/08/10/62806.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>全面从liferay的portal研究 转向 jetspeed2 兼 liferay 的研究</title><link>http://www.blogjava.net/hk2000c/archive/2006/08/08/62463.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Tue, 08 Aug 2006 15:05:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2006/08/08/62463.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/62463.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2006/08/08/62463.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/62463.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/62463.html</trackback:ping><description><![CDATA[Liferay 二次开发太困难，花了N*N个小时，除了搭建了一套可以调试部署的环境之外，部署了几个示例实例之外，几乎毫无建树。<br />liferay代码可读性是我见过最差的，乍看觉得可能是反编译的代码。昏过去，我要骂娘了。什么编码规范！呕了！！！<br />网上support 的效率非常低，几乎没人帮忙，遇到问题简直就是灾难。继续下去的信心简直快要破灭了。<br /><br />Jetspeed 2 就比较好了 ， 源代码，文档，二次开发比较容易。<br />而且国内弄得人也多，可以相互交流支持，不像liferay 一条小道走不到底的感觉。<br /><br />不过Liferay 还是比较好的一个项目，速度比jetspeed2 不知道快多少，而且拥有很多很实用的portlet .<br />但愿 Jetspeed2 会做得更好。毕竟开源需要众人去做，才会有生命力。<br /><br /><img src ="http://www.blogjava.net/hk2000c/aggbug/62463.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2006-08-08 23:05 <a href="http://www.blogjava.net/hk2000c/archive/2006/08/08/62463.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java技术经验积累</title><link>http://www.blogjava.net/hk2000c/archive/2006/08/08/62360.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Tue, 08 Aug 2006 07:25:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2006/08/08/62360.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/62360.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2006/08/08/62360.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/62360.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/62360.html</trackback:ping><description><![CDATA[准备每个知识点的几个例子，梳理一下自己的知识树结构，避免时间长了，技术生疏<br /><br />暂时需要整理的知识点例子有<br /><br />tag<br /><br />jms<br /><br />oscache<br /><br />hiberante<br /><br />spring<br /><br />SWF spring web flow<br /><br />struts tiles<br /><br />axis webservice<br /><br />准备阅读相关的JSR标准<br />编写一个Axis的例子<br /><br /><br />pdf liberay<br /><br />nutch search<br /><br />SSO<br /><br /><br /><img src ="http://www.blogjava.net/hk2000c/aggbug/62360.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2006-08-08 15:25 <a href="http://www.blogjava.net/hk2000c/archive/2006/08/08/62360.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSR-168 Portal 规范翻译 第8章 翻译节选</title><link>http://www.blogjava.net/hk2000c/archive/2006/07/12/jsr_168_s_ch8.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Wed, 12 Jul 2006 03:01:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2006/07/12/jsr_168_s_ch8.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/57761.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2006/07/12/jsr_168_s_ch8.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/57761.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/57761.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">Portlet </span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">Portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的形态直白的说，就是</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">功能的表现形式。通常，</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">根据他们自己功能的不同，执行不同的任务以及生成不同的内容。</span>
				<span lang="EN-US">Portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态直接预示着他们担任什么样的功能并且将会显示什么样的内容。当</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">被调用的时候，</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">容器会为其提供的一个的当前</span>
				<span lang="EN-US">portal</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态。</span>
				<span lang="EN-US">Portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">可以很方便的在处理一个</span>
				<span lang="EN-US">action</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">请求的时候改变它的形态。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<span style="mso-tab-count: 1">       </span>Portal</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">规范定义了</span>
				<span lang="EN-US">3</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">个</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态。他们分别是</span>
				<span lang="EN-US">VIEW</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，</span>
				<span lang="EN-US">EDIT</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">以及</span>
				<span lang="EN-US">HELP</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</span>
				<span lang="EN-US">PortletMode</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类定义了这些形态的常量。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<span style="mso-tab-count: 1">       </span>Portal</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态还用于对用户的权限功能控制，比方说一个未认证用户只能察看</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</span>
				<span lang="EN-US">VIEW</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">以及</span>
				<span lang="EN-US">HELP</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态，而认证用户则能访问</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</span>
				<span lang="EN-US">EDIT</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /?>
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">8.1 Portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</span>
				<span lang="EN-US">VIEW</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<span style="mso-tab-count: 1">       </span>Portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</span>
				<span lang="EN-US">VIEW</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态的主要功能是通过生成标记语言来显示</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的当前状态。比方说，一个</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</span>
				<span lang="EN-US">VIEW</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态可能包含一到两个页面，用户可以浏览或者做某些操作。它也可能仅仅是一张静态页面而不做任何事情。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<span style="mso-tab-count: 1">       </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">开发者可以简单的通过重载</span>
				<span lang="EN-US">GenericPortlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</span>
				<span lang="EN-US">doView()</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法来获得这项功能</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<span style="mso-tab-count: 1">       </span>Portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">必须支持</span>
				<span lang="EN-US">VIEW</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">8.2 EDIT </span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<span style="mso-tab-count: 1">       </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在</span>
				<span lang="EN-US">EDIT</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态下面，</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">应该提供相关的内容以及逻辑给用户，以便能够让用户可以自定义</span>
				<span lang="EN-US">portlet </span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">行为。一个</span>
				<span lang="EN-US">EDIT </span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态的</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">应该有</span>
				<span lang="EN-US">1</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">到多个窗口，这样用户就能从这些窗口进入他们自己自定义的数据了。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<span style="mso-tab-count: 1">       </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">通常，</span>
				<span lang="EN-US">EDIT</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态的</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">会设置或者更新</span>
				<span lang="EN-US">Portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">参数。参考</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">参数一节获得更多的细节。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">开发者可以简单的通过重载</span>
				<span lang="EN-US">GenericPortlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</span>
				<span lang="EN-US">doEdit()</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法来获得这项功能</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">
				<span lang="EN-US">Portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">不必支持</span>
				<span lang="EN-US">EDIT</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">8.3 HELP</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<span style="mso-tab-count: 1">       </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在</span>
				<span lang="EN-US">help</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态下面，</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">应该提供</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">本身的相关帮助信息。一个</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的帮助信息可以是介绍</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的完整帮助或者是内容相关的帮助文本。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">开发者可以简单的通过重载</span>
				<span lang="EN-US">GenericPortlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</span>
				<span lang="EN-US">doHelp()</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法来获得这项功能</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">
				<span lang="EN-US">Portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">不必支持</span>
				<span lang="EN-US">HELP</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">8.4 portlet </span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">自定义形态</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<span style="mso-tab-count: 1">       </span>Portlal</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的提供者可以自定义</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态用来提供自己指定的功能</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<span style="mso-tab-count: 1">       </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">要使用自定义</span>
				<span lang="EN-US">Portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态，首先需要在部署描述器中添加</span>
				<span lang="EN-US">custom-portlet-mode</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">元素</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，其次需要在运行期找到该形态的</span>
				<span lang="EN-US">portal</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">实现。如果在运行期间找不到该自定义形态的</span>
				<span lang="EN-US">portal</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">实现，这个</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">就不应该被调用</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<span style="mso-tab-count: 1">       </span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">打个比方，</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">应用需要支持</span>
				<span lang="EN-US">clipsboard</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">以及</span>
				<span lang="EN-US">config </span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态的</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，那么部署描述器里面可能这么写：</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">&lt;portlet-app&gt;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">... </span>
				<span lang="EN-US" style="FONT-SIZE: 12pt; mso-font-kerning: 0pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">&lt;custom-portlet-mode&gt;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">&lt;description&gt;Creates content for Cut and Paste&lt;/description&gt;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">&lt;name&gt;clipboard&lt;/name&gt;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">&lt;/custom-portlet-mode&gt;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">&lt;custom-portlet-mode&gt;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">&lt;description&gt;Provides administration functions&lt;/description&gt;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">&lt;name&gt;config&lt;/name&gt;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">&lt;/custom-portlet-mode&gt;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">... </span>
				<span lang="EN-US" style="FONT-SIZE: 12pt; mso-font-kerning: 0pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">&lt;/portlet-app&gt;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在《扩展</span>
				<span lang="EN-US">Portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态》附录中列出了建议的</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态的命名参考以及他们的使用参考。如果</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在部署描述器中定义了一个自定义的形态，并且</span>
				<span lang="EN-US">portal</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">容器实现了这种形态的话，那么</span>
				<span lang="EN-US">Portal</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">容器可以立即自动地映射这种支持形态。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">8.5 GenericPorlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">渲染方法的处理</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<span style="mso-tab-count: 1">       </span>GenericPorlet </span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">通过</span>
				<span lang="EN-US">render</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法来分发用户的请求给</span>
				<span lang="EN-US">doView , doEdit , doHelp </span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法。这个指定形态分发的动作在</span>
				<span lang="EN-US">doDispatch</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">里面都会指明。如果</span>
				<span lang="EN-US">portal</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">容器提供者需要支持一种新的形态，那么必须重载</span>
				<span lang="EN-US">doDispatch</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; mso-list: l0 level2 lfo1; tab-stops: list 21.0pt">
				<span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'">
						<span style="mso-list: Ignore">8.6<span style="FONT: 7pt 'Times New Roman'">     </span></span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">定义</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt">
				<span lang="EN-US">Portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">通过在它的部署描述器内配置</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态来获得它能使用的</span>
				<span lang="EN-US">portal</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">容器支持的形态。每个</span>
				<span lang="EN-US">Portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">都必须支持</span>
				<span lang="EN-US">VIEW</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态，而且</span>
				<span lang="EN-US">VIEW</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态无需特别指定。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">下面的例子显示了一个配置</span>
				<span lang="EN-US">Portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态的样本：</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">...<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">&lt;supports&gt;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">&lt;mime-type&gt;text/html&lt;/mime-type&gt;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">&lt;portlet-mode&gt;edit&lt;/portlet-mode&gt;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">&lt;portlet-mode&gt;help&lt;/portlet-mode&gt;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">... </span>
				<span lang="EN-US" style="FONT-SIZE: 12pt; mso-font-kerning: 0pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">&lt;/supports&gt;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">&lt;supports&gt;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">&lt;mime-type&gt;text/vnd.wap.wml&lt;/mime-type&gt;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">&lt;portlet-mode&gt;help&lt;/portlet-mode&gt;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">... </span>
				<span lang="EN-US" style="FONT-SIZE: 12pt; mso-font-kerning: 0pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">&lt;/supports&gt;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Courier; mso-font-kerning: 0pt; mso-bidi-font-family: Courier">...<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">以上的配置说明了，该</span>
				<span lang="EN-US">portlet</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在</span>
				<span lang="EN-US">html</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">标记语言下支持</span>
				<span lang="EN-US">edit ,help</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态，当然还支持默认的</span>
				<span lang="EN-US">view</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态。在</span>
				<span lang="EN-US">wml</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">语言环境下，支持</span>
				<span lang="EN-US">help</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">以及</span>
				<span lang="EN-US">view</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形态。</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> ===<br /></o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p>
								<br />以上是翻译节选，以后会陆续刊出其它章节<br />欢迎转载共同交流<br /><br /> </o:p>
				</span>
		</p>
<img src ="http://www.blogjava.net/hk2000c/aggbug/57761.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2006-07-12 11:01 <a href="http://www.blogjava.net/hk2000c/archive/2006/07/12/jsr_168_s_ch8.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JBoss装载应用出现log4j 装载错误</title><link>http://www.blogjava.net/hk2000c/archive/2006/04/28/56714.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Fri, 28 Apr 2006 15:21:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2006/04/28/56714.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/56714.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2006/04/28/56714.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/56714.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/56714.html</trackback:ping><description><![CDATA[
		<p>装载JBoss 应用的时候出现经典log错误 org.apache.commons.logging.LogConfigurationException: Class org.apache. commons.logging.impl.Log4JCategoryLog does not implement Log</p>
		<p>检查应用路径 %App_path%/WEB-INF/lib ，把下面 log4j.jar以及 commons-logging.jar 均删除，问题解决</p>
		<p>原理解释文章在以下位置</p>
		<p>
				<a href="http://www.qos.ch/logging/thinkAgain.jsp">http://www.qos.ch/logging/thinkAgain.jsp</a>
		</p>
		<p>以前也遇到类似问题</p>
		<p>如果是tomcat 5.x 版本，需要这样处理</p>
		<p>删除tomcat/webapps/%apps%/WEB-INF/lib/下面的<br />commons-logging-api-1.0.4.jar 包<br />然后换成</p>
		<p>log4j.jar以及 commons-logging.jar </p>
<img src ="http://www.blogjava.net/hk2000c/aggbug/56714.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2006-04-28 23:21 <a href="http://www.blogjava.net/hk2000c/archive/2006/04/28/56714.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA 安全三部曲之一　JAAS编程指南（前篇）</title><link>http://www.blogjava.net/hk2000c/archive/2006/03/23/jaas.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Thu, 23 Mar 2006 00:07:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2006/03/23/jaas.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/56715.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2006/03/23/jaas.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/56715.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/56715.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Java Authentication Authorization Service（JAAS，Java验证和授权API）提供了灵活和可伸缩的机制来保证客户端或服务器端的Java程序。Java早期的安全框架强调的是通过验证代码的来源和作者，保护用户避免受到下载下来的代码的攻击。JAAS强调的是通过验证谁在运行代码以及他／她的权限来保护系统面受用户的攻击。它让你能够将一些标准的安全机制，例如Solar...&nbsp;&nbsp;<a href='http://www.blogjava.net/hk2000c/archive/2006/03/23/jaas.html'>阅读全文</a><img src ="http://www.blogjava.net/hk2000c/aggbug/56715.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2006-03-23 08:07 <a href="http://www.blogjava.net/hk2000c/archive/2006/03/23/jaas.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDOM真的比DOM4j要慢么？</title><link>http://www.blogjava.net/hk2000c/archive/2005/03/21/jdom.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Sun, 20 Mar 2005 21:00:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2005/03/21/jdom.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/56716.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2005/03/21/jdom.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/56716.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/56716.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 有一部分xml解析器使用者认为 JDOM 很慢，至少比起Dom4j来说效率不快。其实JDOM和DOM4J一样，同属优秀的开源XML解析器， 完全不必这样担心。 现在就实际拿一些实际使用的例子，作为简单的测试用例，对JDOM以及DOM4J最基本的文档解析功能来说明这个问题。 JDOM测试用例如下：      public Document getDoc(String filename) throws...&nbsp;&nbsp;<a href='http://www.blogjava.net/hk2000c/archive/2005/03/21/jdom.html'>阅读全文</a><img src ="http://www.blogjava.net/hk2000c/aggbug/56716.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2005-03-21 05:00 <a href="http://www.blogjava.net/hk2000c/archive/2005/03/21/jdom.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使XML编程更简单---JDOM介绍及编程指南</title><link>http://www.blogjava.net/hk2000c/archive/2003/09/27/jdom_introduce.html</link><dc:creator>hk2000c</dc:creator><author>hk2000c</author><pubDate>Fri, 26 Sep 2003 23:19:00 GMT</pubDate><guid>http://www.blogjava.net/hk2000c/archive/2003/09/27/jdom_introduce.html</guid><wfw:comment>http://www.blogjava.net/hk2000c/comments/56720.html</wfw:comment><comments>http://www.blogjava.net/hk2000c/archive/2003/09/27/jdom_introduce.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hk2000c/comments/commentRss/56720.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hk2000c/services/trackbacks/56720.html</trackback:ping><description><![CDATA[
		<p align="center">
				<strong>
						<font size="5">JDOM 介绍及使用指南</font>
				</strong>
		</p>
		<p>
				<strong>
						<font size="4">一、JDOM 简介</font>
				</strong>
				<br />JDOM是一个开源项目，它基于树型结构，利用纯JAVA的技术对XML文档实现解析、生成、序列化以及多种操作。<br />JDOM 直接为JAVA编程服务。它利用更为强有力的JAVA语言的诸多特性（方法重载、集合概念以及映射），把SAX和DOM的功能有效地结合起来。<br />在使用设计上尽可能地隐藏原来使用XML过程中的复杂性。利用JDOM处理XML文档将是一件轻松、简单的事。<br />JDOM 在2000年的春天被Brett McLaughlin和Jason Hunter开发出来，以弥补DOM及SAX在实际应用当中的不足之处。<br />这些不足之处主要在于SAX没有文档修改、随机访问以及输出的功能，而对于DOM来说，JAVA程序员在使用时来用起来总觉得不太方便。<br />DOM的缺点主要是来自于由于Dom是一个接口定义语言（IDL）,它的任务是在不同语言实现中的一个最低的通用标准，并不是为JAVA特别设计的。JDOM的最新版本为JDOM Beta 9。最近JDOM被收录到JSR-102内，这标志着JDOM成为了JAVA平台组成的一部分。</p>
		<p>
				<font size="5">
				</font>
				<br />
				<strong>
						<font size="4">二、JDOM 包概览</font>
				</strong>
				<br />JDOM是由以下几个包组成的<br />org.JDOM<br />org.JDOM.input<br />org.JDOM.output<br />org.JDOM.adapters<br />org.JDOM.transform</p>
		<p>
				<strong>
						<font size="4">三、JDOM 类说明</font>
				</strong>
		</p>
		<p>org.JDOM<br />这个包里的类是你解析xml文件后所要用到的所有数据类型。<br />Attribute<br />CDATA<br />Coment<br />DocType<br />Document<br />Element<br />EntityRef<br />Namespace<br />ProscessingInstruction<br />Text</p>
		<p>org.JDOM.transform<br />在涉及xslt格式转换时应使用下面的2个类<br />JDOMSource<br />JDOMResult</p>
		<p>org.JDOM.input<br />输入类，一般用于文档的创建工作<br />SAXBuilder<br />DOMBuilder<br />ResultSetBuilder</p>
		<p>org.JDOM.output<br />输出类，用于文档转换输出<br />XMLOutputter<br />SAXOutputter<br />DomOutputter<br />JTreeOutputter</p>
		<p>使用前注意事项：<br />1.JDOM对于JAXP 以及 TRax 的支持<br />JDOM 支持JAXP1.1：你可以在程序中使用任何的parser工具类,默认情况下是JAXP的parser。<br />制定特别的parser可用如下形式<br />SAXBuilder parser <br />  = new SAXBuilder("org.apache.crimson.parser.XMLReaderImpl");<br /> Document doc = parser.build("<a href="http://www.cafeconleche.org/" _fcksavedurl="http://www.cafeconleche.org/">http://www.cafeconleche.org/</a>");<br /> // work with the document...<br />JDOM也支持TRaX：XSLT可通过JDOMSource以及JDOMResult类来转换（参见以后章节）<br />2.注意在JDOM里文档（Document）类由org.JDOM.Document 来表示。这要与org.w3c.dom中的Document区别开，这2种格式如何转换在后面会说明。<br />以下如无特指均指JDOM里的Document。</p>
		<p>
				<br />
				<strong>
						<font size="4">四、JDOM主要使用方法</font>
				</strong>
				<br />
				<strong>1.Ducument类</strong>
				<br />(1)Document的操作方法：<br />Element root = new Element("GREETING");<br />Document doc = new Document(root);<br />root.setText("Hello JDOM!");<br />或者简单的使用Document doc = new Document(new Element("GREETING").setText("Hello JDOM!t"));</p>
		<p>这点和DOM不同。Dom则需要更为复杂的代码，如下：<br />DocumentBuilderFactory factory =DocumentBuilderFactory.newInstance();<br />DocumentBuilder builder =factory.newDocumentBuilder();<br />Document doc = builder.newDocument();<br />Element root =doc.createElement("root");<br />Text text = doc.createText("This is the root");<br />root.appendChild(text);<br />doc.appendChild(root);</p>
		<p>
				<br />注意事项：JDOM不允许同一个节点同时被2个或多个文档相关联，要在第2个文档中使用原来老文档中的节点的话。首先需要使用detach()把这个节点分开来。<br /><br />(2)从文件、流、系统ID、URL得到Document对象：<br />DOMBuilder builder = new DOMBuilder();<br />Document doc = builder.build(new File("jdom_test.xml"));</p>
		<p>SAXBuilder builder = new SAXBuilder();<br />Document doc = builder.build(url);<br />在新版本中DOMBuilder 已经Deprecated掉 DOMBuilder.builder(url)，用SAX效率会比较快。</p>
		<p>这里举一个小例子，为了简单起见，使用String对象直接作为xml数据源：</p>
		<p> public jdomTest() {<br />    String textXml = null;<br />    textXml = "&lt;note&gt;";<br />    textXml = textXml +<br />        "&lt;to&gt;aaa&lt;/to&gt;&lt;from&gt;bbb&lt;/from&gt;&lt;heading&gt;ccc&lt;/heading&gt;&lt;body&gt;ddd&lt;/body&gt;";<br />    textXml = textXml + "&lt;/note&gt;";<br />    SAXBuilder builder = new SAXBuilder();<br />    Document doc = null;<br />    Reader in= new StringReader(textXml);<br />    try {<br />      doc = builder.build(in);<br />      Element root = doc.getRootElement();<br />      List ls = root.getChildren();//注意此处取出的是root节点下面的一层的Element集合<br />      for (Iterator iter = ls.iterator(); iter.hasNext(); ) {<br />        Element el = (Element) iter.next();<br />        if(el.getName().equals("to")){<br />         System.out.println(el.getText());<br />        }<br />      }<br />    }<br />    catch (IOException ex) {<br />      ex.printStackTrace();<br />    }<br />    catch (JDOMException ex) {<br />      ex.printStackTrace();<br />    }<br />  }</p>
		<p>很简单把。</p>
		<p>
				<br />(3)DOM的document和JDOM的Document之间的相互转换使用方法，简单！<br />DOMBuilder builder = new DOMBuilder();<br />org.jdom.Document jdomDocument = builder.build(domDocument);<br />// work with the JDOM document…</p>
		<p>DOMOutputter converter = new DOMOutputter();<br />org.w3c.dom.Document domDocument = converter.output(jdomDocument);<br />// work with the DOM document…</p>
		<p>
				<strong>2.XML文档输出</strong>
				<br />XMLOutPutter类：<br />JDOM的输出非常灵活,支持很多种io格式以及风格的输出<br />Document doc = new Document(...);<br />XMLOutputter outp = new XMLOutputter();<br />// Raw output<br />outp.output(doc, fileOutputStream);<br />// Compressed output<br />outp.setTextTrim(true);<br />outp.output(doc, socket.getOutputStream());<br />// Pretty output<br />outp.setIndent(" ");<br />outp.setNewlines(true);<br />outp.output(doc, System.out);<br />......<br />详细请参阅最新的JDOM API手册</p>
		<p>
				<br />
				<strong>3.Element 类：</strong>
				<br />(1)浏览Element树<br />//获得根元素element<br />Element root = doc.getRootElement();<br />// 获得所有子元素的一个list<br />List allChildren = root.getChildren();<br />// 获得指定名称子元素的list<br />List namedChildren = root.getChildren("name");<br />//获得指定名称的第一个子元素<br />Element child = root.getChild("name");<br />（这里的List是java.util.List）</p>
		<p>JDOM给了我们很多很灵活的使用方法来管理子元素<br />List allChildren = root.getChildren();<br />// 删除第四个子元素<br />allChildren.remove(3);<br />// 删除叫“jack”的子元素<br />allChildren.removeAll(root.getChildren("jack"));</p>
		<p>root.removeChildren("jack"); // 便捷写法<br />// 加入<br />allChildren.add(new Element("jane"));</p>
		<p>root.addContent(new Element("jane")); // 便捷写法<br />allChildren.add(0, new Element("first"));</p>
		<p>
				<br />(2)移动Elements:<br />在JDOM里很简单<br />Element movable = new Element("movable");<br />parent1.addContent(movable); // place<br />parent1.removeContent(movable); // remove<br />parent2.addContent(movable); // add</p>
		<p>在Dom里<br />Element movable = doc1.createElement("movable");<br />parent1.appendChild(movable); // place<br />parent1.removeChild(movable); // remove<br />parent2.appendChild(movable); // 出错!</p>
		<p>补充：<br />纠错性<br />JDOM的Element构造函数（以及它的其他函数）会检查element是否合法。<br />而它的add/remove方法会检查树结构，检查内容如下：<br />1.在任何树中是否有回环节点<br />2.是否只有一个根节点<br />3.是否有一致的命名空间（Namespaces）</p>
		<p> </p>
		<p>(3)Element的text内容读取<br />&lt;description&gt;<br />A cool demo<br />&lt;/description&gt;</p>
		<p>// The text is directly available<br />// Returns "\n A cool demo\n"<br />String desc = element.getText();</p>
		<p>// There's a convenient shortcut<br />// Returns "A cool demo"<br />String desc = element.getTextTrim();</p>
		<p>(4)Elment内容修改<br />element.setText("A new description");<br />3.可正确解释特殊字符<br />element.setText("&lt;xml&gt; content");<br />4.CDATA的数据写入、读出<br />element.addContent(new CDATA("&lt;xml&gt; content"));<br />String noDifference = element.getText();</p>
		<p>混合内容<br />element可能包含很多种内容，比如说</p>
		<p>&lt;table&gt;<br />&lt;!-- Some comment --&gt;<br />Some text<br />&lt;tr&gt;Some child element&lt;/tr&gt;<br />&lt;/table&gt;</p>
		<p>取table的子元素tr<br />String text = table.getTextTrim();<br />Element tr = table.getChild("tr");</p>
		<p>也可使用另外一个比较简单的方法<br />List mixedCo = table.getContent();<br />Iterator itr = mixedCo.iterator();<br />while (itr.hasNext()) {<br />Object o = i.next();<br />if (o instanceof Comment) {<br />...<br />}<br />// 这里可以写成Comment, Element, Text, CDATA,ProcessingInstruction, 或者是EntityRef的类型<br />}<br />// 现在移除Comment,注意这里游标应为1。这是由于回车键也被解析成Text类的缘故,所以Comment项应为1。<br />mixedCo.remove(1);</p>
		<p> </p>
		<p>
				<strong>4.Attribute类</strong>
				<br />&lt;table width="100%" border="0"&gt; &lt;/table&gt;<br />//获得attribute<br />String width = table.getAttributeValue("width");<br />int border = table.getAttribute("width").getIntValue();<br />//设置attribute<br />table.setAttribute("vspace", "0");<br />// 删除一个或全部attribute<br />table.removeAttribute("vspace");<br />table.getAttributes().clear();</p>
		<p> </p>
		<p>
				<strong>5.处理指令(Processing Instructions)操作</strong>
				<br />一个Pls的例子<br />&lt;?br?&gt;<br />&lt;?cocoon-process type="xslt"?&gt;<br />          |        |<br />          |        |<br />        目标     数据</p>
		<p>处理目标名称(Target)<br />String target = pi.getTarget();<br />获得所有数据（data），在目标（target）以后的所有数据都会被返回。<br />String data = pi.getData();<br />获得指定属性的数据<br />String type = pi.getValue("type");<br />获得所有属性的名称<br />List ls = pi.getNames();</p>
		<p>
				<strong>6.命名空间操作<br /></strong>&lt;xhtml:html <br /> xmlns:xhtml="<a href="http://www.w3.org/1999/xhtml" _fcksavedurl="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</a>"&gt;<br />&lt;xhtml:title&gt;Home Page&lt;/xhtml:title&gt;<br />&lt;/xhtml:html&gt;</p>
		<p>Namespace xhtml = Namespace.getNamespace("xhtml", "<a href="http://www.w3.org/1999/xhtml" _fcksavedurl="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</a>");<br />List kids = html.getChildren("title", xhtml);<br />Element kid = html.getChild("title", xhtml);<br />kid.addContent(new Element("table", xhtml));</p>
		<p>
				<strong>7.XSLT格式转换</strong>
				<br />使用以下函数可对XSLT转换<br />最后如果你需要使用w3c的Document则需要转换一下。<br />public static Document transform(String stylesheet，Document in)<br />                                        throws JDOMException {<br />     try {<br />       Transformer transformer = TransformerFactory.newInstance()<br />                             .newTransformer(new StreamSource(stylesheet));<br />       JDOMResult out = new JDOMResult();<br />       transformer.transform(new JDOMSource(in), out);<br />       return out.getDeocument();<br />     }<br />     catch (TransformerException e) {<br />       throw new JDOMException("XSLT Trandformation failed", e);<br />     }<br />   }</p>
		<p>参考书目：</p>
		<p>1.JDOM官方网站： <a href="http://www.jdom.org/" _fcksavedurl="http://www.jdom.org">http://www.jdom.org</a></p>
		<p>2.&lt;&lt;Processing XML with Java&gt;&gt; Elliotte Rusty Harold 2002</p>
		<p>3.JDOM API Documentation</p>
		<p>4.&lt;&lt;JDOM Makes XML Easy&gt;&gt;Jason Hunter Co-Creator JDOM Project</p>
		<p>5.WSDP Tutorial </p>
		<p> </p>
		<p> </p>
		<p> </p>
		<p> </p>
		<a href="http://blog.csdn.net/hk2000c/archive/2003/09/26/15239.aspx">
		</a>
<img src ="http://www.blogjava.net/hk2000c/aggbug/56720.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hk2000c/" target="_blank">hk2000c</a> 2003-09-27 07:19 <a href="http://www.blogjava.net/hk2000c/archive/2003/09/27/jdom_introduce.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>