How Tomcat Works(六)

系统 1474 0

本文继续分析HttpProcessor类,该类实现了org.apache.catalina.Lifecycle接口和java.lang.Runnable接口

我们先分析它的构造函数

      
        /**
      
      
        
     * The HttpConnector with which this processor is associated.
     
      
      
        */
      
      
        private
      
       HttpConnector connector = 
      
        null
      
      
        ;


      
      
        /**
      
      
        
     * The HTTP request object we will pass to our associated container.
     
      
      
        */
      
      
        private
      
       HttpRequestImpl request = 
      
        null
      
      
        ;

    
      
      
        /**
      
      
        
     * The HTTP response object we will pass to our associated container.
     
      
      
        */
      
      
        private
      
       HttpResponseImpl response = 
      
        null
      
      
        ;

 
      
      
        /**
      
      
        
     * Construct a new HttpProcessor associated with the specified connector.
     *
     * 
      
      
        @param
      
      
         connector HttpConnector that owns this processor
     * 
      
      
        @param
      
      
         id Identifier of this HttpProcessor (unique per connector)
     
      
      
        */
      
      
        public
      
       HttpProcessor(HttpConnector connector, 
      
        int
      
      
         id) {

        
      
      
        super
      
      
        ();
        
      
      
        this
      
      .connector =
      
         connector;
        
      
      
        this
      
      .debug =
      
         connector.getDebug();
        
      
      
        this
      
      .id =
      
         id;
        
      
      
        this
      
      .proxyName =
      
         connector.getProxyName();
        
      
      
        this
      
      .proxyPort =
      
         connector.getProxyPort();
        
      
      
        this
      
      .request =
      
         (HttpRequestImpl) connector.createRequest();
        
      
      
        this
      
      .response =
      
         (HttpResponseImpl) connector.createResponse();
        
      
      
        this
      
      .serverPort =
      
         connector.getPort();
        
      
      
        this
      
      .threadName =
          "HttpProcessor[" + connector.getPort() + "][" + id + "]"
      
        ;

    }
      
    

构造函数用于初始化成员变量HttpConnector connector = null、HttpRequestImpl request = null、HttpResponseImpl response = null等

当调用它的start()方法时,用于启动处理器线程

      
        /**
      
      
        
     * Start the background thread we will use for request processing.
     *
     * 
      
      
        @exception
      
      
         LifecycleException if a fatal startup error occurs
     
      
      
        */
      
      
        public
      
      
        void
      
       start() 
      
        throws
      
      
         LifecycleException {

        
      
      
        if
      
      
         (started)
            
      
      
        throw
      
      
        new
      
      
         LifecycleException
                (sm.getString(
      
      "httpProcessor.alreadyStarted"
      
        ));
        lifecycle.fireLifecycleEvent(START_EVENT, 
      
      
        null
      
      
        );
        started 
      
      = 
      
        true
      
      
        ;

        threadStart();

    }
      
    

调用threadStart()方法

      
        /**
      
      
        
     * Start the background processing thread.
     
      
      
        */
      
      
        private
      
      
        void
      
      
         threadStart() {

        log(sm.getString(
      
      "httpProcessor.starting"
      
        ));

        thread 
      
      = 
      
        new
      
       Thread(
      
        this
      
      
        , threadName);
        thread.setDaemon(
      
      
        true
      
      
        );
        thread.start();

        
      
      
        if
      
       (debug >= 1
      
        )
            log(
      
      " Background thread has been started"
      
        );

    }
      
    

 即启动处理器线程,下面是run()方法

      
        /**
      
      
        
     * The background thread that listens for incoming TCP/IP connections and
     * hands them off to an appropriate processor.
     
      
      
        */
      
      
        public
      
      
        void
      
      
         run() {

        
      
      
        //
      
      
         Process requests until we receive a shutdown signal
      
      
        while
      
       (!
      
        stopped) {

            
      
      
        //
      
      
         Wait for the next socket to be assigned
      
      
            Socket socket =
      
         await();
            
      
      
        if
      
       (socket == 
      
        null
      
      
        )
                
      
      
        continue
      
      
        ;

            
      
      
        //
      
      
         Process the request from this socket
      
      
        try
      
      
         {
                process(socket);
            } 
      
      
        catch
      
      
         (Throwable t) {
                log(
      
      "process.invoke"
      
        , t);
            }

            
      
      
        //
      
      
         Finish up this request
      
      
            connector.recycle(
      
        this
      
      
        );

        }

        
      
      
        //
      
      
         Tell threadStop() we have shut ourselves down successfully
      
      
        synchronized
      
      
         (threadSync) {
            threadSync.notifyAll();
        }

    }
      
    

