阅读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内部的运行,对于配置文件 的加载及会话区别还未仔细看