1. tomcat 核心组件
Server
Service
ProtocalHanler
EndPoint
ThreadPoolExecutor
Processor
Adapater
Container
engine
host
context
wrapper
2. tomcat 启动流程
Lifecycle接口实现生命周期
LifeCycleBase生命周期的基类
Container接口实现容器的组合模块
ContainerBase容器的基类
* <pre>
* start()
* -----------------------------
* | |
* | init() |
* NEW -?-- INITIALIZING |
* | | | | ------------------?-----------------------
* | | |auto | | |
* | | \|/ start() \|/ \|/ auto auto stop() |
* | | INITIALIZED --?-- STARTING_PREP --?- STARTING --?- STARTED --?--- |
* | | | | |
* | |destroy()| | |
* | --?-----?-- ------------------------?-------------------------------- ^
* | | | |
* | | \|/ auto auto start() |
* | | STOPPING_PREP ----?---- STOPPING ------?----- STOPPED -----?-----
* | \|/ ^ | ^
* | | stop() | | |
* | | -------------------------- | |
* | | | | |
* | | | destroy() destroy() | |
* | | FAILED ----?------ DESTROYING ---?----------------- |
* | | ^ | |
* | | destroy() | |auto |
* | --------?----------------- \|/ |
* | DESTROYED |
* | |
* | stop() |
* ----?-----------------------------?------------------------------
核心类图
PlantUml
@startuml tomcat
Bootstrap -> Bootstrap: main()
Bootstrap -> Catalina : load()
Catalina -> StandardServer: initInternal()
StandardServer -> StandardService : initInternal()
StandardService -> StandardEngine : initInternal()
StandardService -> Executor : init()
StandardService -> mapperListener : init()
Bootstrap -> Catalina: start()
Catalina -> StandardServer : startInternal()
StandardServer -> StandardService : startInternal()
StandardService -> StandardEngine : startInternal()
StandardService -> StandardThreadExecutor : startInternal()
StandardService -> mapperListener : startInternal()
StandardEngine -> StandardHost : startInternal()
StandardHost -> HostConfig : lifecycleEvent()
HostConfig -> HostConfig :deployApps()
HostConfig -> StandardContext:
StandardContext -> ServletContainerInitializer : startInternal()
ServletContainerInitializer -> SpringServletContainerInitializer: onStratUp()
@enduml
?
3. tomcat 核心请求流程
?
核心是Pipeline-Valve 是责任链模式
在基类ContainerBase中构建一个Pipeline数组作为责任链
以StandardEngine容器为例?
/**
* Create a new StandardEngine component with the default basic Valve.
*/
public StandardEngine() {
super();
// 在构造方法中塞入StandardEngineValve 最为最后一个Valve
pipeline.setBasic(new StandardEngineValve());
/* Set the jmvRoute using the system property jvmRoute */
try {
setJvmRoute(System.getProperty("jvmRoute"));
} catch(Exception ex) {
log.warn(sm.getString("standardEngine.jvmRouteFail"));
}
// By default, the engine will hold the reloading thread
backgroundProcessorDelay = 10;
}
执行下一个容器的Valve
还是以StandardEngine为例子
/**
* Select the appropriate child Host to process this request,
* based on the requested server name. If no matching Host can
* be found, return an appropriate HTTP error.
*
* @param request Request to be processed
* @param response Response to be produced
*
* @exception IOException if an input/output error occurred
* @exception ServletException if a servlet error occurred
*/
@Override
public final void invoke(Request request, Response response)
throws IOException, ServletException {
// Select the Host to be used for this Request
Host host = request.getHost();
if (host == null) {
// HTTP 0.9 or HTTP 1.0 request without a host when no default host
// is defined.
// Don't overwrite an existing error
if (!response.isError()) {
response.sendError(404);
}
return;
}
if (request.isAsyncSupported()) {
request.setAsyncSupported(host.getPipeline().isAsyncSupported());
}
// Ask this Host to process this request
// 执行 host的一个Valve
host.getPipeline().getFirst().invoke(request, response);
}
执行当前容器的Valve
以AbstractAccessLogValve为例子
/**
* Log a message summarizing the specified request and response, according
* to the format specified by the <code>pattern</code> property.
*
* @param request Request being processed
* @param response Response being processed
*
* @exception IOException if an input/output error has occurred
* @exception ServletException if a servlet error has occurred
*/
@Override
public void invoke(Request request, Response response) throws IOException,
ServletException {
if (tlsAttributeRequired) {
// The log pattern uses TLS attributes. Ensure these are populated
// before the request is processed because with NIO2 it is possible
// for the connection to be closed (and the TLS info lost) before
// the access log requests the TLS info. Requesting it now causes it
// to be cached in the request.
request.getAttribute(Globals.CERTIFICATES_ATTR);
}
if (cachedElements != null) {
for (CachedElement element : cachedElements) {
element.cache(request);
}
}
getNext().invoke(request, response);
}
|