Tomcat源码解析(四):StandardServer和StandardService

Tomcat源码系列文章

Tomcat源码解析(一):Tomcat整体架构

Tomcat源码解析(二):Bootstrap和Catalina

Tomcat源码解析(三):LifeCycle生命周期管理

Tomcat源码解析(四):StandardServer和StandardService



前言

  前文Tomcat源码解析(二):Bootstrap和Catalina介绍Tomcat的启动类的加载,在Catalina初始化时加载了server.xml,创建ServerServiceConnector等一些列组件,然后调用Serverinitstart方法,启动tomcatTomcat源码解析(三):LifeCycle生命周期管理介绍了组件init、start、stop等共同生命周期方法,使用模板方法设计模式,具体的实现类由子类去实现。

在这里插入图片描述


一、StandardServer

1、StandardServer实例化

  • 一个Server类的实例就代表了一个Tomcat的容器,一个Tomcat进程只会有一个Server实例

1.1、Server接口

  Server(实现类StandardServer)类图如下,只需要关注左边部分即可。

在这里插入图片描述

  右边部分为jmx内容,tomcat允许我们使用jmx对tomcat进行监控、管理,截图如下。以后有机会出文章单独讲,所以此篇文章涉及Jmx接口内容就不细讲了。

在这里插入图片描述

1.2、解析server.xml

  • 通过解析server.xml实例化StandardServer,并设置server.xml文件中定义的属性初始化
  <!-- 1.Server 相关
    Server的主要任务,就是提供一个接口让客户端能访问到这个Service集合,同时维护它所包含的所有的Service的生命周期
    port:指定一个端口,这个端口负责监听关闭Tomcat的请求
    shutdown:向以上端口发送的关闭服务器的命令字符串
  -->
<Server port="8005" shutdown="SHUTDOWN">

  <!-- 2.Listener 相关 -->
  <Listener className="org.apache.catalina.core.AprLifecycleListener" />
  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener"/>

  <!-- 3.GlobalNamingResources 相关 -->
  <GlobalNamingResources>
    <Environment name="simpleValue" type="java.lang.Integer" value="30"/>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
       description="User database that can be updated and saved"
           factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
          pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>

  <!-- 4.service 相关 -->
  <Service name="Catalina">
  		...
  </Service>
</Server>

1.3、解析<Server>标签

  • <Server>标签内容用来实例化StandardServer组件
# Catalina#createStartDigester方法
/** 解析<server>标签实例化StandardServer对象,并push到操作栈中 **/
digester.addObjectCreate("Server",
                         "org.apache.catalina.core.StandardServer",
                         "className");
                         
/** 解析<server>标签将标签中属性值映射到StandardServer对象中**/  
digester.addSetProperties("Server");

