??xml version="1.0" encoding="utf-8" standalone="yes"?>欧美中文在线观看,有码一区二区三区,在线中文字幕视频http://www.aygfsteel.com/lingy/category/39869.htmlzh-cnFri, 30 Jul 2010 03:58:42 GMTFri, 30 Jul 2010 03:58:42 GMT60《设计模式》之Java解读--桥接Bridge http://www.aygfsteel.com/lingy/archive/2010/07/29/327422.html林光?/dc:creator>林光?/author>Thu, 29 Jul 2010 05:56:00 GMThttp://www.aygfsteel.com/lingy/archive/2010/07/29/327422.html阅读全文

]]>
Java Class Loaderhttp://www.aygfsteel.com/lingy/archive/2009/08/30/293221.html林光?/dc:creator>林光?/author>Sun, 30 Aug 2009 12:54:00 GMThttp://www.aygfsteel.com/lingy/archive/2009/08/30/293221.htmlE序~制一般需l编辑、编译、连接、加载和q行几个步骤。在我们的应用中Q有一些公׃码是需要反复用,把q些代码~译?#8220;?#8221;文gQ在q接步骤中,q接器将从库文g取得所需的代码,复制到生成的可执行文件中。这U库UCؓ静态库Q其特点是可执行文g中包含了库代码的一份完整拷贝;~点是被多ơ用就会有多䆾冗余拯?/p>

Z克服q个~点可以采用动态连接库。这个时候连接器仅仅是在可执行文件中打上标志Q说明需要用哪些动态连接库Q当q行E序Ӟ加蝲器根据这些标志把所需的动态连接库加蝲到内存?/p>

另外在当前的~程环境中,一般都提供Ҏ让程序在q行的时候把某个特定的动态连接库加蝲q运行,也可以将其卸载(例如Win32的LoadLibrary()&FreeLibrary()和Posix的dlopen()&dlclose()Q。这个功能被q泛地用于在E序q行时刻更新某些功能模块或者是E序外观?/p>

What is ClassLoader?

与普通程序不同的是,JavaE序Qclass文gQƈ不是本地的可执行E序。当q行JavaE序Ӟ首先q行JVMQJava虚拟机)Q然后再把Java class加蝲到JVM里头q行Q负责加载Java class的这部分叫做Class Loader?/p>

JVM本n包含了一个ClassLoaderUCؓBootstrap ClassLoaderQ和JVM一PBootstrap ClassLoader是用本地代码实现的,它负责加载核心Java ClassQ即所有java.*开头的c)。另外JVMq会提供两个ClassLoaderQ它们都是用Java语言~写的,由Bootstrap ClassLoader加蝲Q其中Extension ClassLoader负责加蝲扩展的Java classQ例如所有javax.*开头的cd存放在JRE的ext目录下的c)QApplication ClassLoader负责加蝲应用E序自n的类?/p>

When to load the class?

什么时候JVM会用ClassLoader加蝲一个类呢?当你使用javaL行一个类QJVM使用Application ClassLoader加蝲q个c;然后如果cA引用了类BQ不是直接引用q是用Class.forName()引用QJVM׃扑ֈ加蝲cA的ClassLoaderQƈ用这个ClassLoader来加载类B?/p>

Why use your own ClassLoader?

gJVM自n的ClassLoader已经_了,Z么我们还需要创qClassLoader呢?

因ؓJVM自带的ClassLoader只是懂得从本地文件系l加载标准的java class文gQ如果编写你自己的ClassLoaderQ你可以做到Q?br /> 1Q在执行非置信代码之前,自动验证数字{֐
2Q动态地创徏W合用户特定需要的定制化构建类
3Q从特定的场所取得java classQ例如数据库?br /> 4) {等

事实上当使用Applet的时候,qC特定的ClassLoaderQ因旉要从|络上加载java classQƈ且要查相关的安全信息?/p>

目前的应用服务器大都使用了ClassLoader技术,即你不需要创qClassLoaderQ了解其原理也有助于更好地部|自q应用?nbsp;

ClassLoader Tree & Delegation Model

当你军_创徏你自qClassLoaderӞ需要承java.lang.ClassLoader或者它的子cR在实例化每个ClassLoader对象Ӟ需要指定一个父对象Q如果没有指定的话,pȝ自动指定ClassLoader.getSystemClassLoader()为父对象。如下图Q?/p>

在Java 1.2后,java class的加载采用所谓的委托模式QDelegation ModleQ,当调用一个ClassLoader.loadClass()加蝲一个类的时候,遵循以下的步骤Q?br /> 1Q检查这个类是否已经被加载进来了Q?br /> 2Q如果还没有加蝲Q调用父对象加蝲该类
3Q如果父对象无法加蝲Q调用本对象的findClass()取得q个cR?/p>

所以当创徏自己的Class LoaderӞ只需要重载findClass()q个Ҏ?/p>

Unloading? Reloading?

当一个java class被加载到JVM之后Q它有没有可能被卸蝲呢?我们知道Win32有FreeLibrary()函数QPosix有dlclose()函数可以被调用来卸蝲指定的动态连接库Q但是Javaq没有提供一个UnloadClass()的方法来卸蝲指定的类?/p>

在Java中,java class的卸载仅仅是一U对pȝ的优化,有助于减应用对内存的占用。既然是一U优化方法,那么完全是JVM自行军_如何实现Q对Java开发h员来说是完全透明的?/p>

在什么时候一个java class/interface会被卸蝲呢?Sun公司?a class or interface may be unloaded if and only if its class loader is unreachable. Classes loaded by the bootstrap loader may not be unloaded."

事实上我们关心的不是如何卸蝲cȝQ我们关心的是如何更新已l被加蝲了的cM而更新应用的功能。JSP则是一个非常典型的例子Q如果一个JSP文g被更改了Q应用服务器则需要把更改后的JSP重新~译Q然后加载新生成的类来响应后l的h?/p>

其实一个已l加载的cL无法被更新的Q如果你试图用同一个ClassLoader再次加蝲同一个类Q就会得到异常(java.lang.LinkageError: duplicate class definitionQ,我们只能够重新创Z个新的ClassLoader实例来再ơ加载新cR至于原来已l加载的c,开发h员不必去它Q因为它可能q有实例正在被用,只要相关的实例都被内存回收了Q那么JVM׃在适当的时候把不会再用的cd载?/p>

]]>
TOMCAT源码ȝ一http://www.aygfsteel.com/lingy/archive/2009/08/30/293216.html林光?/dc:creator>林光?/author>Sun, 30 Aug 2009 12:05:00 GMThttp://www.aygfsteel.com/lingy/archive/2009/08/30/293216.html首先不得不说q个corg.apache.tomcat.util.net.JIoEndpointQ它负责所有的TCPhq接Q实C一个服务器模式Q启用一个后台监听线E,负责接收到来的socketQ然后从U程池中取出响应的workerQ扔lworkerq行处理Q自ql监听。其ơworker是一个负责处理socket的一个线E,是它带着用户的请求开始进入Tomcat世界的,默认的workerd?00个,卻I最?00个线E。当处理完一个请求的时候,q个U程q不会销毁,而是q入waitdQ这个线E的对象也不会销毁,是进入了一个栈里面Q对应workstack那个数据l构。每当接收线E拿C个socket的时候,先从栈里面拿出一个已有的U程对象Q然后就利用该对象的assignҎQ将q个socketl它Qƈ调用notify重新唤醒q个worker的处理线E。以后我们做型服务器的时候,可以借鉴它的实现方式。正在研I多U程的朋友,q个cȝ对让你可以学的透彻Q?/p>

相对应的q有一个org.apache.tomcat.util.net.NioEndpointQ这个和前面那个功能差不多,但是用了NIO包里的APIQ有一个最大的区别是Q接收线E接收一个socket之后Q可能会这个socket先放入缓存池Q然后worker从池里面拿socketd理,比前面那个类看v来功能和性能都会提升很多Q不q代码行?K多,相当复杂Q设计不够精巧,有兴可以去研究下?/p>

