博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Tomcat源码分析----一个http请求的经历
阅读量:7235 次
发布时间:2019-06-29

本文共 5146 字,大约阅读时间需要 17 分钟。

hot3.png

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

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

protected class Acceptor extends AbstractEndpoint.Acceptor { 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 = 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/OsetSocketWrapper(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处理:

转载于:https://my.oschina.net/u/3229047/blog/1358171

你可能感兴趣的文章
ASP.NET Web API 过滤器创建、执行过程(二)
查看>>
python读取excel(xlrd)
查看>>
RSA的公钥、私钥
查看>>
Uniform Resource Identifier
查看>>
UWP 浏览本地图片及对图片的裁剪
查看>>
Xshell高级后门完整分析报告
查看>>
一起谈.NET技术,数组排序方法的性能比较(3):LINQ排序实现分析
查看>>
括号自动补全
查看>>
Redis复制与可扩展集群搭建
查看>>
Express入门教程:一个简单的博客
查看>>
一份React-Native学习指南-感谢分享
查看>>
在Linux中使用VS Code编译调试C++项目
查看>>
JS创建select的optgroup
查看>>
win7无法ping通原因
查看>>
Javascript综合手册
查看>>
宏定义中使用do{}while(0)的好处 (转载)
查看>>
div 分页
查看>>
POJ_2392 Space Elevator(多重背包)
查看>>
常用user agent
查看>>
html中的caption是什么用
查看>>