zoukankan      html  css  js  c++  java
  • How Tomcat Works(五)

    本文接下来介绍tomcat的默认连接器,Tomcat中的默认连接器必须满足以下要求:

    • 实现org.apache.catalina.Connector接口

    • 负责创建实现org.apache.catalina.Request接口的Request对象

    • 负责创建实现org.apache.catalina.Response接口的Response对象

    org.apache.catalina.Connector接口最重要的方法是getContainer() 、setContainer()、creatRequest()、 creatResponse(),setContainer()方法用于设置相关联的servlet容器,getContainer()方法获取相关连的servlet容器,creatRequest()方法为http请求创建request对象,creatResponse()方法创建response对象

    下面来分析HttpConnector类实现,HttpConnector类同时实现了org.apache.catalina.Connector接口org.apache.catalina.Lifecycle接口(用于生命周期管理)、java.lang.Runnable接口(多线程接口)

    在HttpConnector对象的初始化方法initialize()里面,调用私有方法open(),创建ServerSocket实例

    private ServerSocket open()
        throws IOException, KeyStoreException, NoSuchAlgorithmException,
               CertificateException, UnrecoverableKeyException,
               KeyManagementException
        {
    
            // Acquire the server socket factory for this Connector
            ServerSocketFactory factory = getFactory();
    
            // If no address is specified, open a connection on all addresses
            if (address == null) {
                log(sm.getString("httpConnector.allAddresses"));
                try {
                    return (factory.createSocket(port, acceptCount));
                } catch (BindException be) {
                    throw new BindException(be.getMessage() + ":" + port);
                }
            }
    
            // Open a server socket on the specified address
            try {
                InetAddress is = InetAddress.getByName(address);
                log(sm.getString("httpConnector.anAddress", address));
                try {
                    return (factory.createSocket(port, acceptCount, is));
                } catch (BindException be) {
                    throw new BindException(be.getMessage() + ":" + address +
                                            ":" + port);
                }
            } catch (Exception e) {
                log(sm.getString("httpConnector.noAddress", address));
                try {
                    return (factory.createSocket(port, acceptCount));
                } catch (BindException be) {
                    throw new BindException(be.getMessage() + ":" + port);
                }
            }
    
        }

    上面的ServerSocketFactory factory = getFactory()显然是创建ServerSocket实例的工厂,方法如下

     /**
         * Return the server socket factory used by this Container.
         */
        public ServerSocketFactory getFactory() {
    
            if (this.factory == null) {
                synchronized (this) {
                    this.factory = new DefaultServerSocketFactory();
                }
            }
            return (this.factory);
    
        }

    工厂类DefaultServerSocketFactory实现了ServerSocketFactory接口

    public final class DefaultServerSocketFactory implements ServerSocketFactory {
       
        public ServerSocket createSocket (int port)
        throws IOException, KeyStoreException, NoSuchAlgorithmException,
               CertificateException, UnrecoverableKeyException,
               KeyManagementException {
    
            return (new ServerSocket(port));
    
        }
       
        public ServerSocket createSocket (int port, int backlog)
        throws IOException, KeyStoreException, NoSuchAlgorithmException,
               CertificateException, UnrecoverableKeyException,
               KeyManagementException {
    
            return (new ServerSocket(port, backlog));
    
        }
        
        public ServerSocket createSocket (int port, int backlog,
                                          InetAddress ifAddress)
        throws IOException, KeyStoreException, NoSuchAlgorithmException,
               CertificateException, UnrecoverableKeyException,
               KeyManagementException {
    
            return (new ServerSocket(port, backlog, ifAddress));
    
        }
    
    }

    下面接着分析用于生命周期的start()方法

    /**
         * Begin processing requests via this Connector.
         *
         * @exception LifecycleException if a fatal startup error occurs
         */
        public void start() throws LifecycleException {
    
            // Validate and update our current state
            if (started)
                throw new LifecycleException
                    (sm.getString("httpConnector.alreadyStarted"));
            threadName = "HttpConnector[" + port + "]";
            lifecycle.fireLifecycleEvent(START_EVENT, null);
            started = true;
    
            // Start our background thread
            threadStart();
    
            // Create the specified minimum number of processors
            while (curProcessors < minProcessors) {
                if ((maxProcessors > 0) && (curProcessors >= maxProcessors))
                    break;
                HttpProcessor processor = newProcessor();
                recycle(processor);
            }
    
        }

    首先是启动HttpConnector连接器线程,然后是初始化最少数量的HttpProcessor处理器入栈

     /**
         * Start the background processing thread.
         */
        private void threadStart() {
    
            log(sm.getString("httpConnector.starting"));
    
            thread = new Thread(this, threadName);
            thread.setDaemon(true);
            thread.start();
    
        }

    由于HttpConnector连接器实现了java.lang.Runnable接口,我们分析它的run()方法实现

    /**
         * The background thread that listens for incoming TCP/IP connections and
         * hands them off to an appropriate processor.
         */
        public void run() {
            // Loop until we receive a shutdown command
            while (!stopped) {
                // Accept the next incoming connection from the server socket
                Socket socket = null;
                try {
                    //                if (debug >= 3)
                    //                    log("run: Waiting on serverSocket.accept()");
                    socket = serverSocket.accept();
                    //                if (debug >= 3)
                    //                    log("run: Returned from serverSocket.accept()");
                    if (connectionTimeout > 0)
                        socket.setSoTimeout(connectionTimeout);
                    socket.setTcpNoDelay(tcpNoDelay);
                } catch (AccessControlException ace) {
                    log("socket accept security exception", ace);
                    continue;
                } catch (IOException e) {
                    //                if (debug >= 3)
                    //                    log("run: Accept returned IOException", e);
                    try {
                        // If reopening fails, exit
                        synchronized (threadSync) {
                            if (started && !stopped)
                                log("accept error: ", e);
                            if (!stopped) {
                                //                    if (debug >= 3)
                                //                        log("run: Closing server socket");
                                serverSocket.close();
                                //                        if (debug >= 3)
                                //                            log("run: Reopening server socket");
                                serverSocket = open();
                            }
                        }
                        //                    if (debug >= 3)
                        //                        log("run: IOException processing completed");
                    } catch (IOException ioe) {
                        log("socket reopen, io problem: ", ioe);
                        break;
                    } catch (KeyStoreException kse) {
                        log("socket reopen, keystore problem: ", kse);
                        break;
                    } catch (NoSuchAlgorithmException nsae) {
                        log("socket reopen, keystore algorithm problem: ", nsae);
                        break;
                    } catch (CertificateException ce) {
                        log("socket reopen, certificate problem: ", ce);
                        break;
                    } catch (UnrecoverableKeyException uke) {
                        log("socket reopen, unrecoverable key: ", uke);
                        break;
                    } catch (KeyManagementException kme) {
                        log("socket reopen, key management problem: ", kme);
                        break;
                    }
    
                    continue;
                }
    
                // Hand this socket off to an appropriate processor
                HttpProcessor processor = createProcessor();
                if (processor == null) {
                    try {
                        log(sm.getString("httpConnector.noProcessor"));
                        socket.close();
                    } catch (IOException e) {
                        ;
                    }
                    continue;
                }
                //            if (debug >= 3)
                //                log("run: Assigning socket to processor " + processor);
                processor.assign(socket);
    
                // The processor will recycle itself when it finishes
    
            }
    
            // Notify the threadStop() method that we have shut ourselves down
            //        if (debug >= 3)
            //            log("run: Notifying threadStop() that we have shut down");
            synchronized (threadSync) {
                threadSync.notifyAll();
            }
    
        }

    上面方法中,监听客户端的http请求,当监听到http请求时,获取Socket实例,然后委派给HttpProcessor对象进行处理(处理器线程吧),最后是如果收到停止连接器线程命令, 则事件通知可以停止线程了

    在上面我们还没有来得及分析HttpProcessor对象的初始化相关,所以要重新回到start()方法(源码分析有时要跟踪方法中对多个其他方法的调用,深度优先则顾此失彼,难以兼顾;而广度优先则不便纵向深入)

     // Create the specified minimum number of processors
            while (curProcessors < minProcessors) {
                if ((maxProcessors > 0) && (curProcessors >= maxProcessors))
                    break;
                HttpProcessor processor = newProcessor();
                recycle(processor);
            }

    这里是创建最少数量的HttpProcessor处理器并入栈,我们先分析newProcessor()方法的实现

    /**
         * Create and return a new processor suitable for processing HTTP
         * requests and returning the corresponding responses.
         */
        private HttpProcessor newProcessor() {
    
            //        if (debug >= 2)
            //            log("newProcessor: Creating new processor");
            HttpProcessor processor = new HttpProcessor(this, curProcessors++);
            if (processor instanceof Lifecycle) {
                try {
                    ((Lifecycle) processor).start();
                } catch (LifecycleException e) {
                    log("newProcessor", e);
                    return (null);
                }
            }
            created.addElement(processor);
            return (processor);
    
        }

    我们可以看到,这里主要是实例化HttpProcessor对象,传入HttpConnector实例本身(里面要用到HttpConnector对象的创建Request对象方法和创建Response对象方法),然后向上转型为Lifecycle接口类型,并调用它的start()方法,接着Vector created = new Vector()成员变量添加该HttpProcessor对象(Vector实现List接口,内部采用数组实现,其操作方法支持线程同步),最后返回实例

    /**
         * Recycle the specified Processor so that it can be used again.
         *
         * @param processor The processor to be recycled
         */
        void recycle(HttpProcessor processor) {
    
            //        if (debug >= 2)
            //            log("recycle: Recycling processor " + processor);
            processors.push(processor);
    
        }

    这里将HttpProcessor对象入栈,成员变量Stack processors = new Stack()继承自Vector,是一种先进后出的数据结构

    我们现在来分析run()方法里面的相关源码,也许更容易理解

    /**
         * Create (or allocate) and return an available processor for use in
         * processing a specific HTTP request, if possible.  If the maximum
         * allowed processors have already been created and are in use, return
         * <code>null</code> instead.
         */
        private HttpProcessor createProcessor() {
    
            synchronized (processors) {
                if (processors.size() > 0) {
                    // if (debug >= 2)
                    // log("createProcessor: Reusing existing processor");
                    return ((HttpProcessor) processors.pop());
                }
                if ((maxProcessors > 0) && (curProcessors < maxProcessors)) {
                    // if (debug >= 2)
                    // log("createProcessor: Creating new processor");
                    return (newProcessor());
                } else {
                    if (maxProcessors < 0) {
                        // if (debug >= 2)
                        // log("createProcessor: Creating new processor");
                        return (newProcessor());
                    } else {
                        // if (debug >= 2)
                        // log("createProcessor: Cannot create new processor");
                        return (null);
                    }
                }
            }
    
        }

    这里是从Stack processors = new Stack()成员变量里面获取HttpProcessor对象 ,后面的代码不用多加解释了吧,你懂的!

    后面那段代码是干嘛的

    // Notify the threadStop() method that we have shut ourselves down
            //        if (debug >= 3)
            //            log("run: Notifying threadStop() that we have shut down");
            synchronized (threadSync) {
                threadSync.notifyAll();
            }

    我们看到threadStop()方法里面的代码,可以看出上面的代码块是用来通知线程停止的

    /**
         * Stop the background processing thread.
         */
        private void threadStop() {
    
            log(sm.getString("httpConnector.stopping"));
    
            stopped = true;
            try {
                threadSync.wait(5000);
            } catch (InterruptedException e) {
                ;
            }
            thread = null;
    
        }

    由于HttpProcessor处理器类的源码分析相对独立,加上篇幅还比较多,因此本文先到这里,下文继续……

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

    本系列How Tomcat Works系本人原创 

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

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

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

  • 相关阅读:
    mysql远程连接失败的解决方法(CentOS版)
    【lamp】搭建
    【wamp】WAMP配置与单IP多域名功能设置
    【centos】网卡自动联网
    stm32之keil开发环境搭建
    利用ffmpeg将H264流 解码为RGB 分类: VC++ ffmpeg-SDL-VLC-Live555 2015-08-07 11:39 155人阅读 评论(0) 收藏
    使用ffserver实现转发实时流媒体(摄像头捕获) 分类: TI-AM335X arm-linux-Ubuntu ffmpeg-SDL-VLC-Live555 2015-08-04 09:36 5人阅读 评论(0) 收藏
    ffmpeg+ffserver搭建流媒体服务器 分类: arm-linux-Ubuntu ffmpeg-SDL-VLC-Live555 TI-AM335X 2015-08-04 09:35 6人阅读 评论(0) 收藏
    嵌入式linux------ffmpeg移植 编码H264(am335x编码H264) 分类: TI-AM335X ffmpeg-SDL-VLC-Live555 arm-linux-Ubuntu 2015-08-04 09:34 5人阅读 评论(0) 收藏
    嵌入式linux------ffmpeg移植 解码H264(am335x解码H264到yuv420并通过SDL显示) 分类: arm-linux-Ubuntu TI-AM335X ffmpeg-SDL-VLC-Live555 2015-07-29 10:28 154人阅读 评论(0) 收藏
  • 原文地址:https://www.cnblogs.com/chenying99/p/3235530.html
Copyright © 2011-2022 走看看