下面关键是分析await()方法与assign()方法是怎么同步的了,这里可以理解为经典的生产者与消费者模型

我们先来看assign()方法

      
        /**
      
      
        
     * Process an incoming TCP/IP connection on the specified socket.  Any
     * exception that occurs during processing must be logged and swallowed.
     * <b>NOTE</b>:  This method is called from our Connector's thread.  We
     * must assign it to our own thread so that multiple simultaneous
     * requests can be handled.
     *
     * 
      
      
        @param
      
      
         socket TCP socket to process
     
      
      
        */
      
      
        synchronized
      
      
        void
      
      
         assign(Socket socket) {

        
      
      
        //
      
      
         Wait for the Processor to get the previous Socket
      
      
        while
      
      
         (available) {
            
      
      
        try
      
      
         {
                wait();
            } 
      
      
        catch
      
      
         (InterruptedException e) {
            }
        }

        
      
      
        //
      
      
         Store the newly available Socket and notify our thread
      
      
        this
      
      .socket =
      
         socket;
        available 
      
      = 
      
        true
      
      
        ;
        notifyAll();

        
      
      
        if
      
       ((debug >= 1) && (socket != 
      
        null
      
      
        ))
            log(
      
      " An incoming request is being assigned"
      
        );

    }
      
    

成员变量默认为boolean available = false

下面是await()方法

      
        /**
      
      
        
     * Await a newly assigned Socket from our Connector, or <code>null</code>
     * if we are supposed to shut down.
     
      
      
        */
      
      
        private
      
      
        synchronized
      
      
         Socket await() {

        
      
      
        //
      
      
         Wait for the Connector to provide a new Socket
      
      
        while
      
       (!
      
        available) {
            
      
      
        try
      
      
         {
                wait();
            } 
      
      
        catch
      
      
         (InterruptedException e) {
            }
        }

        
      
      
        //
      
      
         Notify the Connector that we have received this Socket
      
      
        Socket socket = 
      
        this
      
      
        .socket;
        available 
      
      = 
      
        false
      
      
        ;
        notifyAll();

        
      
      
        if
      
       ((debug >= 1) && (socket != 
      
        null
      
      
        ))
            log(
      
      "  The incoming request has been awaited"
      
        );

        
      
      
        return
      
      
         (socket);

    }
      
    

显然这里是采用notifyAll()方法与wait()方法相同通信,当await()方法执行notifyAll()并返回socket后,assign()方法又可以继续接收请求socket对象了

await()方法里面采用的是局部变量,为了不占用成员变量引用(Socket socket = null),返回的socket对象供处理器线程进行处理,又要回到run()方法了

Socket socket = await()这里也是采用了局部变量,与await()方法里面采用局部变量同样的原因

获取socket实例后,调用process()方法进行处理,处理完毕后将处理器对象重新入栈,最后是如果收到停止处理器线程命令,则事件通知可以停止线程了

