Tomcat处理请求的线程模型详解

网友投稿 374 2022-08-18


Tomcat处理请求的线程模型详解

目录一、前言二、tomcat结构三、探讨tomcat是如何处理请求1、初始化2、如何处理客户端请求总结

一、前言

java后端项目,运行在容器tomcat中,由于现在springboot的内置tomcat容器,其默认配置屏蔽了很多对tomcat的认知,但是对tomcat的学习和认识是比较重要的,所以专门查资料加深了理解,本文主要讨论在springboot集成下的tomcat9的请求过程,线程模型为NIO。

二、tomcat结构

找了张结构图,每个模块的意思和作用就不详解了,可以搜其他文章

三、探讨tomcat是如何处理请求

自己画了一个connector的结构

1、初始化

在springboot启动后,org.springframework.context.support.AbstractApplicationContext#finishRefresh,这里进去调用org.springframework.boot.web.servlet.context.WebServerStartStopLifecycle.start()方法启动TomcatWebServer,初始化tomcat。

通过这样的调用链到达org.apache.tomcat.util.net.NioEndpoint#startInternal(),进行初始化Endpoint中的Acceptor和Poller,这两者都实现了Runnable接口,初始化后就通过线程start启动了。

2、如何处理客户端请求

Acceptor: 接收器,作用是接受scoket网络请求,并调用setSocketOptions()封装成为NioSocketWrapper,并注册到Poller的events中。注意查看run方法org.apache.tomcat.util.net.Acceptor#run

@Override

public void run() {

int errorDelay = 0;

try {

// Loop until we receive a shutdown command

while (!stopCalled) {

// Loop if endpoint is paused

while (endpoint.isPaused() && !stopCalled) {

state = AcceptorState.PAUSED;

try {

Thread.sleep(50);

} catch (InterruptedException e) {

// Ignore

}

}

if (stopCalled) {

break;

}

state = AcceptorState.RUNNING;

try {

//if we have reached max connections, wait

endpoint.countUpOrAwaitConnection();

// Endpoint might have been paused while waiting for latch

// If that is the case, don't accept new connections

if (endpoint.isPaused()) {

continue;

}

U socket = null;

try {

// 等待下一个请求进来

socket = endpoint.serverSocketAccept();

} catch (Exception ioe) {

// We didn't get a socket

endpoint.countDownConnection();

if (endpoint.isRunning()) {

// Introduce delay if necessary

errorDelay = handleExceptionWithDelay(errorDelay);

// re-throw

throw ioe;

} else {

break;

}

}

// Successful accept, reset the error delay

errorDelay = 0;

// Configure the socket

if (!stopCalled && !endpoint.isPaused()) {

// 注册socket到Poller,生成PollerEvent事件

if (!endpoint.setSocketOptions(socket)) {

endpoint.closeSocket(socket);

}

} else {

endpoint.destroySocket(socket);

}

} catch (Throwable t) {

ExceptionUtils.handleThrowable(t);

String msg = sm.getString("endpoint.accept.fail");

// APR specific.

// Could push this down but not sure it is worth the trouble.

if (t instanceof Error) {

Error e = (Error) t;

if (e.getError() == 233) {

// Not an error on HP-UX so log as a warning

// so it can be filtered out on that platform

// See bug 50273

log.warn(msg, t);

} else {

log.error(msg, t);

}

} else {

log.error(msg, t);

}

}

}

} finally {

stopLatch.countDown();

}

state = AcceptorState.ENDED;

}

Poller:轮询器,轮询是否有事件达到,有请求事件到达后,以NIO的处理方式,查询Selector取出所有请求,遍历每个请求的需求,分配给Executor线程池执行。查看org.apache.tomcat.util.net.NioEndpoint.Poller#run()

public void run() {

// Loop until destroy() is called

while (true) {

boolean hasEvents = false;

try {

if (!close) {

hasEvents = events();

if (wakeupCounter.getAndSet(-1) > 0) {

// If we are here, means we have other stuff to do

// Do a non blocking select

keyCount = selector.selectNow();

} else {

keyCount = selector.select(selectorTimeout);

}

http:// wakeupCounter.set(0);

}

if (close) {

events();

timeout(0, false);

try {

selector.close();

} catch (IOException ioe) {

log.error(sm.getString("endpoint.nio.selectorCloseFail"), ioe);

}

break;

}

// Either we timed out or we woke up, process events first

if (keyCount == 0) {

hasEvents = (hasEvents | events());

}

} catch (Throwable x) {

ExceptionUtils.handleThrowable(x);

log.error(sm.getString("endpoint.nio.selectorLoopError"), x);

continue;

}

//查询selector取出所有请求

Iterator iterator =

keyCount > 0 ? selector.selectedKeys().iterator() : null;

// Walk through the collection of ready keys and dispatch

// any active event.

while (iterator != null && iterator.hasNext()) {

SelectionKey sk = iterator.next();

iterator.remove();

NioSocketWrapper socketWrapper = (NioSocketWrapper) sk.attachment();

//处理请求key

if (socketWrapper != null) {

processKey(sk, socketWrapper);

}

}

http:// // Process timeouts

timeout(keyCount,hasEvents);

}

getStopLatch().countDown();

}

请求过程大致如下图:

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java 9 中的模块Module系统
下一篇:spring security结合jwt实现用户重复登录处理
相关文章

 发表评论

暂时没有评论,来抢沙发吧~