`
yayagepei
  • 浏览: 7113 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

tomcat源码分析系列之请求处理---请君入瓮

阅读更多

    费了九牛二虎之力,tomcat终于启动起来了,接下来我们要看看tomcat是如何处理一个请求的。上回 说到JIoEndpoint是负责处理请求的,这个类里面有几个内部接口和内部类,其中有一个就是我们要关注的Acceptor

// --------------------------------------------------- Acceptor Inner Class
    /**
     * Server socket acceptor thread.
     */
    protected class Acceptor implements Runnable {


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

            int errorDelay = 0;

            // Loop until we receive a shutdown command
            while (running) {

                // Loop if endpoint is paused
                while (paused && running) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // Ignore
                    }
                }

                if (!running) {
                    break;
                }
                try {
                    //超过最大连接数,就等待
                    //if we have reached max connections, wait
                    countUpOrAwaitConnection();
                    
                    Socket socket = null;
                    try {
                        // Accept the next incoming connection from the server
                        // socket
                        socket = serverSocketFactory.acceptSocket(serverSocket);
                    } catch (IOException ioe) {
                        /**
                          * 触发一种延迟处理,如果errorDelay>0,线程会sleep相应的毫秒,主要是为后面的程序处理异常
                          * 争取时间,从而避免在短时间大量占用CPU
                          * 每多一个异常,会延迟50ms,直到达到最大阀值1.6s
                          **/
                        // Introduce delay if necessary
                        errorDelay = handleExceptionWithDelay(errorDelay);
                        // re-throw
                        throw ioe;
                    }
                    // Successful accept, reset the error delay
                    errorDelay = 0;

                    // Configure the socket
                    if (setSocketOptions(socket)) {
                        // Hand this socket off to an appropriate processor
                        if (!processSocket(socket)) {
                            // Close socket right away
                            try {
                                socket.close();
                            } catch (IOException e) {
                                // Ignore
                            }
                        }
                    } else {
                        // Close socket right away
                        try {
                            socket.close();
                        } catch (IOException e) {
                            // Ignore
                        }
                    }
                } catch (IOException x) {
                    if (running) {
                        log.error(sm.getString("endpoint.accept.fail"), x);
                    }
                } catch (NullPointerException npe) {
                    if (running) {
                        log.error(sm.getString("endpoint.accept.fail"), npe);
                    }
                } catch (Throwable t) {
                    ExceptionUtils.handleThrowable(t);
                    log.error(sm.getString("endpoint.accept.fail"), t);
                }
                // The processor will recycle itself when it finishes
            }
        }
    }

 前面说过,JIoEndpoint启动了多个Acceptor来处理请求,每个Acceptor都是一个线程,Acceptor的run方法里主要就是调用processSocket(socket),这是JIoEndpoint里的方法,进入这个方法看一下

 /**
     * Process a new connection from a new client. Wraps the socket so
     * keep-alive and other attributes can be tracked and then passes the socket
     * to the executor for processing.
     * 
     * @param socket    The socket associated with the client.
     * 
     * @return          <code>true</code> if the socket is passed to the
     *                  executor, <code>false</code> if something went wrong or
     *                  if the endpoint is shutting down. Returning
     *                  <code>false</code> is an indication to close the socket
     *                  immediately.
     */
    protected boolean processSocket(Socket socket) {
        // Process the request from this socket
        try {
            SocketWrapper<Socket> wrapper = new SocketWrapper<Socket>(socket);
            wrapper.setKeepAliveLeft(getMaxKeepAliveRequests());
            // During shutdown, executor may be null - avoid NPE
            if (!running) {
                return false;
            }
            getExecutor().execute(new SocketProcessor(wrapper));
        } catch (RejectedExecutionException x) {
            log.warn("Socket processing request was rejected for:"+socket,x);
            return false;
        } catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
            // This means we got an OOM or similar creating a thread, or that
            // the pool and its queue are full
            log.error(sm.getString("endpoint.process.fail"), t);
            return false;
        }
        return true;
    }

  方法的注释已经说的很明白了,它就是将socket包装了一下,以便扩展传递一些扩展属性,接下来调用 getExecutor().execute(new SocketProcessor(wrapper));getExecutor()在前面已经提到过,它是一个线程池对象,里面存放了一个个将要被执行的请求线程。这个SocketProcessor是JIoEndpoint里的另一个内部类,也是一个多线程:

 // ------------------------------------------- SocketProcessor Inner Class


    /**
     * This class is the equivalent of the Worker, but will simply use in an
     * external Executor thread pool.
     */
    protected class SocketProcessor implements Runnable {
        
        protected SocketWrapper<Socket> socket = null;
        protected SocketStatus status = null;
        
        public SocketProcessor(SocketWrapper<Socket> socket) {
            if (socket==null) throw new NullPointerException();
            this.socket = socket;
        }

        public SocketProcessor(SocketWrapper<Socket> socket, SocketStatus status) {
            this(socket);
            this.status = status;
        }

        @Override
        public void run() {
            boolean launch = false;
            synchronized (socket) {
                try {
                    SocketState state = SocketState.OPEN;

                    try {
                          //首先对ssl请求做特殊处理,如果不是ssl请求,这个方法什么也不做
                         // SSL handshake
                        serverSocketFactory.handshake(socket.getSocket());
                    } catch (Throwable t) {
                        ExceptionUtils.handleThrowable(t);
                        if (log.isDebugEnabled()) {
                            log.debug(sm.getString("endpoint.err.handshake"), t);
                        }
                        // Tell to close the socket
                        state = SocketState.CLOSED;
                    }
                    //如果不是ssl请求    
                    if ((state != SocketState.CLOSED)) {
                        //处理请求
                        if (status == null) {
                            state = handler.process(socket, SocketStatus.OPEN);
                        } else {
                            state = handler.process(socket,status);
                        }
                    }
                    if (state == SocketState.CLOSED) {
                        // Close socket
                        if (log.isTraceEnabled()) {
                            log.trace("Closing socket:"+socket);
                        }
                        countDownConnection();//处理连接数
                        try {
                            socket.getSocket().close();//关闭socket连接
                        } catch (IOException e) {
                            // Ignore
                        }
                    } else if (state == SocketState.OPEN){
                        socket.setKeptAlive(true);
                        socket.access();
                        launch = true;
                    } else if (state == SocketState.LONG) {
                        socket.access();
                        waitingRequests.add(socket);
                    }
                } finally {
                    if (launch) {
                        try {
                            getExecutor().execute(new SocketProcessor(socket, SocketStatus.OPEN));
                        } catch (NullPointerException npe) {
                            if (running) {
                                log.error(sm.getString("endpoint.launch.fail"),
                                        npe);
                            }
                        }
                    }
                }
            }
            socket = null;
            // Finish up this request
        }
        
    }

  我们看一下实际请求的处理state = handler.process(socket, SocketStatus.OPEN);这个handler是什么东西?具体的协议对象,在这里是Http11Protocol对象实例。我们先看一下Http11Protocol的类关系图:

                                                      http11Protocol类关系图

process方法在AbstractProtocol类的静态内部类AbstractConnectionHandler里:

public SocketState process(SocketWrapper<S> socket,
                SocketStatus status) {
            /**将socket从connections Map里移除,这只针对SocketState.LONG的情况有效**/              
            P processor = connections.remove(socket.getSocket());

            socket.setAsync(false);

            try {
                if (processor == null) {
                    processor = recycledProcessors.poll();//从池里取得一个processor
                }
                if (processor == null) {
                    processor = createProcessor();//没有就新建一个processor
                }

                initSsl(socket, processor);

                SocketState state = SocketState.CLOSED;
                do {
                    if (processor.isAsync() || state == SocketState.ASYNC_END) {
                        state = processor.asyncDispatch(status);
                    } else if (processor.isComet()) {//如果是comet
                        state = processor.event(status);//tomcat不支持comet,所以此方法只是简单的抛出异常
                    } else {//普通的处理
                        state = processor.process(socket);
                    }
    
                    if (state != SocketState.CLOSED && processor.isAsync()) {
                        state = processor.asyncPostProcess();
                    }
                } while (state == SocketState.ASYNC_END);

                if (state == SocketState.LONG) {
                    // In the middle of processing a request/response. Keep the
                    // socket associated with the processor. Exact requirements
                    // depend on type of long poll
                    longPoll(socket, processor);
                } else if (state == SocketState.OPEN){
                    // In keep-alive but between requests. OK to recycle
                    // processor. Continue to poll for the next request.
                    release(socket, processor, false, true);//释放processor
                } else {
                    // Connection closed. OK to recycle the processor.
                    release(socket, processor, true, false);//释放processor
                }
                return state;
            } catch(java.net.SocketException e) {
                // SocketExceptions are normal
                getLog().debug(sm.getString(
                        "ajpprotocol.proto.socketexception.debug"), e);
            } catch (java.io.IOException e) {
                // IOExceptions are normal
                getLog().debug(sm.getString(
                        "ajpprotocol.proto.ioexception.debug"), e);
            }
            // Future developers: if you discover any other
            // rare-but-nonfatal exceptions, catch them here, and log as
            // above.
            catch (Throwable e) {
                ExceptionUtils.handleThrowable(e);
                // any other exception or error is odd. Here we log it
                // with "ERROR" level, so it will show up even on
                // less-than-verbose logs.
                getLog().error(sm.getString("ajpprotocol.proto.error"), e);
            }
            release(socket, processor, true, false);
            return SocketState.CLOSED;
        }

先说下relese(socket,processor,true,false)方法,这个方法虽然带了4个参数,但目前实际使用的只有前2个参数,后2个直接没管了,不知道是留着后续扩展的目的?此方法在Http11Protocol类的内部类Http11ConnectionHandler

/**
         * Expected to be used by the handler once the processor is no longer
         * required.
         * 
         * @param socket            Not used in BIO
         * @param processor
         * @param isSocketClosing   Not used in HTTP
         * @param addToPoller       Not used in BIO
         */
        @Override
        public void release(SocketWrapper<Socket> socket,
                Http11Processor processor, boolean isSocketClosing,
                boolean addToPoller) {
            processor.recycle();
            recycledProcessors.offer(processor);
        }

 回去看processor吧,首先我们要知道我们的processor是哪个对象:

@Override
        protected Http11Processor createProcessor() {
            Http11Processor processor = new Http11Processor(
                    proto.getMaxHttpHeaderSize(), (JIoEndpoint)proto.endpoint,
                    proto.getMaxTrailerSize());
            processor.setAdapter(proto.adapter);
            processor.setMaxKeepAliveRequests(proto.getMaxKeepAliveRequests());
            processor.setKeepAliveTimeout(proto.getKeepAliveTimeout());
            processor.setConnectionUploadTimeout(
                    proto.getConnectionUploadTimeout());
            processor.setDisableUploadTimeout(proto.getDisableUploadTimeout());
            processor.setCompressionMinSize(proto.getCompressionMinSize());
            processor.setCompression(proto.getCompression());
            processor.setNoCompressionUserAgents(proto.getNoCompressionUserAgents());
            processor.setCompressableMimeTypes(proto.getCompressableMimeTypes());
            processor.setRestrictedUserAgents(proto.getRestrictedUserAgents());
            processor.setSocketBuffer(proto.getSocketBuffer());
            processor.setMaxSavePostSize(proto.getMaxSavePostSize());
            processor.setServer(proto.getServer());
            processor.setDisableKeepAlivePercentage(
                    proto.getDisableKeepAlivePercentage());
            register(processor);
            return processor;
        }

 Http11Processor与Http11Protocol有类似类关系图的Http11Processor--->AbstractHttp11Processor-->AbstractProcessor-->Processor

AbstractProcessor虽然是个抽象类,但它有自己的构造函数

public AbstractProcessor(AbstractEndpoint endpoint) {
        this.endpoint = endpoint;
        asyncStateMachine = new AsyncStateMachine(this);
        
        request = new Request();

        response = new Response();
        response.setHook(this);
        request.setResponse(response);

    }

 之所以提到这个构造函数,因为它生成了request和response对象,后面我们需要围绕这两个对象团团转,还是在此先供奉一下吧,把它老人家的底细弄清楚了,后面才不至于被这两活宝糊弄。

  我们回到processor.process(socket);的处理,这个方法所作的事情就是解析http请求数据,组装request和response对象,最后将response输出,详细的细节,我们下节讨论。到目前为止我们已经把请求请到家里来了,并且我们知道后面谁会去处理这些东西,后面接下来要解决的就是,如何去解析、处理这个请求了,欲知后事如何,且听下回分解。

 

 

 

 

  • 大小: 37.3 KB
分享到:
评论

相关推荐

    初中语文文摘社会请君入瓮除迷信

    而小孩以彼之道还施彼身,通过“请君入瓮”的方法,用郭宗林自己的逻辑反击,成功地打破了迷信的枷锁,展示了理性和逻辑的力量。 迷信在很多情况下是人们对未知世界的恐惧和不安的产物,它往往缺乏科学依据,但能够...

    (备战中考)中考语文课外文言文专练请君入瓮.docx

    (备战中考)中考语文课外文言文专练请君入瓮.docx

    初一文言文课外阅读练习题附答案.doc

    - 俊臣与兴方推事对食:正在一起处理案件并吃饭。 - 囚多不承:囚犯大多不承认罪行。 - 当为何法:应该采用什么方法。 - 因起谓兴曰:于是起身对周兴说。 2. “之”字的解释: - 太后命来俊臣鞫之:代指周兴。...

    人教版七年级下课外文言文阅读训练+答案.doc

    本文包含两篇文言文故事,分别是“请君入瓮”和“覆巢之下安有完卵”,以及“鲁人曹沫”和“马价十倍”。下面是针对这些故事的知识点解析: 1. “请君入瓮”讲述了唐朝时期来俊臣审讯周兴的故事。来俊臣利用周兴...

    六年级基训辅导PPT教案学习.pptx

    - “请君入瓮”源自酷吏的典故,寓意以彼之道还治彼身,提醒人们不要做害人之事,同时也揭示了灵活应对的方法。 - “买椟还珠”警告我们不要只看表面,忽视实质。 - “郑人买履”教育我们要根据实际情况灵活处理...

    谈判-课件(新).doc

    退让并非轻易之举,而是应当遵循一定的原则和方法。首先,理解退让的基本概念,它是谈判双方为了接近共同目标,自愿降低自己的期望值,以促进协议的形成。有效的退让并不意味着牺牲利益,而是通过策略性的让步来推进...

    外汇保证金交易营销话术.ppt

    6. 客户异议处理:销售人员需要掌握异议处理的技巧,例如,如果客户表示异议,可以引导客户了解新的投资方式,或者提供更多的信息,解决客户的疑问。 7. 客户关系建立:销售人员需要建立与客户的关系,例如,通过...

    小学数学数学故事探险故事荒岛历险5步长之谜

    故事中的"5步长之谜"涉及到长度单位、测量和逻辑推理。 首先,故事中提到古埃及人使用“腕尺”作为长度单位,这是一种基于人体部位的标准,但因为人的前臂长度不同,所以选择国王的前臂作为标准,确保测量的一致性...

    七年级下课外文言文阅读训练(详细版).doc

    在《请君入瓮》的故事中,来俊臣运用了“以其人之道,还治其人之身”的策略,巧妙地利用周兴自己的残忍手段来审问他。周兴提议用大瓮烤火的方式逼囚犯招供,结果来俊臣将这个方法用来对付周兴自身,使其不得不承认...

    初中语文文摘社会今夜谁也别睡

    5. **文化融合**:卢沛宁用“请君入瓮”的中国故事来传达信息,体现了跨文化的沟通技巧。在日益全球化的IT行业,理解和运用不同文化背景的知识可以增强团队的多元化,促进创新。 6. **决策的预见性**:奥巴马提前...

    学校六一儿童节游园活动方案.doc

    该方案旨在通过一系列趣味盎然的游戏活动,既让孩子们在快乐中度过节日,又能在活动中锻炼能力,增进知识,实现寓教于乐,全面推动素质教育的实施。 活动定于2020年5月31日的上午8:30在学校操场举行。在活动筹备...

    七年级下语文课外文言文复习练习题.doc

    3. 成语来源:第一篇文言文可以提炼出成语“请君入瓮”,意指以其人之道还治其人之身,用来讽刺那些设计害人最后反被他人利用的人。 4. 人性与道德:第二篇文言文讲述了秦西巴放生小鹿的故事,展示了人物的道德选择...

    做人做事三局:设局、入局、破局.doc

    良好的沟通技巧,如请君入瓮的说话布局法,能帮助我们更好地影响他人。同时,了解自己和他人,制定策略,利用各种资源,如优秀的企业文化,都能助我们取得成功。 破局,即突破困境,寻求胜利。这要求我们运用战术,...

    备战2016年高考语文晨读晚练第26周忙碌与休闲1

    文中讨论了“快哉”之意,揭示了人们面对逆境时的心态调整,提出即使在贬谪之中也能找到快乐,表达了士人在世的豁达态度。 5. 文化历史:文章提到了历史上的人物如曹孟德、孙仲谋、周瑜、陆逊等,这些都是三国时期...

    国学小名士小学组.doc

    25. 中庸之道的“博学之,审问之,慎思之,明辨之,笃行之”是儒家强调的学习方法。 26. “孔子登东山而小鲁,登泰山而小天下”体现了孔子的广阔胸怀和远大理想。 27. 西湖的白堤得名于唐代白居易在杭州任职时所做的...

    六年级语文下册 期中检测试题(无答案) 人教版 试题.doc

    4. 成语填充:要求学生填写合适的成语,如“循循善诱、斤斤计较、栩栩如生、天籁之音、欣欣向荣、源源不断、面面俱到、默默无闻”,这些都是常见的成语,旨在锻炼学生的记忆和应用成语的能力。 5. 词语搭配与补充:...

    高中历史热门阅读司马光砸的真的是缸么?素材

    然而,通过对历史文献的分析,我们可以发现这个故事可能并非我们想象中的那样。 司马光,字君实,是北宋时期的著名政治家、史学家,编纂了重要的历史著作《资治通鉴》。他的童年故事——砸缸救人,讲述了他在孩童...

    100道中华文化常识题与答案.docx

    36. “请君入瓮”中的“请”是针对周兴,意为以其人之道还治其人之身。 37. “桃花潭水深千尺,不及汪伦送我情”中的“我”是指李白。 38. “阳春白雪”和“下里巴人”最初分别指的是高雅和通俗的音乐。 39. “路...

    中国古代官僚体制.pdf

    而“请君入瓮”的故事则揭示了酷吏滥用权力可能导致冤假错案的问题。 古代官僚机构的设计旨在强化皇权,确保帝国的有效治理。秦汉时期,设立了丞相协助皇帝管理国家,随后发展为隋唐的三省六部制,将权力进一步分化...

    100道中华文化常识题和答案解析.doc

    36. “请君入瓮”中的“请”是指周兴,这个成语源自武则天时期的一个典故。 37. “桃花潭水深千尺,不及汪伦送我情”中的“我”是李白,这首诗表达了他对友人汪伦的深厚友情。 38. “阳春白雪”和“下里巴人”最初...

Global site tag (gtag.js) - Google Analytics