Tomcat 组成与原理以及相关源码解析

组成

img

  • Server:指的就是整个 Tomcat 服 务器,包含多组服务,负责管理和 启动各个 Service,同时监听 8005 端口发过来的 shutdown 命令,用 于关闭整个容器 ;
  • Service:Tomcat 封装的、对外提 供完整的、基于组件的 web 服务,一个service可以包括多个connector和一个container 核心组件,以及多个功能组件,各 个 Service 之间是独立的,但是共享 同一 JVM 的资源 ;
  • Connector:Tomcat 与外部世界的连接器,监听固定端口接收外部请求,传递给 Container,并 将 Container 处理的结果返回给外部;
  • Container:Catalina,Servlet 容器,内部有多层容器组成,用于管理
  • Servlet 生命周期,调用 servlet 相关方法。
  • Loader:封装了 Java ClassLoader,用于 Container 加载类文件;
  • Realm:Tomcat 中为 web 应用程序提供访问认证和角色管理的机制;
  • JMX:Java SE 中定义技术规范,是一个为应用程序、设备、系统等植入管理功能的框架,通过 JMX 可以远程监控 Tomcat 的运行状态;
  • Jasper:Tomcat 的 Jsp 解析引擎,用于将 Jsp 转换成 Java 文件,并编译成 class 文件。 Session:负责管理和创建 session,以及 Session 的持久化(可自定义),支持 session 的集群。
  • Pipeline:在容器中充当管道的作用,管道中可以设置各种 valve(阀门),请求和响应在经由管 道中各个阀门处理,提供了一种灵活可配置的处理请求和响应的机制。
  • Naming:命名服务,JNDI, Java 命名和目录接口,是一组在 Java 应用中访问命名和目录服务的 API。命名服务将名称和对象联系起来,使得我们可以用名称访问对象,目录服务也是一种命名 服务,对象不但有名称,还有属性。Tomcat 中可以使用 JNDI 定义数据源、配置信息,用于开发 与部署的分离。

  • Engine:Servlet 的顶层容器,包含一 个或多个 Host 子容器;

  • Host:虚拟主机,负责 web 应用的部 署和 Context 的创建;
  • Context:Web 应用上下文,包含多个 Wrapper,负责 web 配置的解析、管 理所有的 Web 资源;
  • Wrapper:最底层的容器,是对 Servlet 的封装,负责 Servlet 实例的创 建、执行和销毁。




时序图

1
2
3
4
5
sequenceDiagram
SpringApplication->>SpringApplication:refresh
SpringApplication->>AbstractApplicationContext:refresh
AbstractApplicationContext->>EmbeddedWebApplicationContext:onRefresh
EmbeddedWebApplicationContext->>EmbeddedWebApplicationContext:createEmbeddedServletContainer
1
2
3
4
5
sequenceDiagram
EmbeddedWebAppContext->>EmbeddedWebAppContext:getEmbeddedServletContainerFactory
EmbeddedWebAppContext->>TomcatEmbedSerContainerFactory:getEmbeddedServletContainer
TomcatEmbedSerContainerFactory->>TomcatEmbedSerContainerFactory:new TomcatEmbeddedServletContainer
TomcatEmbedSerContainerFactory->>TomcatEmbedSerContainer:initialize

img

Server

Tomcat

TomcatEmbeddedServletContainer#initialize

this.tomcat.start();

server.start();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
tomcat#start ----->LifecycleBase#start

