本文主要向大家展示“Tomcat9请求处理流程和启动部署流程示例分析”,简单易懂,条理清晰,希望能帮大家解惑。让边肖带领大家学习和研究文章《Tomcat9请求处理流程和启动部署流程实例分析》。
Overview
连接器启动后,将为请求处理的不同阶段启动一组线程。
接受者线程组用于接受新连接,封装新连接,并选择一个轮询器将新连接添加到轮询器的事件队列中。
轮询线程组。用于监视套接字事件,当套接字可读或可写时,等等。封装套接字并将其添加到工作线程池的任务队列中。
工作线程组。用于处理请求,包括分析请求消息和创建请求对象,调用容器的管道进行处理。
接受者、轮询者和工作者所在的线程池执行器在NioEndpoint中维护。
Connector Init and Start
ServerSocket(),通过ServerSocketChannel.open()打开一个服务器套接字,默认绑定到端口8080,默认连接等待队列长度为100。当超过100个时,服务将被拒绝。我们可以通过在conf/server.xml中配置连接器的acceptCount属性来自定义连接器
CreateExecutor()用于创建工作线程池。默认情况下,将启动10个Worker线程,在Tomcat处理请求期间,最多不会超过200个woker。我们可以通过在conf/server.xml中配置连接器的minSpareThreads和maxThreads来自定义这两个属性
轮询器用于检测就绪套接字。默认情况下不超过2个,math.min (2,runtime.getruntime()。可用处理器());我们可以通过配置pollerThreadCount对其进行自定义。
接受者用于接受新的连接。默认值为1。我们可以通过配置acceptorThreadCount对其进行自定义。
Request Process
Acceptor
启动后,接受者将在ServerSocketChannel.accept()中阻止;方法,该方法在新连接到达时返回一个SocketChannel。
配置完套接字后,将套接字打包到NioChannel中,并将其注册到Poller。其价值在于,我们在开始时启动了许多轮询器线程,当注册时,连接被公平地分配给每个轮询器。NioEndpoint维护一组轮询器。当一个连接被分配给轮询器[index]时,下一个连接将被分配给轮询器[(index 1)% poller . length]。
addEvent()方法将套接字添加到此轮询器的轮询中。
nt 队列中。到此 Acceptor 的任务就完成了。
Poller
-
selector.select(1000)。当 Poller 启动后因为 selector 中并没有已注册的 Channel,所以当执行到该方法时只能阻塞。所有的 Poller 共用一个 Selector,其实现类是 sun.nio.ch.EPollSelectorImpl
-
events() 方法会将通过 addEvent() 方法添加到事件队列中的 Socket 注册到 EPollSelectorImpl,当 Socket 可读时,Poller 才对其进行处理
-
createSocketProcessor() 方法将 Socket 封装到 SocketProcessor 中,SocketProcessor 实现了 Runnable 接口。worker 线程通过调用其 run() 方法来对 Socket 进行处理。
-
execute(SocketProcessor) 方法将 SocketProcessor 提交到线程池,放入线程池的 workQueue 中。workQueue 是 BlockingQueue 的实例。到此 Poller 的任务就完成了。
Worker
-
worker 线程被创建以后就执行 ThreadPoolExecutor 的 runWorker() 方法,试图从 workQueue 中取待处理任务,但是一开始 workQueue 是空的,所以 worker 线程会阻塞在 workQueue.take() 方法。
-
当新任务添加到 workQueue后,workQueue.take() 方法会返回一个 Runnable,通常是 SocketProcessor,然后 worker 线程调用 SocketProcessor 的 run() 方法对 Socket 进行处理。
-
createProcessor() 会创建一个 Http11Processor, 它用来解析 Socket,将 Socket 中的内容封装到 Request 中。注意这个 Request 是临时使用的一个类,它的全类名是 org.apache.coyote.Request,
-
postParseRequest() 方法封装一下 Request,并处理一下映射关系(从 URL 映射到相应的 Host、Context、Wrapper)。
-
CoyoteAdapter 将 Rquest 提交给 Container 处理之前,并将 org.apache.coyote.Request 封装到 org.apache.catalina.connector.Request,传递给 Container 处理的 Request 是 org.apache.catalina.connector.Request。
-
connector.getService().getMapper().map(),用来在 Mapper 中查询 URL 的映射关系。映射关系会保留到 org.apache.catalina.connector.Request 中,Container 处理阶段 request.getHost() 是使用的就是这个阶段查询到的映射主机,以此类推 request.getContext()、request.getWrapper() 都是。
-
connector.getService().getContainer().getPipeline().getFirst().invoke() 会将请求传递到 Container 处理,当然了 Container 处理也是在 Worker 线程中执行的,但是这是一个相对独立的模块,所以单独分出来一节。
Container
-
需要注意的是,基本上每一个容器的 StandardPipeline 上都会有多个已注册的 Valve,我们只关注每个容器的 Basic Valve。其他 Valve 都是在 Basic Valve 前执行。
-
request.getHost().getPipeline().getFirst().invoke() 先获取对应的 StandardHost,并执行其 pipeline。
-
request.getContext().getPipeline().getFirst().invoke() 先获取对应的 StandardContext,并执行其 pipeline。
-
request.getWrapper().getPipeline().getFirst().invoke() 先获取对应的 StandardWrapper,并执行其 pipeline。
-
最值得说的就是 StandardWrapper 的 Basic Valve,StandardWrapperValve
-
allocate() 用来加载并初始化 Servlet,值的一提的是 Servlet 并不都是单例的,当 Servlet 实现了 SingleThreadModel 接口后,StandardWrapper 会维护一组 Servlet 实例,这是享元模式。当然了 SingleThreadModel在 Servlet 2.4 以后就弃用了。
-
createFilterChain() 方法会从 StandardContext 中获取到所有的过滤器,然后将匹配 Request URL 的所有过滤器挑选出来添加到 filterChain 中。
-
doFilter() 执行过滤链,当所有的过滤器都执行完毕后调用 Servlet 的 service() 方法。
以上是“Tomcat9请求处理流程与启动部署过程的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!
内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/142790.html