阅读TOMCAT 8源码(一)

xiaoxiao2021-02-28  98

阅读TOMCAT 8源码(一)

了解TOMCAT工作主体流程 :

启动监听端口创建线程

tomcat 是通过socket服务及多线程来构建容器的,并通过java的nio来获取请求数据并写回返回数据

1、启动

启动是在网上阅读其它前辈的笔记的,目前学习源码感觉找源头比较痛苦,TOMCAT还好,有一个统计一的源码入口,其它的框架类感觉不太好找,有好的方法同学请不吝赐教 TOMCAT的启动类型是Bootstrap开始,这个类有一个main方法,使用Debug方式阅读每行代码的运行。 这个类许多都是做了初始化操作,具体关注StandradContext(很多基本服务都是存在该实例内或由这个实例窗口提供 ),NioeEndPoint类主要处理请求服务及分发。 启动时会做许多初始化的操作,比如实例化NioEndPoint、线程池等

2、网络

TOMCAT本身还是以SOCKET来监听网络端口的请求,他创建一个ServerSocket来绑定端口号,并通过while(true)来监听请求,所有的请求都是监听端口,并获取端口的通过数据。 TOMCAT默认通过ServerSocket来监听8080端口,用一个单独的NioEndPoint.Acceptor 线程来监听ServerSocket.accept(),当有请求时,NioEndPoint.Poller 线程会用一个标签死循环来监听请求通道是否有数据,如果有的话就会处理,创建一个SocketProcess线程来处理这个请求,该线程是使用线程池来处理,在NioEndPoint类内,使用了3个内部线程类(Acceptor,Poller,SocketProcessor)用于处理请求。NioEndPoint.Acceptor类专门用于监听服务端口请求。NioEndPoint.Poller用于获取请求数据,Poller其实用的是一个poller数组(2个元素)用于处理线程,tomcat默认的线程池处理数所有的请求,所以tomcat的并发极限默认也是200,Poller获取到请求通道后,执行SocketProcess线程,并通过线程池执行这个线程。

3、线程

在tomcat中用的最多 的就是多线程及nio,所有的请求及监听都是用多线程,所有的数据获取及返回都是用的nio。线程的集中处理都是NioEndPoint中,可以重点看这个类,处理逻辑中网络一节中有说明。获取数据都是用nio,获取到的请求都是用tomcat的Request类来构造,这个类实现了HttpServletRequest,并构造Response类,该类实现了HttpServletResponse,构造完请求后,及返回类后,调用servlet的service方法,并返回response的执行状态码,通过由代码根据结果的不同状态码生成对应的HTML界面。 Request的SessionID,不是一开始生成 的,而是在获取的时候生成,用的也JAVA本身SecureRandom来生成,并通过缓存判断是否与历史重复,重复再重新生成.

Poller监听Socket请求通道,处理Socket通道 是通过一个2个元素大小的数组

public void run() { // Loop until destroy() is called while (true) { try { // Loop if endpoint is paused while (paused && (!close) ) { try { Thread.sleep(100); } catch (InterruptedException e) { // Ignore } } boolean hasEvents = false; // Time to terminate? if (close) { events(); timeout(0, false); try { selector.close(); } catch (IOException ioe) { log.error(sm.getString( "endpoint.nio.selectorCloseFail"), ioe); } break; } else { hasEvents = events(); } try { if ( !close ) { 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); } wakeupCounter.set(0); } if (close) { events(); timeout(0, false); try { selector.close(); } catch (IOException ioe) { log.error(sm.getString( "endpoint.nio.selectorCloseFail"), ioe); } break; } } catch (Throwable x) { ExceptionUtils.handleThrowable(x); log.error("",x); continue; } //either we timed out or we woke up, process events first if ( keyCount == 0 ) hasEvents = (hasEvents | events()); Iterator<SelectionKey> 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(); KeyAttachment attachment = (KeyAttachment)sk.attachment(); // Attachment may be null if another thread has called // cancelledKey() if (attachment == null) { iterator.remove(); } else { attachment.access(); iterator.remove(); processKey(sk, attachment); } }//while //process timeouts timeout(keyCount,hasEvents); if ( oomParachute > 0 && oomParachuteData == null ) checkParachute(); } catch (OutOfMemoryError oom) { try { oomParachuteData = null; releaseCaches(); log.error("", oom); }catch ( Throwable oomt ) { try { System.err.println(oomParachuteMsg); oomt.printStackTrace(); }catch (Throwable letsHopeWeDontGetHere){ ExceptionUtils.handleThrowable(letsHopeWeDontGetHere); } } } }//while stopLatch.countDown(); }

SocketProcess线程处理请求,由线程池运行

protected boolean processSocket(KeyAttachment attachment, SocketStatus status, boolean dispatch) { try { if (attachment == null) { return false; } SocketProcessor sc = processorCache.pop(); if ( sc == null ) sc = new SocketProcessor(attachment, status); else sc.reset(attachment, status); Executor executor = getExecutor(); if (dispatch && executor != null) { executor.execute(sc); } else { sc.run(); } } catch (RejectedExecutionException ree) { log.warn(sm.getString("endpoint.executor.fail", attachment.getSocket()), ree); return false; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); // This means we got an OOM or similar creating a thread, or that // the pool and its queue are full log.error(sm.getString("endpoint.process.fail"), t); return false; } return true; }

说明

第一阶段了解了TOMCAT内部的运行,对于配置文件 的加载及会话区别还未仔细看

转载请注明原文地址: https://www.6miu.com/read-77922.html

最新回复(0)