下面关键是process()方法,这个方法有点长

      
        /**
      
      
        
     * Process an incoming HTTP request on the Socket that has been assigned
     * to this Processor.  Any exceptions that occur during processing must be
     * swallowed and dealt with.
     *
     * 
      
      
        @param
      
      
         socket The socket on which we are connected to the client
     
      
      
        */
      
      
        private
      
      
        void
      
      
         process(Socket socket) {
        
      
      
        boolean
      
       ok = 
      
        true
      
      
        ;
        
      
      
        boolean
      
       finishResponse = 
      
        true
      
      
        ;
        SocketInputStream input 
      
      = 
      
        null
      
      
        ;
        OutputStream output 
      
      = 
      
        null
      
      
        ;

        
      
      
        //
      
      
         Construct and initialize the objects we will need
      
      
        try
      
      
         {
            input 
      
      = 
      
        new
      
      
         SocketInputStream(socket.getInputStream(),
                                          connector.getBufferSize());
        } 
      
      
        catch
      
      
         (Exception e) {
            log(
      
      "process.create"
      
        , e);
            ok 
      
      = 
      
        false
      
      
        ;
        }

        keepAlive 
      
      = 
      
        true
      
      
        ;

        
      
      
        while
      
       (!stopped && ok &&
      
         keepAlive) {

            finishResponse 
      
      = 
      
        true
      
      
        ;

            
      
      
        try
      
      
         {
                request.setStream(input);
                request.setResponse(response);
                output 
      
      =
      
         socket.getOutputStream();
                response.setStream(output);
                response.setRequest(request);
                ((HttpServletResponse) response.getResponse()).setHeader
                    (
      
      "Server"
      
        , SERVER_INFO);
            } 
      
      
        catch
      
      
         (Exception e) {
                log(
      
      "process.create"
      
        , e);
                ok 
      
      = 
      
        false
      
      
        ;
            }


            
      
      
        //
      
      
         Parse the incoming request
      
      
        try
      
      
         {
                
      
      
        if
      
      
         (ok) {

                    parseConnection(socket);
                    parseRequest(input, output);
                    
      
      
        if
      
       (!
      
        request.getRequest().getProtocol()
                        .startsWith(
      
      "HTTP/0"
      
        ))
                        parseHeaders(input);
                    
      
      
        if
      
      
         (http11) {
                        
      
      
        //
      
      
         Sending a request acknowledge back to the client if
                        
      
      
        //
      
      
         requested.
      
      
                                ackRequest(output);
                        
      
      
        //
      
      
         If the protocol is HTTP/1.1, chunking is allowed.
      
      
        if
      
      
         (connector.isChunkingAllowed())
                            response.setAllowChunking(
      
      
        true
      
      
        );
                    }

                }
            } 
      
      
        catch
      
      
         (EOFException e) {
                
      
      
        //
      
      
         It's very likely to be a socket disconnect on either the
                
      
      
        //
      
      
         client or the server
      
      
                ok = 
      
        false
      
      
        ;
                finishResponse 
      
      = 
      
        false
      
      
        ;
            } 
      
      
        catch
      
      
         (ServletException e) {
                ok 
      
      = 
      
        false
      
      
        ;
                
      
      
        try
      
      
         {
                    ((HttpServletResponse) response.getResponse())
                        .sendError(HttpServletResponse.SC_BAD_REQUEST);
                } 
      
      
        catch
      
      
         (Exception f) {
                    ;
                }
            } 
      
      
        catch
      
      
         (InterruptedIOException e) {
                
      
      
        if
      
       (debug > 1
      
        ) {
                    
      
      
        try
      
      
         {
                        log(
      
      "process.parse"
      
        , e);
                        ((HttpServletResponse) response.getResponse())
                            .sendError(HttpServletResponse.SC_BAD_REQUEST);
                    } 
      
      
        catch
      
      
         (Exception f) {
                        ;
                    }
                }
                ok 
      
      = 
      
        false
      
      
        ;
            } 
      
      
        catch
      
      
         (Exception e) {
                
      
      
        try
      
      
         {
                    log(
      
      "process.parse"
      
        , e);
                    ((HttpServletResponse) response.getResponse()).sendError
                        (HttpServletResponse.SC_BAD_REQUEST);
                } 
      
      
        catch
      
      
         (Exception f) {
                    ;
                }
                ok 
      
      = 
      
        false
      
      
        ;
            }

            
      
      
        //
      
      
         Ask our Container to process this request
      
      
        try
      
      
         {
                ((HttpServletResponse) response).setHeader
                    (
      
      "Date"
      
        , FastHttpDateFormat.getCurrentDate());
                
      
      
        if
      
      
         (ok) {
                    connector.getContainer().invoke(request, response);
                }
            } 
      
      
        catch
      
      
         (ServletException e) {
                log(
      
      "process.invoke"
      
        , e);
                
      
      
        try
      
      
         {
                    ((HttpServletResponse) response.getResponse()).sendError
                        (HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                } 
      
      
        catch
      
      
         (Exception f) {
                    ;
                }
                ok 
      
      = 
      
        false
      
      
        ;
            } 
      
      
        catch
      
      
         (InterruptedIOException e) {
                ok 
      
      = 
      
        false
      
      
        ;
            } 
      
      
        catch
      
      
         (Throwable e) {
                log(
      
      "process.invoke"
      
        , e);
                
      
      
        try
      
      
         {
                    ((HttpServletResponse) response.getResponse()).sendError
                        (HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                } 
      
      
        catch
      
      
         (Exception f) {
                    ;
                }
                ok 
      
      = 
      
        false
      
      
        ;
            }

            
      
      
        //
      
      
         Finish up the handling of the request
      
      
        if
      
      
         (finishResponse) {
                
      
      
        try
      
      
         {
                    response.finishResponse();
                } 
      
      
        catch
      
      
         (IOException e) {
                    ok 
      
      = 
      
        false
      
      
        ;
                } 
      
      
        catch
      
      
         (Throwable e) {
                    log(
      
      "process.invoke"
      
        , e);
                    ok 
      
      = 
      
        false
      
      
        ;
                }
                
      
      
        try
      
      
         {
                    request.finishRequest();
                } 
      
      
        catch
      
      
         (IOException e) {
                    ok 
      
      = 
      
        false
      
      
        ;
                } 
      
      
        catch
      
      
         (Throwable e) {
                    log(
      
      "process.invoke"
      
        , e);
                    ok 
      
      = 
      
        false
      
      
        ;
                }
                
      
      
        try
      
      
         {
                    
      
      
        if
      
       (output != 
      
        null
      
      
        )
                        output.flush();
                } 
      
      
        catch
      
      
         (IOException e) {
                    ok 
      
      = 
      
        false
      
      
        ;
                }
            }

            
      
      
        //
      
      
         We have to check if the connection closure has been requested
            
      
      
        //
      
      
         by the application or the response stream (in case of HTTP/1.0
            
      
      
        //
      
      
         and keep-alive).
      
      
        if
      
       ( "close".equals(response.getHeader("Connection"
      
        )) ) {
                keepAlive 
      
      = 
      
        false
      
      
        ;
            }

            
      
      
        //
      
      
         End of request processing
      
      
            status =
      
         Constants.PROCESSOR_IDLE;

            
      
      
        //
      
      
         Recycling the request and the response objects
      
      
                    request.recycle();
            response.recycle();

        }

        
      
      
        try
      
      
         {
            shutdownInput(input);
            socket.close();
        } 
      
      
        catch
      
      
         (IOException e) {
            ;
        } 
      
      
        catch
      
      
         (Throwable e) {
            log(
      
      "process.invoke"
      
        , e);
        }
        socket 
      
      = 
      
        null
      
      
        ;

    }
      
    

上面方法中,首先根据参数socket的输入流与输出流初始化request对象与response对象,接着是解析输入流并填充request对象和 response对象 ,接下来调用容器对象的void invoke(Request request, Response response)方法具体进行处理

接下来清理并回收request对象和response对象

注:keepAlive表示是否是持久连接

最后是检查输入流是否有未读完的字节并跳过这些字节和关闭socket实例。

下面是一个简单的容器,实现了org.apache.catalina.Container接口,关键代码如下

      
        public
      
      
        class
      
       SimpleContainer 
      
        implements
      
      
         Container {

  
      
      
        public
      
      
        static
      
      
        final
      
       String WEB_ROOT =
      
        
    System.getProperty(
      
      "user.dir") + File.separator  + "webroot"
      
        ;

  
      
      
        public
      
      
         SimpleContainer() {
  } 
      
      
        public
      
      
         Loader getLoader() {
    
      
      
        return
      
      
        null
      
      
        ;
  }

  
      
      
        public
      
      
        void
      
      
         setLoader(Loader loader) {
  } 
      
      
        public
      
      
        void
      
      
         invoke(Request request, Response response)
    
      
      
        throws
      
      
         IOException, ServletException {

    String servletName 
      
      =
      
         ( (HttpServletRequest) request).getRequestURI();
    servletName 
      
      = servletName.substring(servletName.lastIndexOf("/") + 1
      
        );
    URLClassLoader loader 
      
      = 
      
        null
      
      
        ;
    
      
      
        try
      
      
         {
      URL[] urls 
      
      = 
      
        new
      
       URL[1
      
        ];
      URLStreamHandler streamHandler 
      
      = 
      
        null
      
      
        ;
      File classPath 
      
      = 
      
        new
      
      
         File(WEB_ROOT);
      String repository 
      
      = (
      
        new
      
       URL("file", 
      
        null
      
      , classPath.getCanonicalPath() +
      
         File.separator)).toString() ;
      urls[
      
      0] = 
      
        new
      
       URL(
      
        null
      
      
        , repository, streamHandler);
      loader 
      
      = 
      
        new
      
      
         URLClassLoader(urls);
    }
    
      
      
        catch
      
      
         (IOException e) {
      System.out.println(e.toString() );
    }
    Class myClass 
      
      = 
      
        null
      
      
        ;
    
      
      
        try
      
      
         {
      myClass 
      
      =
      
         loader.loadClass(servletName);
    }
    
      
      
        catch
      
      
         (ClassNotFoundException e) {
      System.out.println(e.toString());
    }

    Servlet servlet 
      
      = 
      
        null
      
      
        ;

    
      
      
        try
      
      
         {
      servlet 
      
      =
      
         (Servlet) myClass.newInstance();
      servlet.service((HttpServletRequest) request, (HttpServletResponse) response);
    }
    
      
      
        catch
      
      
         (Exception e) {
      System.out.println(e.toString());
    }
    
      
      
        catch
      
      
         (Throwable e) {
      System.out.println(e.toString());
    }

  }  

}
      
    

该方法与前面文章的ServletProcessor类的process()方法类似,不再具体分析

--------------------------------------------------------------------------- 

本系列How Tomcat Works系本人原创 

转载请注明出处 博客园 刺猬的温驯 

本人邮箱: chenying998179 # 163.com ( #改为@

本文链接 http://www.cnblogs.com/chenying99/p/3235534.html

How Tomcat Works(六)


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论