LifecycleBase#start
public final synchronized void start() throws LifecycleException {
if (state.equals(LifecycleState.NEW)) {
init();
} else if (state.equals(LifecycleState.FAILED)) {
stop();
} else if (!state.equals(LifecycleState.INITIALIZED) &&
!state.equals(LifecycleState.STOPPED)) {
invalidTransition(Lifecycle.BEFORE_START_EVENT);
}

try {
startInternal();
if (state.equals(LifecycleState.FAILED)) {
stop();
} else if (!state.equals(LifecycleState.STARTING)) {
invalidTransition(Lifecycle.AFTER_START_EVENT);
} else {
setStateInternal(LifecycleState.STARTED, null, false);
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
setStateInternal(LifecycleState.FAILED, null, false);
throw new LifecycleException(sm.getString("lifecycleBase.startFail", toString()), t);
}
}

LifecycleBase全局看进行每个组件StandardServer,StandardEngine等的initInternal&&startInternal方法

Server的Init走的步骤不多

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
StandardServer#init--->StandardService#init--->StandardEngine#init

StanardEngine#init一调用走LifeCycleBase#init--->StandardEngine#initInternal--->ContainerBase#initInternal

在ContainerBase#initInternal

protected void initInternal() throws LifecycleException {
BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<>();
startStopExecutor = new ThreadPoolExecutor(
getStartStopThreadsInternal(),
getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,
startStopQueue,
new StartStopThreadFactory(getName() + "-startStop-"));
startStopExecutor.allowCoreThreadTimeOut(true);
super.initInternal();
}

起了线程池"-startStop-" : startStopExecutor

init后接着就开始各个组件的start

以下所有的组件将经历模板设计模式的历练

某调用者对 组件A#start-> LifeCycleBase#start -> 组件A#startInternal -> 引出内部组件B#start …….

Server

StandardServer#start 接上server.start()

默认进入到父类 LifecycleBase.start()

StandardServer#startInternal

1
2
3
4
5
6
7
8
9
10
11
12
13
protected void startInternal() throws LifecycleException {

fireLifecycleEvent(CONFIGURE_START_EVENT, null);
setState(LifecycleState.STARTING);

globalNamingResources.start();

synchronized (servicesLock) {
for (int i = 0; i < services.length; i++) {
services[i].start();
}
}
}

servicesStandardService

Service

StandardService#start 接上services[i].start()

默认进入到父类 LifecycleBase.start()

StandardService#startInternal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@Override
protected void startInternal() throws LifecycleException {

if(log.isInfoEnabled())
log.info(sm.getString("standardService.start.name", this.name));
setState(LifecycleState.STARTING);

if (engine != null) {
synchronized (engine) {
engine.start();
}
}

synchronized (executors) {
for (Executor executor: executors) {
executor.start();
}
}

mapperListener.start();

synchronized (connectorsLock) {
for (Connector connector: connectors) {
try {
// If it has already failed, don't try and start it
if (connector.getState() != LifecycleState.FAILED) {
connector.start();
}
} catch (Exception e) {
log.error(sm.getString(
"standardService.connector.startFailed",
connector), e);
}
}
}
}

engineStandardEngine

Container 实例化

  • (1)Engine:引擎,用来管理多个站点,一个Service最多只能有一个Engine;
  • (2)Host:代表一个站点,也可以叫虚拟主机,通过配置Host就可以添加站点;
  • (3)Context:代表一个应用程序,对应着平时开发的一套程序,或者一个WEB-INF目录以及下面的web.xml文件;
  • (4)Wrapper:每一Wrapper封装着一个Servlet;

Engine

  • StandardEngine#start 接上engine.start();

默认进入到父类 LifecycleBase.start()

StandardEngine#startInternal

1
2
3
4
5
6
7
protected synchronized void startInternal() throws LifecycleException {

if(log.isInfoEnabled())
log.info( "Starting Servlet Engine: " + ServerInfo.getServerInfo());

super.startInternal();
}
  • ContainerBase#startInternal 接上super.startInternal();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
protected synchronized void startInternal() throws LifecycleException {

logger = null;
getLogger();
Cluster cluster = getClusterInternal();
if (cluster instanceof Lifecycle) {
((Lifecycle) cluster).start();
}
Realm realm = getRealmInternal();
if (realm instanceof Lifecycle) {
((Lifecycle) realm).start();
}

Container children[] = findChildren();
List<Future<Void>> results = new ArrayList<>();
for (int i = 0; i < children.length; i++) {
results.add(startStopExecutor.submit(new StartChild(children[i])));
}

boolean fail = false;
for (Future<Void> result : results) {
try {
result.get();
} catch (Exception e) {
log.error(sm.getString("containerBase.threadedStartFailed"), e);
fail = true;
}

}
if (fail) {
throw new LifecycleException(
sm.getString("containerBase.threadedStartFailed"));
}

if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start();


setState(LifecycleState.STARTING);

threadStart();

}
  • Tomcat-startStop- 线程池起线程
1
results.add(startStopExecutor.submit(new StartChild(children[i])));
  • 后续操作

ContainerBackgroundProcessor[StandardEngine[Tomcat]]起线程

1
threadStart();

Host – Tomcat-startStop- 线程

  • LifecycleBase#start
  • StandardHost#startInternal
  • ContainerBase#startInternal
    1
    2
    3
    4
    //又起线程
    //线程名:localhost-startStop-

    results.add(startStopExecutor.submit(new StartChild(children[i])));

Context – localhost-startStop- 线程

  • LifecycleBase#start

    优先进入了LifecycleBase#init函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    LifeCycleBase#init -----> StandardContext#initInternal -> ContainerBase#initInternal 又启动一个线程池

    @Override
    protected void initInternal() throws LifecycleException {
    BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<>();
    startStopExecutor = new ThreadPoolExecutor(
    getStartStopThreadsInternal(),
    getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,
    startStopQueue,
    new StartStopThreadFactory(getName() + "-startStop-"));
    startStopExecutor.allowCoreThreadTimeOut(true);
    super.initInternal();
    }
  • StandardContext#startInternal

    1
    2
    3
    4
    5
    for (Container child : findChildren()) {
    if (!child.getState().isAvailable()) {
    child.start();
    }
    }

Wrapper

  • LifecycleBase#start

    优先进入了LifecycleBase#init函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    LifeCycleBase#init -----> StandardWrapper#initInternal(暂未实现直接跳上级方法) -> ContainerBase#initInternal 又启动一个线程池default-startStop

    @Override
    protected void initInternal() throws LifecycleException {
    BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<>();
    startStopExecutor = new ThreadPoolExecutor(
    getStartStopThreadsInternal(),
    getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,
    startStopQueue,
    new StartStopThreadFactory(getName() + "-startStop-"));
    startStopExecutor.allowCoreThreadTimeOut(true);
    super.initInternal();
    }
  • StandardContext#startInternal

1
2
3
4
entry.getKey().onStartup(entry.getValue(),
getServletContext());

//初始化Servlet
  • TomcatStarter#onStartup
1
2
3
4
5
6
7
8
initializer.onStartup(servletContext);
//直接跳转到
EmbeddedWebApplicationContext#selfInitialize

//至此各个Servlet ContextInitializer bean启动
for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
beans.onStartup(servletContext);
}

