﻿<?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-dyerac</title><link>http://www.blogjava.net/dyerac/</link><description>dyerac In Java</description><language>zh-cn</language><lastBuildDate>Tue, 28 Apr 2026 20:46:49 GMT</lastBuildDate><pubDate>Tue, 28 Apr 2026 20:46:49 GMT</pubDate><ttl>60</ttl><item><title>Openfire, spark, red5</title><link>http://www.blogjava.net/dyerac/archive/2007/09/29/149692.html</link><dc:creator>dyerac in java...</dc:creator><author>dyerac in java...</author><pubDate>Sat, 29 Sep 2007 14:06:00 GMT</pubDate><guid>http://www.blogjava.net/dyerac/archive/2007/09/29/149692.html</guid><wfw:comment>http://www.blogjava.net/dyerac/comments/149692.html</wfw:comment><comments>http://www.blogjava.net/dyerac/archive/2007/09/29/149692.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/dyerac/comments/commentRss/149692.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dyerac/services/trackbacks/149692.html</trackback:ping><description><![CDATA[<p>Openfire（原来的Wildfire）是一个跨平台，采用Java开发，开源的实时协作（RTC）服务器基于XMPP（Jabber）协议。Openfire安装和使用都非常简单，并利用Web进行管理。单台服务器可支持上万并发用户<br />
<br />
Spark是Openfire的客户端？<br />
<br />
Red5是基于java的flash流媒体服务器</p>
<p>&nbsp;</p>
<p>以后有兴趣就研究一下子吧</p>
<img src ="http://www.blogjava.net/dyerac/aggbug/149692.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dyerac/" target="_blank">dyerac in java...</a> 2007-09-29 22:06 <a href="http://www.blogjava.net/dyerac/archive/2007/09/29/149692.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>手动创建一个新Class</title><link>http://www.blogjava.net/dyerac/archive/2007/08/13/136473.html</link><dc:creator>dyerac in java...</dc:creator><author>dyerac in java...</author><pubDate>Mon, 13 Aug 2007 10:52:00 GMT</pubDate><guid>http://www.blogjava.net/dyerac/archive/2007/08/13/136473.html</guid><wfw:comment>http://www.blogjava.net/dyerac/comments/136473.html</wfw:comment><comments>http://www.blogjava.net/dyerac/archive/2007/08/13/136473.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dyerac/comments/commentRss/136473.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dyerac/services/trackbacks/136473.html</trackback:ping><description><![CDATA[要让Java这个面向&#8220;对象&#8221;的世界正常运作，创建对象就是一项不可或缺的操作。<br><br>public class NewMain {<br>&nbsp;&nbsp;&nbsp; public static void main(String[] args) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new Object();<br>&nbsp;&nbsp;&nbsp; }<br>}<br><br>用javap反编译上面的代码，我们可以得到下面的指令，这里省去了javac暗中创建的构造函数。<br><br>public class NewMain extends java.lang.Object{<br>&nbsp;&nbsp;&nbsp; ...<br>public static void main(java.lang.String[]);<br>&nbsp; Code:<br>&nbsp;&nbsp; 0:&nbsp;&nbsp; new&nbsp;&nbsp;&nbsp;&nbsp; #3; //class java/lang/Object<br>&nbsp;&nbsp; 3:&nbsp;&nbsp; invokespecial&nbsp;&nbsp; #8; //Method java/lang/Object."&lt;init&gt;":()V<br>&nbsp;&nbsp; 6:&nbsp;&nbsp; return<br>}<br><br>从这段代码中，我们可以清晰的看出创建对象（new）和调用构造函数（invokespecial）两个过程。关于这个问题，我在《<a href="http://dreamhead.blogbus.com/logs/456837.html" target=_blank><font color=#4a664d>对象的生命</font></a>》中曾经进行过讨论。<br><br>既然javac将一个new的动作被解释为两条指令，那在JVM的层面上，我们当然就可以将它们分开。下面是一段没什么实际用途的代码，只是证明这个观点可行性。<br><br>public class NewGenerator {<br>&nbsp;&nbsp;&nbsp; public static void main(String[] args) throws Exception {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String className = "New";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cw.visit(Opcodes.V1_2, Opcodes.ACC_PUBLIC, className, null, "java/lang/Object", null);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Method m = Method.getMethod("void main (String[])");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, m, null, null, cw);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mg.newInstance(Type.getType(Object.class));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Label label = mg.newLabel();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mg.ifNonNull(label);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mg.mark(label);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mg.getStatic(Type.getType(System.class), "out", Type.getType(PrintStream.class));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mg.push("new object is not null");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mg.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod("void println(java.lang.String)"));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mg.pop();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mg.returnValue();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mg.endMethod();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cw.visitEnd();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OutputStream os = null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os = new FileOutputStream(className + ".class");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.write(cw.toByteArray());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } finally {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (os != null) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.close();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>}<br><br>这段代码生成的类是能够运行的，有兴趣的可以自己试一下。这段代码的作用是new出一个对象之后，如果这个对象非空的话，就会产生一个输出：<br>&nbsp;&nbsp;&nbsp; new object is not null<br><br>当然，如果尝试用这个对象做一些其它的操作，会有错误等待着我们，因为这个对象并不是一个完整的对象。在<a href="http://java.sun.com/docs/books/jvms/" target=_blank><font color=#4a664d>JVM规范</font></a>中有相关的解释：<a href="http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2.doc10.html" target=_blank><font color=#4a664d>new指令</font></a>并不能完整创建出一个新的对象，直到对未初始化的对象调用了实例初始化方法才会完成实例的创建。这段代码也正好符合《<a href="http://dreamhead.blogbus.com/logs/456837.html" target=_blank><font color=#4a664d>对象的生命</font></a>》中的解释，它只是负责做出申请内存。当然，在JVM中，它的实际工作要略多一些，如果这个对象的类没有加载，就会加载相应的类。<br>
<img src ="http://www.blogjava.net/dyerac/aggbug/136473.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dyerac/" target="_blank">dyerac in java...</a> 2007-08-13 18:52 <a href="http://www.blogjava.net/dyerac/archive/2007/08/13/136473.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Google Ajax Search api 以及 web api 的设计和架构?</title><link>http://www.blogjava.net/dyerac/archive/2007/07/25/132362.html</link><dc:creator>dyerac in java...</dc:creator><author>dyerac in java...</author><pubDate>Wed, 25 Jul 2007 09:52:00 GMT</pubDate><guid>http://www.blogjava.net/dyerac/archive/2007/07/25/132362.html</guid><wfw:comment>http://www.blogjava.net/dyerac/comments/132362.html</wfw:comment><comments>http://www.blogjava.net/dyerac/archive/2007/07/25/132362.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dyerac/comments/commentRss/132362.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dyerac/services/trackbacks/132362.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: <br>题记:<br>   其实我这篇文章纯粹是抛砖引玉之意<br>   Google Ajax Search 的api使用起来并不困难,如果有高手对此不屑一顾的话,不妨回答一下我的真正用意,那就是一个出色的web api该如何设计呢? 它的体系架构是什么? 我对此有个初步的想法, 前端开发自己的js库, 调用远端的服务. 但是具体实施该如何呢? 传输方式该是如何? JSON? 自定义XML? 还是SOAP? 现在很火的REST对 web api的设计有什么影响. 还望各位高手赐教 ^_^<br><br>    回到正题,看看如何用google api构建自己的ajax 搜索.&nbsp;&nbsp;<a href='http://www.blogjava.net/dyerac/archive/2007/07/25/132362.html'>阅读全文</a><img src ="http://www.blogjava.net/dyerac/aggbug/132362.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dyerac/" target="_blank">dyerac in java...</a> 2007-07-25 17:52 <a href="http://www.blogjava.net/dyerac/archive/2007/07/25/132362.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>动态代理(Dynamic Proxy）Java Servlet </title><link>http://www.blogjava.net/dyerac/archive/2007/07/24/132051.html</link><dc:creator>dyerac in java...</dc:creator><author>dyerac in java...</author><pubDate>Tue, 24 Jul 2007 07:10:00 GMT</pubDate><guid>http://www.blogjava.net/dyerac/archive/2007/07/24/132051.html</guid><wfw:comment>http://www.blogjava.net/dyerac/comments/132051.html</wfw:comment><comments>http://www.blogjava.net/dyerac/archive/2007/07/24/132051.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dyerac/comments/commentRss/132051.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dyerac/services/trackbacks/132051.html</trackback:ping><description><![CDATA[&nbsp;这篇文章讲的很好<br>基本上了解了动态代理的机制<br>就差写个代码实验一下<br><br><br>------------------------------------------------------------------------------------------------------------------------<br><br><br>从JDK1.3开始，Java就引入了动态代理的概念。动态代理（Dynamic Proxy）可以帮助你减少代码行数，真正提高代码的可复用度。例如，你不必为所有的类的方法里面都写上相同的Log代码行，取而代之的是实用类的动态代理类。当然，这种便利是有条件的。本文简单介绍Java动态代理的原理，并实现一个被代理的Servlet创建，和调用的过程。
<div>&nbsp;</div>
<div style="MARGIN-LEFT: 18pt; TEXT-INDENT: -18pt"><span>1．</span>代理模式（Proxy Pattern）</div>
<div style="TEXT-INDENT: 18pt">在JDK1.3以前，代理模式就已流行，所以得代理模式是生成一个和类相同接口的代理类，用户通过使用代理类来封装某个实现类。如图1，其目的是加强实现类的某个方法的功能，而不必改变原有的源代码。</div>
<div style="TEXT-INDENT: 18pt"><img alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/tyrone1979/proxy1.JPG"></div>
<p><span></span></p>
<div style="MARGIN-LEFT: 18pt; TEXT-INDENT: -18pt"><span>2．</span>动态代理（Dynamic Proxy）</div>
<div style="TEXT-INDENT: 24pt">随着Proxy的流行，Sun把它纳入到JDK1.3实现了Java的动态代理。动态代理和普通的代理模式的区别，就是动态代理中的代理类是由java.lang.reflect.Proxy类在运行期时根据接口定义，采用Java反射功能动态生成的。和java.lang.reflect.InvocationHandler结合，可以加强现有类的方法实现。如图2，图中的自定义Handler实现InvocationHandler接口，自定义Handler实例化时，将实现类传入自定义Handler对象。自定义Handler需要实现invoke方法，该方法可以使用Java反射调用实现类的实现的方法，同时当然可以实现其他功能，例如在调用实现类方法前后加入Log。而Proxy类根据Handler和需要代理的接口动态生成一个接口实现类的对象。当用户调用这个动态生成的实现类时，实际上是调用了自定义Handler的invoke方法。</div>
<div style="MARGIN-LEFT: 18pt">&nbsp;&nbsp;</div>
<div style="MARGIN-LEFT: 18pt"><img style="WIDTH: 602px; HEIGHT: 284px" height=284 alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/tyrone1979/proxy2.JPG" width=683></div>
<br clear=all>
<div>3．动态代理Servlet</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>虽然Web Application Server的产品很多，但Servlet的处理原理是相似的：动态加载Servlet，调用Servlet的init方法（只被调用一次），并保存到Servlet容器；Servlet使用时，调用Servlet的service方法。本文动态代理Servlet接口，使其init和service被调用时会在控制台打出方法调用前后信息。</div>
<div>首先实现2个Servlet，DefaultServlet和UserServlet</div>
<div>&nbsp;</div>
<div>package org.colimas.servlet;</div>
<div>&nbsp;</div>
<div>import javax.servlet.Servlet;</div>
<div>import javax.servlet.ServletException;</div>
<div>import javax.servlet.http.HttpServlet;</div>
<div>&nbsp;</div>
<div>public class DefaultServlet extends HttpServlet implements Servlet {</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void init() throws ServletException {</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super.init();</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(DefaultServlet.class.getName()+":Running init");</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div>&nbsp;</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public String getServletInfo() {</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return DefaultServlet.class.getName();</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div>}</div>
<div>&nbsp;</div>
<div>package org.colimas.servlet;</div>
<div>&nbsp;</div>
<div>import java.io.IOException;</div>
<div>&nbsp;</div>
<div>import javax.servlet.Servlet;</div>
<div>import javax.servlet.ServletException;</div>
<div>import javax.servlet.http.HttpServlet;</div>
<div>import javax.servlet.http.HttpServletRequest;</div>
<div>import javax.servlet.http.HttpServletResponse;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>public class UserServlet extends HttpServlet implements Servlet {</div>
<div>&nbsp;</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private static final long serialVersionUID = -7016554795165038652L;</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void init() throws ServletException {</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super.init();</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(UserServlet.class.getName()+":Running init");</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(UserServlet.class.getName()+":Do UserSErvlet Get");</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public String getServletInfo() {</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return UserServlet.class.getName();</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div>&nbsp;</div>
<div>}</div>
<div>&nbsp;</div>
<div>然后实现InvocationHandler</div>
<div>package org.colimas.webapp;</div>
<div>&nbsp;</div>
<div>import java.lang.reflect.InvocationHandler;</div>
<div>import java.lang.reflect.Method;</div>
<div>&nbsp;</div>
<div>import javax.servlet.Servlet;</div>
<div>&nbsp;</div>
<div>public class ServletHandler implements InvocationHandler {</div>
<div>&nbsp;</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private Servlet obj;</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public ServletHandler(Servlet obj){</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.obj=obj;</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Object invoke(Object arg0, Method arg1, Object[] arg2)</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws Throwable {</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(arg1.getName().compareTo("init")==0) //</span>调用init时</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(obj.getServletInfo()+":Init servlet starting..."); //</span>增加控制台输出。</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; arg1.invoke(obj,arg2); //</span>调用init方法</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(obj.getServletInfo()+":Init servlet ending..."); //</span>增加控制台输出。</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }else if(arg1.getName().compareTo("service")==0){ //</span>调用service时</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(obj.getServletInfo()+":service starting..."); //</span>增加控制台输出。</div>
<div>&nbsp;</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; arg1.invoke(obj,arg2); //</span>调用service方法。</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(obj.getServletInfo()+":service ending..."); //</span>增加控制台输出。</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div>&nbsp;</div>
<div>}</div>
<div>&nbsp;</div>
<div>实现Servlet的调用</div>
<div>package org.colimas.webapp;</div>
<div>&nbsp;</div>
<div>import java.lang.reflect.InvocationHandler;</div>
<div>import java.lang.reflect.Proxy;</div>
<div>&nbsp;</div>
<div>import javax.servlet.Servlet;</div>
<div>import javax.servlet.ServletConfig;</div>
<div>import javax.servlet.ServletContext;</div>
<div>import javax.servlet.ServletException;</div>
<div>&nbsp;</div>
<div>public class ServletWrapperImp {</div>
<div><span>&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp; private Class servletClass;</span></div>
<div><span>&nbsp;&nbsp;&nbsp; private ServletConfig config;</span></div>
<div><span>&nbsp;&nbsp;&nbsp; private String _servletname;</span></div>
<div><span>&nbsp;&nbsp;&nbsp; private Servlet _theServlet;</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private ServletContext context;</span></div>
<div><span>&nbsp;&nbsp;&nbsp; public ServletWrapperImp(ServletConfig config){</span></div>
<div><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.config=config;</span></div>
<div><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this._servletname=this.config.getServletName();</span></div>
<div><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.context=this.config.getServletContext();</span></div>
<div><span>&nbsp;&nbsp;&nbsp; }</span></div>
<div><span>&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp; public Servlet getServlet() throws ServletException{</span></div>
<div>&nbsp;</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; destroy();</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WebAppClassLoader loader=new WebAppClassLoader(this.getClass().getClassLoader()); //</span>自定义class loader</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String name=getServletName(); //</span>从ServletConfig中获得Servlet Name</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;synchronized (context) {</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Servlet theServlet=context.getServlet(name); //</span>在ServletContext中查找Servlet</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(theServlet==null){&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</span>如果ServletContext没有。<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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; servletClass = loader.loadClass(name); //</span>由Class loader 加载Servlet class。</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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; theServlet = (Servlet) servletClass.newInstance(); //Servlet</span>实例化。</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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; WebAppContext.addServlet(name,theServlet); //</span>将Servlet实例存入ServletContext。</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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; InvocationHandler handler=new ServletHandler(theServlet); //</span>自定义ServletHandler，参见ServletHandler类。</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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; _theServlet=(Servlet)Proxy.newProxyInstance(theServlet.getClass().getClassLoader(),</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new Class[]{Servlet.class},handler); //</span>代理类实例化。</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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; _theServlet.init(config); //Servlet</span>代理对象调用init方法。参见ServletHandler的invoke方法。</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }else{ //ServletContext</span>里已存在。</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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; InvocationHandler handler=new ServletHandler(theServlet); //</span>自定义ServletHandler，参见ServletHandler类。</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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; _theServlet=(Servlet)Proxy.newProxyInstance(theServlet.getClass().getClassLoader(),</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new Class[]{Servlet.class},handler);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //</span>代理Servlet接口，动态生成代理类，并实例化。<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return _theServlet; //</span>返回Servlet代理对象</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch( ClassNotFoundException ex1 ) {</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch( InstantiationException ex ) {</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }catch(IllegalAccessException ex2){</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return null;</span></div>
<div><span>&nbsp;&nbsp;&nbsp; }</span></div>
<div><span>&nbsp;&nbsp;&nbsp; public void destroy() {</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (_theServlet != null) {</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _theServlet.destroy();</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div><span>&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp; protected String getServletName(){</span></div>
<div><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return _servletname;</span></div>
<div><span>&nbsp;&nbsp;&nbsp; }</span></div>
<div>}</div>
<div>&nbsp;</div>
<div>其中的ServletConfig保存Servlet相关信息。ServletContext保存所有的Servlet对象。WebAppClassLoader为自定义class loader,参见<a href="http://blog.csdn.net/tyrone1979/archive/2006/09/03/1164262.aspx"><u><font color=#0000ff>http://blog.csdn.net/tyrone1979/archive/2006/09/03/1164262.aspx</font></u></a>。</div>
<div>&nbsp;</div>
<div>最后编写测试类Main，该类模拟10个用户访问Servlet，5人访问DefaultServlet，5人访问UserServlet。</div>
<div>package org.colimas.main;</div>
<div>&nbsp;</div>
<div>import java.io.IOException;</div>
<div>&nbsp;</div>
<div>import javax.servlet.Servlet;</div>
<div>import javax.servlet.ServletConfig;</div>
<div>import javax.servlet.ServletException;</div>
<div>&nbsp;</div>
<div>import org.colimas.webapp.HttpServletRequestWrapper;</div>
<div>import org.colimas.webapp.HttpServletResponseWrapper;</div>
<div>import org.colimas.webapp.ServletConfigImpl;</div>
<div>import org.colimas.webapp.ServletWrapper;</div>
<div>import org.colimas.webapp.ServletWrapperImp;</div>
<div>import org.colimas.webapp.WebAppContext;</div>
<div>&nbsp;</div>
<div>public class Main {</div>
<div>&nbsp;</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private ThreadGroup _threadGroup;</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private Thread[] _threads; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String defaultServletName="org.colimas.servlet.DefaultServlet";</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String userServletName="org.colimas.servlet.UserServlet";</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WebAppContext context=WebAppContext.newInstance();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void doStart(){</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _threadGroup=new ThreadGroup("SERVLETS");</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i=0;</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _threads=new ServletThread[10]; //</span>模拟10位用户。</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(i=0;i&lt;5;i++){</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _threads[i]=new ServletThread(_threadGroup,new Integer(i).toString(),</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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; defaultServletName); </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _threads[i].start();</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(i=5;i&lt;10;i++){</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _threads[i]=new ServletThread(_threadGroup,new Integer(i).toString(),</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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; userServletName);</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _threads[i].start();</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;* @param args</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;*/</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String[] args) {</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Main _main=new Main();</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _main.doStart();</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</span>模拟用户线程</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private class ServletThread extends Thread{</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private String servletName;</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public ServletThread(ThreadGroup group,String threadname,String servletname){</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super(group,threadname);</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; servletName=servletname;</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</span>调用Servlet的service.</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run() { //</span>用户调用Servlet</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ServletConfig config=new ServletConfigImpl(servletName,context); //</span>调用的Servlet信息。</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ServletWrapperImp wrapper=new ServletWrapperImp(config); </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Servlet defaultServlet=wrapper.getServlet(); //</span>获得Servlet对象，实际是Servlet的代理对象</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; defaultServlet.service(new HttpServletRequestWrapper(), </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new HttpServletResponseWrapper()); </span>调用代理对象的service方法，参见ServletHandler的invoke方法。</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (ServletException e) {</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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;&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; e.printStackTrace();</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch(IOException e){</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div>}</div>
<div>HttpServletRequestWrapper和HttpServletResponseWrapper实现HttpServletRequest，和HttpServletResponse。</div>
<div>测试结果如下</div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.DefaultServlet:Init servlet starting...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black">org.colimas.servlet.DefaultServlet:Running init</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.DefaultServlet:Init servlet ending...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.UserServlet:Init servlet starting...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black">org.colimas.servlet.UserServlet:Running init</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.UserServlet:Init servlet ending...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.DefaultServlet:service starting...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.DefaultServlet:service ending...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.DefaultServlet:service starting...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.DefaultServlet:service ending...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.UserServlet:service starting...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black">org.colimas.servlet.UserServlet:Do UserSErvlet Get</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.UserServlet:service ending...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.UserServlet:service starting...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black">org.colimas.servlet.UserServlet:Do UserSErvlet Get</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.UserServlet:service ending...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.UserServlet:service starting...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black">org.colimas.servlet.UserServlet:Do UserSErvlet Get</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.UserServlet:service ending...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.UserServlet:service starting...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.DefaultServlet:service starting...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.UserServlet:service starting...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.DefaultServlet:service starting...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.DefaultServlet:service starting...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black">org.colimas.servlet.UserServlet:Do UserSErvlet Get</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.DefaultServlet:service ending...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black">org.colimas.servlet.UserServlet:Do UserSErvlet Get</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.DefaultServlet:service ending...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.DefaultServlet:service ending...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.UserServlet:service ending...</span></div>
<div align=left><span style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red">org.colimas.servlet.UserServlet:service ending...</span></div>
<div>&nbsp;</div>
<div>2个Servlet第一次Load时初始化，被调用init，之后保存到ServletContext中。第二次直接从ServletContext获得，执行service。红字表示代理类里增加的输出结果。</div>
<div>&nbsp;</div>
<div>4．动态代理的限制</div>
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JDK</span>的动态代理并不能随心所欲的代理所有的类。Proxy.newProxyInstance方法的第二个参数只能是接口数组， 也就是Proxy只能代理接口。</div>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/dyerac/aggbug/132051.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dyerac/" target="_blank">dyerac in java...</a> 2007-07-24 15:10 <a href="http://www.blogjava.net/dyerac/archive/2007/07/24/132051.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>动态代理,包装器模式</title><link>http://www.blogjava.net/dyerac/archive/2007/07/24/132037.html</link><dc:creator>dyerac in java...</dc:creator><author>dyerac in java...</author><pubDate>Tue, 24 Jul 2007 06:03:00 GMT</pubDate><guid>http://www.blogjava.net/dyerac/archive/2007/07/24/132037.html</guid><wfw:comment>http://www.blogjava.net/dyerac/comments/132037.html</wfw:comment><comments>http://www.blogjava.net/dyerac/archive/2007/07/24/132037.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dyerac/comments/commentRss/132037.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dyerac/services/trackbacks/132037.html</trackback:ping><description><![CDATA[<p>转的这篇文章虽然是讲动态代理的<br>但是其中涉及到了Decorator模式 也是一个学习的亮点<br><br><br><br><br>-----------------------------------------------------------------------------------------------------<br>记忆是衍生自Lisp,Python,和Perl等过程性语言的一种设计模式，它可以对前次的计算结果进行记忆。&nbsp;一个实现了记忆功能的函数,&nbsp;带有显式的cache,&nbsp;所以,&nbsp;已经计算过的结果就能直接从cache中获得,&nbsp;而不用每次都进行计算.<br>记忆能显著的提升大计算量代码的效率.&nbsp;而且是一种可重用的方案.<br>本文阐述了在Java中使用这一模式的方法,并提供了一个可以提供上述功能的"记忆类":<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Foo&nbsp;foo&nbsp;=&nbsp;(Foo)&nbsp;Memoizer.memoize(new&nbsp;FooImpl());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这里,Foo是一个接口,它含有的方法是需要记忆的.FooImpl是Foo的一个实现.foo是Foo的一个引用.方法与FooImpl基本相同,区别在于Foo返回的值,会被缓存起来.单个记忆类的优点在于为任何类添加记忆功能是很简单的:定义一个包含需要记忆的方法的接口,然后调用memoize来实现一个实例.<br><br>&nbsp;&nbsp;&nbsp;&nbsp;为了理解记忆类是怎么实现的,我们将分几步来解释.首先,我解释一下为何缓存能够在需要它的类中实现.然后,我测试一下如何为一个特定的类添加缓存包装器.最后,我解释一下如何才能使得一个缓存包装器能够通用于任意的类.<br><br><strong>为大计算量的程序添加缓存</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;作为一个大计算量程序的例子,我们考虑PiBinaryDigitsCalculator这个例子-计算二进制数据pi.仅有的public方法calculateBinaryDigit带有一个参数:整数n,代表需要精确到的位数.例如,1000000,将会返回小数点后的一百万位,通过byte值返回-每位为0或者1.(算法可以参考:&nbsp;<a href="http://www.cecm.sfu.ca/~pborwein/PAPERS/P123.pdf" target=_blank><font color=#002c99><u>http://www.cecm.sfu.ca/~pborwein/PAPERS/P123.pdf</u></font></a>)<br><br><code>public&nbsp;class&nbsp;PiBinaryDigitsCalculator&nbsp;{<br>&nbsp;&nbsp;/**<br>&nbsp;&nbsp;&nbsp;*&nbsp;Returns&nbsp;the&nbsp;coefficient&nbsp;of&nbsp;2^n&nbsp;in&nbsp;the&nbsp;binary<br>&nbsp;&nbsp;&nbsp;*&nbsp;expansion&nbsp;of&nbsp;pi.<br>&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;n&nbsp;the&nbsp;binary&nbsp;digit&nbsp;of&nbsp;pi&nbsp;to&nbsp;calculate.<br>&nbsp;&nbsp;&nbsp;*&nbsp;@throws&nbsp;ValidityCheckFailedException&nbsp;if&nbsp;the&nbsp;validity<br>&nbsp;&nbsp;&nbsp;*&nbsp;check&nbsp;fails,&nbsp;this&nbsp;means&nbsp;the&nbsp;implementation&nbsp;is&nbsp;buggy<br>&nbsp;&nbsp;&nbsp;*&nbsp;or&nbsp;n&nbsp;is&nbsp;too&nbsp;large&nbsp;for&nbsp;sufficient&nbsp;precision&nbsp;to&nbsp;be<br>&nbsp;&nbsp;&nbsp;*&nbsp;retained.<br>&nbsp;&nbsp;&nbsp;*/<br>&nbsp;&nbsp;public&nbsp;byte&nbsp;calculateBinaryDigit(final&nbsp;int&nbsp;n)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;runBBPAlgorithm(n);<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;private&nbsp;byte&nbsp;runBBPAlgorithm(final&nbsp;int&nbsp;n)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Lengthy&nbsp;routine&nbsp;goes&nbsp;here&nbsp;...<br>&nbsp;&nbsp;}<br><br>}</code><br>&nbsp;&nbsp;&nbsp;&nbsp;最简单直接的方法来缓存返回值可以通过修改这个类来实现:添加一个Map来保存之前计算得到的值,如下:<br><code>import&nbsp;java.util.HashMap;<br><br>public&nbsp;class&nbsp;PiBinaryDigitsCalculator&nbsp;{<br><br>&nbsp;&nbsp;private&nbsp;HashMap&nbsp;cache&nbsp;=&nbsp;new&nbsp;HashMap();<br><br>&nbsp;&nbsp;public&nbsp;synchronized&nbsp;byte&nbsp;calculateBinaryDigit(<br>&nbsp;&nbsp;final&nbsp;int&nbsp;n)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;Integer&nbsp;N&nbsp;=&nbsp;new&nbsp;Integer(n);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Byte&nbsp;B&nbsp;=&nbsp;(Byte)&nbsp;cache.get(N);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(B&nbsp;==&nbsp;null)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte&nbsp;b&nbsp;=&nbsp;runBBPAlgorithm(n);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cache.put(N,&nbsp;new&nbsp;Byte(b));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;b;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;B.bytevalue();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;private&nbsp;byte&nbsp;runBBPAlgorithm(final&nbsp;int&nbsp;n)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Lengthy&nbsp;routine&nbsp;goes&nbsp;here&nbsp;...<br>&nbsp;&nbsp;}<br>}</code><br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;calculateBinaryDigit方法首先会检查HashMap里面是否缓存了这个关键字-参数n,如果找到了,就直接返回这个值.否则,就会进行这个冗长的计算,并将结果保存到缓存里面.在添加进HashMap的时候,在原始类型和对象之间还要进行小小的转换.<br>&nbsp;&nbsp;&nbsp;&nbsp;尽管这个方法是可行的,但是有几个缺点.首先,进行缓存的代码和正常的算法代码不是显著分开的.一个类,不仅负责进行计算,也要负责进行维护缓存数据.这样,要进行一些测试就会显得很困难.比如,不能写一个测试程序来测试这个算法持续地返回相同的值,因为,从第二次开始,结果都是直接从cache中获得了.<br>&nbsp;&nbsp;&nbsp;&nbsp;其次,当缓存代码不再需要,移除它会变得困难,因为它和算法块地代码是紧密结合在一起的.所以,要想知道缓存是否带来了很高的效率提升也是很困难的,因为不能写一个测试程序是和缓存数据分开的.当你改进了你的算法,缓存有可能失效-但是这个时候你并不知道.<br>&nbsp;&nbsp;&nbsp;&nbsp;第三,缓存代码不能被重用.尽管代码遵从了一个普通的模式,但是都是在一个类-&nbsp;PiBinaryDigitsCalculator里面.<br><br>&nbsp;&nbsp;&nbsp;&nbsp;前面两个问题都可以通过构造一个缓存包装器来解决.<br><br><strong style="COLOR: #993366">缓存包装器</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;通过使用Decorator模式,要分开计算代码和缓存代码是很容易的.首先,定义一个接口,里面定义基本的方法.<br>&nbsp;&nbsp;&nbsp;&nbsp; <code>public&nbsp;interface&nbsp;BinaryDigitsCalculator&nbsp;{<br><br>&nbsp;&nbsp;public&nbsp;byte&nbsp;calculateBinaryDigit(final&nbsp;int&nbsp;n);<br>}</code><br>&nbsp;&nbsp;&nbsp;&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff0000">然后定义两个实现,分别负责两个任务:</span><br><code>public&nbsp;class&nbsp;PiBinaryDigitsCalculator<br>&nbsp;&nbsp;implements&nbsp;BinaryDigitsCalculator&nbsp;{<br><br>&nbsp;&nbsp;public&nbsp;byte&nbsp;calculateBinaryDigit(final&nbsp;int&nbsp;n)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;runBBPAlgorithm(n);<br>&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;private&nbsp;byte&nbsp;runBBPAlgorithm(final&nbsp;int&nbsp;n)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Lengthy&nbsp;routine&nbsp;goes&nbsp;here&nbsp;...<br>&nbsp;&nbsp;}<br><br>}<br><br>import&nbsp;java.util.HashMap;<br><br>public&nbsp;class&nbsp;CachingBinaryDigitsCalculator&nbsp;implements<br>BinaryDigitsCalculator&nbsp;{<br><br>&nbsp;&nbsp;private&nbsp;BinaryDigitsCalculator&nbsp;binaryDigitsCalculator;<br>&nbsp;&nbsp;private&nbsp;HashMap&nbsp;cache&nbsp;=&nbsp;new&nbsp;HashMap();<br><br>&nbsp;&nbsp;public&nbsp;CachingBinaryDigitsCalculator(<br>&nbsp;&nbsp;BinaryDigitsCalculator&nbsp;calculator)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.binaryDigitsCalculator&nbsp;=&nbsp;calculator;<br>&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;public&nbsp;synchronized&nbsp;byte&nbsp;calculateBinaryDigit(int&nbsp;n)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;Integer&nbsp;N&nbsp;=&nbsp;new&nbsp;Integer(n);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Byte&nbsp;B&nbsp;=&nbsp;(Byte)&nbsp;cache.get(N);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(B&nbsp;==&nbsp;null)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte&nbsp;b&nbsp;=<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;binaryDigitsCalculator.calculateBinaryDigit(n);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cache.put(N,&nbsp;new&nbsp;Byte(b));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;b;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;B.bytevalue();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;}<br>}</code><br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;这是很之前的实现PiBinaryDigitsCalculator的一种简单的refactored版本.&nbsp;CachingBinaryDigitsCalculator包装了BinaryDigitsCalculator句柄,并增加了缓存,供calculateBinaryDigit的方法调用.&nbsp;这种方法提高了代码的可读性与可维护性.&nbsp;用户不能直接使用BinaryDigitsCalculator接口来实现算法,所以,如果需要关闭缓存块,将是很容易实现的.<br>&nbsp;&nbsp;&nbsp;&nbsp;还有,合适的测试程序很容易写出来.比如,我们写一个假的BinaryDigitsCalculator实现,每次calculateBinaryDigit被调用,赋予相同的参数,返回不同的值.&nbsp;这样,我们就能测试缓存是否工作了,因为如果每次都返回相同的值,则证明缓存是正常工作了.&nbsp;这种测试在之前那种简单的实现是不可能的.<br><br>这是很之前的实现PiBinaryDigitsCalculator的一种简单的refactored版本.&nbsp;CachingBinaryDigitsCalculator包装了BinaryDigitsCalculator句柄,并增加了缓存,供calculateBinaryDigit的方法调用.&nbsp;这种方法提高了代码的可读性与可维护性.&nbsp;用户不能直接使用BinaryDigitsCalculator接口来实现算法,所以,如果需要关闭缓存块,将是很容易实现的.<br><br>&nbsp;&nbsp;&nbsp;&nbsp;还有,合适的测试程序很容易写出来.比如,我们写一个假的BinaryDigitsCalculator实现,每次calculateBinaryDigit被调用,赋予相同的参数,返回不同的值.&nbsp;这样,我们就能测试缓存是否工作了,因为如果每次都返回相同的值,则证明缓存是正常工作了.&nbsp;这种测试在之前那种简单的实现是不可能的。<br>通过动态代理类来创建一个通用的缓存包装器\r<br><br>&nbsp;&nbsp;&nbsp;&nbsp;上面第二种方法仅有的缺点就是缓存包装器不能重用,每次我们希望添加一个缓存给某个类,我们就要写一个特殊的缓存包装器给目标接口.这是一个很慢,容易出错的过程.<br><br>&nbsp;&nbsp;&nbsp;&nbsp;Jdk1.3开始支持动态代理类:&nbsp;特别的类能够在运行期决定实现哪个接口-通常的模式都是,在运行期即决定实现哪个接口.通过这个,我们有可能实现一个通用的缓存包装器,我们称它为Memoizer,在运行期决定实现哪个接口.这样,&nbsp;CachingBinaryDigitsCalculator就是不再需要的.它是这样被调用的:<br><br>BinaryDigitsCalculator&nbsp;calculator&nbsp;=<br>new&nbsp;CachingBinaryDigitsCalculator(<br>new&nbsp;PiBinaryDigitsCalculator()<br>);&nbsp;&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;可以通过Memoizer来重写如下:<br><br>BinaryDigitsCalculator&nbsp;calculator&nbsp;=<br>(BinaryDigitsCalculator)&nbsp;Memoizer.memoize(<br>new&nbsp;PiBinaryDigitsCalculator()<br>);<br><br>Memoizer的代码如下:<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">package</span><span style="COLOR: #000000">&nbsp;demo.proxy;<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000">&nbsp;java.lang.reflect.InvocationHandler;<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000">&nbsp;java.lang.reflect.InvocationTargetException;<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000">&nbsp;java.lang.reflect.Method;<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000">&nbsp;java.lang.reflect.Proxy;<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000">&nbsp;java.util.Arrays;<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000">&nbsp;java.util.Collections;<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000">&nbsp;java.util.HashMap;<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000">&nbsp;java.util.List;<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000">&nbsp;java.util.Map;<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><br><img id=Codehighlighter1_361_1538_Open_Image onclick="this.style.display='none'; Codehighlighter1_361_1538_Open_Text.style.display='none'; Codehighlighter1_361_1538_Closed_Image.style.display='inline'; Codehighlighter1_361_1538_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_361_1538_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_361_1538_Closed_Text.style.display='none'; Codehighlighter1_361_1538_Open_Image.style.display='inline'; Codehighlighter1_361_1538_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;Memorizer&nbsp;</span><span style="COLOR: #0000ff">implements</span><span style="COLOR: #000000">&nbsp;InvocationHandler&nbsp;</span><span id=Codehighlighter1_361_1538_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"></span><span id=Codehighlighter1_361_1538_Open_Text><span style="COLOR: #000000">{<br><img id=Codehighlighter1_409_543_Open_Image onclick="this.style.display='none'; Codehighlighter1_409_543_Open_Text.style.display='none'; Codehighlighter1_409_543_Closed_Image.style.display='inline'; Codehighlighter1_409_543_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_409_543_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_409_543_Closed_Text.style.display='none'; Codehighlighter1_409_543_Open_Image.style.display='inline'; Codehighlighter1_409_543_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;Object&nbsp;memorize(Object&nbsp;object)&nbsp;</span><span id=Codehighlighter1_409_543_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"></span><span id=Codehighlighter1_409_543_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;Proxy.newProxyInstance(object.getClass().getClassLoader(),<br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;object.getClass().getInterfaces(),&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;Memorizer(object));<br><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">&nbsp;Object&nbsp;object;<br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">&nbsp;Map&nbsp;caches&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;HashMap();<br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top><br><img id=Codehighlighter1_643_670_Open_Image onclick="this.style.display='none'; Codehighlighter1_643_670_Open_Text.style.display='none'; Codehighlighter1_643_670_Closed_Image.style.display='inline'; Codehighlighter1_643_670_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_643_670_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_643_670_Closed_Text.style.display='none'; Codehighlighter1_643_670_Open_Image.style.display='inline'; Codehighlighter1_643_670_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">&nbsp;Memorizer(Object&nbsp;object)&nbsp;</span><span id=Codehighlighter1_643_670_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"></span><span id=Codehighlighter1_643_670_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">.object&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;object;<br><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;Object&nbsp;invoke(Object&nbsp;proxy,&nbsp;Method&nbsp;method,&nbsp;Object[]&nbsp;args)<br><img id=Codehighlighter1_759_1125_Open_Image onclick="this.style.display='none'; Codehighlighter1_759_1125_Open_Text.style.display='none'; Codehighlighter1_759_1125_Closed_Image.style.display='inline'; Codehighlighter1_759_1125_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_759_1125_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_759_1125_Closed_Text.style.display='none'; Codehighlighter1_759_1125_Open_Image.style.display='inline'; Codehighlighter1_759_1125_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throws</span><span style="COLOR: #000000">&nbsp;Throwable&nbsp;</span><span id=Codehighlighter1_759_1125_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"></span><span id=Codehighlighter1_759_1125_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Don't&nbsp;cache&nbsp;void&nbsp;methods</span><span style="COLOR: #008000"><br><img id=Codehighlighter1_839_875_Open_Image onclick="this.style.display='none'; Codehighlighter1_839_875_Open_Text.style.display='none'; Codehighlighter1_839_875_Closed_Image.style.display='inline'; Codehighlighter1_839_875_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_839_875_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_839_875_Closed_Text.style.display='none'; Codehighlighter1_839_875_Open_Image.style.display='inline'; Codehighlighter1_839_875_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(method.getReturnType().equals(Void.TYPE))&nbsp;</span><span id=Codehighlighter1_839_875_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"></span><span id=Codehighlighter1_839_875_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;invoke(method,&nbsp;args);<br><img id=Codehighlighter1_882_1122_Open_Image onclick="this.style.display='none'; Codehighlighter1_882_1122_Open_Text.style.display='none'; Codehighlighter1_882_1122_Closed_Image.style.display='inline'; Codehighlighter1_882_1122_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_882_1122_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_882_1122_Closed_Text.style.display='none'; Codehighlighter1_882_1122_Open_Image.style.display='inline'; Codehighlighter1_882_1122_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;</span><span id=Codehighlighter1_882_1122_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"></span><span id=Codehighlighter1_882_1122_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Map&nbsp;cache&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;getCache(method);<br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&nbsp;key&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;Arrays.asList(args);<br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;value&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;cache.get(key);<br><img id=Codehighlighter1_1035_1101_Open_Image onclick="this.style.display='none'; Codehighlighter1_1035_1101_Open_Text.style.display='none'; Codehighlighter1_1035_1101_Closed_Image.style.display='inline'; Codehighlighter1_1035_1101_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1035_1101_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1035_1101_Closed_Text.style.display='none'; Codehighlighter1_1035_1101_Open_Image.style.display='inline'; Codehighlighter1_1035_1101_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(value&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">null</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">cache.containsKey(key))&nbsp;</span><span id=Codehighlighter1_1035_1101_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"></span><span id=Codehighlighter1_1035_1101_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;invoke(method,&nbsp;args);<br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cache.put(key,&nbsp;value);<br><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;value;<br><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top><br><img id=Codehighlighter1_1198_1327_Open_Image onclick="this.style.display='none'; Codehighlighter1_1198_1327_Open_Text.style.display='none'; Codehighlighter1_1198_1327_Closed_Image.style.display='inline'; Codehighlighter1_1198_1327_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1198_1327_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1198_1327_Closed_Text.style.display='none'; Codehighlighter1_1198_1327_Open_Image.style.display='inline'; Codehighlighter1_1198_1327_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">&nbsp;Object&nbsp;invoke(Method&nbsp;method,&nbsp;Object[]&nbsp;args)&nbsp;</span><span style="COLOR: #0000ff">throws</span><span style="COLOR: #000000">&nbsp;Throwable&nbsp;</span><span id=Codehighlighter1_1198_1327_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"></span><span id=Codehighlighter1_1198_1327_Open_Text><span style="COLOR: #000000">{<br><img id=Codehighlighter1_1206_1249_Open_Image onclick="this.style.display='none'; Codehighlighter1_1206_1249_Open_Text.style.display='none'; Codehighlighter1_1206_1249_Closed_Image.style.display='inline'; Codehighlighter1_1206_1249_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1206_1249_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1206_1249_Closed_Text.style.display='none'; Codehighlighter1_1206_1249_Open_Image.style.display='inline'; Codehighlighter1_1206_1249_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000">&nbsp;</span><span id=Codehighlighter1_1206_1249_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"></span><span id=Codehighlighter1_1206_1249_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;method.invoke(object,&nbsp;args);<br><img id=Codehighlighter1_1287_1324_Open_Image onclick="this.style.display='none'; Codehighlighter1_1287_1324_Open_Text.style.display='none'; Codehighlighter1_1287_1324_Closed_Image.style.display='inline'; Codehighlighter1_1287_1324_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1287_1324_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1287_1324_Closed_Text.style.display='none'; Codehighlighter1_1287_1324_Open_Image.style.display='inline'; Codehighlighter1_1287_1324_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000">&nbsp;(InvocationTargetException&nbsp;e)&nbsp;</span><span id=Codehighlighter1_1287_1324_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"></span><span id=Codehighlighter1_1287_1324_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;e.getTargetException();<br><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top><br><img id=Codehighlighter1_1375_1536_Open_Image onclick="this.style.display='none'; Codehighlighter1_1375_1536_Open_Text.style.display='none'; Codehighlighter1_1375_1536_Closed_Image.style.display='inline'; Codehighlighter1_1375_1536_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1375_1536_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1375_1536_Closed_Text.style.display='none'; Codehighlighter1_1375_1536_Open_Image.style.display='inline'; Codehighlighter1_1375_1536_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">synchronized</span><span style="COLOR: #000000">&nbsp;Map&nbsp;getCache(Method&nbsp;m)&nbsp;</span><span id=Codehighlighter1_1375_1536_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"></span><span id=Codehighlighter1_1375_1536_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Map&nbsp;cache&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;(Map)&nbsp;caches.get(m);<br><img id=Codehighlighter1_1433_1517_Open_Image onclick="this.style.display='none'; Codehighlighter1_1433_1517_Open_Text.style.display='none'; Codehighlighter1_1433_1517_Closed_Image.style.display='inline'; Codehighlighter1_1433_1517_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1433_1517_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1433_1517_Closed_Text.style.display='none'; Codehighlighter1_1433_1517_Open_Image.style.display='inline'; Codehighlighter1_1433_1517_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(cache&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">null</span><span style="COLOR: #000000">)&nbsp;</span><span id=Codehighlighter1_1433_1517_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"></span><span id=Codehighlighter1_1433_1517_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cache&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;Collections.synchronizedMap(</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;HashMap());<br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;caches.put(m,&nbsp;cache);<br><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;cache;<br><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">&nbsp;</span></div>
<p><br><br>当调用静态方法memoize的时候,将会创建一个新的代理实例-也就是一个java.lang.reflect.proxy的实例.实现了一个接口集.这个接口集由object.getClass().getInterfaces()来决定.每个代理实例包含一个java.lang.reflect.InvocationHandler实例来处理这个代理实例调用的相关方法.在我们的例子里,Memoizer就是一个InvocationHandler实例.</p>
<p>&nbsp;&nbsp;&nbsp; 当一个方法在代理实例里被调用,比如, calculateBinaryDigit,那么, Memoizer实例里的invoke方法就会被调用,相关信息会传给invoke方法,以决定proxy实例调用了哪个方法,包含参数信息.在我们的例子里,传入Memoizer的java.lang.Method参数是calculateBinaryDigit,而参数信息则是pi需要精确的位数-整数n.在这个基础上,Memoizer能够进一步进行缓存操作的.</p>
<p>&nbsp;&nbsp;&nbsp; 在例子里(caches是一个Hashmap,cache是一个map)里用到的Key,主要是传入的方法信息:Method对象和参数对象. 为了实现的简单与通用性,Memoizer有一个关于cache的HashMap caches,每个method是一个key,对应的value为一个cache.然后把参数信息转化成一个List对象,作为cache的Key.使用List是很方便的,同时也可以保证equals()方法,所以能够保证当且仅当参数信息完全相同的时候这个List才相等.</p>
<p>&nbsp;&nbsp;&nbsp; 一旦一个cache的Key被创建,那么,计算之前都会先查找这个cache,如果找到,则返回cache里的值.否则,如果带有这些参数的这个方法没有被调用过,那么,则会通过invoke来调用这个method.在我们的例子里, 实例PiBinaryDigitsCalculator 里的calculateBinaryDigit方法将会通过invoke被调用.而且计算结果将会被存在cache里.<br>何时使用Memoizer</p>
<p>&nbsp;&nbsp;&nbsp; 作为一条通用的规则,Memoizer能够在任何需要传统的cache的时候使用-比如上面提到的例子. 特别地,接口里每个需要使用记忆功能的method需要满足下面几条条件:</p>
<p>&nbsp;&nbsp;&nbsp; 1. 这个method的返回值最好不要每次调用都会改变\r</p>
<p>&nbsp;&nbsp;&nbsp; 2. 这个method不要有副效应</p>
<p>&nbsp;&nbsp;&nbsp; 3. 这个method的参数是确定的,非mutable的.</p>
<p>&nbsp;&nbsp;&nbsp; 显然,如果每次调用这个method返回值都不同,那么cache就毫无用处了.同样也是很重要的一点是,因为有副效应的method不会被重复,所以这个method不能有副效应(method自动更新某些状态).当然,void方法除外.</p>
<p>&nbsp;&nbsp;&nbsp; 同样,memorize一个带有未定(mutable)参数的method是很危险的,因为,要把这些参数储存到hashmap里会是很危险的一件事.根据Map的定义,当这个Map里的key发生改变,Map是不知道的.所以,当你执行了一次这个method之后,相关信息添加进了Map,然后参数发生变异(mutate),第二次调用的时候,就会得到错误的结果.</p>
<p>&nbsp;&nbsp;&nbsp; 性能</p>
<p>&nbsp;&nbsp;&nbsp; 使用cache的主要目的就是为了提升你的程序的速度.然而,reflection确是众所周知的低效(在jdk1.4里有所改进,通过reflection调用方法是普通调用速度的1/2,这个比jdk1.3要快40倍).Memoizer主要依靠reflection来调用方法,所以,它看上去并不是一个好的途径.但是,如果使用cache能给程序速度带来的提升远高于reflection对速度的影响,那么,使用Memoizer是值得考虑的.</p>
<p>&nbsp;&nbsp;&nbsp; 在我们对PiBinaryDigitsCalculator的测试中,测试环境为jdk1.4,当n小于10的时候,使不使用cache速度是相当的.但是,当n增大的时候,使用cache的优势就开始显示出来.所以,经常使用PiBinaryDigitsCalculator的用户,可以考虑使用cache.</p>
<p>&nbsp;&nbsp;&nbsp; 不幸的是,唯一测试你的程序是否需要cache的途径是比较你的程序在两种情况下的运行效率.尽管如此,因为为一个程序构造一个cache包装器是很容易的一件事,移除它也是很容易的,下面的建议可以作为一个参考的步骤:</p>
<p>&nbsp;&nbsp;&nbsp; 1. 选择需要记忆操作的类\r</p>
<p>&nbsp;&nbsp;&nbsp; 2. 运行它\r</p>
<p>&nbsp;&nbsp;&nbsp; 3. 如果效率是满意的,go to 6</p>
<p>&nbsp;&nbsp;&nbsp; 4. 添加memoizer,使用cache</p>
<p>&nbsp;&nbsp;&nbsp; 5. 如果效率没有显著提升,移初memoizer</p>
<p>&nbsp;&nbsp;&nbsp; 6. 如果需要,重试.</p>
<p>&nbsp;&nbsp;&nbsp; 理论上,你需要分析为一个类添加记忆功能对整个系统的影响.只有你自己清楚是否值得添加.有些方法,即使是计算量很大的,但是在这个系统里很少被调用,所以,没必要为它添加记忆功能.为了保证这个,我开发了一个更有特点的Memoizer,实现了一个叫做CacheStatistics的接口,你能从它得到cache的数量以及无效的cache.你可以使用它作为判断的一个尺度.</p>
<p>&nbsp;&nbsp;&nbsp; 扩展Memoizer</p>
<p>&nbsp;&nbsp;&nbsp; 修改Memoizer类来支持不同的cache策略是很简单的.一个比较普通的类型就是Least-Recently-Used(LRU)cahce,拥有固定数量的入口.这个cache确保入口不大于它的最大数目,如果超过,就摒弃最旧的缓存数据.也就是,能够从cache里得到的是新的数据.一个类可以使用LRU cache来防止一个程序长期保持一个状态.你可以仅仅传递一个参数给CacheFactory里的memoize方法来选择你需要的cache类型.下面的例子,LRU cache最多有1000个入口:</p>
<p>BinaryDigitsCalculator calculator =<br>(BinaryDigitsCalculator) Memoizer.memoize(<br>new PiBinaryDigitsCalculator(),<br>new LruCacheFactory(1000)<br>); </p>
<p>&nbsp;&nbsp;&nbsp; 即使是这么简单,Memoizer也应该是java程序员一个有用的工具.</p>
<img src ="http://www.blogjava.net/dyerac/aggbug/132037.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dyerac/" target="_blank">dyerac in java...</a> 2007-07-24 14:03 <a href="http://www.blogjava.net/dyerac/archive/2007/07/24/132037.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>XML,RPC,RMI,SOAP,WSDL,RESR,Web Services Relations</title><link>http://www.blogjava.net/dyerac/archive/2007/07/24/132004.html</link><dc:creator>dyerac in java...</dc:creator><author>dyerac in java...</author><pubDate>Tue, 24 Jul 2007 03:10:00 GMT</pubDate><guid>http://www.blogjava.net/dyerac/archive/2007/07/24/132004.html</guid><wfw:comment>http://www.blogjava.net/dyerac/comments/132004.html</wfw:comment><comments>http://www.blogjava.net/dyerac/archive/2007/07/24/132004.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dyerac/comments/commentRss/132004.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dyerac/services/trackbacks/132004.html</trackback:ping><description><![CDATA[&nbsp;
<p>RMI<span>&nbsp;&nbsp; </span>is<span>&nbsp;&nbsp; </span>object<span>&nbsp;&nbsp; </span>based<span>&nbsp;&nbsp; </span>protocal<span>&nbsp;&nbsp; </span>which<span>&nbsp;&nbsp; </span>you<span>&nbsp;&nbsp; </span>can<span>&nbsp;&nbsp; </span>serialize<span>&nbsp;&nbsp; </span>your<span>&nbsp;&nbsp; </span>object<span>&nbsp;&nbsp; </span>and<span>&nbsp;&nbsp; </span>make<span>&nbsp;&nbsp; </span>a<span>&nbsp;&nbsp; </span>remote<span>&nbsp;&nbsp; </span>call<span>&nbsp;&nbsp; </span>on<span>&nbsp;&nbsp; </span>object<span>&nbsp;&nbsp; </span>thru<span>&nbsp;&nbsp; </span>it.</p>
<p>XMLRPC<span>&nbsp;&nbsp; </span>is<span>&nbsp;&nbsp; </span>message<span>&nbsp;&nbsp; </span>(XML)<span>&nbsp;&nbsp; </span>based<span>&nbsp;&nbsp; </span>and<span>&nbsp;&nbsp; </span>you<span>&nbsp;&nbsp; </span>can<span>&nbsp;&nbsp; </span>not<span>&nbsp;&nbsp; </span>use<span>&nbsp;&nbsp; </span>object<span>&nbsp;&nbsp; </span>at<span>&nbsp;&nbsp; </span>all.<span>&nbsp;&nbsp; </span>The<span>&nbsp;&nbsp; </span>advantage<span>&nbsp;&nbsp; </span>is<span>&nbsp;&nbsp; </span>security<span>&nbsp;&nbsp; </span>and<span>&nbsp;&nbsp; </span>reliability.<span>&nbsp;&nbsp; </span>With<span>&nbsp;&nbsp; </span>XML<span>&nbsp;&nbsp; </span>you<span>&nbsp;&nbsp; </span>can<span>&nbsp;&nbsp; </span>encrypt<span>&nbsp;&nbsp; </span>and<span>&nbsp;&nbsp; </span>validate<span>&nbsp;&nbsp; </span>any<span>&nbsp;&nbsp; </span>way<span>&nbsp;&nbsp; </span>you<span>&nbsp;&nbsp; </span>like.<span>&nbsp;&nbsp; </span>SOAP<span>&nbsp;&nbsp; </span>is<span>&nbsp;&nbsp; </span>XMLRPC<span>&nbsp;&nbsp; </span>on<span>&nbsp;&nbsp; </span>HTTP<span>&nbsp;&nbsp; </span>by<span>&nbsp;&nbsp; </span>XML<span>&nbsp;&nbsp; </span>message</p>
<img src ="http://www.blogjava.net/dyerac/aggbug/132004.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dyerac/" target="_blank">dyerac in java...</a> 2007-07-24 11:10 <a href="http://www.blogjava.net/dyerac/archive/2007/07/24/132004.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>定义自己的热键</title><link>http://www.blogjava.net/dyerac/archive/2007/07/24/132002.html</link><dc:creator>dyerac in java...</dc:creator><author>dyerac in java...</author><pubDate>Tue, 24 Jul 2007 03:06:00 GMT</pubDate><guid>http://www.blogjava.net/dyerac/archive/2007/07/24/132002.html</guid><wfw:comment>http://www.blogjava.net/dyerac/comments/132002.html</wfw:comment><comments>http://www.blogjava.net/dyerac/archive/2007/07/24/132002.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/dyerac/comments/commentRss/132002.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dyerac/services/trackbacks/132002.html</trackback:ping><description><![CDATA[<p>* 一个使用KeyStroke自定义快捷键的示例<br>&nbsp;*&nbsp;<br>*/<br>public class MnemonicT extends JFrame {<br>&nbsp;private int count = 0;</p>
<p>&nbsp;private JButton button;</p>
<p>&nbsp;public MnemonicT() {<br>&nbsp;&nbsp;super("Mnemonic Test");<br>&nbsp;&nbsp;JPanel panel = new JPanel();<br>&nbsp;&nbsp;panel.setPreferredSize(new Dimension(320, 240));<br>&nbsp;&nbsp;panel.setLayout(new FlowLayout());</p>
<p>&nbsp;&nbsp;button = new JButton(new AbstractAction("ClickTimes:" + count) {<br>&nbsp;&nbsp;&nbsp;public void actionPerformed(ActionEvent e) {<br>&nbsp;&nbsp;&nbsp;&nbsp;button.setText("ClickTimes:" + (++count));<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;});<br>&nbsp;&nbsp;panel.add(button);<br>&nbsp;&nbsp;add(panel);</p>
<p>&nbsp;&nbsp;InputMap im = button.getInputMap(JButton.WHEN_IN_FOCUSED_WINDOW);<br>&nbsp;&nbsp;im.put(KeyStroke.getKeyStroke("control A"), "buttonAction"); // 按CTRL+A<br>&nbsp;&nbsp;button.getActionMap().put("buttonAction", button.getAction());<br>&nbsp;&nbsp;pack();<br>&nbsp;&nbsp;setDefaultCloseOperation(EXIT_ON_CLOSE);<br>&nbsp;}</p>
<p>&nbsp;public static void main(String[] args) {<br>&nbsp;&nbsp;SwingUtilities.invokeLater(new Runnable() {<br>&nbsp;&nbsp;&nbsp;public void run() {<br>&nbsp;&nbsp;&nbsp;&nbsp;new MnemonicT().setVisible(true);<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;});<br>&nbsp;}<br>}</p>
<img src ="http://www.blogjava.net/dyerac/aggbug/132002.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dyerac/" target="_blank">dyerac in java...</a> 2007-07-24 11:06 <a href="http://www.blogjava.net/dyerac/archive/2007/07/24/132002.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>（zt）annotation relations</title><link>http://www.blogjava.net/dyerac/archive/2007/07/22/131760.html</link><dc:creator>dyerac in java...</dc:creator><author>dyerac in java...</author><pubDate>Sun, 22 Jul 2007 14:42:00 GMT</pubDate><guid>http://www.blogjava.net/dyerac/archive/2007/07/22/131760.html</guid><wfw:comment>http://www.blogjava.net/dyerac/comments/131760.html</wfw:comment><comments>http://www.blogjava.net/dyerac/archive/2007/07/22/131760.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/dyerac/comments/commentRss/131760.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dyerac/services/trackbacks/131760.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 基础学习教程：Java Annotation入门摘要：　本文针对java初学者或者annotation初次使用者全面地说明了annotation的使用方法、定义方式、分类。初学者可以通过以上的说明制作简单的annotation程序，但是对于一些高级的annotation应用（例如使用自定义annotation生成javabean映射xml文件）还需要进一步的研究和探讨。涉及到深入a...&nbsp;&nbsp;<a href='http://www.blogjava.net/dyerac/archive/2007/07/22/131760.html'>阅读全文</a><img src ="http://www.blogjava.net/dyerac/aggbug/131760.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dyerac/" target="_blank">dyerac in java...</a> 2007-07-22 22:42 <a href="http://www.blogjava.net/dyerac/archive/2007/07/22/131760.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>学习计划</title><link>http://www.blogjava.net/dyerac/archive/2007/07/19/131329.html</link><dc:creator>dyerac in java...</dc:creator><author>dyerac in java...</author><pubDate>Thu, 19 Jul 2007 09:57:00 GMT</pubDate><guid>http://www.blogjava.net/dyerac/archive/2007/07/19/131329.html</guid><wfw:comment>http://www.blogjava.net/dyerac/comments/131329.html</wfw:comment><comments>http://www.blogjava.net/dyerac/archive/2007/07/19/131329.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/dyerac/comments/commentRss/131329.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dyerac/services/trackbacks/131329.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 考了个GRE，发现自己已经深深落伍了，5555<br>&nbsp;&nbsp;&nbsp; 现在开始学习啦，列个小小的计划吧：<br>&nbsp;&nbsp;&nbsp; 论文阅读计划：REST， Blueprint 4 mashup， J2EE Clustering<br>&nbsp;&nbsp;&nbsp; 框架学习计划：Apache CXF， Dom4J， DB4O，AspectJ<br>&nbsp;&nbsp;&nbsp; 基础学习计划：XML<br>&nbsp;&nbsp;&nbsp; 语言学习计划：Javascript，Python<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp; 重点学习计划：Ajax，REST，Web Services<br><br><br>顺便总结下这几天看的几个名词：<br><br>REST：<br>Atom：<br>Feed：<br>SOAP：<br>WSDL：<br>JSON：<br>Mashup：
<img src ="http://www.blogjava.net/dyerac/aggbug/131329.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dyerac/" target="_blank">dyerac in java...</a> 2007-07-19 17:57 <a href="http://www.blogjava.net/dyerac/archive/2007/07/19/131329.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Editplus配置</title><link>http://www.blogjava.net/dyerac/archive/2007/07/17/130884.html</link><dc:creator>dyerac in java...</dc:creator><author>dyerac in java...</author><pubDate>Tue, 17 Jul 2007 08:48:00 GMT</pubDate><guid>http://www.blogjava.net/dyerac/archive/2007/07/17/130884.html</guid><wfw:comment>http://www.blogjava.net/dyerac/comments/130884.html</wfw:comment><comments>http://www.blogjava.net/dyerac/archive/2007/07/17/130884.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/dyerac/comments/commentRss/130884.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/dyerac/services/trackbacks/130884.html</trackback:ping><description><![CDATA[其实没什么好说的，只是为了以后方便而已<br>1. 以sql为例，需要sql.stx(语法)&nbsp; sql.acp（auto completement）放到editplus目录下即可<br>2. 另外修改settings.ini等几个ini文件（主要是针对acp文件）<br>3. 并启动editplus用tool工具导入stx文件 并设置高亮染色方案（alert！我只发现了导入 没找到手工修改的方&nbsp; <br>&nbsp;&nbsp;&nbsp; 法）<br>4. 创建template.sql文件 并修改template.ini 注意 也要修改ini中显示的模板数目（而非仅仅添加）<br>5. that's all
<img src ="http://www.blogjava.net/dyerac/aggbug/130884.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/dyerac/" target="_blank">dyerac in java...</a> 2007-07-17 16:48 <a href="http://www.blogjava.net/dyerac/archive/2007/07/17/130884.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>