/** 解析</server>标签将操作栈栈顶对象设置到次栈顶对象属性中**/
//将StandardServer对象设置到Catalina启动类对象的server属性中
digester.addSetNext("Server",
                    "setServer",
                    "org.apache.catalina.Server"
  • 将<server>标签属性映射到StandardServer对象属性中
/**
 * Tomcat shutdown操作,对应字符串指令
 */
private String shutdown = "SHUTDOWN";

/**
 * Tomcat ShutDown操作,服务端监听Socket端口号。
 */
private int port = 8005;

/**
 * Tomcat ShutDown执行,服务端监听Socket地址。
 */
private String address = "localhost";

在这里插入图片描述

2、init初始化

初始化方法是在Catlina的load方法中加载server.xml后,调用getServer().init()触发的

2.1、LifecycleBase#init

  • StandardServer的init方法由父类LifecycleBase实现
  • LifecycleBase使用模板模式将初始化的具体操作留给了每个容器自己实现
@Override
public final synchronized void init() throws LifecycleException {
    // 非NEW状态,不允许调用init()方法
    if (!state.equals(LifecycleState.NEW)) {
    	// 抛出异常
        invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
    }
 
    try {
        // 初始化逻辑之前,先将状态变更为`INITIALIZING(初始化过程中状态)`
        setStateInternal(LifecycleState.INITIALIZING, null, false);
        // 初始化,该方法为一个abstract方法,需要组件自行实现
        initInternal();
        // 初始化完成之后,状态变更为`INITIALIZED(初始化完成状态)`
        setStateInternal(LifecycleState.INITIALIZED, null, false);
    } catch (Throwable t) {
        // 初始化的过程中,可能会有异常抛出,这时需要捕获异常,并将状态变更为`FAILED(异常状态)`
        ExceptionUtils.handleThrowable(t);
        setStateInternal(LifecycleState.FAILED, null, false);
        throw new LifecycleException(
                sm.getString("lifecycleBase.initFail",toString()), t);
    }
}
// 真正的初始化方法,需要子类实现此方法
protected abstract void initInternal() throws LifecycleException;

2.2、LifecycleMBeanBase#initInternal

  • LifecycleBase的父类LifecycleMBeanBase可以看到initInternal方法的实现
  • 但这些都是jmx的内容,跳过,再往上找父类也就是StandardServer了
@Override
protected void initInternal() throws LifecycleException {
    if (oname == null) {
        mserver = Registry.getRegistry(null, null).getMBeanServer();
        oname = register(this, getObjectNameKeyProperties());
    }
}

3.2、StandServer#initInternal

  • 核心内容就是最后一行内容,初始化当前Server下的所有Services
  • Server里的service是在server.xml里定义的,在Catalina解析server.xml的时候初始化,并注入到Server对象里
  • JNDI:就是通过配置一些xml文件,方便用户直接调用API使用某些通用的资源(不常用,不做过多介绍了)
@Override
protected void initInternal() throws LifecycleException {
    // 调用父类LifecycleMBeanBase中的实现
    super.initInternal();

    // JNDI服务初始化
    globalNamingResources.init();
    
	// 省略jmx注册对象内容
	...
	
    // 初始化Services
    for (int i = 0; i < services.length; i++) {
        services[i].init();
    }
}

3、start启动

启动方法是在Catlina的start方法中调用getServer().start()触发的

3.1、LifecycleBase#start

  • 和init方法一样,StandardServer的start方法也是父类LifecycleBase实现,具体实现留给子类
  • 和init方法不一样,LifecycleBase的父类LifecycleMBeanBase没有startInternal方法的实现
public final synchronized void start() throws LifecycleException {
    // `STARTING_PREP启动前`、`STARTING启动中`和`STARTED启动完成时,将忽略start()逻辑
    if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) ||
            LifecycleState.STARTED.equals(state)) {
        return;
    }
 
    // `NEW`状态时,执行init()方法
    if (state.equals(LifecycleState.NEW)) {
        init();
    }
 
    // `FAILED`状态时,执行stop()方法
    else if (state.equals(LifecycleState.FAILED)) {
        stop();
    }
 
    // 不是`INITIALIZED初始化完成`和`STOPPED停止完成`时,则说明是非法的操作
    else if (!state.equals(LifecycleState.INITIALIZED) &&
            !state.equals(LifecycleState.STOPPED)) {
        // 抛出异常
        invalidTransition(Lifecycle.BEFORE_START_EVENT);
    }
 
 	// 一般流程会走到这里,刚走完初始化流程,状态为INITIALIZED(初始化完成状态)
    try {
        // start前的状态设置
        setStateInternal(LifecycleState.STARTING_PREP, null, false);
        // start逻辑,抽象方法,由组件自行实现
        startInternal();
        // start过程中,可能因为某些原因失败,这时需要stop操作
        if (state.equals(LifecycleState.FAILED)) {
            stop();
        } else if (!state.equals(LifecycleState.STARTING)) {
        	// 抛出异常
            invalidTransition(Lifecycle.AFTER_START_EVENT);
        } else {
            // 设置状态为STARTED(启动完成状态)
            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);
    }
}