Connector 实例化

img

与Containner配合工作
起Io线程-Service装配Connector

基本构造

Acceptor

接收socket线程,这里虽然是基于NIO的connector,但是在接收socket方面还是传统的serverSocket.accept()方式,获得SocketChannel对象,然后封装在一个tomcat的实现类org.apache.tomcat.util.net.NioChannel对象中。然后将NioChannel对象封装在一个PollerEvent对象中,并将PollerEvent对象压入events queue里。这里是个典型的生产者-消费者模式,Acceptor与Poller线程之间通过queue通信,Acceptor是events queue的生产者,Poller是events queue的消费者。

Poller

Poller线程中维护了一个Selector对象,NIO就是基于Selector来完成逻辑的。在connector中并不止一个Selector,在socket的读写数据时,为了控制timeout也有一个Selector,在后面的BlockSelector中介绍。可以先把Poller线程中维护的这个Selector标为主Selector。 Poller是NIO实现的主要线程。首先作为events queue的消费者,从queue中取出PollerEvent对象,然后将此对象中的channel以OP_READ事件注册到主Selector中,然后主Selector执行select操作,遍历出可以读数据的socket,并从Worker线程池中拿到可用的Worker线程,然后将socket传递给Worker。整个过程是典型的NIO实现。

Worker

Worker线程拿到Poller传过来的socket后,将socket封装在SocketProcessor对象中。然后从Http11ConnectionHandler中取出Http11NioProcessor对象,从Http11NioProcessor中调用CoyoteAdapter的逻辑,跟BIO实现一样。在Worker线程中,会完成从socket中读取http request,解析成HttpServletRequest对象,分派到相应的servlet并完成逻辑,然后将response通过socket发回client。在从socket中读数据和往socket中写数据的过程,并没有像典型的非阻塞的NIO的那样,注册OP_READ或OP_WRITE事件到主Selector,而是直接通过socket完成读写,这时是阻塞完成的,但是在timeout控制上,使用了NIO的Selector机制,但是这个Selector并不是Poller线程维护的主Selector,而是BlockPoller线程中维护的Selector,称之为辅Selector。