org.apache.tomcat.util.buf.MessageBytesQ这是一个接q底层的字符串处理类Qؓ什么说是接q底层,是因为socket接收q来的都是字节类型,而java用的是char或者StringQ这之间的{换涉及到~码问题和性能问题Q所以凡是socket收进来的信息Q全部都用这个类表示Q只有当要输出字W串的时候,才会里面的字节q行转换Q实CUgq加载的懒模式,被Tomcat底层所使用的Requestc,是大量使用了这个类来存放数据。我们来小H视一下,Requestc:

  1. private MessageBytes methodMB = MessageBytes.newInstance();
  2.     private MessageBytes unparsedURIMB = MessageBytes.newInstance();
  3.     private MessageBytes uriMB = MessageBytes.newInstance();
  4.     private MessageBytes decodedUriMB = MessageBytes.newInstance();
  5.     private MessageBytes queryMB = MessageBytes.newInstance();
  6.     private MessageBytes protoMB = MessageBytes.newInstance();
  7.  
  8.     // remote address/host
  9.     private MessageBytes remoteAddrMB = MessageBytes.newInstance();
  10.     private MessageBytes localNameMB = MessageBytes.newInstance();
  11.     private MessageBytes remoteHostMB = MessageBytes.newInstance();
  12.     private MessageBytes localAddrMB = MessageBytes.newInstance();
  13.     
  14.     private MimeHeaders headers = new MimeHeaders();

或许大家会觉得,构造出q么多的c,性能会高到哪里去Q其实不是这LQ不停的构造和销毁对象的会损耗相当的性能Q但是一个对象被构造出来,可以重复利用Q那q当完了Q这个类是如此的设计,其中有一个回收资源的ҎQ叫recycle()Q这个方法可以清I里面的数组Q清I里面的对象Q而不会销毁自己本w,因ؓ使用它的对象Q只要调用recycleQ以后又可以重复使用了?/p>

MessageBytes其实内置?个重要的c,org.apache.tomcat.util.buf.ByteChunk和org.apache.tomcat.util.buf.CharChunkQ这2个类带我们回CC时代Qؓ什么这么说Q因为它直就是一个字W串处理c,一些眼熟的法全部映入眼帘Q比如字W{匚w法QindexOfQstartsWithQ判断字W{是否相等Q查扑֭W,{等Q比之JDK提供的性能更好Q功能更强大Q这句话说过了,呵呵Q?/p>

q有一个实用的值得学习的数据结构是Qorg.apache.tomcat.util.buf.AsciiQ如果知道表驱动的朋友们Q一定对q个cd熟悉了,判断大小写?判断是不是英文单词?判断是不是空白符Q判断是不是数字Q将字节cd转换为int、longcdQ大写转换Q等{。这些都是大学计机评的课后练习题



]]>
如何处理HTTP POST/GEThhttp://www.aygfsteel.com/lingy/archive/2009/08/29/293078.html林光?/dc:creator>林光?/author>Sat, 29 Aug 2009 03:56:00 GMThttp://www.aygfsteel.com/lingy/archive/2009/08/29/293078.html     [全屏查看全文]
Servlet通过下面的方法来提供服务Q?
  • 实现serviceҎ?br />
  • 实现HttpServlet的doMethodҎQdoGet、doDelete、doOptions?doPost、doPut、doTraceQ?/li>
    通常QserviceҎ用来从客戯求(requestQ中提取信息Q访问扩展资源,q基于上面的信息提供响应QresponseQ?

    对于HTTP ServletsQ正提供响应的q程是首先填写响应(responseQ的头信息,然后从响应(responseQ中得到输出,最后向输出中写入内容信息。响应(responseQ头信息必须最先设|。下面将描述如何从请求(requestQ中获得信息和生HTTP响应QresponseQ?

    
  • 取得客户端请?
        一个HttpServletRequest对象提供到达HTTP 头部数据Q也允许你获取客L的数据。怎样获取q些数据取决于HTTP端请求方法。不用MHTTP方式Q你都可以用 getParameterValuesҎq回特定名称的参数倹{对于用 HTTP GET h的方式,q个getQueryStringҎ会q回一个可以用来分析的倹{?

        客户端请求(requestQ包含了从客L传递到Servlet的数据。所有的hQrequestQ都实现了ServletRequest接口。这个接口定义了一些方法访问下面的信息Q如?4-1所C?

    ?4-1  ServletRequest接口Ҏ
                c???q?                         ????
                参数Q用来在客户端和Servlet之间传送信?getAttribute(String name)
                getAttributeNames()
                getInputStream()
                getParameter(String name)
                getParameterMap()
                getParameterNames()
                getParameterValues(String name)
                对象值属性,用来在Servlet容器和Servlet
                之间Q或者协作的Servlet之间传递信?    removeAttribute(String name)
                setAttribute(String name, Object o)
                有关h使用的协议信息,
                客户端和服务器在h中的调用	   getContentLength()
                getContentType()
                getProtocol()
                getReader()
                getRealPath(String path)
                getRemoteAddr()
                getRemoteHost()
                getRequestDispatcher(String path)
                有关h使用的协议信息,
                客户端和服务器在h中的调用       getScheme()
                getServerName()
                getServerPort()
                isSecure()
                有关localization的信?       getCharacterEncoding()
                getLocale()
                getLocales()
                setCharacterEncoding(String env)


        下面的代码段C了如何用request中的Ҏ获得客户端信息?

    Enumeration params = request.getParameterNames();
                String paramName = null;
                String[] paramValues = null;
                while (params.hasMoreElements()) {
                paramName = (String) params.nextElement();
                paramValues = request.getParameterValues(paramName);
                System.out.println("\nParameter name is " + paramName);
                for (int i = 0; i < paramValues.length; i++) {
                System.out.println(", value " + i + " is " + paramValues[i].toString());
                }
                }


        HTTP Servlets使用HTTP request对象QHttpServletRequestQ,它包含了request URL、HTTP头信息、查询字W串Q等{。HTTP request URL 包括几个部分Q?br />     http://: ?

        一般情况下Q?

    requestURI = contextPath + servletPath + pathInfo
                Context pathQ通过getContextPathҎ获得?
                Servlet PathQ通过getServletPathҎ获得?
                PathInfoQ通过getPathInfoҎ获得?/ccid_code>


        如表14-2所C?

    ?4-2  路径的对?
                Request Path	            Path Elements
                /catalog/help/feedback.jsp	ContextPath: /catalog ServletPath:
                /help/feedback.jsp PathInfo: null


        
  • 提供HTTP响应
        响应QresponseQ包含了在服务器和客L之间传递的数据。所有的响应QresponseQ都实现了ServletResponse接口。这个接口定义了一些方法提供给开发h员用,如表14-3所C?

    ?4-3  ServletResponse接口Ҏ
                c???q?                          ????
                获得向客L发送数据的输出? 发送字W流QgetWriter()
                发送字节流QgetOutputStream()
                指示响应q回的内容类型(例如Qtext/htmlQ?
                已经注册的内容类型名UC存在IANA
                QInternet Assigned Numbers AuthorityQ?setContentType(java.lang.String type)
                指出是否是缓冲输出。默认情况下写入输出?
                内容被立卛_送到客户端。用缓冲后写入输出的内容先
                不发送到客户端,q样Servlet有更多的旉讄相应?
                状态码和头信息Q或者{Ud其他的Web资源	 flushBuffer()
                getBufferSize()
                isCommitted()
                reset()
                resetBuffer()
                setBufferSize(int size)
                setContentLength(int len)
                讄localization信息	            getCharacterEncoding()
                getLocale()
                setLocale(java.util.Locale loc)


        HTTP responsec(HttpServletResponseQ有一些代表HTTP头信息的域:
        
  • 状态码用来指出响应QresponseQ失败的原因?


        
  • Cookies在客L存储应用相关的信息,有时cookies用来l护和标识用Lsession?

        Servlet首先讄响应QresponseQ头信息Q包括响应(responseQ的内容cd和缓冲区大小Q然后在doGetҎ中从响应QresponseQ获得PrintWriter Q最后向输出中写入HTML代码Q调用close()Ҏ提交q次对客L的响应(responseQ。示范代码如下:

    public void doGet (HttpServletRequest request,
                HttpServletResponse response)
                throws ServletException, IOException
                {
                // 讄头信?
                response.setContentType("text/html");
                response.setBufferSize(8192);
                PrintWriter out = response.getWriter();
                // 向response中输?
                out.println("<html>" +
                "<head><title>+
                messages.getString("TitleBookDescription")
                +</title></head>");
                ...
                out.println("</body></html>");
                // 关闭输出?
                out.close();
                }


  • ]]>
    TOMCAT源码分析(消息处理)http://www.aygfsteel.com/lingy/archive/2009/08/26/292716.html林光?/dc:creator>林光?/author>Wed, 26 Aug 2009 12:53:00 GMThttp://www.aygfsteel.com/lingy/archive/2009/08/26/292716.html我们知道了tomcat的整体框架了Q?也明白了里面都有些什么组Ӟ 以及各个lg是干什么用的了?/span>

    http://www.csdn.net/Develop/read_article.asp?id=27225

    我想Q接下来我们应该M解一?tomcat 是如何处理jsp和servleth的?/span>

    1.  我们以一个具体的例子Q来跟踪TOMCATQ?/span>看看它是如何?/span>Request一层一层地递交l下一个容器,q最后交l?/span>Wrapper来处理的?/span>

    ?/span>http://localhost:8080/web/login.jspZ?/span>

    Q以下例子,都是?/span>tomcat4 源码为参考)

    q篇心得主要分ؓ3个部分: 前期Q?中期Q?和末期?/span>

     前期Q讲解了在浏览器里面输入一个URLQ是怎么被tomcat抓住的?/span>

    中期Q讲解了被tomcat抓住后,又是怎么在各个容器里面穿梭, 最后到达最后的处理地点?/span>

    末期Q讲解到达最后的处理地点后,又是怎么具体处理的?/span>

    2?/span> 前期 Request的born.

        在这里我先简单讲一下requestq个东西?/span>

         我们先看着q个URLQ?/span>http://localhost:8080/web/login.jsp 它是动用?080端口来进行socket通讯的?/span>

         我们知道, 通过

           InputStream in = socket.getInputStream() ?/span>

           OutputStream out = socket.getOutputStream()

         可以实现消息的来来往往了?/span>

         但是如果把Streaml应用层看,昄操作h不方ѝ?

         所以,在tomcat 的Connector里面Q?socket被封装成了Request和Responseq两个对象?/span>

         我们可以单地把Request看成发到服务器来的数据Q把Response看成惛_出服务器的数据?/span>

         

         但是q样又有其他问题了啊Q?Requestq个对象是把socket装h了, 但是他提供的又东西太多了?/span>

         诸如Request.getAuthorization(), Request.getSocket()?nbsp;像Authorizationq种东西开发h员拿来基本上用不太着Q而像socketq种东西Q暴露给开发h员又有潜在的危险?而且啊, 在Servlet Specification里面标准的通信cLServletRequest和HttpServletRequestQ而非q个RequestcR?So, So, So. Tomcat必须得捣持捣持Request才行?最后tomcat选择了用捣持模式(应该叫适配器模式)来解册个问题。它把org.apache.catalina.Request 捣持成了 org.apache.coyote.tomcat4.CoyoteRequest?而CoyoteRequest又实CServletRequest和HttpServletRequest q两U接口?q样提供给开发h员需要且刚刚需要的Ҏ了?/span>

     

        ok, ?/span>我们?tomcat的顶层容?- StandardEngin 的invoke()Ҏq里讄一个断点, 然后讉K

        http://localhost:8080/web/login.jspQ?我们来看看在前期都会路过哪些地方Q?/span>

           1. run(): 536, java.lang.Thread, Thread.java

           CurrentThread

          2. run():666, org.apache.tomcat.util.threads.ThreadPool$ControlRunnable, ThreadPool.java

                   ThreadPool

           3. runIt():589, org.apache.tomcat.util.net.TcpWorkerThread, PoolTcpEndpoint.java

             ThreadWorker

    4.        processConnection():  549

    org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler, Http11Protocol.java

                      http protocol parser

          5. Process(): 781, org.apache.coyote.http11.Http11Processor, Http11Processor.java

              http request processor

           6. service(): 193, org.apache.coyote.tomcat4.CoyoteAdapter,CoyoteAdapter.java

             adapter

           7. invoke(): 995, org.apache.catalina.core.ContainerBase, ContainerBase.java

       StandardEngin

        1. ȝE?/span>

        2. 启动U程?

        3. 调出U程池里面空闲的工作U程?/span>

        4. ?080端口传过来由httpd协议装的数据,解析成Request和Response对象?/span>

        5. 使用Http11Processor来处理request

        6. ?/span>Http11Processor里面Q?又会call CoyoteAdapter来进行适配处理Q把Request适配成实CServletRequest和HttpServletRequest接口?/span>CoyoteRequest.

    7. Cq里Q前期的L拔皮工作基本上搞定Q可以交l?/span>StandardEngin 做核心的处理工作了?/span>

    3. 中期?在各个容器间的穿梭?/span>

        Request在各个容器里面的I梭大致是这样一U方式:

        每个容器里面都有一个管道(piplineQ, 专门用来传送Request用的?/span>

        道里面又有好几个阀门(valveQ, 专门用来qoRequest用的?/span>

        在管道的低部通常都会放上一个默认的阀们?q个阀们至会做一件事情,是把Request交给子容器?/span>

        让我们来惌一下:

         当一个Requestq入一个容器后Q?它就在管道里面流动,波罗~ 波罗~ 波罗~ 地穿q各个阀门。在到最后一个阀门的时候,吧唧~ 那个该死的阀门就把它扔给了子容器?然后又开?波罗~ 波罗~ 波罗~ ... 吧唧~.... 波罗~ 波罗~ 波罗~ ....吧唧~....

        是通过q种方式Q?Request 走完了所有的容器。( 感觉有点像消化系l,最后一个地Ҏ点像那里~ Q?/span>

        OKQ?让我们具体看看都有些什么容器, 各个容器里面又都有些什么阀门,q些阀们都Ҏ们的Request做了些什么吧Q?/span>

    3.1 StandardEngin 的pipeline里面攄是:StandardEnginValve

    在这里,VALVE做了三g事:

    1.   验证传递过来的request是不?/span>httpservletRequest.

    2    验证传递过来的 request 是否携带?/span>host header信息.

    3    选择相应?/span>hostd理它。(一般我们都只有一个host:localhostQ也是127.0.0.1Q?/span>

    Cq个地方Q?/span>我们?/span>request已l完成了?/span>Enginq个部分的历史命,通向前途未卜的下一站: host了?/span>

    3.2 StandardHost 的pipline里面攄是: StandardHostValve

    1.   验证传递过来的request是不?/span>httpservletRequest.

    2.   ҎRequest来确定哪?/span>Context来处理?/span>

    Context其实是webappQ?/span>比如http://localhost:8080/web/login.jsp

    q里webContext|!

    3.   既然定了是哪个Context了,那么应该把那个Context?/span>classloader付给当前U程了?/span>

            Thread.currentThread().setContextClassLoader(context.getLoader().getClassLoader());

       q样request只看得见指定的context下面?/span>classes啊, jar啊这些,而看不见tomcat本n的类Q?/span>什?/span>Engin啊, Valve啊?/span>不然q得了啊Q?/span>

    4. 既然requestCq里了,看来用户是准备访问webq个web app了,咋们得更C下这个用Lsession不是Q?Ok , qmanager更新一下用Lsession信息

    5. 交给具体的Context 容器ȝl处理Request.

    6. Context处理完毕了,?/span>classloaderq回来?/span>

    3.3 StandardContext 的pipline里面攄是: StandardContextValve

    1.   验证传递过来的request是不?/span>httpservletRequest.

    2.   如果request意图不轨Q想要访?/span>/meta-inf, /web-infq些目录下的东西Q呵呵,没有用D!

    3.   q个时候就会根?/span>Request到底?/span>ServletQ?/span>q是jspQ?/span>q是静态资源来军_到底用哪U?/span>Wrapper来处理这?/span>Reqeust了?/span>

    4.   一旦决定了到底用哪U?/span>WrapperQ?/span>OKQ交l那?/span>Wrapper处理?/span>

    4. 末期?不同的需求是怎么处理?

    StandardWrapper

    之前对Wrapper没有做过讲解Q其实它是这样一U东ѝ?/span>

    我们在处理Request的时候,可以分成3U?/span>

    处理静态的Q?org.apache.catalina.servlets.DefaultServlet  

    处理jsp的:org.apache.jasper.servlet.JspServlet

    处理servlet的:org.apache.catalina.servlets.InvokerServlet

    不同的requestqq?U不同的servletd理?/span>

    Wrapper是对它们的一U简单的装Q有了Wrapper后,我们可以轻村֜拦截每次的Request。也可以Ҏ地调用servlet的init()和destroy()ҎQ?便于理嘛!

    具体情况是这么滴Q?/span>

       如果request是找jsp文gQStandardWrapper里面׃装一个org.apache.jasper.servlet.JspServletd理它?/span>

       如果request是找 静态资?QStandardWrapper里面׃装一个org.apache.jasper.servlet.DefaultServlet d理它?/span>

       如果request是找servlet QStandardWrapper里面׃装一个org.apache.jasper.servlet.InvokerServlet d理它?/span>

    StandardWrapper同样也是容器Q既然是容器Q?那么里面一定留了一个管道给requestȝQ管道低部肯定也有一个阀??)Q用来做最后一道拦截工?

    在这最底部的阀门里Q其实就主要做了两g?

       一是启动过滤器Q让request在N个过滤器里面{一通,如果OKQ?那就PASS?否则p到其他地方去了?/span>

       二是servlet.service((HttpServletRequest) request,(HttpServletResponse) response); q个Ҏ.

         如果?JspServletQ?那么先把jsp文g~译成servlet_xxx, 再invoke servlet_xxx的servie()Ҏ?/span>

         如果?DefaultServletQ?q接找到静态资源,取出内容Q?发送出厅R?/span>

         如果?InvokerServletQ?p用那个具体的servlet的service()Ҏ?/span>

       ok! 完毕?/span>

    ?: StandardWrapper 里面的阀门是最后一道关口了?如果q个阀门欲意把request交给StandardWrapper 的子容器处理?对不P 在设计考虑的时候, Wrapperp考虑成最末的一个容器, 压根儿就不会lWrapperd子容器的ZQ?如果是要调用addChild(), 立马抛出IllegalArgumentExceptionQ?/span>

    参考:

         <http://jakarta.apache.org/tomcat/>
       <
    http://www.onjava.com/pub/a/onjava/2003/05/14/java_webserver.html>

     


    相关文章


    ]]>
    TOMCAT源码分析(启动框架http://www.aygfsteel.com/lingy/archive/2009/08/26/292715.html林光?/dc:creator>林光?/author>Wed, 26 Aug 2009 12:49:00 GMThttp://www.aygfsteel.com/lingy/archive/2009/08/26/292715.html
    TOMCAT源码分析(启动框架)     选择?ThomasHuang ?Blog
    关键?/font>   tomcat 源代?源码 source code architecture
    出处  

    TOMCAT源码分析(启动框架)
    前言Q?br />    本文是我阅读了TOMCAT源码后的一些心得?主要是讲解TOMCAT的系l框Ӟ 以及启动程。若有错漏之处,敬请批评指教Q?br /> Q?br />    毕竟TOMCAT的框架还是比较复杂的Q?单是从文字上理解Q?是不那么Ҏ掌握TOMCAT的框架的?所以得实践、实c再实践?下蝲一份TOMCAT的源码, 调试通过Q?然后单步跟踪其启动过E?如果有不明白的地方, 再来查阅本文Q?看是否能得到帮助?我相信这h果以及学习速度都会好很多!
      
    1. Tomcat的整体框架结?br />    Tomcat的基本框Ӟ 分ؓ4个层ơ?br />    Top Level Elements:
        Server
        Service  
       Connector
        HTTP
        AJP
       Container
       Engine
         Host
       Context
       Component 
        manager
       logger
       loader
       pipeline
       valve
             ...
       站在框架的顶层的是Server和Service
       Server:  其实是BackGroudE序Q?在Tomcat里面的Server的用处是启动和监听服务端事gQ诸如重启、关闭等命o?在tomcat的标准配|文Ӟserver.xml里面Q?我们可以看到“<Server port="8005" shutdown="SHUTDOWN" debug="0">”q里?SHUTDOWN"是server在监听服务端事g的时候所使用的命令字Q?br />    ServiceQ?在tomcat里面Q?service是指一c问题的解决Ҏ?nbsp; 通常我们会默认用tomcat提供的:Tomcat-Standalone 模式的service?在这U方式下的service既给我们提供解析jsp和servlet的服务, 同时也提供给我们解析静态文本的服务?br />   
       Connector: Tomcat都是在容器里面处理问题的Q?而容器又到哪里去取得输入信息呢?
    Connector是专干q个的?他会把从socket传递过来的数据Q?装成Request, 传递给容器来处理?br />    通常我们会用CUConnector,一U叫http connectoerQ?用来传递http需求的?另一U叫AJPQ?在我们整合apache与tomcat工作的时候, apache与tomcat之间是通过q个协议来互动的?Q说到apache与tomcat的整合工作, 通常我们的目的是Z让apache 获取静态资源, 而让tomcat来解析动态的jsp或者servlet。)
       Container: 当http connector把需求传递给的container: Engin的时候, 我们的视U就应该Ud到Containerq个层面来了?br />    在Containerq个层, 我们包含?U容器: Engin, Host, Context.
       Engin: 收到service传递过来的需求, 处理后, 结果返回给service( service 是通过 connector q个媒介来和Engin互动?).
       Host: Engin收到service传递过来的需求后Q不会自己处理, 而是交给合适的Host来处理?br /> Host在这里就是虚拟主机的意思, 通常我们都只会用一个主机,?#8220;localhost”本地机来处理?
       Context: Host接到了从Host传过来的需求后Q?也不会自己处理, 而是交给合适的Context来处理?
       比如Q?<http://127.0.0.1:8080/foo/index.jsp>
             <http://127.0.1:8080/bar/index.jsp>
       前者交lfooq个Context来处理, 后者交lbarq个Context来处理?br />    很明昑֐Q?context的意思其实就是一个web app的意思?br />    我们通常都会在server.xml里面做这L配置
       <Context path="/foo" docBase="D:/project/foo/web" />
       q个context容器Q就是用来干我们该干的事儿的地方的?br />   
       Compenent: 接下来, 我们l箋讲讲component是干什么用的?br />    我们得先理解一下容器和lg的关pR?br />    需求被传递到了容器里面, 在合适的时候, 会传递给下一个容器处理?br />    而容器里面又盛装着各种各样的组Ӟ 我们可以理解为提供各U各L增值服务?br />    manager: 当一个容器里面装了managerlg后,q个容器支持session理了, 事实上在tomcat里面的session理Q?是靠的在context里面装的manager component.
       logger: 当一个容器里面装了loggerlg后, q个容器里所发生的事情, p该组件记录下来啦Q?我们通常会在logs/ q个目录下看?catalina_log.time.txt 以及 localhost.time.txt 和localhost_examples_log.time.txt?q就是因为我们分别ؓQengin, host以及context(examples)q三个容器安装了loggerlgQ?q也是默认安装, 又叫做标?Q)
       loader: loaderq个lg通常只会l我们的context容器使用Q?loader是用来启动context以及理q个context的classloader用的?br />     pipline: pipeline是这样一个东西, 当一个容器决定了要把从上U传递过来的需求交l子容器的时候, 他就把这个需求放q容器的道(pipeline)里面厅R?而需求傻呼呼得在道里面动的时候, ׃被管道里面的各个阀门拦截下来?比如道里面放了两个阀门?W一个阀门叫?#8220;access_allow_vavle”Q?也就是说需求流q来的时候,它会看这个需求是哪个IPq来的, 如果q个IP已经在黑名单里面了, sure, 杀Q?W二个阀门叫?#8220;defaul_access_valve”它会做例行的查, 如果通过的话QOKQ?把需求传递给当前容器的子容器?是通过q种方式Q?需求就在各个容器里面传递,动Q?最后抵辄的地的了?br />     valve: 是上面所说的阀门啦?br />    Tomcat里面大概是q么些东西, 我们可以单地q么理解tomcat的框Ӟ它是一U自上而下Q?容器里又包含子容器的q样一U结构?br /> 2. Tomcat的启动流E?br />    q篇文章是讲tomcat怎么启动的,既然我们大体上了解了TOMCAT的框架结构了Q?那么我们可以望文生意地就猜到tomcat的启动, 会先启动父容器,然后逐个启动里面的子容器?启动每一个容器的时候, 都会启动安插在他w上的组件?当所有的lg启动完毕Q?所有的容器启动完毕的时候, tomcat本n也就启动完毕了?br />    理成章圎ͼ 我们同样可以猜到Q?tomcat的启动会分成两大部分Q?W一步是装配工作?W二步是启动工作?
       装配工作是为父容器装上子容器, 为各个容器安插进lg的工作?q个地方我们会用到digester模式Q?至于digester模式什么, 有什么用Q?怎么工作? 请参?<http://software.ccidnet.com/pub/article/c322_a31671_p2.html>
       启动工作是在装配工作之后Q?一旦装配成功了Q?我们只需要点燃最上面的一根导U, 整个tomcat׃被激zv来?q就好比我们要开一辆已l装配好了的汽R的时候一P我们只要把钥匙插q钥匙孔Q一拧,汽R的引擎就会发动v来,I׃开hQ?安全装置׃生效Q?如此一来,汽R整个发动v来了。(q个q程实和TOMCAT的启动过E不谋而和Q?让我们不得不怀?TOMCAT的设计者是在GE做JAVA开发的Q?br /> 2.1 一些有意思的名称Q?br />    Catalina
       Tomcat
       Bootstrap
       Engin
       Host
       Context
       他们的意思很有意思:
       Catalina: q程轰炸?br />    Tomcat: 熊猫轰炸?-- 轰炸机的一U(q让我想起了让国人引以ؓ豪的熊猫手机Q是不是英文可以叫做tomcat??? Q?又让我想起了另一则广告: 波导-手机中的战斗机、L?客机中的战斗?Q?br />    Bootstap: 引导
       Engin: 发动?br />    Host: LQ领?br />    Context: 内容Q?目标Q?上下?br />   
       ... 在许多许多年后, C人类已经灭绝?后现代生物发Cq些单词零落零落在一块?一个自以ؓ聪明的家伙把q些东西译出来了:
       在地勤h员的引导(bootstrap)下, 一架蘪炸架(catalina)腄跃vQ?q看是熊猫蘪炸机(tomcat)Q?q看q是熊猫轰炸机! 凭借着优秀的发动机技?engin)Q?q架熊猫轰炸机飞临了敌国的领土上I?host)Q?对准目标(context)投下了毁天灭地的核弹_波~ C生物p么隔屁了~
     
       lg所qͼ q又不得不让惛_GE是不是也参与了军事设备的生呢?
       反对帝国主义! 反对霸权主义! 和^万岁Q?自由万岁Q?br />   
    2.2  历史是那么惊h的相| tomcat的启动就是从org.apache.catalina.startup.Bootstrapq个cL然启动的Q?br />    在Bootstrap里做了两件事Q?br />    1. 指定?U类型classloader:
          commonLoader: common/classes、common/lib、common/endorsed
          catalinaLoader: server/classes、server/lib、commonLoader
          sharedLoaderQ?nbsp; shared/classes、shared/lib、commonLoader
       2. 引导Catalina的启动?br />       用Reflection技术调用org.apache.catalina.startup.Catalina的processҎQ?q传递参数过厅R?br />   
    2.3 Catalina.java
       Catalina完成了几个重要的dQ?br />    1. 使用Digester技术装配tomcat各个容器与组件?br />       1.1 装配工作的主要内Ҏ安装各个大g?比如server下有什么样的servcie?Host会容U_个context?Context都会使用到哪些组件等{?
          1.2 同时呢, 在装配工作这一步, q完成了mbeans的配|工作?在这里,我简单地但不十分_地描qC下mbean是什么,q什么用的?br />           我们自己生成的对象, 自己理Q?天经CQ?但是如果我们创徏了对象了Q?惌别h来管Q?怎么办呢Q?我想臛_得告诉别人我们都有什么, 以及通过什么方法可以找?nbsp; 吧! JMX技术给我们提供了一U手Dc?JMX里面主要?U东ѝMbean, agent, connector.
           MbeanQ?用来映射我们的对象。也许mbean是我们创徏的对象, 也许不是Q?但有了它Q?可以引用到我们的对象了?br />        Agent:  通过它, 可以找到mbean了?br />        Connector: q接Agent的方式?可以是http的, 也可以是rmi的,q可以直接通过socket?br />       发生在tomcat 装配q程中的事情:  GlobalResourcesLifecycleListener cȝ初始化会被触发:
             protected static Registry registry = MBeanUtils.createRegistry();  会运?br />          MBeanUtils.createRegistry()  会依?org/apache/catalina/mbeans/mbeans-descriptors.xmlq个配置文g创徏 mbeans. Ok, 外界有了条途径讉Ktomcat中的各个lg了。(有点像后门儿Q?br />    2. 为top level 的server 做初始化工作?实际上就是做通常会配|给service的两条connector.(http, ajp)
       3. 从serverq个容器开始启动, 点燃整个tomcat.
       4. 为server做一个hookE序Q?当server shutdown的时候, 关闭tomcat的各个容器用?br />    5. 监听8005端口Q?如果发?SHUTDOWN"Q默认培植下字符Ԍq来Q?关闭8005serverSocket?br /> 2.4 启动各个容器
       1. Server
          触发Server容器启动?before_start)Q?启动?start)Q?启动?after_start)3个事Ӟ q运行相应的事g处理器?br />       启动Server的子容器QServcie.
       2. Service
          启动Service的子容器QEngin
          启动Connector
       3. Engin
          CEnginq个层次Q以及以下别的容器Q?Tomcat׃用了比较一致的启动方式了?br />       首先Q?nbsp; q行各个容器自己Ҏ一些Q?br />       随后Q?nbsp; 触发启动前事?br />       立即Q?nbsp; 讄标签Q就表示该容器已l启?br />       接着Q?nbsp; 启动容器中的各个lgQ?loader, logger, manager{等
          再接着Q启动mappinglg。(?Q?br />       紧跟着Q启动子容器?br />       接下来,启动该容器的道(pipline)
          然后Q?nbsp; 触发启动中事?br />       最后,  触发启动后事件?br />  
          Engin大致会这么做Q?Host大致也会q么做, Context大致q是会这么做?那么很显然地Q?我们需要在q里使用C码复用的技术?tomcat在处理这个问题的时候, 漂亮C用了抽象cL处理?ContainerBase. 最后得这部分完成复杂功能的代码显得干净利落Q?q练爽快Q?实在是o得叹止, l细品来Q?直觉如n佳珍Q?另h齉K留香Q?留恋往q啊Q?br />      
          Engin的触发启动前事g里, 会激zȝ定在Engin上的唯一一个ListenerQEnginConfig?br />       q个EnginConfigcd本上没有做什么事情, 是把EnginConfig的调试别设|ؓ和Engin相当?另外是输出几行文本Q?表示Engin已经配置完毕Q?q没有做什么实质性的工作?br />       ?: mappinglg的用处是Q?当一个需求将要从父容器传递到子容器的时候, 而父容器又有多个子容器的话, 那么应该选择哪个子容器来处理需求呢Q?q个由mapping lg来定夺?br />    
       4. Host
           同Engin一P 也是调用ContainerBase里面的start()ҎQ?不过之前做了些自个儿的Q?是往Hostq个容器的通道QpiplineQ里面, 安装了一个叫?br />  “org.apache.catalina.valves.ErrorReportValve”的阀门?br />        q个阀门的用处是这LQ?nbsp; 需求在被Engin传递给Host后, 会l传递给Context做具体的处理?q里需求其实就是作为参C递的Request, Response?所以在context把需求处理完后, 通常会改动response?而这个org.apache.catalina.valves.ErrorReportValve的作用就是检察response是否包含错误Q?如果有就做相应的处理?br />    5. Context
           Cq里Q?q于轮Ctomcat启动中真正的重头戏,启动Context了?br />  StandardContext.start() q个启动Context容器的方法被StandardHost调用.
     5.1 webappResources 该context所指向的具体目?br />  5.2 安装defaultContex, DefaultContext 是默认Context?如果我们在一个Host下面安装了DefaultContextQ而且defaultContext里面又安装了一个数据库q接池资源的话?那么其他所有的在该Host下的Context, 都可以直接用这个数据库q接池, 而不用格外做配置了?br />   5.3 指定Loader. 通常用默认的org.apache.catalina.loader.WebappLoaderq个cR?nbsp;  Loader是用来指定q个context会用到哪些类啊, 哪些jar包啊q些什么的?br />  5.4 指定 Manager. 通常使用默认的org.apache.catalina.session. StandardManager ?Manager是用来管理session的?br />      其实session的管理也很好实现?以一U简单的session理Z?当需求传递过来的时候, 在Request对象里面有一个sessionId 属性?OKQ?得到q个sessionId后, 我们可以把它作为map的keyQ而value我们可以攄一个HashMap. HashMap里边儿, 再放我们x的东ѝ?br />  5.5 postWorkDirectory (). Tomcat下面有一个work目录?我们把时文仉扔在那儿厅R?q个步骤是在那里创Z个目录?一般说来会?CATALINA_HOME%/work/Standalone\localhost\ q个地方生成一个目录?br /> 5.6  Binding thread。到了这里, 应该发?class Loader 互换了?之前是看得见tomcat下面所有的class和lib. 接下来需要看得见当前context下的class?所以要讄contextClassLoader, 同时q要把旧的ClassLoader记录下来Q因Z后还要用的?br /> 5.7  启动 Loader. 指定q个Context具体要用哪些classesQ?用到哪些jar文g?如果reloadable讄成了true, ׃启动一个线E来监视classes的变化, 如果有变化就重新启动Context?br /> 5.8  启动logger
    5.9  触发安装在它w上的一个监听器?br />  lifecycle.fireLifecycleEvent(START_EVENT, null);
     作ؓ监听器之一QContextConfig会被启动. ContextConfig是用来配置web.xml的?比如q个Context有多ServletQ?又有多少FilterQ?是在这里给Context装上ȝ?br />  5.9.1 defaultConfig. 每个context都得配置 tomcat/conf/web.xml q个文g?br />  5.9.2 applicationConfig 配置自己?WEB-INF/web.xml 文g
    5.9.3 validateSecurityRoles 权限验证?通常我们在访?admin 或?manager的时候,需要用戯么是admin的要么是manager的, 才能讉K?而且我们q可以限刉些资源可以访问, 而哪些不能?都是在这里实现的?br /> 5.9.4 tldScan: 扫描一下, 需要用到哪些标{?tag lab)
    5.10 启动 manager
    5.11 postWelcomeFiles() 我们通常会用到的3个启动文件的名称Q?br /> index.html、index.htm、index.jsp p默认地绑在了q个context?br />  5.12 listenerStart 配置listener
     5.13 filterStart 配置 filter
     5.14 启动带有<load-on-startup>1</load-on-startup>的Servlet.
      序是从到大: 1,2,3… 最后是0
      默认情况下, 臛_会启动如?个的Servlet:
      org.apache.catalina.servlets.DefaultServlet  
          处理静态资源的Servlet. 什么图片啊Q?html啊, css啊, js啊都找他
      org.apache.catalina.servlets.InvokerServlet
          处理没有做Servlet Mapping的那些Servlet.
      org.apache.jasper.servlet.JspServlet
          处理JSP文g?
           5.15  标识context已经启动完毕?br />  C多少个步骤啊Q?Contextȝ是启动完毕喽?br />     OK! 走到了这里, 每个容器以及lg都启动完毕?Tomcatl于不辞辛劳Cؓ人民服务了!
    3. 参考文献:
        <http://jakarta.apache.org/tomcat/>
        <http://www.onjava.com/pub/a/onjava/2003/05/14/java_webserver.html>
       
    4. 后记
        q篇文章是讲解tomcat启动框架的,q有文章是讲解TOMCAT里面的消息处理流E的l节的?文章内容已经写好了, 现在正在整理阶段?怿很快可以做出来Q?大家共同研究共同q步?br />     q篇文章是独自分析TOMCAT源码所写的Q?所以一定有地方是带有个Z观色彩, 隑օ会有片面之处。若有不当之处敬h评指教,q样不仅可以使刚开始研ITOMCAT的兄弟们走弯\Q?我也可以学到东西?br />     email: sojan_java@yahoo.com.cn

    5. tomcat源码分析(消息处理)



    ]]>
    用Digester化XML文档处理http://www.aygfsteel.com/lingy/archive/2009/08/26/292713.html林光?/dc:creator>林光?/author>Wed, 26 Aug 2009 12:27:00 GMThttp://www.aygfsteel.com/lingy/archive/2009/08/26/292713.html 

    Digester框架属于Jakarta CommonsQ它以规则和模式为基处理XML文档。与SAX和DOM之类的标准API相比QDigester不涉及太多的l节问题Q非帔R合于对XML文档q行单的处理?

    在Java和XML开发中Q一个常见的d是把XML文档转换成对应的Java Bean对象的层ơ结构。h们经常用标准的SAX和DOM API来完成这个Q务。虽然这两种API都很强大和灵z,但对于某些简单的d来说Q它们显得操作层ơ太低,也就是说Q涉及了太多的细节问题。Jakarta Digester框架能够很好地满cd合的需要?

    Digester框架?

    Jakarta的Digester框架从Struts框架发展而来Q原先被用来处理struts-config.xml配置文gQ但很快Z认识到它有着更广泛的用途,把它转入了Jakarta Commons目。Jakarta Commons的目标是提供一?#8220;可重用Javalg的仓?#8221;。Digester最新的版本?.3Q于2002q??3日发布?

    Digester框架允许开发者指定一l动作,当解析器在XML文档中发现某些特定的单模式时动作被执行。Digester框架带有10个预定义的规则(RuleQ,늛了unmarshalling XMLQ例如创建Bean或设|Bean属性)的大多数需求( marshalling的原意是?#8220;配制整齐Q编l列?#8221;Qmarshalling是在内存中ؓJava对象生成XML描述文档的过E,而unmarshalling是指把XML形式的描q{换到可用Java代码操作的对象的q程Q我们称之ؓ“反配?#8221;Q,但必要时用户可以定义和实现自q规则?

    在本文的例子中,我们反配制下面q个XML文档Q?

    <?xml version="1.0"?>
                <catalog library="somewhere">
                <book>
                <author>Author 1</author>
                <title>Title 1</title>
                </book>
                <book>
                <author>Author 2</author>
                <title>His One Book</title>
                </book>
                <magazine>
                <name>Mag Title 1</name>
                <article page="5">
                <headline>Some Headline</headline>
                </article>
                <article page="9">
                <headline>Another Headline</headline>
                </article>
                </magazine>
                <book>
                <author>Author 2</author>
                <title>His Other Book</title>
                </book>
                <magazine>
                <name>Mag Title 2</name>
                <article page="17">
                <headline>Second Headline</headline>
                </article>
                </magazine>
                </catalog>

    下面是Bean的代码。注意用Digester框架ӞBeancdd义成public?

    import java.util.Vector;
                public class Catalog {
                private Vector books;
                private Vector magazines;
                public Catalog() {
                books = new Vector();
                magazines = new Vector();
                }
                public void addBook( Book rhs ) {
                books.addElement( rhs );
                }
                public void addMagazine( Magazine rhs ) {
                magazines.addElement( rhs );
                }
                public String toString() {
                String newline = System.getProperty( "line.separator" );
                StringBuffer buf = new StringBuffer();
                buf.append( "--- Books ---" ).append( newline );
                for( int i=0; i<books.size(); i++ ){
                buf.append( books.elementAt(i) ).append( newline );
                }
                buf.append( "--- Magazines ---" ).append( newline );
                for( int i=0; i<magazines.size(); i++ ){
                buf.append( magazines.elementAt(i) ).append( newline );
                }
                return buf.toString();
                }
                }
                //===================================================
                public class Book {
                private String author;
                private String title;
                public Book() {}
                public void setAuthor( String rhs ) { author = rhs; }
                public void setTitle(  String rhs ) { title  = rhs; }
                public String toString() {
                return "Book: Author='" + author + "' Title='" + title + "'";
                }
                }
                //===================================================
                import java.util.Vector;
                public class Magazine {
                private String name;
                private Vector articles;
                public Magazine() {
                articles = new Vector();
                }
                public void setName( String rhs ) { name = rhs; }
                public void addArticle( Article a ) {
                articles.addElement( a );
                }
                public String toString() {
                StringBuffer buf = new StringBuffer( "Magazine: Name='" + name + "' ");
                for( int i=0; i<articles.size(); i++ ){
                buf.append( articles.elementAt(i).toString() );
                }
                return buf.toString();
                }
                }
                //===================================================
                public class Article {
                private String headline;
                private String page;
                public Article() {}
                public void setHeadline( String rhs ) { headline = rhs; }
                public void setPage(     String rhs ) { page     = rhs; }
                public String toString() {
                return "Article: Headline='" + headline + "' on page='" + page + "' ";
                }
                }

    1 2 下一?gt;>

    Digester框架以模式(PatternQ和规则QRuleQؓ基础处理输入的XML。模式必MXML元素匚wQ包括其名字和在文档树内的位|。描q匹配模式的语法cM于XPath匚w模式Q例如:catalog模式匚w层?ccid_code><catalog>元素Qcatalog/book模式匚w直接嵌套?lt;catalog>元素内的<book>元素Q但不匹配文档内其他位置?lt;book>元素Q?/ccid_code>?

    所有的模式都必L定其完整名称——从根元素开始的完整路径。唯一的例外是包含通配W(“*”Q的模式Q例?/name模式匚wXML文档内Q何位|的<name>元素。但是根元素不必特别指出Q因为所有的路径都是从根元素开始的l对路径?

    当Digester发现一个指定的模式Q它执行关联的d。由此可见,Digester框架昄与SAX解析器有着密切的关p(实际上,DigestercdCorg.xml.sax.ContentHandlerQƈl护着解析栈)。所有在Digester中用的规则必须扩展org.apache.commons.digester.RuleQ后者本w提供了一些类gSAX的ContentHandler回调函数的方法。例如,当遇到匹配元素的开始标记和l束标记Ӟbegin()Ҏ和end()Ҏ分别被调用?

    一旦遇到匹配元素的内容Qbody()Ҏ被调用;最后被调用的方法是finish()Q这个方法在匚w元素的结束标记处理完毕之后被调用Q用来执行可能需要的事后清理d。然而,大多数时候我们不必关注这些方法,因ؓ框架提供的标准规则很可能已经提供了所有必需的功能?

    要反配制一个文档,首先创徏一个org.apache.commons.digester.Digestercȝ实例Q如果必要的话,q行一些配|操作,指定必需的模式和规则Q最后向parse()Ҏ传递一个XML文g的引用。下面的DigesterDriverC了这一处理q程Q必d命o行上指定输入XML文档的名Uͼ?

    import org.apache.commons.digester.*;
                import java.io.*;
                import java.util.*;
                public class DigesterDriver {
                public static void main( String[] args ) {
                try {
                Digester digester = new Digester();
                digester.setValidating( false );
                digester.addObjectCreate( "catalog", Catalog.class );
                digester.addObjectCreate( "catalog/book", Book.class );
                digester.addBeanPropertySetter( "catalog/book/author", "author" );
                digester.addBeanPropertySetter( "catalog/book/title", "title" );
                digester.addSetNext( "catalog/book", "addBook" );
                digester.addObjectCreate( "catalog/magazine", Magazine.class );
                digester.addBeanPropertySetter( "catalog/magazine/name", "name" );
                digester.addObjectCreate( "catalog/magazine/article", Article.class );
                digester.addSetProperties( "catalog/magazine/article", "page", "page" );
                digester.addBeanPropertySetter( "catalog/magazine/article/headline" );
                digester.addSetNext( "catalog/magazine/article", "addArticle" );
                digester.addSetNext( "catalog/magazine", "addMagazine" );
                File input = new File( args[0] );
                Catalog c = (Catalog)digester.parse( input );
                System.out.println( c.toString() );
                } catch( Exception exc ) {
                exc.printStackTrace();
                }
                }
                }

    在上面的代码中,我们首先创徏了Digestercȝ一个实例digesterQ然后指定它不要用DTD验证XML文档的合法性——这是因为我们没有ؓXML文档定义DTD。接下来Q我们指定了模式和关联的规则QObjectCreateRule创徏指定cȝ一个实例,q将它压入解析栈。SetPropertiesRule把Bean属性设|成当前XML元素的属性值——规则的W一个参数是XML属性的名称Q第二个参数是Bean属性的名称?

    SetPropertiesRule获取的是XML属性的|而BeanPropertySetterRule获取的是位于当前元素内的原始字符数据倹{用BeanPropertySetterRule时不必指定要讄的Bean属性名字,默认是当前XML元素的名U。在上面的例子中Q在匚wcatalog/magazine/article/headline模式的规则定义中使用的就是默认倹{最后,SetNextRule弹出解析栈顶部的对象Qƈ把该对象传递给它下面对象的指定名称的方法——通常用来把一个配|完毕的Bean插入父对象?

    注意Q我们可以ؓ同一个模式注册多个规则。如果注册了多个规则Q则q些规则按照它们被加入到Digester的次序执行,例如Q如果要处理catalog/magazine/article?article>元素Q我们首先创建合适的article BeanQ然后设|page属性,最后弹出完成后的article BeanQƈ把它插入magazine?

    调用LҎ

    我们不仅可以讄Bean的属性,而且q可以调用堆栈内对象的Q意方法。这通过CallMethodRule完成Q我们只需指定Ҏ名字Q如有必要,再说明调用的参数cd和数量。CallParamRule用来定义传递给被调用函数的参数|参数值可以从当前XML元素的命名的属性获取,也可以从当前元素包含的原始字W数据获取。例如,在前面实现DigesterDriver的例子中Q我们可以不用BeanPropertySetterRuleQ而是通过昑ּ调用属性的setҎ辑ֈ同样的目的:

    digester.addCallMethod( "catalog/book/author", "setAuthor", 1 );
                digester.addCallParam( "catalog/book/author", 0 );

    上面的第一行代码给Z要调用的ҎQ即setAuthor()Q,以及该调用需要的参数数量Q即1Q。第二行代码的意思是?author>元素包含的字W数据获取函数参数的|把它作ؓ参数数组的第一个传入(即烦引是0的数l元素)。如果我们指定了XML元素属性的名称Q例如digester.addCallParam( "catalog/book/author", 0, "author" );Q,则参数值将从当前元素的相应属性D取?

    q里必须注意的是Q?#8220;digester.addCallMethod( "pattern", "methodName", 0 );”q个语句不是指定了一个不带参数的Ҏ调用Q而是指定了带有一个参数的Ҏ调用Q它的值就是当前XML元素的字W数据!q样Q我们又有了另一U替代BeanPropertySetterRule的办法:

    digester.addCallMethod( "catalog/book/author", "setAuthor", 0 );

    如果要调用一个确实没有参数的ҎQ必采用如下Ş式:digester.addCallMethod( "pattern", "methodName" );?

    标准规则概要

    下面要说明所有标准规则?

    创徏

    ObjectCreateRuleQ利用指定类的默认构造函敎ͼ创徏该类的一个对象,q把对象压入栈。当元素处理l束Ӟ对象被弹出。被实例化的cd通过class对象或类的全U给出?

    FactoryCreateRuleQ利用指定的工厂cdZ个对象,把对象压入栈。对于没有提供默认构造函数的c,q一规则很有用。用于该规则的工厂类必须实现org.apache.commons.digester.ObjectCreationFactory接口?

    讄属?

    SetPropertiesRuleQ利用指定名U的XML元素属性|讄层Bean的一个或者多个指定名U的属性。XML元素的属性名U和Bean的属性名UCString[]数组形式传入该规则(通常用来处理

    之类的结构)?

    BeanPropertySetterRuleQ把层Bean的指定名U的属性设|成当前XML元素包含的字W数据。(通常用来处理<page>10</page>之类的结构)?

    SetPropertyRuleQ设|顶层Bean的一个属性。无论是Bean属性的名称Q还是赋予该属性的|都在当前XML元素中以属性的形式指定Q例如:<article key="page" value="10" />?

    理?子关p?

    SetNextRuleQ弹出栈的对象Q把它传递给紧接其下的另一个对象的指定名称的方法。通常用来把一个已l初始化的Bean插入到父对象?

    SetTopRuleQ把栈里面上数第二的对象传递给层的对象。当子对象提供了一个setParenetҎӞq一规则很有用?

    SetRootRuleQ调用栈底对象的一个方法,q把栈顶的对象作为参C入?

    调用LҎ

    CallMethodRuleQ调用顶层Bean的指定名U的Ҏ。被调用的方法可以有L多个参数Q参数的值通过后的CallParamRulel出?

    CallParamRuleQ表C方法调用的参数。参数的值或者取自指定名U的XML元素的属性,或者是当前元素包含的原始字W数据。这个规则要求用一个整数指定它在参数列表中的位|?

    通过XML指定规则

    在前面的内容中,我们用程序代码的方式指定模式和规则,q些模式和规则都是在~译的时候就已经定Q虽然从概念上来讲比较简单,但却不能说尽善尽:Digester框架的M目标是在q行时识别和处理各种数据l构Q但如果我们用编E的Ҏ指定模式和规则,则所有行为在~译时已l固定!如果Java源程序中包含了大量固定的字符Ԍ通常意味着E序在执行某些配|操作,q部分操作可以被Q或许是应该被)延迟到运行时q行?

    org.apache.commons.digester.xmlrules包解决了q个问题。这个包提供了一个DigesterLoaderc,它能够从XML文档d模式/规则对,q回配置好的Digester对象。用来配|Digester对象的XML文档必须遵从digester-rules.dtdQ这个DTD是xmlrules包的一部分?

    下面是本文例子的配|文件rules.xml。有几点必须说明?

    首先Q模式可以用两种方式指定Q或者?ccid_code><pattern>元素Q或者通过代表规则的XML元素的属性。这两种办法可以混合使用Q且<pattern>元素是可以嵌套的。其ơ,<alias>元素?lt;set-properties-rule>一起用,用来把XML属性映到Bean属性。最后,当前发行的Digester软g包而言Q我们不能在配置文g中指定BeanPropertySetterRuleQ正如前面所介绍的,我们用CallMethodRule来达到同L目标?

    <?xml version="1.0"?>
                <digester-rules>
                <object-create-rule pattern="catalog" classname="Catalog" />
                <set-properties-rule pattern="catalog" >
                <alias attr-name="library" prop-name="library" />
                </set-properties-rule>
                <pattern value="catalog/book">
                <object-create-rule classname="Book" />
                <call-method-rule pattern="author" methodname="setAuthor"
                paramcount="0" />
                <call-method-rule pattern="title" methodname="setTitle"
                paramcount="0" />
                <set-next-rule methodname="addBook" />
                </pattern>
                <pattern value="catalog/magazine">
                <object-create-rule classname="Magazine" />
                <call-method-rule pattern="name" methodname="setName" paramcount="0" />
                <pattern value="article">
                <object-create-rule classname="Article" />
                <set-properties-rule>
                <alias attr-name="page" prop-name="page" />
                </set-properties-rule>
                <call-method-rule pattern="headline" methodname="setHeadline"
                paramcount="0" />
                <set-next-rule methodname="addArticle" />
                </pattern>
                <set-next-rule methodname="addMagazine" />
                </pattern>
                </digester-rules>

    现在Q所有实际的操作都{Ud了Digester和DigesterLoaderc,XmlRulesDrivercd变得相当单。运行下面的XmlRulesDriverӞ在第一个命令行参数中指定目录文档的名字Q在W二个参C指定rules.xmlQ注意,DigesterLoader不是从File或者org.xml.sax.InputSourcedrules.xml文gQ而是要求指定一个URLQ因此,下面代码中File引用被{换成了等LURLQ?

    import org.apache.commons.digester.*;
                import org.apache.commons.digester.xmlrules.*;
                import java.io.*;
                import java.util.*;
                public class XmlRulesDriver {
                public static void main( String[] args ) {
                try {
                File input = new File( args[0] );
                File rules = new File( args[1] );
                Digester digester = DigesterLoader.createDigester( rules.toURL() );
                Catalog catalog = (Catalog)digester.parse( input );
                System.out.println( catalog.toString() );
                } catch( Exception exc ) {
                exc.printStackTrace();
                }
                }
                }

    l束语:本文对Jakarta Commons Digester的介l就到这里结束。当Ӟq有许多内容q里未涉及。其中一个在q里忽略的主题是XML名称I间QDigester允许把规则定义成只能Ҏ一个名U空间内定义的元素v作用?

    另外Q我们简单地提及了通过扩展Rulecd发定制规则的问题。按照习惯,DigestercL供了push()、peek()和pop()ҎQ得开发者能够自由地直接操作解析栈?

    参考:

    Jakarta Commons Digester Homepage

    Jakarta Struts Homepage



    ]]>ThreadLocal与synchronized http://www.aygfsteel.com/lingy/archive/2009/08/25/292559.html林光?/dc:creator>林光?/author>Tue, 25 Aug 2009 12:36:00 GMThttp://www.aygfsteel.com/lingy/archive/2009/08/25/292559.html相关文章:  
    正确理解ThreadLocal
    ThreadLocal与synchronized

    推荐圈子: Pipboy
    更多相关推荐
    昨天上Java版块逛了一圈,一??千h览的帖子引起了偶滴注意 ThreadLocal与synchronized Q?以上的回复Q见大家对q个问题的兴?

    老实_从看到这个帖子的题目开始,p得帖子的作者估计是在概念上有所h?于是乎想写个咚咚Q同大家分n一下自q心得?

    帖子上,讨论的h很多Q高手不乏,各抒pQ但不知新手们看明白没有Q因此,q里偶以最z列表方式来说一说相关问题?

    1Q区别ThreadLocal ?synchronized

    ThreadLocal是一个线E隔?或者说是线E安?的变量存储的理实体Q注意:不是存储用的Q,它以JavacL式表玎ͼ
    synchronized是Java的一个保留字Q只是一个代码标识符Q它依靠JVM的锁机制来实C界区的函数、变量在CPUq行讉K中的原子性?
    两者的性质、表现及设计初衷不同Q因此没有可比较性?

    2.理解ThreadLocal中提到的变量副本
    事实上,我们向ThreadLocal中set的变量不是由ThreadLocal来存储的Q而是ThreadU程对象自n保存。当用户调用ThreadLocal对象的set(Object o)Ӟ该方法则通过Thread.currentThread()获取当前U程Q将变量存入Thread中的一个Map内,而Map的Key是当前的ThreadLocal实例。请看源码,q是最主要的两个函敎ͼ能看出ThreadLocal与Thread的调用关p:

    Java代码
    public void set(T value) {   
            Thread t = Thread.currentThread();   
            ThreadLocalMap map = getMap(t);   
            if (map != null)   
                map.set(this, value);   
            else  
                createMap(t, value);   
    }   
      
    ThreadLocalMap getMap(Thread t) {   
            return t.threadLocals;   
    }  
    public void set(T value) {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
    }

    ThreadLocalMap getMap(Thread t) {
            return t.threadLocals;
    }

    Q有兴趣的朋友可以阅读Java的ThreadLocal源码Q因此,我们可以知道Q所谓的变量副本Q即是对Object ReferenceQ对象引用)的拷贝?

    3.理解Thread?ThreadLocal对变量的引用关系
    实际上Thread和ThreadLocal对变量引用关pd像是坐标pM的X轴和Y_是从两个l度上来l织对变量的引用的?

    首先说Thread?我们知道一个ThreadOne的执行会贯穿多个ҎMethodA、MethodB、MethodCq些Ҏ可能分布于不同的cd例。假设,q些Ҏ分别使用了ThreadLocalA、ThreadLocalB、ThreadLocalC来保存线E本地变量,那么q些变量都存于ThreadOne的Map中,q用各自的ThreadLocal实例作ؓkey?因此Q可以认为,借助ThreanLocal的setҎQ在X轴上QThread横向兌同一U程上下文中来自多个Method的变量引用副本?


     


    接着说ThreadLocal?一个MethodA中的X变量被多个U程ThreadOne、ThreadTwo、ThreadThree所讉K。假设MethodA使用ThreadLocal存储XQ通过setҎQ以ThreadLocal作ؓkey|不同线E来访时的不同的变量值引用保存于ThreadOne、ThreadTwo、ThreadThree的各自线E上下文中,保每个U程有自q一个变量倹{因此,可以认ؓQThreadLocal是以Method为Y_U向兌了处于同一Ҏ中的不同U程上的变量?


     

    希望能对大家有所帮助Q这样可以少走很多弯路哦?

    本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/yangairong1984/archive/2008/04/15/2294572.aspx



    ]]>
    ant+cactus+tomcat5.5容器内单元测?/title><link>http://www.aygfsteel.com/lingy/archive/2009/06/22/283575.html</link><dc:creator>林光?/dc:creator><author>林光?/author><pubDate>Mon, 22 Jun 2009 07:06:00 GMT</pubDate><guid>http://www.aygfsteel.com/lingy/archive/2009/06/22/283575.html</guid><description><![CDATA[ 一、下载ƈ解压~cactus<br />   下蝲地址为http://Java.chinaitlab.com/tools/45970.Html 。将cactus的lib目录下的cactus-ant-1.7.1.jar复制到ant的lib目录?br />   二、配|cactus<br />   cactus的配|很单,新徏一个cactus.properties文gQƈ把它攑֜ant脚本中的cactusd的classpath下,文g中包括如下内?br />   cactus.sysproperties=cactus.contextURL<br highlighted="1" />   #cactus-sample-servlet-cactified是你的试应用所在\径,8080?zmkey style="border-bottom: #ff6c00 2px dotted; float: none; cursor: pointer; font-weight: bold; margin-right: 3px; cssfloat: none" class="zoomino-searchword" offset="52" path="body > div:eq(0) > div:eq(3) > table:eq(2) > tbody:eq(0) > tr:eq(0) > td:eq(0) > div:eq(0) > #content:eq(0) > br:eq(4)" anchorType="previous" jQuery1245654007453="6">端口?img style="border-bottom: medium none; border-left: medium none; padding-bottom: 0px; margin: 0px; padding-left: 0px; width: 12px; padding-right: 0px; display: inline; background-position: -18px -23px; float: none; height: 14px; border-top: medium none; border-right: medium none; padding-top: 0px; cssfloat: none" class="zoominoBgImage" src="http://static.zoomino.cn/static-ox/images/blank.gif" width="1" height="1" alt="" /></zmkey><br />   cactus.contextURL = http://localhost:8080/cactus-sample-servlet-cactified<br />   cactus.servletReDirectorName = ServletRedirector<br />   cactus.jspRedirectorName = JspRedirector<br />   cactus.filterRedirectorName = FilterRedirector <br />   具体的做法结合ant脚本再进一步解释?br />   三、运行ant脚本<br />    ant脚本主要执行以下d<br />   1、设定classpath<br />   <path id="project.classpath"><br />    <fileset dir="${lib.dir}"><br />    <include name="*.jar"/><br />    </fileset><br />    <!-- cactus.properties文g需要放在lib.dir所对应的\径中 --><br />    <pathelement location="${lib.dir}"/><br />    <pathelement location="${tomcat.home}/common/lib/jsp-api.jar"/><br />    <pathelement location="${tomcat.home}/common/lib/servlet-api.jar"/><br />    </path><br />   2、定义相关Q?br />   <taskdef resource="cactus.tasks" classpathref="project.classpath"/><br />    <taskdef name="runservertests" classname="org.apache.cactus.integration.ant.RunServerTestsTask"><br />    <classpath><br />    <path refid="project.classpath"/><br />    </classpath><br />    </taskdef><br />   3、编译应用的cL件和试的类文g<br />   4、打包整个应用ؓwar文g<br />   需要注重的是,不仅要打包应用类Q测试类也要打包<br />   <target name="war" depends="compile.java"<br />    description="Generate the runtime war"><br />    <war warfile="${target.dir}/${project.name}.war"<br />    webXML="${src.webapp.dir}/WEB-INF/web.xml"><br />    <fileset dir="${src.webapp.dir}"><br />    <exclude name="cactus-report.xsl"/><br />    <exclude name="WEB-INF/cactus-web.xml"/><br />    <exclude name="WEB-INF/web.xml"/><br />    </fileset><br />    <classes dir="${target.classes.java.dir}"/><br />    <!-- 别忘了打包测试类 --><br />    <classes dir="${target.classes.test.dir}"/><br />    <!-- 别忘了打包各U相关的jar文g --><br />    < lib dir="project.classpath"/><br />    </war><br />    </target><br />   5、在应用的web.xml文g中添加测试所需的各U映?br />   cactus提供了两个task来完成这个工作,CactifyWar和WebXmlMerge?br />   CactifyWar的功能是自动在已l打包的应用的web.xml文g中添加所需的映。WebXmlMerge是提供合q两个web.xml文g的功能?br />   <target name="test.prepare"<br />    depends="war, compile.cactus, test.prepare.logging"><br />    <!-- Cactify the web-app archive --><br />    <cactifywar srcfile="${target.dir}/${project.name}.war"<br />    destfile="${tomcat.home}/webapps/${project.name}-cactified.war"<br />    ><br />    <classes dir="${target.classes.java.dir}"/><br />    <classes dir="${target.classes.test.dir}"/><br />    <lib dir="project.classpath"/><br />    </cactifywar><br />   </target><br />   6、运行测?br />   cactus提供了cactus和RunServerTests两个task来运行测试?br highlighted="1" />   "cactus" task是通过复制容器服务器的最文件ƈq行来运行测试,因此需要制定容器服务器的类型,启动速度E快点,另外配置比较方便Q但是无法测试象tomcat<zmkey style="border-bottom: #ff6c00 2px dotted; float: none; cursor: pointer; font-weight: bold; margin-right: 3px; cssfloat: none" class="zoomino-searchword" offset="84" path="body > div:eq(0) > div:eq(3) > table:eq(2) > tbody:eq(0) > tr:eq(0) > td:eq(0) > div:eq(0) > #content:eq(0) > br:eq(64)" anchorType="previous" jQuery1245654007453="7">q接?img style="border-bottom: medium none; border-left: medium none; padding-bottom: 0px; margin: 0px; padding-left: 0px; width: 12px; padding-right: 0px; display: inline; background-position: -18px -23px; float: none; height: 14px; border-top: medium none; border-right: medium none; padding-top: 0px; cssfloat: none" class="zoominoBgImage" src="http://static.zoomino.cn/static-ox/images/blank.gif" width="1" height="1" alt="" /></zmkey>{资源。另外对tomcat5.5的支持也不好?br />   "RunServerTests"是通过直接启动容器服务hq行试Q因此速度E慢Q且配置较麻烦,但能试各种资源?br />   <target name="test" depends="test.prepare"<br />    description="Run tests on Tomcat "><br />    <!-- Start the servlet engine, wait for it to be started, run the<br />    unit tests, stop the servlet engine, wait for it to be stopped.<br />    The servlet engine is stopped if the tests fail for any reason --><br />    <!-- 8080是服务器的端口号Q?{project.name}-cactified是项目的路径Q和上一步的cactifywar 的destfile相对?--><br />    <runservertests<br />    testURL="http://localhost:8080/${project.name}-cactified/ServletRedirector?Cactus_Service=RUN_TEST"<br />    startTarget="_StartTomcat"<br />    stopTarget="_StopTomcat"<br />    testTarget="_Test"/><br />    </target><br />   <!-- _Test是一个普通的junitd --><br />    <target name="_Test"><br />    <junit printsummary="yes" fork="yes"><br />    <classpath><br />    <path refid="project.classpath"/><br />    <pathelement location="${target.classes.java.dir}"/><br />    <pathelement location="${target.classes.test.dir}"/><br />    </classpath><br />    <formatter type="brief" usefile="false"/><br />    <formatter type="xml"/><br />    <batchtest><br />    <fileset dir="${src.test.dir}"><br />    <!-- Due to some Cactus synchronization bug, the 'unit' tests need<br />    to run before the 'sample' tests --><br />    <include name="**/Test*.java"/><br />    <exclude name="**/Test*All.java"/><br />    </fileset><br />    </batchtest><br />    </junit><br />    </target><br />   文章来源: baike.duba.net <img src ="http://www.aygfsteel.com/lingy/aggbug/283575.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/lingy/" target="_blank">林光?/a> 2009-06-22 15:06 <a href="http://www.aygfsteel.com/lingy/archive/2009/06/22/283575.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>lservlet写单元测试的ȝhttp://www.aygfsteel.com/lingy/archive/2009/06/22/283551.html林光?/dc:creator>林光?/author>Mon, 22 Jun 2009 05:39:00 GMThttp://www.aygfsteel.com/lingy/archive/2009/06/22/283551.html lservlet写单元测试的ȝ收藏
    servlet的测试一般来说需要容器的支持Q不是像通常的javacȝjunit试一L单,
     
    下面通过对HelloWorld代码的测试阐qC几种servlet试Ҏ?br />  
    被测试的HelloWorldcȝ代码如下Q?br />  
    /**
     * 被测试的servlet
     */

    import java.io.IOException;
     
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.apache.cactus.WebRequest;
    import org.apache.cactus.server.HttpServletRequestWrapper;
     
    public class HelloWorld extends HttpServlet{
     
     public void saveToSession(HttpServletRequest request) {

             request.getSession().setAttribute("testAttribute",request.getParameter("testparam"));

     }
     
     public void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException{

             String username=request.getParameter("username");

             response.getWriter().write(username+":Hello World!");
           
     }
     
     public boolean authenticate(){
            
            return true;
     
     }

    }
     
    以HelloWorldZQ我ȝ了Servlet的多U测试方法如下:
     
    一.使用HttpUnit试
     
    import com.meterware.httpunit.GetMethodWebRequest;
    import com.meterware.httpunit.WebRequest;
    import com.meterware.httpunit.WebResponse;
    import com.meterware.servletunit.InvocationContext;
    import com.meterware.servletunit.ServletRunner;
    import com.meterware.servletunit.ServletUnitClient;
    import junit.framework.Assert;
    import junit.framework.TestCase;
     
    public class HttpUnitTestHelloWorld extends TestCase {
     
     protected void setUp() throws Exception {
      super.setUp();
     }
     
     protected void tearDown() throws Exception {
      super.tearDown();
     }
     
     public void testHelloWorld() {
     
      try {

       // 创徏Servlet的运行环?/p>

       ServletRunner sr = new ServletRunner();

       // 向环境中注册Servlet

       sr.registerServlet("HelloWorld", HelloWorld.class.getName());
     
       // 创徏讉KServlet的客L

       ServletUnitClient sc = sr.newClient();

       // 发送请?/p>

       WebRequest request = new GetMethodWebRequest("http://localhost/HelloWorld");
       request.setParameter("username", "testuser");

       InvocationContext ic = sc.newInvocation(request);

       HelloWorld is = (HelloWorld) ic.getServlet();
     
       // 试servlet的某个方?/p>

       Assert.assertTrue(is.authenticate());

       // 获得模拟服务器的信息

       WebResponse response = sc.getResponse(request);

       // 断言

       Assert.assertTrue(response.getText().equals("testuser:Hello World!"));

      } catch (Exception e) {

       e.printStackTrace();

      }

     }
     
    }
     
    上述例子其实是junit的一个测试例子,在其中用了httpunit模拟的servlet环境,使用上述Ҏ试
     
    servlet可以q容器Q容易把该测试写入ant或maven脚本Q让试q行?br />  
    httpunit|址Qhttp://httpunit.sourceforge.net/
     
    使用该种Ҏ试的弱点就是:如果要用request(response)的setCharercterEncodingҎӞ试会出C些问?
     
    而且httpunit在测试servlet行ؓӞ采用的是完全模拟览器,有时试比较隑ֆ?br />  
    ?使用cactus试
     
    /**
     * cactus试servlet的例?br />  * 必须要有tomcat的支?br />  *
     */
     
    import junit.framework.Test;
    import junit.framework.TestSuite;
    import org.apache.cactus.ServletTestCase;
    import org.apache.cactus.WebRequest;
    import org.apache.cactus.WebResponse;
    public class CactusHelloWorld extends ServletTestCase{
     
         HelloWorld servlet;
         public CactusHelloWorld(String theName) {
             super(theName);
         }
     
         protected void setUp() throws Exception {
             super.setUp();
             servlet = new HelloWorld();
         }
     
         protected void tearDown() throws Exception {
             super.tearDown();
         }
     
         /**
          * 试Ҏ试参数在此讄
          *
          * @param webrequest
          */
     
         public void beginSaveToSessionOK(WebRequest request) {
             request.addParameter("testparam", "it works!");
         }
        
         /**
          * 试Ҏ试参数在此讄
          *
          * @param webrequest
          */
     
         public void beginDoGet(WebRequest request) {
             request.addParameter("username", "testuser");
         }
     
         /**
          * 调用servlet的测试方?br />       * 
          */

         public void testSaveToSessionOK() {
             servlet.saveToSession(request);
             assertEquals("it works!", session.getAttribute("testAttribute"));
         }
     
         public void testDoGet() {
             try {
                 servlet.doGet(request, response);
             } catch (Exception e) {
                 e.printStackTrace();
             }
         }
     
         /**
          * 此方法可以判断测试方法的输出Q会传递测试方法的reponselend***,q且格式化ؓcactus
          * 的WebResponse或者可以跟httpunit集成Q格式化为httpunit的response
          *
          * @param response
          */

         public void endDoGet(WebResponse response) {
             String content;        
             content = response.getText();
             assertEquals("testuser:Hello World!", content);
         }
    }
     
    cactus具备丰富灉|的测试功能,如要试doGetҎQ分为beginDoGet(模拟试参数讄)、DoGet(执行试)、endDoGet(状态结果验?
     
    相比httpunit来说Q写试更ؓҎQ测试servlet更ؓ专业,程更ؓ清晰Q但是cactus需要容器支持,使得试不可以自动进行,但是
     
    如果使用一个嵌入式的容器,试可以自动了?br />  
    cactus是一个servlet和jsp的测试框?http://jakarta.apache.org/cactus/getting_started.html
     
    ?使用Jetty作ؓ嵌入式容器测试servlet.
     
    /**
     * 一个关于嵌入式jetty试的例子,jetty作ؓstubs的一个例?br />  *
     */
    package com.easyjf.testexample;
     
    import org.mortbay.jetty.Connector;
    import org.mortbay.jetty.Server;
    import org.mortbay.jetty.bio.SocketConnector;
    import org.mortbay.jetty.servlet.ServletHandler;
     
    import com.meterware.httpunit.WebClient;
    import com.meterware.httpunit.WebConversation;
    import com.meterware.httpunit.WebResponse;
     
    import junit.framework.Assert;
    import junit.framework.TestCase;
     
    public class JettySampleTest extends TestCase {
     
     Server server;
     protected void setUp() throws Exception {
          //通过代码讄q启动一个服务器Q该服务器是servlet的测试容?br />       super.setUp();
          server = new Server();
          Connector connector=new SocketConnector();
          connector.setPort(80);
          server.setConnectors(new Connector[]{connector});
          ServletHandler handler=new ServletHandler();
          server.setHandler(handler);
          handler.addServletWithMapping("HelloWorld", "/");
          server.start();
     }
     
     protected void tearDown() throws Exception {
      super.tearDown();
      server.stop();
     }
     
     public void testHellWorld() {
      try {
       WebConversation wc = new WebConversation();
       WebResponse web = wc.getResponse("http://127.0.0.1/HelloWorld");
       String result=web.getText();
       Assert.assertEquals(result,"it works!");
      } catch (Exception e) {
       e.printStackTrace();
      }
     }
    }
     
    可以发现Qjetty可以充当一个servlet的容器,方便的是,jetty支持嵌入式服务,卛_以通过代码来启动,
     
    所以要写自动测试的例子很方便,可以l合httpunit或者cactusq行servlet试?br />  
    jetty主页Qhttp://docs.codehaus.org/display/JETTY/Embedding+Jetty


    ?使用mock对象Q此处用easymock
     
    import java.io.PrintWriter;
    import java.io.Writer;
    import javax.servlet.ServletConfig;
    import javax.servlet.ServletContext;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
     
    import junit.framework.Assert;
    import junit.framework.TestCase;
    import static org.easymock.EasyMock.*;
    public class MockTestServlet extends TestCase {
     
        public void testService() throws Exception {

            System.out.println("service");

            HttpServletRequest request = createMock(HttpServletRequest.class);

            HttpServletResponse response = createMock(HttpServletResponse.class);

            //Creating the ServletConfig mock here

            ServletConfig servletConfig = createMock(ServletConfig.class);

            //Creating the ServletContext mock here

            ServletContext servletContext = createMock(ServletContext.class);
           
            //Create the target object 
         
            HelloWorld4 instance = new HelloWorld();

            //初始化servlet,一般由容器承担Q一般调用servletConfig作ؓ参数初始化,此处模拟容器行ؓ

            instance.init(servletConfig);
     
            //在某些方法被调用时设|期望的q回|如下q样׃会去实际调用servletConfig的getServletContextҎQ而是直接q回
     
            //servletContext,׃servletConfig是mock出来的,所以可以完全控制?/p>

            expect(servletConfig.getServletContext()).andReturn(servletContext).anyTimes();

            expect(request.getParameter("username")).andReturn("testuser");

            PrintWriter pw=new PrintWriter(System.out,true);

            expect(response.getWriter()).andReturn(pw).anyTimes();
           
            //以上均是录制Q下面ؓ重放Q该U机制ؓeasymock试机制Q要理解Leasymock试的一些资?br />         replay(request);
            replay(response);
            replay(servletConfig);
            replay(servletContext);
     
            instance.doGet(request, response);

            pw.flush();
           
     
            //验证l果是否预期Q如果预期,则会在pw上写出testuser.
            verify(request);
            verify(response);
            verify(servletConfig);
            verify(servletContext);
       }
    }
     
    mock试注重行ؓQmock对象其实都是模拟的对象,Ҏ一般直接给Z个返回|没有具体的对象逻辑Qmock对象
     
    是用来帮助测试要试的类的。比如要试servlet的内部行为,又不惌容器{环境,可以采用mock试?br />  
    easymock是mock试的一个框Ӟhttp://www.easymock.org/
     
    发表?@ 2007q?2?0?22:13:00|评论(2)

    C? 设计模式之创建模?| 旧一? 服务定位器模?service locator)wldandanpig 发表?007q??4?10:09:40  IP:举报
    请问g
    public String saveInfo()
    {
    String reqInfo = request.getParameter("reqInfo");
    String sessInfo = (String)request.getSession().getAttribute("sessInfo");

    request.setAttribute("reqInfo" , "response:"+reqInfo);
    request.getSession().setAttribute("sessInfo", "response:"+reqInfo);

    return "SUCCESS";
    }
    q个Ҏ怎么试啊cz_hyf 发表?007q??4?17:20:23  IP:举报
    如果用httpunit的话

    public void testHelloWorld() {

    try {

    // 创徏Servlet的运行环?/p>

    ServletRunner sr = new ServletRunner();

    // 向环境中注册Servlet

    sr.registerServlet("HelloWorld", HelloWorld.class.getName());

    // 创徏讉KServlet的客L

    ServletUnitClient sc = sr.newClient();

    // 发送请?/p>

    WebRequest request = new GetMethodWebRequest("http://localhost/HelloWorld");
    request.setParameter("reqInfo", "......");

    InvocationContext ic = sc.newInvocation(request);

    HelloWorld is = (HelloWorld) ic.getServlet();

    // 试servlet的某个方?/p>

    Assert.assertEquals(is.saveInfo,"SUCCESS");

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

    如果q不攑ֿQ不妨把request和request.session中的值取出来看看是否是你放进ȝ


    本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/cz_hyf/archive/2007/02/10/1507211.aspx



    ]]>
    jsp内徏对象http://www.aygfsteel.com/lingy/archive/2009/06/04/279972.html林光?/dc:creator>林光?/author>Thu, 04 Jun 2009 02:59:00 GMThttp://www.aygfsteel.com/lingy/archive/2009/06/04/279972.htmlJSP的内建对象不需要由JSP~写人员实例?它们均由容器理和实?在所有的JSP面中都能?只在Scriptlet或者表辑ּ中?它们?

    Q.request对象:

               代表h对象,被包装成HttpServletRequest接口,通过getParameterҎ得到request参数,通过 GET,POST,HEAD{方法得到request的类?通过Cookies,Referer{可以得到Http?来自客户端的hl?Servlet容器处理?由request对象q行装,作ؓjspService()Ҏ的一个参数由容器传递给JSP面.主要Ҏ?request.getAttribute("..");request.getParameter("xxx");request.getParameterValues("xxx");request.getHeader("xxx") 获取HTTP协议定义的文件头信息.request.getRequestURI()获取发出h字符串的客户端地址.request.getRemoteHost()客户端名,request.getRemoteAddr()客户端IP地址.request.getServerName()服务?/a>名字.request.getServletPath();客户端所h的脚本文件的文g路径.request.getServerPort()获取

    Q.response

               响应h对象,被包装成HttpServletResponse接口,与requst对象一?是缓冲输出流,可以讄Http状态码和response 响应?主要的方法有:response.addCookie(Cookie cookie);response.encodeURL();response.getOutputStream();response.sendRedirect("xxx") 把响应发到另一位置q行处理.

    Q.pageContext

              被封装成javax.servlet.jsp.pageContext接口,它ؓJSP面包装面的上下文.由容器创建和初始?理对属于JSP中特D可见部分中已命名对象的讉K.可用getServletContext()q回Servlet Context对象(q个Servlet ContextҎ有的面都是׃n?),forward("xxx")把页面重定向到另一面或者Servletlg?

     Q.session对象

               用来保存每个用户信息,以便跟踪每个用户的操作状?其中session信息保存在容器中,session的ID保存在客h的Cookiek .(一般情况中,用户每次dpȝ时容器会l此用户分配一个唯一的标识session id,用于区别其它用户,当用户退出系l时,q个标识׃自动消失.其接口ؓHttpSession.主要的方法有:session.getId();getLastAccessedTime();setAttribute();

    Q.application

             ?a class="channel_keylink" >服务?/a>启动后创?直到服务?/a>关闭而停?为多个应用程序保存信?

    Q.out对象:

                被封装成javax.servlet.jsp.JspWriter接口,它表CZؓ客户打开的输出流,PrintWriter使用它向客户端发送输出流.即简单说向客L输出数据.Ҏ:out.print(....),out.newLine();out.flush();out.close();{?q可获取输出~冲区的相关信息.如果要在面中真正输Z个空?需要用out.println("<br>")来实?

    Q.config

             被封装ؓjavax.servlet.ServletConfig接口,它表CZServlet的配|?当一个Servlet初始化时,容器把某些信息通过 此对象传递给q个Servlet.,常用的方法有:getServletContext();

    Q.page

             是java.lang.Objectcȝ一个实?它指的是JSP实现cȝ实例.

    Q.exception 

            是java.lang.Throwablecȝ一个实?它指的是q行时的异常,也就是被调用的错误页面的l果,只有在错误页?在指令里有isErrorPage=true的页面中)才可以?/p>

    ]]>
    վ֩ģ壺 ƽ| | ֵ| ɿ| | | ʯȪ| | Ҿ| | | | | | ɯ| | ں| | | | ̩| | | | | ޭ| ̨| | | | ¡| ȫ| | ƽ| | ޶| ͼ| | Ƽ| | |