// 真正的启动方法,需要子类实现此方法
protected abstract void startInternal() throws LifecycleException;

3.2、StandardServer#start

  • 更正当前组件状态为STARTING(启动过程中状态)
  • 核心内容启动所有service组件
@Override
protected void startInternal() throws LifecycleException {
    // 通知监听器当前组件触发 CONFIGURE_START_EVENT事件
    fireLifecycleEvent(CONFIGURE_START_EVENT, null);
    
    // 更正当前组件状态为STARTING(启动过程中状态)
    setState(LifecycleState.STARTING);
    
    // 启动JNDI服务
    globalNamingResources.start();
    
    // 启动所有service组件
    synchronized (servicesLock) {
        for (int i = 0; i < services.length; i++) {
            services[i].start();
        }
    }
}

4、stop停止

停止方法是在Catlina的stop方法中调用getServer().stop()触发的

  • StandardServer的stop方法也是父类LifecycleBase实现,具体实现留给子类
  • LifecycleBase里面无非就是状态切换,直接进入StandardServer#stopInternal
  • 核心内容关闭所有service组件
@Override
protected void stopInternal() throws LifecycleException {
    // 通知监听器当前组件触发 CONFIGURE_STOP_EVENT事件
    fireLifecycleEvent(CONFIGURE_STOP_EVENT, null);
    
    // 更正当前组件状态为STOPPING
    setState(LifecycleState.STOPPING);
    
    // 关闭所有service组件
    for (int i = 0; i < services.length; i++) {
        services[i].stop();
    }

    // 关闭JNDI服务
    globalNamingResources.stop();

    // 停止监听 shutdown命令 Socket服务
    stopAwait();
}
  • 设置stopAwait标识为true,跳出阻塞SHUTDOWN的socket服务
  • 设置awaitSocket为null,关闭Socket服务,不在监听SHUTDOWN命令
public void stopAwait() {
    stopAwait=true;
    Thread t = awaitThread;
    if (t != null) {
        ServerSocket s = awaitSocket;
        if (s != null) {
            awaitSocket = null;
            try {
                s.close();
            } catch (IOException e) {
                // Ignored
            }
        }
        t.interrupt();
        try {
            t.join(1000);
        } catch (InterruptedException e) {
            // Ignored
        }
    }
}

在这里插入图片描述

5、destroy销毁

销毁方法是在Catlina的stop方法中调用getServer().destroy()触发的

  • StandardServer的destroy方法也是父类LifecycleBase实现,具体实现留给子类
  • 核心内容调用所有Service组件destroy方法
@Override
protected void destroyInternal() throws LifecycleException {
    // 调用所有Service子组件启动方法destroy 
    for (int i = 0; i < services.length; i++) {
        services[i].destroy();
    }
    // 销毁JND全局资源
    globalNamingResources.destroy();

	// 省略jmx内容
	...
}

二、StandardService

1、StandardService实例化

1.1、Service接口

  Service(实现类StandardService)类图如下,只需要关注左边部分即可,右边部分为jmx内容。

在这里插入图片描述

1.2、解析server.xml

  • 大概可以分为4个部分,service属性、executor属性、connector属性、engine属性
  • Service作用是把Connector和Engine组装在一起,对外提供服务
    • Connector的作用是从客户端接受请求
    • Engine的作用是处理接受进来的请求
  • Tomcat源码解析(一):Tomcat整体架构讲过,一个Server实例可以包含多个Service对象(一个容器和多个连接器组合)
    • 一个容器就是Engine表示顶级容器,包含Host、Context(web应用)、Wrapper(Servlet)
    • 多个连接器就是Connector,同个容器可以支持不同协议和端口的部署访问
<!--
    每个Service元素只能有一个Engine元素
    元素处理在同一个<Service>中所有<Connector>元素接收到的客户请求
