文档章节

Tomcat源码分析----一个http请求的经历

圆梦巨人
 圆梦巨人
发布于 2017/07/12 11:12
字数 890
阅读 11
收藏 0

摘要: 本章节对http请求到tomcat服务端,从监听到处理过程展现给大家。

1 请求获取与包装处理 本章节对http请求到服务端,从监听到处理展现给大家。 在上文中有分析Connector在启动的时候会监听端口。继续以JIoEndpoint为例,在其Accptor类中:

protected class Acceptor extends AbstractEndpoint.Acceptor { @Override public void run() { while (running) { …… try { //当前连接数 countUpOrAwaitConnection(); Socket socket = null; try { //取出队列中的连接请求 socket = serverSocketFactory.acceptSocket(serverSocket); } catch (IOException ioe) { countDownConnection(); } if (running && !paused && setSocketOptions(socket)) { //处理请求 if (!processSocket(socket)) { countDownConnection(); closeSocket(socket); } } else { countDownConnection(); // Close socket right away closeSocket(socket); } } …… } } } 在上面的代码中,socket = serverSocketFactory.acceptSocket(serverSocket);与客户端建立连接,将连接的socket交给processSocket(socket)来处理。在processSocket中,对socket进行包装一下交给线程池来处理:

protected boolean processSocket(Socket socket) { try { SocketWrapper<Socket> wrapper = new SocketWrapper<Socket>(socket); wrapper.setKeepAliveLeft(getMaxKeepAliveRequests()); wrapper.setSecure(isSSLEnabled()); //交给线程池处理连接 getExecutor().execute(new SocketProcessor(wrapper)); } …… return true; } 线程池处理的任务SocketProccessor,通过代码分析:

protected class SocketProcessor implements Runnable {

protected SocketWrapper<Socket> socket = null;
protected SocketStatus status = null;

[@Override](https://my.oschina.net/u/1162528)
public void run() {
    boolean launch = false;
    synchronized (socket) {
        SocketState state = SocketState.OPEN;
        try {
            serverSocketFactory.handshake(socket.getSocket());
        } 
        ……
        if ((state != SocketState.CLOSED)) {
            //委派给Handler来处理
            if (status == null) {
                state = handler.process(socket, SocketStatus.OPEN_READ);
            } else {
                state = handler.process(socket,status);
            }
        }}}
        ……

} 即在SocketProcessor中,将Socket交给handler处理,这个handler就是在Http11Protocol的构造方法中赋值的Http11ConnectionHandler,在该类的父类process方法中通过请求的状态,来创建Http11Processor处理器进行相应的处理,切到Http11Proccessor的父类AbstractHttp11Proccessor中。

public SocketState process(SocketWrapper socketWrapper) { RequestInfo rp = request.getRequestProcessor(); rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);

// Setting up the I/O
setSocketWrapper(socketWrapper);
getInputBuffer().init(socketWrapper, endpoint);
getOutputBuffer().init(socketWrapper, endpoint);

while (!getErrorState().isError() && keepAlive && !comet && !isAsync() &&
        upgradeInbound == null &&
        httpUpgradeHandler == null && !endpoint.isPaused()) {
    ……
    if (!getErrorState().isError()) {
        // Setting up filters, and parse some request headers
        rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
        try {
            //请求预处理
            prepareRequest();
        } 
        ……
    }
    ……
    if (!getErrorState().isError()) {
        try {
            rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
            //交由适配器处理
            adapter.service(request, response);

            if(keepAlive && !getErrorState().isError() && (
                    response.getErrorException() != null ||
                            (!isAsync() &&
                            statusDropsConnection(response.getStatus())))) {
                setErrorState(ErrorState.CLOSE_CLEAN, null);
            }
            setCometTimeouts(socketWrapper);
        } 
    }
}
……

}
代码很长,删掉的部分比较多,在这个方法里面,可以看到Request和Response的生成,从Socket中获取请求数据,keep-alive处理,数据包装等等信息,最后交给了CoyoteAdapter的service方法

2 请求传递给Container 在CoyoteAdapter的service方法中,主要有2个任务:

第一个是org.apache.coyote.Request和org.apache.coyote.Response到继承自HttpServletRequest的org.apache.catalina.connector.Request和org.apache.catalina.connector.Response转换,和Context,Wrapper定位。 第二个是将请求交给StandardEngineValve处理。 public void service(org.apache.coyote.Request req, org.apache.coyote.Response res) { …… postParseSuccess = postParseRequest(req, request, res, response); …… connector.getService().getContainer().getPipeline().getFirst().invoke(request, response); …… } 在postParseRequest方法中代码片段:

connector.getMapper().map(serverName, decodedURI, version, request.getMappingData()); request.setContext((Context) request.getMappingData().context); request.setWrapper((Wrapper) request.getMappingData().wrapper);

request通过URI的信息找到属于自己的Context和Wrapper。而这个Mapper保存了所有的容器信息,不记得的同学可以回到Connector的startInternal方法中,最有一行代码是mapperListener.start(); 在MapperListener的start()方法中,

public void startInternal() throws LifecycleException {

setState(LifecycleState.STARTING);
findDefaultHost();

Engine engine = (Engine) connector.getService().getContainer();
addListeners(engine);

Container[] conHosts = engine.findChildren();
for (Container conHost : conHosts) {
    Host host = (Host) conHost;
    if (!LifecycleState.NEW.equals(host.getState())) {
        registerHost(host);
    }
}

} MapperListener.startInternal()方法将所有Container容器信息保存到了mapper中。那么,现在初始化把所有容器都添加进去了,如果容器变化了将会怎么样?这就是上面所说的监听器的作用,容器变化了,MapperListener作为监听者。他的生成图示: screenshot

通过Mapper找到了该请求对应的Context和Wrapper后,CoyoteAdapter将包装好的请求交给Container处理。

3 Container处理请求流程 从下面的代码片段,我们很容易追踪整个Container的调用链: screenshot 用时序图画出来则是: screenshot 最终StandardWrapperValve将请求交给Servlet处理完成 pipeline+valve处理:

© 著作权归作者所有

圆梦巨人
粉丝 12
博文 174
码字总数 145692
作品 0
西城
程序员
私信 提问
Tomcat7.0源码分析——请求原理分析(中)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/beliefer/article/details/51828607 前言   在《Tomcat7.0源码分析——请求原理分析(上)》一文中已经介绍...

泰山不老生
2016/07/07
0
0
Tomcat源码分析之getParameter(String)与getQueryString()

欢迎点击「算法与编程之美」↑关注我们! 本文首发于微信公众号:"算法与编程之美",欢迎关注,及时了解更多此系列博客。 本文有些地方的描述对某些人来说可能比较罗嗦,如果想直接进入正题,...

算法与编程之美
2013/04/07
5.7K
1
Tomcat源码分析

下面谈谈我对Tomcat架构的理解 总体架构: 1、面向组件架构 2、基于JMX 3、事件侦听 1)面向组件架构 tomcat代码看似很庞大,但从结构上看却很清晰和简单,它主要由一堆组件组成,如Server、...

五大三粗
2015/09/28
181
0
Tomcat7.0源码分析——请求原理分析(上)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/beliefer/article/details/51645799 前言   谈起Tomcat的诞生,最早可以追溯到1995年。近20年来,Tomcat始终...

泰山不老生
2016/06/30
0
0
Tomcat处理HTTP请求源码分析(上)

很多开源应用服务器都是集成tomcat作为web container的,而且对于tomcat的servlet container这部分代码很少改动。这样,这些应用服务器的性能基本上就取决于Tomcat处理HTTP请求的connector模...

taote
2011/12/21
724
0

没有更多内容

加载失败,请刷新页面

加载更多

如何在NSString中添加百分号

我想在数字后加一个百分号。 大概是75%。 我该怎么做? 我试过了: [NSString stringWithFormat:@"%d\%", someDigit]; 但这对我没有用。 #1楼 如果在某些情况下有帮助,则可以使用unicode...

javail
25分钟前
35
0
Java中的原生关键字是什么?

在玩这个谜题 (这是Java关键字琐事游戏)时,我遇到了native关键字。 Java中的native关键字用于什么? #1楼 实现本机代码的函数被声明为本机。 Java本机接口(JNI)是一个编程框架,使在Jav...

技术盛宴
今天
54
0
博通与苹果达成150亿美元协议,覆盖未来3年苹果产品

  据外媒报道,芯片供应商博通(Broadcom)宣布已与苹果公司签署了一份协议,为其提供“高性能的无线组件和模块”,博通表示,这些芯片将在未来 3 年半的时间内用于自 2020 年 1 月份以后发...

水果黄瓜
今天
95
0
《算法》笔记 17 - 数据压缩

读写二进制数据 基因组数据的压缩 游程编码 位图 霍夫曼压缩 前缀码和单词查找树 构造前缀码的单词查找树 写入和读取单词查找树 使用前缀码压缩 使用前缀码展开 LZW压缩 LZW的单词查找树 LZ...

zhixin9001
今天
55
0
#技术分享# 再论DDD之【实体】建模

2020年春节第一天,早早醒来,出去晨跑一下,目前武汉以及周边的疫情处于红色报警状态,今年春节宅家是最安全的做法。闲暇之余,还需要探索技术,跑步中忽然想到了【忒修斯之船】的小故事,感...

边缘行者
今天
88
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部