<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Sparkle&#039;s Workshop &#187; Java</title>
	<atom:link href="http://weavesky.com/tag/java/feed/" rel="self" type="application/rss+xml" />
	<link>http://weavesky.com</link>
	<description></description>
	<lastBuildDate>Fri, 30 Dec 2011 08:14:49 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>基于MINA构建简单高性能的NIO应用-优化指南</title>
		<link>http://weavesky.com/2010/02/19/mina-article-4/</link>
		<comments>http://weavesky.com/2010/02/19/mina-article-4/#comments</comments>
		<pubDate>Fri, 19 Feb 2010 09:26:13 +0000</pubDate>
		<dc:creator>Sparkle</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[mina]]></category>

		<guid isPermaLink="false">http://weavesky.com/?p=600</guid>
		<description><![CDATA[本文为Sparkle发于《程序员》2008年2月刊的文章，与《程序员》的协议，可以在个人博客中发布，转载请保留出处。 优化指南 MINA默认配置的性能并不是很高的，部分原因是MINA目前还保留初期版本的架构，另外一个原因是因为JVM的发展。 首先我们关闭默认的ThreadModel设置 IoAcceptor acceptor = ...; IoServiceConfig acceptorConfig = acceptor.getDefaultConfig&#40;&#41;; acceptorConfig.setThreadModel&#40;ThreadModel.MANUAL&#41;; ThreadModel是一个很简单的线程实现，用于IoService。但是它实在太弱，以至于在并发环境产生大量问题。在MINA 2.0中，ThreadModel直接被取消。你应该使用ExecutorFilter来实现线程。 然后我们增加I/O处理线程(Article by Sparkle) 每一个Acceptor/Connector都使用一个线程来处理连接，然后把连接发送给I/O processor进行读写操作，我们只可以修改I/O processor使用的线程数，用以下代码设置 IoAcceptor acceptor = new SocketAcceptor&#40;Runtime.getRuntime&#40;&#41;.availableProcessors&#40;&#41; + 1, Executors.newCachedThreadPool&#40;&#41;&#41;; 当然是要将ExecutorFilter加入，上文已经很详细地描述了 acceptor.getDefaultConfig&#40;&#41;.getFilterChain&#40;&#41;.addLast&#40;&#34;threadPool&#34;, new ExecutorFilter&#40;Executors.newCachedThreadPool&#40;&#41;&#41;; 笔者在开发过程中，多次遇到OutOfMemoryError，经过研究之后才发现原因。MINA默认是使用direct memory实现ByteBuffer池的方案（以下简称direct buffer），通过JNI在内存开辟一段空间来使用，该方案在早期的MINA版本中是一个非常好的特性，那是因为MINA开发初期，JVM并没有现在的强大，带有池效果的direct buffer性能比较好。但是当我们使用-Xms -Xmx等指令增加JVM可使用的内存，那仅仅增加了堆的内存空间，而direct memory的空间并没有增加，导致MINA实际使用的时候经常出现OutOfMemoryError。如果你的确想使用direct memory，可以通过-XX:MaxDirectMemorySize选项来设置。不过笔者不建议这样做，因为最新的测试表明，在现代的JVM里面，direct &#8230; <a class="more-link" href="http://weavesky.com/2010/02/19/mina-article-4/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<blockquote><p>本文为Sparkle发于《程序员》2008年2月刊的文章，与《程序员》的协议，可以在个人博客中发布，转载请保留出处。</p></blockquote>
<p><strong>优化指南</strong><br />
MINA默认配置的性能并不是很高的，部分原因是MINA目前还保留初期版本的架构，另外一个原因是因为JVM的发展。</p>
<p>首先我们关闭默认的ThreadModel设置</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">IoAcceptor acceptor <span style="color: #339933;">=</span> ...<span style="color: #339933;">;</span>
IoServiceConfig acceptorConfig <span style="color: #339933;">=</span> acceptor.<span style="color: #006633;">getDefaultConfig</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
acceptorConfig.<span style="color: #006633;">setThreadModel</span><span style="color: #009900;">&#40;</span>ThreadModel.<span style="color: #006633;">MANUAL</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>ThreadModel是一个很简单的线程实现，用于IoService。但是它实在太弱，以至于在并发环境产生大量问题。在MINA 2.0中，ThreadModel直接被取消。你应该使用ExecutorFilter来实现线程。</p>
<p>然后我们增加I/O处理线程<span style="color: #ffffff;">(Article by Sparkle)</span><br />
每一个Acceptor/Connector都使用一个线程来处理连接，然后把连接发送给I/O processor进行读写操作，我们只可以修改I/O processor使用的线程数，用以下代码设置</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">IoAcceptor acceptor <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> SocketAcceptor<span style="color: #009900;">&#40;</span><span style="color: #003399;">Runtime</span>.<span style="color: #006633;">getRuntime</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">availableProcessors</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #cc66cc;">1</span>, Executors.<span style="color: #006633;">newCachedThreadPool</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>当然是要将ExecutorFilter加入，上文已经很详细地描述了</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">acceptor.<span style="color: #006633;">getDefaultConfig</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getFilterChain</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">addLast</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;threadPool&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> ExecutorFilter<span style="color: #009900;">&#40;</span>Executors.<span style="color: #006633;">newCachedThreadPool</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>笔者在开发过程中，多次遇到OutOfMemoryError，经过研究之后才发现原因。MINA默认是使用direct memory实现ByteBuffer池的方案（以下简称direct buffer），通过JNI在内存开辟一段空间来使用，该方案在早期的MINA版本中是一个非常好的特性，那是因为MINA开发初期，JVM并没有现在的强大，带有池效果的direct buffer性能比较好。但是当我们使用-Xms -Xmx等指令增加JVM可使用的内存，那仅仅增加了堆的内存空间，而direct memory的空间并没有增加，导致MINA实际使用的时候经常出现OutOfMemoryError。如果你的确想使用direct memory，可以通过-XX:MaxDirectMemorySize选项来设置。不过笔者不建议这样做，因为最新的测试表明，在现代的JVM里面，direct memory比堆的表现更差。这里可能有读者会觉得奇怪，为什么不用池，而要用堆呢，而且还需要gc。那是因为现在的JVM gc能力已经很强了，而且在并发环境里面，pool的同步也是一个性能的问题。我们可以通过这样的代码进行设置<span style="color: #ffffff;">(Article by Sparkle)</span></p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">ByteBuffer.<span style="color: #006633;">setUseDirectBuffers</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
ByteBuffer.<span style="color: #006633;">setAllocator</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> SimpleByteBufferAllocator<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>MINA 2.0已经默认把直接内存分配改成堆，为了提供最好的性能和稳定性。</p>
<p>最后一条优化技巧就是，把你的应用部署在Linux上，并且打开Java NIO使用Linux epoll的功能。可能你还没听过epoll，但是你应该听过Lighttpd、Nginx、Squid等，得益于epoll，它们提供很高的网络性能，还占用非常少的系统资源。JDK6已经默认把epoll配置打开，因此笔者建议把你的应用部署在JDK6上面，也同时因为JDK6还有别的优化特性。如果你的应用必须部署在JDK5上，你也可以通过参数把epoll支持打开。</p>
<p><strong>文章快速索引</strong></p>
<ol>
<li><a href="http://weavesky.com/2010/02/19/mina-article-1/">前言</a></li>
<li><a href="http://weavesky.com/2010/02/19/mina-article-2/">一个简单的例子</a></li>
<li><a href="http://weavesky.com/2010/02/19/mina-article-3/">MINA架构</a></li>
<li>优化指南</li>
</ol>
<h2  class="related_post_title">Related Posts</h2><ul class="related_post"><li><a href="http://weavesky.com/2010/02/19/mina-article-3/" title="基于MINA构建简单高性能的NIO应用-MINA架构">基于MINA构建简单高性能的NIO应用-MINA架构</a></li><li><a href="http://weavesky.com/2010/02/19/mina-article-2/" title="基于MINA构建简单高性能的NIO应用-一个简单的例子">基于MINA构建简单高性能的NIO应用-一个简单的例子</a></li><li><a href="http://weavesky.com/2010/02/19/mina-article-1/" title="基于MINA构建简单高性能的NIO应用-前言">基于MINA构建简单高性能的NIO应用-前言</a></li><li><a href="http://weavesky.com/2008/01/05/java-3des/" title="如何用Java进行3DES加密解密">如何用Java进行3DES加密解密</a></li><li><a href="http://weavesky.com/2008/01/05/java-des/" title="如何用Java进行DES加密解密">如何用Java进行DES加密解密</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://weavesky.com/2010/02/19/mina-article-4/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>基于MINA构建简单高性能的NIO应用-MINA架构</title>
		<link>http://weavesky.com/2010/02/19/mina-article-3/</link>
		<comments>http://weavesky.com/2010/02/19/mina-article-3/#comments</comments>
		<pubDate>Fri, 19 Feb 2010 09:21:59 +0000</pubDate>
		<dc:creator>Sparkle</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[mina]]></category>

		<guid isPermaLink="false">http://weavesky.com/?p=585</guid>
		<description><![CDATA[本文为Sparkle发于《程序员》2008年2月刊的文章，与《程序员》的协议，可以在个人博客中发布，转载请保留出处。 MINA架构 这里，我借用了一张Trustin Lee在Asia 2006的ppt里面的图片来介绍MINA的架构。 (图略) Remote Peer就是客户端，而下方的框是MINA的主要结构，各个框之间的箭头代表数据流向。 大家可以对比刚刚的例子来看这个架构图，IoService就是整个MINA的入口，负责底层的IO操作，客户端发过来的消息就是由它处理。刚刚我们使用的IoAcceptor就是一个IoService，之所以抽象成IoService，是因为MINA用同样的架构来处理服务器和客户端编程，IoService的另一个子类就是IoConnector，用于客户端。不过根据笔者的使用经验，使用非阻塞的模型进行客户端编程非常的不方便，你最好寻求其他的阻塞通讯框架。 IoService把数据转化成一个一个的事件，传递给IoFilterChain。你可以加入一连串的IoFilter，进行各种功能。笔者的建议是将一些功能性的，业务不相关的代码，用IoFilter来实现，使得整个应用结构更清晰，也方便代码重用。(Article by Sparkle) 被IoFilter处理过的事件，发送给 IoHandler，然后我们在这里实现具体的业务逻辑。这个部分很简单，如果你有Swing的使用经验的话，你会发现它跟Swing的事件非常相像，你要做的事情，仅仅是重载你需要的方法，然后编写具体的业务功能。在这其中，最重要的一个方法就是messageReceived了。 值得留意的是一个IoSession的类，每一个IoSession实例代表这一个连接，我们需要对连接进行的任何操作都通过这个类来实现。 从IoHandler通过调用IoSession.write等方法向客户端发送的消息，会通过跟输入数据相反的次序依次传递，直至由IoService负责把数据发送给客户端。 这就已经是MINA的全部，是不是很简单。 接下来，我会详细介绍我们编写具体代码的时候主要涉及到的三个类，IoHandler、IoSession和IoFilter。 IoHandler public interface IoHandler &#123; void sessionCreated&#40;IoSession session&#41; throws Exception; void sessionOpened&#40;IoSession session&#41; throws Exception; void sessionClosed&#40;IoSession session&#41; throws Exception; void sessionIdle&#40;IoSession &#8230; <a class="more-link" href="http://weavesky.com/2010/02/19/mina-article-3/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<blockquote><p>本文为Sparkle发于《程序员》2008年2月刊的文章，与《程序员》的协议，可以在个人博客中发布，转载请保留出处。</p></blockquote>
<p><strong>MINA架构</strong></p>
<p>这里，我借用了一张Trustin Lee在Asia 2006的ppt里面的图片来介绍MINA的架构。</p>
<p>(图略)</p>
<p>Remote Peer就是客户端，而下方的框是MINA的主要结构，各个框之间的箭头代表数据流向。<br />
大家可以对比刚刚的例子来看这个架构图，IoService就是整个MINA的入口，负责底层的IO操作，客户端发过来的消息就是由它处理。刚刚我们使用的IoAcceptor就是一个IoService，之所以抽象成IoService，是因为MINA用同样的架构来处理服务器和客户端编程，IoService的另一个子类就是IoConnector，用于客户端。不过根据笔者的使用经验，使用非阻塞的模型进行客户端编程非常的不方便，你最好寻求其他的阻塞通讯框架。<br />
IoService把数据转化成一个一个的事件，传递给IoFilterChain。你可以加入一连串的IoFilter，进行各种功能。笔者的建议是将一些功能性的，业务不相关的代码，用IoFilter来实现，使得整个应用结构更清晰，也方便代码重用。<span style="color: #ffffff;">(Article by Sparkle)</span><br />
被IoFilter处理过的事件，发送给 IoHandler，然后我们在这里实现具体的业务逻辑。这个部分很简单，如果你有Swing的使用经验的话，你会发现它跟Swing的事件非常相像，你要做的事情，仅仅是重载你需要的方法，然后编写具体的业务功能。在这其中，最重要的一个方法就是messageReceived了。<br />
值得留意的是一个IoSession的类，每一个IoSession实例代表这一个连接，我们需要对连接进行的任何操作都通过这个类来实现。<br />
从IoHandler通过调用IoSession.write等方法向客户端发送的消息，会通过跟输入数据相反的次序依次传递，直至由IoService负责把数据发送给客户端。<br />
这就已经是MINA的全部，是不是很简单。</p>
<p>接下来，我会详细介绍我们编写具体代码的时候主要涉及到的三个类，IoHandler、IoSession和IoFilter。</p>
<p><strong> IoHandler</strong></p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> IoHandler <span style="color: #009900;">&#123;</span>
  <span style="color: #000066; font-weight: bold;">void</span> sessionCreated<span style="color: #009900;">&#40;</span>IoSession session<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">void</span> sessionOpened<span style="color: #009900;">&#40;</span>IoSession session<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">void</span> sessionClosed<span style="color: #009900;">&#40;</span>IoSession session<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">void</span> sessionIdle<span style="color: #009900;">&#40;</span>IoSession session, IdleStatus status<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">void</span> exceptionCaught<span style="color: #009900;">&#40;</span>IoSession session, <span style="color: #003399;">Throwable</span> cause<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">void</span> messageReceived<span style="color: #009900;">&#40;</span>IoSession session, <span style="color: #003399;">Object</span> message<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">void</span> messageSent<span style="color: #009900;">&#40;</span>IoSession session, <span style="color: #003399;">Object</span> message<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>MINA的内部实现了一个事件模型，而IoHanlder则是所有事件最终产生响应的位置。每一个方法的名字很明确表明该事件的含义。messageReceived是接收客户端消息的事件，我们应该在这里实现业务逻辑。messageSent是服务器发送消息的事件，一般情况下我们不会使用它。sessionClosed是客户端断开连接的事件，可以在这里进行一些资源回收等操作。值得留意的是，客户端连接有两个事件，sessionCreated和sessionOpened，两者稍有不同，sessionCreated是由I/O processor线程触发的，而sessionOpened在其后，由业务线程触发的，由于MINA的I/O processor线程非常少，因此如果我们真的需要使用sessionCreated，也必须是耗时短的操作，一般情况下，我们应该把业务初始化的功能放在sessionOpened事件中。<span style="color: #ffffff;">(Article by Sparkle)</span><br />
细心的读者可能会发现，我们刚刚的例子继承的是IoHandlerAdapter，IoHandlerAdapter其实就是一个IoHanlder的空的实现，这样我们就可以不用重载不感兴趣的事件。</p>
<p><strong> IoSession</strong><br />
IoSession是一个接口，MINA里很多的地方都使用接口，很好地体现了面向接口编程的思想。它提供了对当前连接的操作功能，还有用户定义属性的存储功能，这点非常重要。IoSession是线程安全的，也就是我们能够在多线程环境中随意操作IoSession，这点给开发带来很大的好处。我们来看看具体提供的方法，笔者列举一些比较常用和重要的方法</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">WriteFuture write<span style="color: #009900;">&#40;</span><span style="color: #003399;">Object</span> message<span style="color: #009900;">&#41;</span>
CloseFuture close<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #003399;">Object</span> getAttribute<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> key<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003399;">Object</span> setAttribute<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> key, <span style="color: #003399;">Object</span> value<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003399;">Object</span> removeAttribute<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> key<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003399;">Set</span> getAttributeKeys<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000066; font-weight: bold;">boolean</span> isConnected<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000066; font-weight: bold;">boolean</span> isClosing<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
SocketAddress getRemoteAddress<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000066; font-weight: bold;">boolean</span> isIdle<span style="color: #009900;">&#40;</span>IdleStatus status<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>在这里，笔者把IoSession的方法大致分成三类<br />
第一类，连接操作功能。<br />
最主要的方法有两个，向客户端发送消息和断开连接。可以看的出，write接受的变量是一个Object，但是实际上应该传入什么类型呢？具体还得看你是否使用了ProtocolCodecFilter（下面会详细介绍），如果使用了ProtocolCodecFilter，那这个message将可能是一个String，或者是一个用户定义的JavaBean。默认的情况，message是一个ByteBuffer。ByteBuffer是MINA的一个类，跟java.nio.ByteBuffer类同名，MINA 2.0将会将它改成IoBuffer，以避免讨论上的误会。<span style="color: #ffffff;">(Article by Sparkle)</span><br />
另一个值得留意的是Future类，MINA是一个非阻塞的通信框架，其中一个明显的体现就是调用IoSession.write方法是不会阻塞的。用户调用了write方法之后，消息内容会发到底层等候发送，至于什么时候发出，就不得而知了。当然，实际上调用了write之后，数据几乎是立刻发出的，这得益与NIO的高性能。但是，如果我们必须确认了消息发出，然后进行某些处理，我们就需要使用Future类，以下是一个很常见的代码</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">IoSession session <span style="color: #339933;">=</span> ...<span style="color: #339933;">;</span>
WriteFuture future <span style="color: #339933;">=</span> session.<span style="color: #006633;">write</span><span style="color: #009900;">&#40;</span>...<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// Wait until the message is completely written out to the O/S buffer.</span>
future.<span style="color: #006633;">join</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span> future.<span style="color: #006633;">isWritten</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>  <span style="color: #009900;">&#123;</span>
  <span style="color: #666666; font-style: italic;">// The message has been written successfully.</span>
<span style="color: #009900;">&#125;</span>  <span style="color: #000000; font-weight: bold;">else</span>  <span style="color: #009900;">&#123;</span>
  <span style="color: #666666; font-style: italic;">// The messsage couldn't be written out completely for some reason.</span>
  <span style="color: #666666; font-style: italic;">// (e.g. Connection is closed)</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>通过调用future.join，程序就会阻塞，直至消息处理结束。我们还能通过future.isWritten得知消息是否成功发送。<br />
在这里，笔者顺便说一个实际使用的发现，消息发送是会自动合并的，简单来说，如果在很短的时间里，对同一个IoSession进行了两次write操作，客户端有可能只收到一条消息，而这条消息就是服务器发出的两条消息前后接起来。这样的设计可以在高并发的时候节省网络开销，而笔者的实际使用过程中，效果也相当好。但是如果这样行为会导致客户端工作不正常，你也可以通过参数关闭它。</p>
<p>第二类，属性存储操作。<br />
通常来说，我们的系统是有用户状态的，我们就需要在连接上存储用户属性，IoSession的Attribute就是这样一个功能。例如两个连接同时连入服务器，一个连接是用户A，用户ID是13，另一个连接是用户B，用户ID是14，我们就可以在用户登录成功之后，调用IoSession.setAttribute(“login_id”,13)，然后在其后的操作中，通过IoSession.getAttribute(“login_id”)获得当前登录用户ID，并进行相应的操作。简单来说，就是一个类似HttpSession的功能，当然具体的实现方法不一样。<span style="color: #ffffff;">(Article by Sparkle)</span></p>
<p>第三类，连接状态。<br />
这里就不多说了，从方法名上我们就能知道它具体的功能。</p>
<p><strong> IoFilter</strong><br />
过滤器是MINA的一个很重要的功能。IoFilter也是一个接口，但是相对比较复杂，这里就不列举它的方法了。简单来说IoFilter就像ServletFilter，在事件被IoHandler处理之前或之后进行一些特定的操作，但是它比ServletFilter复杂，可以处理很多种事件，除了包括IoHandler的7个事件以外，还有一些内部的事件可以进行操作。<br />
MINA提供了一些常用的IoFilter实现，例如有LoggingFilter（日志功能）、BlacklistFilter（黑名单功能）、CompressionFilter（压缩功能）、SSLFilter（SSL支持），这些过滤器比较简单，通过阅读它们的源代码，能够更进一步理解过滤器的实现。笔者在这里要重点介绍两个过滤器，ProtocolCodecFilter和ExecutorFilter</p>
<p><strong>ProtocolCodecFilter</strong><br />
网络传输的内容其实本质是一个二进制流，但是我们的业务功能不会，或者说不应该去直接操作二进制流。MINA默认向IoHandler传入的message是一个ByteBuffer，如果我们直接在IoHandler操作ByteBuffer，会导致大量协议分析的代码和实际的业务代码混杂在一起。最适合的做法，就是在IoFilter把ByteBuffer转换成String或者JavaBean，ProtocolCodecFilter正是这样的一个功能的过滤器。<br />
使用ProtocolCodecFilter很简单，我们只要把ProtocolCodecFilter加入到FilterChain就可以了，但是我们需要提供一个ProtocolCodecFactory。其实ProtocolCodecFilter仅仅是实现了过滤器部分的功能，它会将最终的转换工作，交给从ProtocolCodecFactory获得的Encode和Decode。如果我们需要编写自己的ProtocolCodec，就应该从ProtocolCodecFactory入手。MINA内置了几个ProtocolCodecFactory，比较常用的就是ObjectSerializationCodecFactory和TextLineCodecFactory。<span style="color: #ffffff;">(Article by Sparkle)</span><br />
ObjectSerializationCodecFactory是Java Object序列化之后的内容直接跟ByteBuffer互相转化，比较适合两端都是Java的情况使用。TextLineCodecFactory就是String跟ByteBuffer的转化，说白了就是文本，例如你要实现一个SMTP服务器，或者POP服务器，就可以使用它。而笔者的实际使用，大多数情况都是使用TextLineCodecFactory。<br />
这里提及一下IoFilter的顺序问题，IoFilter是有加入顺序的，例如，先加入LoggingFilter再加入ProtocolCodecFilter，和先加入ProtocolCodecFilter再加入LoggingFilter的效果是不一样的，前者LoggingFilter写入日志的内容是ByteBuffer，而后者写入日志的是转换后具体的类，例如String。实际使用的时候，一定要处理好过滤器的顺序。</p>
<p><strong>ExecutorFilter</strong><br />
另一个重要的过滤器就是ExecutorFilter。这里，我需要先说明一下MINA的线程工作模式，MINA默认是单线程处理所有客户端的消息，也就是说，即使你在一台8CPU的机器上面跑，可能也只用到一个CPU，另外，如果某次消息处理太耗时，就会导致其他消息等待，整体的吞吐量下降。很多朋友抱怨MINA的性能差，其实是因为他们没有加入ExecutorFilter的缘故。ExecutorFilter设计的很精巧，大家可以仔细阅读一下源代码，它会将同一个连接的消息合并起来按顺序调用，不会出现两个线程同时处理同一个连接的情况。<span style="color: #ffffff;">(Article by Sparkle)</span><br />
这里再次提及IoFitler的顺序问题，一般情况下，我们会将ExecutorFilter放在ProtocolCodecFilter之后，因为我们不需要多线程地执行ProtocolCodec操作，用单一线程来进行ProtocolCodec性能会比较高，而具体的业务逻辑可能还设计数据库操作，因此更适合放在不同的线程中运行。</p>
<p><strong>文章快速索引</strong></p>
<ol>
<li><a href="http://weavesky.com/2010/02/19/mina-article-1/">前言</a></li>
<li><a href="http://weavesky.com/2010/02/19/mina-article-2/">一个简单的例子</a></li>
<li>MINA架构</li>
<li><a href="http://weavesky.com/2010/02/19/mina-article-4/">优化指南</a></li>
</ol>
<h2  class="related_post_title">Related Posts</h2><ul class="related_post"><li><a href="http://weavesky.com/2010/02/19/mina-article-4/" title="基于MINA构建简单高性能的NIO应用-优化指南">基于MINA构建简单高性能的NIO应用-优化指南</a></li><li><a href="http://weavesky.com/2010/02/19/mina-article-2/" title="基于MINA构建简单高性能的NIO应用-一个简单的例子">基于MINA构建简单高性能的NIO应用-一个简单的例子</a></li><li><a href="http://weavesky.com/2010/02/19/mina-article-1/" title="基于MINA构建简单高性能的NIO应用-前言">基于MINA构建简单高性能的NIO应用-前言</a></li><li><a href="http://weavesky.com/2008/01/05/java-3des/" title="如何用Java进行3DES加密解密">如何用Java进行3DES加密解密</a></li><li><a href="http://weavesky.com/2008/01/05/java-des/" title="如何用Java进行DES加密解密">如何用Java进行DES加密解密</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://weavesky.com/2010/02/19/mina-article-3/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>基于MINA构建简单高性能的NIO应用-一个简单的例子</title>
		<link>http://weavesky.com/2010/02/19/mina-article-2/</link>
		<comments>http://weavesky.com/2010/02/19/mina-article-2/#comments</comments>
		<pubDate>Fri, 19 Feb 2010 09:05:57 +0000</pubDate>
		<dc:creator>Sparkle</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[mina]]></category>

		<guid isPermaLink="false">http://weavesky.com/?p=583</guid>
		<description><![CDATA[本文为Sparkle发于《程序员》2008年2月刊的文章，与《程序员》的协议，可以在个人博客中发布，转载请保留出处。 一个简单的例子 MINA使用非常简单，笔者以前做过一段时间传统的Java Socket开发，不过一直对Java NIO不是很理解，但是MINA很快就上手了，MINA封装了NIO繁琐的部分，使你可以更专注于业务功能实现。话不多说，让我们来看一个简单的例子，一个很常见的例子，时间服务器。(Article by Sparkle) 我们的实现目标是一个能响应多个客户端的请求，然后返回服务器当前的系统时间的功能。传统的Java Socket程序，我们需要每accept一个客户端连接，就创建一个新的线程来响应，这会令到系统整体负载能力有较大的限制，而且我们必须手工编写连接管理等代码。让我们来看看MINA是怎么处理的。 首先我们从官方网站下载MINA 1.1，这里我们假设JDK为1.5以上的版本，如果你使用的是JDK 1.4，请下载MINA 1.0，MINA 1.0跟1.1几乎一样，但是强烈建议使用JDK 1.5以上以获得更好的性能。 解开压缩包之后，能看见很多jar包，这里暂不介绍每个包的具体作用，可以把所有包都导入项目。值得留意的是MINA使用了一个slf4j的日志库，该日志库大有取缔common-logging之势。 public class TimeServer &#123; public static void main&#40;String&#91;&#93; args&#41; throws IOException &#123; IoAcceptor acceptor = new SocketAcceptor&#40;&#41;; &#160; SocketAcceptorConfig cfg = new SocketAcceptorConfig&#40;&#41;; cfg.getFilterChain&#40;&#41;.addLast&#40; &#8230; <a class="more-link" href="http://weavesky.com/2010/02/19/mina-article-2/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<blockquote><p>本文为Sparkle发于《程序员》2008年2月刊的文章，与《程序员》的协议，可以在个人博客中发布，转载请保留出处。</p></blockquote>
<p><strong>一个简单的例子</strong></p>
<p>MINA使用非常简单，笔者以前做过一段时间传统的Java Socket开发，不过一直对Java NIO不是很理解，但是MINA很快就上手了，MINA封装了NIO繁琐的部分，使你可以更专注于业务功能实现。话不多说，让我们来看一个简单的例子，一个很常见的例子，时间服务器。<span style="color: #ffffff;">(Article by Sparkle)</span><br />
我们的实现目标是一个能响应多个客户端的请求，然后返回服务器当前的系统时间的功能。传统的Java Socket程序，我们需要每accept一个客户端连接，就创建一个新的线程来响应，这会令到系统整体负载能力有较大的限制，而且我们必须手工编写连接管理等代码。让我们来看看MINA是怎么处理的。</p>
<p>首先我们从官方网站下载MINA 1.1，这里我们假设JDK为1.5以上的版本，如果你使用的是JDK 1.4，请下载MINA 1.0，MINA 1.0跟1.1几乎一样，但是强烈建议使用JDK 1.5以上以获得更好的性能。<br />
解开压缩包之后，能看见很多jar包，这里暂不介绍每个包的具体作用，可以把所有包都导入项目。值得留意的是MINA使用了一个slf4j的日志库，该日志库大有取缔common-logging之势。</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> TimeServer <span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> main<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> args<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">IOException</span> <span style="color: #009900;">&#123;</span>
    IoAcceptor acceptor <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> SocketAcceptor<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    SocketAcceptorConfig cfg <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> SocketAcceptorConfig<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    cfg.<span style="color: #006633;">getFilterChain</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">addLast</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;logger&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> LoggingFilter<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    cfg.<span style="color: #006633;">getFilterChain</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">addLast</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;codec&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> ProtocolCodecFilter<span style="color: #009900;">&#40;</span> <span style="color: #000000; font-weight: bold;">new</span> TextLineCodecFactory<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    acceptor.<span style="color: #006633;">bind</span><span style="color: #009900;">&#40;</span> <span style="color: #000000; font-weight: bold;">new</span> InetSocketAddress<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">8123</span><span style="color: #009900;">&#41;</span>, <span style="color: #000000; font-weight: bold;">new</span> TimeServerHandler<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>, cfg<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Time server started.&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>这里是我们的主程序，非常简单。<br />
首先我们需要一个IoAcceptor，这里我们选择了一个SocketAcceptor，也就是TCP协议。<br />
然后，我们给应用加上日志过滤器和协议编码过滤器。<span style="color: #ffffff;">(Article by Sparkle)</span><br />
最后，我们把acceptor bind到本机的8123端口，并且使用TimeServerHandler来实现协议。</p>
<p>TimeServerHandler是我们实现具体业务功能的地方。</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> TimeServerHandler <span style="color: #000000; font-weight: bold;">extends</span> IoHandlerAdapter <span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> messageReceived<span style="color: #009900;">&#40;</span>IoSession session, <span style="color: #003399;">Object</span> msg<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #003399;">String</span> str <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span><span style="color: #009900;">&#41;</span> msg<span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;quit&quot;</span>.<span style="color: #006633;">equalsIgnoreCase</span><span style="color: #009900;">&#40;</span>str<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    session.<span style="color: #006633;">close</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">return</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #003399;">Date</span> date <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Date</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  session.<span style="color: #006633;">write</span><span style="color: #009900;">&#40;</span> date.<span style="color: #006633;">toString</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Message written...&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> sessionCreated<span style="color: #009900;">&#40;</span>IoSession session<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Session created...&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>IoHandlerAdapter提供了7个事件方法，我们要做的事情仅仅是挑选我们需要做出响应的事件进行重载。在我这个例子了，我重载了两个方法。sessionCreated会在客户端连接的时候调用，通常我们会在这里进行一些初始化操作，我这里仅仅是打印一条信息。messageReceived就是整个Handler的中心部分，每一个从客户端发过来的消息都会转化成对该方法的调用。由于我们加入了协议编码过滤器，因此这里获得的Object msg是一个String，而不是默认的ByteBuffer（下文会详细介绍ProtocolCodecFilter）。这里我们实现了一个很简单的业务功能，如果用户输入的是quit，就断开连接，否则就输入当前时间。可以看出，IoSession封装了对当前连接的操作。</p>
<p>至此，我们就实现了一个时间服务器。</p>
<p><strong>文章快速索引</strong></p>
<ol>
<li><a href="http://weavesky.com/2010/02/19/mina-article-1/">前言</a></li>
<li>一个简单的例子</li>
<li><a href="http://weavesky.com/2010/02/19/mina-article-3/">MINA架构</a></li>
<li><a href="http://weavesky.com/2010/02/19/mina-article-4/">优化指南</a></li>
</ol>
<h2  class="related_post_title">Related Posts</h2><ul class="related_post"><li><a href="http://weavesky.com/2010/02/19/mina-article-4/" title="基于MINA构建简单高性能的NIO应用-优化指南">基于MINA构建简单高性能的NIO应用-优化指南</a></li><li><a href="http://weavesky.com/2010/02/19/mina-article-3/" title="基于MINA构建简单高性能的NIO应用-MINA架构">基于MINA构建简单高性能的NIO应用-MINA架构</a></li><li><a href="http://weavesky.com/2010/02/19/mina-article-1/" title="基于MINA构建简单高性能的NIO应用-前言">基于MINA构建简单高性能的NIO应用-前言</a></li><li><a href="http://weavesky.com/2008/01/05/java-3des/" title="如何用Java进行3DES加密解密">如何用Java进行3DES加密解密</a></li><li><a href="http://weavesky.com/2008/01/05/java-des/" title="如何用Java进行DES加密解密">如何用Java进行DES加密解密</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://weavesky.com/2010/02/19/mina-article-2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>基于MINA构建简单高性能的NIO应用-前言</title>
		<link>http://weavesky.com/2010/02/19/mina-article-1/</link>
		<comments>http://weavesky.com/2010/02/19/mina-article-1/#comments</comments>
		<pubDate>Fri, 19 Feb 2010 08:50:41 +0000</pubDate>
		<dc:creator>Sparkle</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[mina]]></category>

		<guid isPermaLink="false">http://weavesky.com/?p=573</guid>
		<description><![CDATA[本文为Sparkle发于《程序员》2008年2月刊的文章，与《程序员》的协议，可以在个人博客中发布，转载请保留出处。 前言 MINA是Trustin Lee最新制作的Java通讯框架。通讯框架的主要作用是封装底层IO操作，提供高级的操作API。比较出名的通讯框架有C++的ACE、Python的Twisted，而Java的通讯框架还有QuickServer、Netty2、Cindy、Grizzly等。 2004年6月，Trustin Lee发布了一个通讯框架Netty2，是Java界第一个事件模型架构的通讯框架，Cindy也从中借鉴了不少思想。由于Netty2的架构不是很好，Trustin Lee在2004年底加入Apache Directory组之后，重写了整个框架，取名为MINA。MINA是一个基于Java NIO的通讯框架，Java从1.4开始引入NIO，提供了一个非阻塞、高性能的IO底层。 目前使用MINA的产品并不是很多，比较出名的就有Apache Directory（作者就在为这个项目效力）、Openfire（Jive出品的一个XMPP产品）、red5（研究flash流媒体flv技术的朋友应该很清楚这个东西，adobe fms的竞争者，国内也有视频网站在使用）等等。 (Article by Sparkle) 笔者在07年初的时候，公司新项目需要用Java实现一个Socket Server，对比了Netty2、Cindy、QuickServer和MINA。当时Netty2已经停止开发，也找不到官方网站和代码，比较了另外三个框架之后，毅然选择了当时文档比较缺乏和使用群较少的MINA，一年以来的使用经验来看，感觉还是很不错的，MINA有着清晰的架构，很方便做自定义的扩充。在1.0发布之后，官方网站充实了很多，增加了不少文档，也听到越来越多的朋友开始使用MINA。后来专门针对JDK 1.5发布了1.1的版本，使用JDK内置的concurrent代替backport-util-concurrent。目前1.0和1.1同时存在，但已经不再增加新功能，仅仅发布bug fix的版本，新功能都在2.0中实现，2.0调整了架构，性能有更大的提升，目前还在开发中。 基本特性 通过Java NIO支持TCP和UDP协议，另外还支持RS232和VM内通讯。由于MINA有清晰的架构，你也能很简单地实现一个底层网络协议。目前不支持阻塞IO，似乎还没有计划支持，当然你可以在其之上实现一个阻塞的模型，不过按照笔者的经验来说，非阻塞IO更适合Server端编程。 一个类似ServletFilter的过滤器模型。这是笔者认为MINA的精髓所在，通过引入过滤器模型，可以将一些非业务的功能独立开来，层次更清晰，很有AOP的思想，可以很方便地进行日志、协议转换、压缩等等功能，还能在运行中动态增加或去掉功能。(Article by Sparkle) 可以直接使用底层的ByteBuffer，也可以使用用户定义的消息Object和编码方式。 高度可定制的线程模型，单线程、一个线程池，或者类似SEDA的多个线程池。 SSL支持，攻击防御和流量控制，mock测试友好，JMX支持，Spring集成，你还需要更多吗。 文章快速索引 前言 一个简单的例子 MINA架构 优化指南 Related Posts基于MINA构建简单高性能的NIO应用-优化指南基于MINA构建简单高性能的NIO应用-MINA架构基于MINA构建简单高性能的NIO应用-一个简单的例子如何用Java进行3DES加密解密如何用Java进行DES加密解密]]></description>
			<content:encoded><![CDATA[<blockquote><p>本文为Sparkle发于《程序员》2008年2月刊的文章，与《程序员》的协议，可以在个人博客中发布，转载请保留出处。</p></blockquote>
<p><strong>前言</strong></p>
<p>MINA是Trustin Lee最新制作的Java通讯框架。通讯框架的主要作用是封装底层IO操作，提供高级的操作API。比较出名的通讯框架有C++的ACE、Python的Twisted，而Java的通讯框架还有QuickServer、Netty2、Cindy、Grizzly等。</p>
<p>2004年6月，Trustin Lee发布了一个通讯框架Netty2，是Java界第一个事件模型架构的通讯框架，Cindy也从中借鉴了不少思想。由于Netty2的架构不是很好，Trustin Lee在2004年底加入Apache Directory组之后，重写了整个框架，取名为MINA。MINA是一个基于Java NIO的通讯框架，Java从1.4开始引入NIO，提供了一个非阻塞、高性能的IO底层。</p>
<p>目前使用MINA的产品并不是很多，比较出名的就有Apache Directory（作者就在为这个项目效力）、Openfire（Jive出品的一个XMPP产品）、red5（研究flash流媒体flv技术的朋友应该很清楚这个东西，adobe fms的竞争者，国内也有视频网站在使用）等等。 <span style="color: #ffffff;">(Article by Sparkle)</span></p>
<p>笔者在07年初的时候，公司新项目需要用Java实现一个Socket Server，对比了Netty2、Cindy、QuickServer和MINA。当时Netty2已经停止开发，也找不到官方网站和代码，比较了另外三个框架之后，毅然选择了当时文档比较缺乏和使用群较少的MINA，一年以来的使用经验来看，感觉还是很不错的，MINA有着清晰的架构，很方便做自定义的扩充。在1.0发布之后，官方网站充实了很多，增加了不少文档，也听到越来越多的朋友开始使用MINA。后来专门针对JDK 1.5发布了1.1的版本，使用JDK内置的concurrent代替backport-util-concurrent。目前1.0和1.1同时存在，但已经不再增加新功能，仅仅发布bug fix的版本，新功能都在2.0中实现，2.0调整了架构，性能有更大的提升，目前还在开发中。</p>
<p><strong>基本特性</strong></p>
<ul>
<li>通过Java NIO支持TCP和UDP协议，另外还支持RS232和VM内通讯。由于MINA有清晰的架构，你也能很简单地实现一个底层网络协议。目前不支持阻塞IO，似乎还没有计划支持，当然你可以在其之上实现一个阻塞的模型，不过按照笔者的经验来说，非阻塞IO更适合Server端编程。</li>
<li>一个类似ServletFilter的过滤器模型。这是笔者认为MINA的精髓所在，通过引入过滤器模型，可以将一些非业务的功能独立开来，层次更清晰，很有AOP的思想，可以很方便地进行日志、协议转换、压缩等等功能，还能在运行中动态增加或去掉功能。<span style="color: #ffffff;">(Article by Sparkle)</span></li>
<li>可以直接使用底层的ByteBuffer，也可以使用用户定义的消息Object和编码方式。</li>
<li>高度可定制的线程模型，单线程、一个线程池，或者类似SEDA的多个线程池。</li>
<li>SSL支持，攻击防御和流量控制，mock测试友好，JMX支持，Spring集成，你还需要更多吗。</li>
</ul>
<p><strong>文章快速索引</strong></p>
<ol>
<li>前言</li>
<li><a href="http://weavesky.com/2010/02/19/mina-article-2/">一个简单的例子</a></li>
<li><a href="http://weavesky.com/2010/02/19/mina-article-3/">MINA架构</a></li>
<li><a href="http://weavesky.com/2010/02/19/mina-article-4/">优化指南</a></li>
</ol>
<h2  class="related_post_title">Related Posts</h2><ul class="related_post"><li><a href="http://weavesky.com/2010/02/19/mina-article-4/" title="基于MINA构建简单高性能的NIO应用-优化指南">基于MINA构建简单高性能的NIO应用-优化指南</a></li><li><a href="http://weavesky.com/2010/02/19/mina-article-3/" title="基于MINA构建简单高性能的NIO应用-MINA架构">基于MINA构建简单高性能的NIO应用-MINA架构</a></li><li><a href="http://weavesky.com/2010/02/19/mina-article-2/" title="基于MINA构建简单高性能的NIO应用-一个简单的例子">基于MINA构建简单高性能的NIO应用-一个简单的例子</a></li><li><a href="http://weavesky.com/2008/01/05/java-3des/" title="如何用Java进行3DES加密解密">如何用Java进行3DES加密解密</a></li><li><a href="http://weavesky.com/2008/01/05/java-des/" title="如何用Java进行DES加密解密">如何用Java进行DES加密解密</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://weavesky.com/2010/02/19/mina-article-1/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>如何用Java进行3DES加密解密</title>
		<link>http://weavesky.com/2008/01/05/java-3des/</link>
		<comments>http://weavesky.com/2008/01/05/java-3des/#comments</comments>
		<pubDate>Sat, 05 Jan 2008 07:19:34 +0000</pubDate>
		<dc:creator>Sparkle</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[des]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://69.197.153.196/?p=527</guid>
		<description><![CDATA[最近一个合作商提出使用3DES交换数据，本来他们有现成的代码，可惜只有.net版本，我们的服务器都是Linux，而且应用都是Java。于是对照他们提供的代码改了一个Java的版本出来，主要是不熟悉3DES，折腾了一天，终于搞定。 所谓3DES，就是把DES做三次，当然不是简单地DES DES DES就行了，中途有些特定的排列。这个我可不关心，呵呵，我的目的是使用它。 在网上搜索了一下3DES，找到很少资料。经过朋友介绍，找到GNU Crypto和Bouncy Castle两个Java扩充包，里面应该有3DES的实现吧。 从GNU Crypto入手，找到一个TripleDES的实现类，发现原来3DES还有一个名字叫DESede，在网上搜索TripleDES和DESede，呵呵，终于发现更多的资料了。 Java的安全API始终那么难用，先创建一个cipher看看算法在不在吧 Cipher cipher = Cipher.getInstance&#40;&#34;DESede&#34;&#41;; 如果没有抛异常的话，就证明这个算法是有效的 突然想看看JDK有没有内置DESede，于是撇开Crypto，直接测试，发现可以正确运行。在jce.jar里面找到相关的类，JDK内置了。 于是直接用DES的代码来改&#038;测试，最后代码变成这样 SecureRandom sr = new SecureRandom&#40;&#41;; DESedeKeySpec dks = new DESedeKeySpec&#40;PASSWORD_CRYPT_KEY.getBytes&#40;&#41;&#41;; SecretKeyFactory keyFactory = SecretKeyFactory.getInstance&#40;&#34;DESede&#34;&#41;; SecretKey securekey = keyFactory.generateSecret&#40;dks&#41;; Cipher cipher = Cipher.getInstance&#40;&#34;DESede&#34;&#41;; cipher.init&#40;Cipher.ENCRYPT_MODE, &#8230; <a class="more-link" href="http://weavesky.com/2008/01/05/java-3des/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>最近一个合作商提出使用3DES交换数据，本来他们有现成的代码，可惜只有.net版本，我们的服务器都是Linux，而且应用都是Java。于是对照他们提供的代码改了一个Java的版本出来，主要是不熟悉3DES，折腾了一天，终于搞定。</p>
<p>所谓3DES，就是把DES做三次，当然不是简单地DES DES DES就行了，中途有些特定的排列。这个我可不关心，呵呵，我的目的是使用它。</p>
<p>在网上搜索了一下3DES，找到很少资料。经过朋友介绍，找到GNU Crypto和Bouncy Castle两个Java扩充包，里面应该有3DES的实现吧。</p>
<p>从GNU Crypto入手，找到一个TripleDES的实现类，发现原来3DES还有一个名字叫DESede，在网上搜索TripleDES和DESede，呵呵，终于发现更多的资料了。</p>
<p>Java的安全API始终那么难用，先创建一个cipher看看算法在不在吧</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">Cipher cipher <span style="color: #339933;">=</span> Cipher.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;DESede&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>如果没有抛异常的话，就证明这个算法是有效的</p>
<p>突然想看看JDK有没有内置DESede，于是撇开Crypto，直接测试，发现可以正确运行。在jce.jar里面找到相关的类，JDK内置了。</p>
<p>于是直接用DES的代码来改&#038;测试，最后代码变成这样</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #003399;">SecureRandom</span> sr <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">SecureRandom</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
DESedeKeySpec dks <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> DESedeKeySpec<span style="color: #009900;">&#40;</span>PASSWORD_CRYPT_KEY.<span style="color: #006633;">getBytes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
SecretKeyFactory keyFactory <span style="color: #339933;">=</span> SecretKeyFactory.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;DESede&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
SecretKey securekey <span style="color: #339933;">=</span> keyFactory.<span style="color: #006633;">generateSecret</span><span style="color: #009900;">&#40;</span>dks<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
Cipher cipher <span style="color: #339933;">=</span> Cipher.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;DESede&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
cipher.<span style="color: #006633;">init</span><span style="color: #009900;">&#40;</span>Cipher.<span style="color: #006633;">ENCRYPT_MODE</span>, securekey, sr<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#40;</span>Hex.<span style="color: #006633;">encodeHex</span><span style="color: #009900;">&#40;</span>cipher.<span style="color: #006633;">doFinal</span><span style="color: #009900;">&#40;</span>str.<span style="color: #006633;">getBytes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>需要留意的是，要使用DESede的Spec、Factory和Cipher才行</p>
<p>事情还没完结，合作商给过来的除了密钥之外，还有一个IV向量。搜索了一下，发现有一个IvParameterSpec类，于是代码变成这样</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #003399;">SecureRandom</span> sr <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">SecureRandom</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
DESedeKeySpec dks <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> DESedeKeySpec<span style="color: #009900;">&#40;</span>PASSWORD_CRYPT_KEY.<span style="color: #006633;">getBytes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
SecretKeyFactory keyFactory <span style="color: #339933;">=</span> SecretKeyFactory.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;DESede&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
SecretKey securekey <span style="color: #339933;">=</span> keyFactory.<span style="color: #006633;">generateSecret</span><span style="color: #009900;">&#40;</span>dks<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
IvParameterSpec iv <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> IvParameterSpec<span style="color: #009900;">&#40;</span>PASSWORD_IV.<span style="color: #006633;">getBytes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
Cipher cipher <span style="color: #339933;">=</span> Cipher.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;DESede&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
cipher.<span style="color: #006633;">init</span><span style="color: #009900;">&#40;</span>Cipher.<span style="color: #006633;">ENCRYPT_MODE</span>, securekey, iv, sr<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#40;</span>Hex.<span style="color: #006633;">encodeHex</span><span style="color: #009900;">&#40;</span>cipher.<span style="color: #006633;">doFinal</span><span style="color: #009900;">&#40;</span>str.<span style="color: #006633;">getBytes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>但是，运行报错了</p>
<blockquote><p>
java.security.InvalidAlgorithmParameterException: ECB mode cannot use IV
</p></blockquote>
<p>ECB是什么呢？我的代码完全没有写ECB什么的</p>
<p>又上网搜索，结果把DES的来龙去脉都搞清楚了</p>
<p>http://www.tropsoft.com/strongenc/des.htm</p>
<p>ECB是其中一种字串分割方式，除了DES以外，其他加密方式也会使用这种分割方式的，而Java默认产生的DES算法就是用ECB方法，ECB不需要向量，当然也就不支持向量了</p>
<p>除了ECB，DES还支持CBC、CFB、OFB，而3DES只支持ECB和CBC两种</p>
<p>http://www.tropsoft.com/strongenc/des3.htm</p>
<p>CBC支持并且必须有向量，具体算法这里就不说了。合作商给的.net代码没有声明CBC模式，似乎是.net默认的方式就是CBC的</p>
<p>于是把模式改成CBC</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">Cipher cipher <span style="color: #339933;">=</span> Cipher.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;DESede/CBC/PKCS5Padding&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>成功运行了</p>
<p>后话：</p>
<p>搜索的过程中，找到一个不错的讨论</p>
<blockquote>
<p>http://www.lslnet.com/linux/dosc1/21/linux-197579.htm</p>
<p>在CBC（不光是DES算法）模式下，iv通过随机数（或伪随机）机制产生是一种比较常见的方法。iv的作用主要是用于产生密文的第一个block，以使最终生成的密文产生差异（明文相同的情况下），使密码攻击变得更为困难，除此之外iv并无其它用途。因此iv通过随机方式产生是一种十分简便、有效的途径。此外，在IPsec中采用了DES-CBC作为缺省的加密方式，其使用的iv是通讯包的时间戳。从原理上来说，这与随机数机制并无二致。
</p></blockquote>
<p>看来，向量的作用其实就是salt</p>
<p>最大的好处是，可以令到即使相同的明文，相同的密钥，能产生不同的密文</p>
<p>例如，我们用DES方式在数据保存用户密码的时候，可以另外增加一列，把向量同时保存下来，并且每次用不同的向量。这样的好处是，即使两个用户的密码是一样的，数据库保存的密文，也会不一样，就能降低猜测的可能性</p>
<p>另外一种用法，就是类似IPsec的做法，两部主机互传数据，保证两部机的时钟同步的前提下（可以取样到分钟或更高的单位避免偏差），用时钟的变化值作为向量，就能增加被sniffer数据的解密难度</p>
<h2  class="related_post_title">Related Posts</h2><ul class="related_post"><li><a href="http://weavesky.com/2008/01/05/java-des/" title="如何用Java进行DES加密解密">如何用Java进行DES加密解密</a></li><li><a href="http://weavesky.com/2010/02/19/mina-article-4/" title="基于MINA构建简单高性能的NIO应用-优化指南">基于MINA构建简单高性能的NIO应用-优化指南</a></li><li><a href="http://weavesky.com/2010/02/19/mina-article-3/" title="基于MINA构建简单高性能的NIO应用-MINA架构">基于MINA构建简单高性能的NIO应用-MINA架构</a></li><li><a href="http://weavesky.com/2010/02/19/mina-article-2/" title="基于MINA构建简单高性能的NIO应用-一个简单的例子">基于MINA构建简单高性能的NIO应用-一个简单的例子</a></li><li><a href="http://weavesky.com/2010/02/19/mina-article-1/" title="基于MINA构建简单高性能的NIO应用-前言">基于MINA构建简单高性能的NIO应用-前言</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://weavesky.com/2008/01/05/java-3des/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>如何用Java进行DES加密解密</title>
		<link>http://weavesky.com/2008/01/05/java-des/</link>
		<comments>http://weavesky.com/2008/01/05/java-des/#comments</comments>
		<pubDate>Sat, 05 Jan 2008 05:08:08 +0000</pubDate>
		<dc:creator>Sparkle</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[des]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://69.197.153.196/?p=526</guid>
		<description><![CDATA[这篇其实是引子，直接贴代码，不多解释了 SecureRandom sr = new SecureRandom&#40;&#41;; DESKeySpec dks = new DESKeySpec&#40;PASSWORD_CRYPT_KEY.getBytes&#40;&#41;&#41;; SecretKeyFactory keyFactory = SecretKeyFactory.getInstance&#40;&#34;DES&#34;&#41;; SecretKey securekey = keyFactory.generateSecret&#40;dks&#41;; Cipher cipher = Cipher.getInstance&#40;&#34;DES&#34;&#41;; cipher.init&#40;Cipher.ENCRYPT_MODE, securekey, sr&#41;; return new String&#40;Hex.encodeHex&#40;cipher.doFinal&#40;str.getBytes&#40;&#41;&#41;&#41;&#41;; SecureRandom sr = new SecureRandom&#40;&#41;; DESKeySpec dks = new DESKeySpec&#40;PASSWORD_CRYPT_KEY.getBytes&#40;&#41;&#41;; SecretKeyFactory &#8230; <a class="more-link" href="http://weavesky.com/2008/01/05/java-des/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>这篇其实是引子，直接贴代码，不多解释了</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #003399;">SecureRandom</span> sr <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">SecureRandom</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
DESKeySpec dks <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> DESKeySpec<span style="color: #009900;">&#40;</span>PASSWORD_CRYPT_KEY.<span style="color: #006633;">getBytes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
SecretKeyFactory keyFactory <span style="color: #339933;">=</span> SecretKeyFactory.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;DES&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
SecretKey securekey <span style="color: #339933;">=</span> keyFactory.<span style="color: #006633;">generateSecret</span><span style="color: #009900;">&#40;</span>dks<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
Cipher cipher <span style="color: #339933;">=</span> Cipher.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;DES&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
cipher.<span style="color: #006633;">init</span><span style="color: #009900;">&#40;</span>Cipher.<span style="color: #006633;">ENCRYPT_MODE</span>, securekey, sr<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#40;</span>Hex.<span style="color: #006633;">encodeHex</span><span style="color: #009900;">&#40;</span>cipher.<span style="color: #006633;">doFinal</span><span style="color: #009900;">&#40;</span>str.<span style="color: #006633;">getBytes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #003399;">SecureRandom</span> sr <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">SecureRandom</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
DESKeySpec dks <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> DESKeySpec<span style="color: #009900;">&#40;</span>PASSWORD_CRYPT_KEY.<span style="color: #006633;">getBytes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
SecretKeyFactory keyFactory <span style="color: #339933;">=</span> SecretKeyFactory.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;DES&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
SecretKey securekey <span style="color: #339933;">=</span> keyFactory.<span style="color: #006633;">generateSecret</span><span style="color: #009900;">&#40;</span>dks<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
Cipher cipher <span style="color: #339933;">=</span> Cipher.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;DES&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
cipher.<span style="color: #006633;">init</span><span style="color: #009900;">&#40;</span>Cipher.<span style="color: #006633;">DECRYPT_MODE</span>, securekey, sr<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#40;</span>cipher.<span style="color: #006633;">doFinal</span><span style="color: #009900;">&#40;</span>Hex.<span style="color: #006633;">decodeHex</span><span style="color: #009900;">&#40;</span>str.<span style="color: #006633;">toCharArray</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<h2  class="related_post_title">Related Posts</h2><ul class="related_post"><li><a href="http://weavesky.com/2008/01/05/java-3des/" title="如何用Java进行3DES加密解密">如何用Java进行3DES加密解密</a></li><li><a href="http://weavesky.com/2010/02/19/mina-article-4/" title="基于MINA构建简单高性能的NIO应用-优化指南">基于MINA构建简单高性能的NIO应用-优化指南</a></li><li><a href="http://weavesky.com/2010/02/19/mina-article-3/" title="基于MINA构建简单高性能的NIO应用-MINA架构">基于MINA构建简单高性能的NIO应用-MINA架构</a></li><li><a href="http://weavesky.com/2010/02/19/mina-article-2/" title="基于MINA构建简单高性能的NIO应用-一个简单的例子">基于MINA构建简单高性能的NIO应用-一个简单的例子</a></li><li><a href="http://weavesky.com/2010/02/19/mina-article-1/" title="基于MINA构建简单高性能的NIO应用-前言">基于MINA构建简单高性能的NIO应用-前言</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://weavesky.com/2008/01/05/java-des/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>PageCacheFilter2</title>
		<link>http://weavesky.com/2007/12/31/page-cache-filter/</link>
		<comments>http://weavesky.com/2007/12/31/page-cache-filter/#comments</comments>
		<pubDate>Mon, 31 Dec 2007 14:24:42 +0000</pubDate>
		<dc:creator>Sparkle</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://69.197.153.196/?p=525</guid>
		<description><![CDATA[/** * 2006-5-1 * @author Sparkle */ public class PageCacheFilter2 implements Filter &#123; private Set&#60;string&#62; cacheUrlSet = new HashSet&#60;string&#62;&#40;&#41;; private Set&#60;string&#62; scacheUrlSet = new HashSet&#60;string&#62;&#40;&#41;; private String baseCachePath, contentType; &#160; public void init&#40;FilterConfig config&#41; throws ServletException &#123; String cacheUrl = &#8230; <a class="more-link" href="http://weavesky.com/2007/12/31/page-cache-filter/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[
<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #008000; font-style: italic; font-weight: bold;">/**
 * 2006-5-1
 * @author Sparkle
 */</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> PageCacheFilter2 <span style="color: #000000; font-weight: bold;">implements</span> Filter <span style="color: #009900;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">private</span> Set<span style="color: #339933;">&lt;</span>string<span style="color: #339933;">&gt;</span> cacheUrlSet <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> HashSet<span style="color: #339933;">&lt;</span>string<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #000000; font-weight: bold;">private</span> Set<span style="color: #339933;">&lt;</span>string<span style="color: #339933;">&gt;</span> scacheUrlSet <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> HashSet<span style="color: #339933;">&lt;</span>string<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> baseCachePath, contentType<span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> init<span style="color: #009900;">&#40;</span>FilterConfig config<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> ServletException <span style="color: #009900;">&#123;</span>
		<span style="color: #003399;">String</span> cacheUrl <span style="color: #339933;">=</span> config.<span style="color: #006633;">getInitParameter</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;cacheUrl&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>cacheUrl <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #003399;">StringTokenizer</span> tk <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">StringTokenizer</span><span style="color: #009900;">&#40;</span>cacheUrl<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #000000; font-weight: bold;">while</span> <span style="color: #009900;">&#40;</span>tk.<span style="color: #006633;">hasMoreTokens</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
				<span style="color: #003399;">String</span> str <span style="color: #339933;">=</span> tk.<span style="color: #006633;">nextToken</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">trim</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">toLowerCase</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>str.<span style="color: #006633;">endsWith</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;?&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
					str <span style="color: #339933;">=</span> str.<span style="color: #006633;">substring</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span>, str.<span style="color: #006633;">length</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
					scacheUrlSet.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span>str<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				<span style="color: #009900;">&#125;</span>
				cacheUrlSet.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span>str<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span>
		<span style="color: #009900;">&#125;</span>
		baseCachePath <span style="color: #339933;">=</span> config.<span style="color: #006633;">getInitParameter</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;cachePath&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		contentType <span style="color: #339933;">=</span> config.<span style="color: #006633;">getInitParameter</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;contentType&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">int</span> urlHashCode<span style="color: #009900;">&#40;</span>HttpServletRequest request<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #003399;">String</span> uri <span style="color: #339933;">=</span> request.<span style="color: #006633;">getRequestURI</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #003399;">String</span> qStr <span style="color: #339933;">=</span> request.<span style="color: #006633;">getQueryString</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>qStr <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			uri <span style="color: #339933;">+=</span> <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'?'</span> <span style="color: #339933;">+</span> qStr<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #003399;">Math</span>.<span style="color: #006633;">abs</span><span style="color: #009900;">&#40;</span>uri.<span style="color: #006633;">hashCode</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> cacheFilePath<span style="color: #009900;">&#40;</span>HttpServletRequest request<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #003399;">String</span> uri <span style="color: #339933;">=</span> request.<span style="color: #006633;">getRequestURI</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000066; font-weight: bold;">int</span> hash <span style="color: #339933;">=</span> urlHashCode<span style="color: #009900;">&#40;</span>request<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>scacheUrlSet.<span style="color: #006633;">contains</span><span style="color: #009900;">&#40;</span>uri.<span style="color: #006633;">toLowerCase</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #003399;">String</span> entityId <span style="color: #339933;">=</span> request.<span style="color: #006633;">getParameter</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;entityId&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>StringUtils.<span style="color: #006633;">isNotBlank</span><span style="color: #009900;">&#40;</span>entityId<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
				<span style="color: #000000; font-weight: bold;">return</span> baseCachePath <span style="color: #339933;">+</span> <span style="color: #0000ff;">&quot;/article/&quot;</span> <span style="color: #339933;">+</span> subDir<span style="color: #009900;">&#40;</span>entityId<span style="color: #009900;">&#41;</span>
						<span style="color: #339933;">+</span> <span style="color: #0000ff;">'/'</span> <span style="color: #339933;">+</span> entityId <span style="color: #339933;">+</span> <span style="color: #0000ff;">'/'</span> <span style="color: #339933;">+</span> hash <span style="color: #339933;">+</span> <span style="color: #0000ff;">&quot;.wml&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #000000; font-weight: bold;">return</span> baseCachePath <span style="color: #339933;">+</span> <span style="color: #0000ff;">&quot;/other/&quot;</span> <span style="color: #339933;">+</span> subDir2<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span>.<span style="color: #006633;">valueOf</span><span style="color: #009900;">&#40;</span>hash<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
				<span style="color: #339933;">+</span> <span style="color: #0000ff;">'/'</span> <span style="color: #339933;">+</span> hash <span style="color: #339933;">+</span> <span style="color: #0000ff;">&quot;.wml&quot;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> subDir<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> str<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000066; font-weight: bold;">int</span> length <span style="color: #339933;">=</span> str.<span style="color: #006633;">length</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>length <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">4</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #000000; font-weight: bold;">return</span> str.<span style="color: #006633;">substring</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span>, length <span style="color: #339933;">-</span> <span style="color: #cc66cc;">4</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #0000ff;">&quot;0&quot;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> subDir2<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> str<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000066; font-weight: bold;">int</span> length <span style="color: #339933;">=</span> str.<span style="color: #006633;">length</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>length <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">4</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #000000; font-weight: bold;">return</span> str.<span style="color: #006633;">substring</span><span style="color: #009900;">&#40;</span>length <span style="color: #339933;">-</span> <span style="color: #cc66cc;">4</span>, length<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #000000; font-weight: bold;">return</span> str<span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">void</span> clearCache<span style="color: #009900;">&#40;</span>HttpServletRequest request, <span style="color: #003399;">File</span> cacheFile<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>scacheUrlSet.<span style="color: #006633;">contains</span><span style="color: #009900;">&#40;</span>request.<span style="color: #006633;">getRequestURI</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">toLowerCase</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #003399;">File</span> cacheDir <span style="color: #339933;">=</span> cacheFile.<span style="color: #006633;">getParentFile</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">File</span> file <span style="color: #339933;">:</span> cacheDir.<span style="color: #006633;">listFiles</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
				file.<span style="color: #006633;">delete</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span>
			cacheDir.<span style="color: #006633;">delete</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
			cacheFile.<span style="color: #006633;">delete</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> doFilter<span style="color: #009900;">&#40;</span>ServletRequest req, ServletResponse res,
			FilterChain chain<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">IOException</span>, ServletException <span style="color: #009900;">&#123;</span>
		HttpServletRequest request <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>HttpServletRequest<span style="color: #009900;">&#41;</span> req<span style="color: #339933;">;</span>
		<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>cacheUrlSet.<span style="color: #006633;">contains</span><span style="color: #009900;">&#40;</span>request.<span style="color: #006633;">getRequestURI</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">toLowerCase</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			chain.<span style="color: #006633;">doFilter</span><span style="color: #009900;">&#40;</span>req, res<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #000000; font-weight: bold;">return</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		HttpServletResponse response <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>HttpServletResponse<span style="color: #009900;">&#41;</span> res<span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #003399;">File</span> cacheFile <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">File</span><span style="color: #009900;">&#40;</span>cacheFilePath<span style="color: #009900;">&#40;</span>request<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>cacheFile.<span style="color: #006633;">isFile</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>request.<span style="color: #006633;">getParameter</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;refresh&quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
				clearCache<span style="color: #009900;">&#40;</span>request, cacheFile<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
				<span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
					<span style="color: #003399;">BufferedReader</span> reader <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">BufferedReader</span><span style="color: #009900;">&#40;</span>
							<span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">FileReader</span><span style="color: #009900;">&#40;</span>cacheFile<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
					response.<span style="color: #006633;">setContentType</span><span style="color: #009900;">&#40;</span>contentType<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
					<span style="color: #003399;">String</span> line<span style="color: #339933;">;</span>
					<span style="color: #003399;">PrintWriter</span> printWriter <span style="color: #339933;">=</span> response.<span style="color: #006633;">getWriter</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
					<span style="color: #000000; font-weight: bold;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>line <span style="color: #339933;">=</span> reader.<span style="color: #006633;">readLine</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
						printWriter.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>line<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
					<span style="color: #009900;">&#125;</span>
					printWriter.<span style="color: #006633;">close</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
					<span style="color: #000000; font-weight: bold;">return</span><span style="color: #339933;">;</span>
				<span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">IOException</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
					<span style="color: #666666; font-style: italic;">// ignore</span>
					response.<span style="color: #006633;">reset</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
					<span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;read cache file error&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				<span style="color: #009900;">&#125;</span>
			<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #003399;">StringWriter</span> strWriter <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">StringWriter</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000066; font-weight: bold;">boolean</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> support <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #000066; font-weight: bold;">boolean</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
		support<span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">true</span><span style="color: #339933;">;</span>
		chain.<span style="color: #006633;">doFilter</span><span style="color: #009900;">&#40;</span>req, <span style="color: #000000; font-weight: bold;">new</span> ContentResponseWrapper<span style="color: #009900;">&#40;</span>response, strWriter,
				support<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>support<span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #339933;">!</span>response.<span style="color: #006633;">isCommitted</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #003399;">String</span> content <span style="color: #339933;">=</span> strWriter.<span style="color: #006633;">getBuffer</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">toString</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
			<span style="color: #003399;">PrintWriter</span> printWriter <span style="color: #339933;">=</span> response.<span style="color: #006633;">getWriter</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			printWriter.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>content<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			printWriter.<span style="color: #006633;">close</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
			<span style="color: #003399;">File</span> cacheDir <span style="color: #339933;">=</span> cacheFile.<span style="color: #006633;">getParentFile</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>cacheDir.<span style="color: #006633;">exists</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
				cacheDir.<span style="color: #006633;">mkdirs</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span>
			<span style="color: #003399;">PrintWriter</span> writer <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">PrintWriter</span><span style="color: #009900;">&#40;</span>cacheFile<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			writer.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>content<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			writer.<span style="color: #006633;">close</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> destroy<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>代码点评：这段代码的作用是，对指定的url进行cache，用了ContentRewriteFilter一样的做法来获取内容，因为具体的细节有些区别，没有继承ContentRewriteFilter而是直接编写代码。先判断是否有cache文件，如果有就输出给用户，但是如果连接上有refresh参数的话，就会清掉cache文件，如果没有cache文件，就会获取Servlet or JSP输出的内容，原原本本保存到磁盘，供下次用户访问使用。如果设置URL的时候，最后一位是问号，就会进入scacheUrlSet，这个是用于文章类型，主要的不同点是有分页，如果要refresh的话，应该要把所有分页的cache文件都清除。至于类名后面有个2，是因为这个是第二个版本。</p>
<p>（最近在考虑用Squid+Etag来实现一样的功能）</p>
<h2  class="related_post_title">Related Posts</h2><ul class="related_post"><li><a href="http://weavesky.com/2010/02/19/mina-article-4/" title="基于MINA构建简单高性能的NIO应用-优化指南">基于MINA构建简单高性能的NIO应用-优化指南</a></li><li><a href="http://weavesky.com/2010/02/19/mina-article-3/" title="基于MINA构建简单高性能的NIO应用-MINA架构">基于MINA构建简单高性能的NIO应用-MINA架构</a></li><li><a href="http://weavesky.com/2010/02/19/mina-article-2/" title="基于MINA构建简单高性能的NIO应用-一个简单的例子">基于MINA构建简单高性能的NIO应用-一个简单的例子</a></li><li><a href="http://weavesky.com/2010/02/19/mina-article-1/" title="基于MINA构建简单高性能的NIO应用-前言">基于MINA构建简单高性能的NIO应用-前言</a></li><li><a href="http://weavesky.com/2008/01/05/java-3des/" title="如何用Java进行3DES加密解密">如何用Java进行3DES加密解密</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://weavesky.com/2007/12/31/page-cache-filter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