-->

<!-- 1. Service
	name:Service的名称
-->
<Service name="Catalina">
 
    <!--2. 一个或多个excecutors -->
    <!--
    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
        maxThreads="150" minSpareThreads="4"/>
    -->
 
    <!--
		3.Connector
		主要作用是接受连接请求,创建Request和Response对象用于和请求端交换数据
		然后分配线程让Engine来处理这个请求,并把产生的Request和Response对象传给Engine
    -->
    
    <!--
		客户端可以通过8080端口使用http协议访问tomcat
		protocol属性规定了请求的协议,port规定了请求的端口号
		redirectPort表示强制要求https而请求是http时,重定向至端口号为8443的Connector。
    -->
    <Connector port="8080" protocol="HTTP/1.1" 
    	connectionTimeout="20000" redirectPort="8443" />
    <!--
		客户端可以通过8009端口使用AJP协议访问Tomcat
		AJP协议负责和其他的HTTP服务器(如Apache)建立连接
		在把Tomcat与其他HTTP服务器集成时,就需要这个连接器
    -->
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
	
    <!--
		4. Engine:作用是处理接受进来的请求
    -->
    <Engine name="Catalina" defaultHost="localhost">
    
    </Engine>
</Service>

1.3、解析<Service>标签

  • 标签内容用来实例化StandardServer组件
  • addService将创建的StandardService对象设置到Server对象下的services集合
# Catalina#createStartDigester方法
/** 解析<Service>标签实例化StandardService对象 **/
digester.addObjectCreate("Server/Service",
                         "org.apache.catalina.core.StandardService",
                         "className");
                         
/** 解析<Service>标签将标签中属性值映射到StandardService对象中 **/       
digester.addSetProperties("Server/Service");

/** 将StandardService对象设置到Server对象的service集合中 **/   
digester.addSetNext("Server/Service",
                    "addService",
                    "org.apache.catalina.Service");

2、init初始化

初始化方法是在Server的initInternal方法循环遍历调用services[i].init()触发的

2.1、StandardService#initInternal

  • StandardService和StandardServer一样也是继承自LifecycleMBeanBase
  • 初始化具体实现留给子类也就是StandardService#initInternal
  • 顶级容器engine、请求url映射Mapper、连接器Connector初始化内容后面章节单独讲
@Override
protected void initInternal() throws LifecycleException {
	// 父类LifecycleMBeanBase注册jmx相关,跳过
    super.initInternal();
	
	// 顶级容器engine初始化
    if (engine != null) {
        engine.init();
    }

    // 执行器Executor也就是线程池,与传统线程池最大区别就是为了兼容所有任务,采用无界队列
    // 默认没有配置线程池,所以这里默认为空,后续nio相关内容会创建
    for (Executor executor : findExecutors()) {
        if (executor instanceof JmxEnabled) {
            ((JmxEnabled) executor).setDomain(getDomain());
        }
        executor.init();
    }

    // 初始化mapperListener,只是注册JMX,跳过
    mapperListener.init();

    // 连接器Connector初始化
    synchronized (connectorsLock) {
        for (Connector connector : connectors) {
            try {
                connector.init();
            } catch (Exception e) {
	...
            }
        }
    }
}

3、start、stop、destroy

  start、stop、destroy的实现内容与initInternal类似,内部都是调用顶级容器engine、请求url映射Mapper、连接器Connector的start、stop、destroy方法,后面章节单独讲


总结

  • 一个Tomcat进程只有一个Server实例,一个Server实例可以包含多个Service对象
  • Server组件通过调用initstart方法来启动tomcat
  • 而Server的init方法和start方法则是调用多个Serviceinitstart方法
  • 而一个Service的init方法和start方法则是调用一个顶级容器engine、一个请求url映射Mapper、多个执行器Executor、多个连接器Connectorinitstart方法

在这里插入图片描述

评论 113
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冬天vs不冷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值