启动流程

1
2
3
4
5
6
7
sequenceDiagram

AbstractApplicationContext->>EmbeddedWebApplicationContext:finishRefresh
EmbeddedWebApplicationContext->>EmbeddedWebApplicationContext:startEmbeddedServletContainer
EmbeddedWebApplicationContext->>TomcatEmbedSerContainer:start
TomcatEmbedSerContainer->>TomcatEmbedSerContainer:addPreviouslyRemovedConnectors
TomcatEmbedSerContainer->>StandardService:addConnector
  • LifecycleBase#start
  • Connector#startInternal

  • AbstractProtocol#start

    1
    2
    3
    4
    5
    6
    7
    8
    9
    asyncTimeout = new AsyncTimeout();
    Thread timeoutThread = new Thread(asyncTimeout, getNameInternal() + "-AsyncTimeout");
    int priority = endpoint.getThreadPriority();
    if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
    priority = Thread.NORM_PRIORITY;
    }
    timeoutThread.setPriority(priority);
    timeoutThread.setDaemon(true);
    timeoutThread.start();
    • AsyncTimeout线程创建
  • NioEndpoint#startInternal

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    public void startInternal() throws Exception {
    if (!running) {
    running = true;
    paused = false;

    processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
    socketProperties.getProcessorCache());
    eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
    socketProperties.getEventCache());
    nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
    socketProperties.getBufferPool());

    // Create worker collection
    if ( getExecutor() == null ) {
    createExecutor();
    }

    initializeConnectionLatch();

    // Start poller threads
    pollers = new Poller[getPollerThreadCount()];
    for (int i=0; i<pollers.length; i++) {
    pollers[i] = new Poller();
    Thread pollerThread = new Thread(pollers[i], getName() + "-ClientPoller-"+i);
    pollerThread.setPriority(threadPriority);
    pollerThread.setDaemon(true);
    pollerThread.start();
    }

    startAcceptorThreads();
    }
    }
    • createExecutor
      创建IO工作线程池 http-nio-端口号-exec

      1
      2
      3
      4
      5
      6
      7
      public void createExecutor() {
      internalExecutor = true;
      TaskQueue taskqueue = new TaskQueue();
      TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());
      executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
      taskqueue.setParent( (ThreadPoolExecutor) executor);
      }
    • pollerThread.start()
      创建ClientPoller线程 http-nio-端口号-ClientPoller

    • startAcceptorThreads
      创建Acceptor线程 http-nio-端口号-Acceptor

访问流程

img

img


Container处理请求是使用Pipeline-Value管道来处理

Pipeline-Value是责任链模式,责任链模式是指在一个请求处理的过程中有很多处理者依次对请求进行处理,每个处理者负责做自己相应的处理,处理完之后将处理后的请求返回,再让下一个处理着继续处理。

  • 1)每个Pipeline都有特定的Value,而且是在管道的最后一个执行,这个Value叫做BaseValue,BaseValue是不可删除的;
  • 2)在上层容器的管道的BaseValue中会调用下层容器的管道。

Container包含四个子容器:StandardEngineValue、StandardHostValue、StandardContextValue、StandardWrapperValue。

细节

  1. Connector在接收到请求后会首先调用最顶层容器的Pipeline来处理,这里的最顶层容器的Pipeline就是EnginePipeline(Engine的管道);

  2. 在Engine的管道中依次会执行EngineValue1、EngineValue2等等,最后会执行StandardEngineValue,在StandardEngineValue中会调用Host管道,然后再依次执行Host的HostValue1、HostValue2等,最后在执行StandardHostValue,然后再依次调用Context的管道和Wrapper的管道,最后执行到StandardWrapperValue。

  3. 当执行到StandardWrapperValue的时候,会在StandardWrapperValue中创建FilterChain,并调用其doFilter方法来处理请求,这个FilterChain包含着我们配置的与请求相匹配的Filter和Servlet,其doFilter方法会依次调用所有的Filter的doFilter方法和Servlet的service方法,这样请求就得到了处理!

  4. 当所有的Pipeline-Value都执行完之后,并且处理完了具体的请求,这个时候就可以将返回的结果交给Connector了,Connector在通过Socket的方式将结果返回给客户端。

参考