Tomcat处理http请求之源码分析 | 京东云技术团队

2023-05-29 0 851

原副标题:Tomcat处置http允诺之源代码预测 | 天猫云控制技术项目组

旅。

1 允诺包装袋处置

tomcat 模块 Connector 在开启的这时候会窃听路由器。以 JIoEndpoint 为例,在其 Acceptor 类中:

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

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);

}

}

}

……

}

求数据,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 作为窃听者。他的生成图示:

Tomcat处理http请求之源码分析 | 京东云技术团队

通过 Mapper 找到了该允诺对应的 Context 和 Wrapper 后,CoyoteAdapter 将包装袋好的允诺交给 Container 处置。

3 Container 处置允诺流程

从下面的代码片段,我们很容易追踪整个 Container 的调用链: 用时序图画出来则是:

Tomcat处理http请求之源码分析 | 京东云技术团队

最终 StandardWrapperValve 将允诺交给 Servlet 处置完成。至此一次 http 允诺处置完毕。

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务