您现在的位置是:首页 > 编程 > 

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

2025-07-21 14:33:52
Tomcat源码解析(四):StandardServer和StandardService Tomcat源码系列文章Tomcat源码解析(一):Tomcat整体架构Tomcat源码解析(二):Bootstrap和CatalinaTomcat源码解析(三):LifeCycle生命周期管理Tomcat源码解析(四):StandardServer和StandardService前言 前文Tomcat源码解

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文件中定义的属性初始化
代码语言:javascript代码运行次数:0运行复制
  <!-- 1.Server 相关
    Server的主要任务,就是提供一个接口让客户端能访问到这个Service集合,同时维护它所包含的所有的Service的生命周期
    port:指定一个端口,这个端口负责监听关闭Tomcat的请求
    shutdown:向以上端口发送的关闭服务器的命令字符串
  -->
<Server port="8005" shutdown="SHUTDOW">

  <!-- 2.Listener 相关 -->
  <Listener classame="org.AprLifecycleListener" />
  <Listener classame="org.ServerLifecycleListener" />
  <Listener classame="org.GlobalResourcesLifecycleListener" />
  <Listener classame="org.storeconfig.StoreConfigLifecycleListener"/>

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

  <!-- 4.service 相关 -->
  <Service name="Catalina">
  		...
  </Service>
</Server>
1.、解析<Server>标签
  • <Server>标签内容用来实例化StandardServer组件
代码语言:javascript代码运行次数:0运行复制
# Catalina#createStartDigester方法
/** 解析<server>标签实例化StandardServer对象,并push到操作栈中 **/
digester.addObjectCreate("Server",
                         "org.StandardServer",
                         "classame");
                         
/** 解析<server>标签将标签中属性值映射到StandardServer对象中**/  
digester.addSetProperties("Server");

/** 解析</server>标签将操作栈栈顶对象设置到次栈顶对象属性中**/
//将StandardServer对象设置到Catalina启动类对象的server属性中
digester.addSetext("Server",
                    "setServer",
                    "org.Server"
  • 将<server>标签属性映射到StandardServer对象属性中
代码语言:javascript代码运行次数:0运行复制
/**
 * Tomcat shutdown操作,对应字符串指令
 */
private String shutdown = "SHUTDOW";

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

/**
 * Tomcat ShutDown执行,服务端监听Socket地址。
 */
private String address = "localhost";
  • 监听SHUTDOW命令Socket服务在前面Tomcat源码解析(二):Bootstrap和Catalina文章里面有讲

2、init初始化

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

2.1、LifecycleBase#init
  • StandardServer的init方法由父类LifecycleBase实现
  • LifecycleBase使用模板模式将初始化的具体操作留给了每个容器自己实现
代码语言:javascript代码运行次数:0运行复制
@Override
public final synchronized void init() throws LifecycleException {
    // 非EW状态,不允许调用init()方法
    if (!(LifecycleState.EW)) {
    	// 抛出异常
        invalidTransition(Lifecycle.BEFORE_IIT_EVET);
    }
 
    try {
        // 初始化逻辑之前,先将状态变更为`IITIALIZIG(初始化过程中状态)`
        setStateInternal(LifecycleState.IITIALIZIG, null, false);
        // 初始化,该方法为一个abstract方法,需要组件自行实现
        initInternal();
        // 初始化完成之后,状态变更为`IITIALIZED(初始化完成状态)`
        setStateInternal(LifecycleState.IITIALIZED, 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了
代码语言:javascript代码运行次数:0运行复制
@Override
protected void initInternal() throws LifecycleException {
    if (oname == null) {
        mserver = Registry.getRegistry(null, null).getMBeanServer();
        oname = register(this, getObjectameKeyProperties());
    }
}
.2、StandServer#initInternal
  • 核心内容就是最后一行内容,初始化当前Server下的所有Services
  • Server里的service是在server.xml里定义的,在Catalina解析server.xml的时候初始化,并注入到Server对象里
  • JDI:就是通过配置一些xml文件,方便用户直接调用API使用某些通用的资源(不常用,不做过多介绍了)
代码语言:javascript代码运行次数:0运行复制
@Override
protected void initInternal() throws LifecycleException {
    // 调用父类LifecycleMBeanBase中的实现
    super.initInternal();

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

、start启动

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

.1、LifecycleBase#start
  • 和init方法一样,StandardServer的start方法也是父类LifecycleBase实现,具体实现留给子类
  • 和init方法不一样,LifecycleBase的父类LifecycleMBeanBase没有startInternal方法的实现
代码语言:javascript代码运行次数:0运行复制
public final synchronized void start() throws LifecycleException {
    // `STARTIG_PREP启动前`、`STARTIG启动中`和`STARTED启动完成时,将忽略start()逻辑
    if (LifecycleState.STARTIG_(state) || LifecycleState.(state) ||
            LifecycleState.(state)) {
        return;
    }
 
    // `EW`状态时,执行init()方法
    if ((LifecycleState.EW)) {
        init();
    }
 
    // `FAILED`状态时,执行stop()方法
    else if ((LifecycleState.FAILED)) {
        stop();
    }
 
    // 不是`IITIALIZED初始化完成`和`STOPPED停止完成`时,则说明是非法的操作
    else if (!(LifecycleState.IITIALIZED) &&
            !(LifecycleState.STOPPED)) {
        // 抛出异常
        invalidTransition(Lifecycle.BEFORE_START_EVET);
    }
 
 	// 一般流程会走到这里,刚走完初始化流程,状态为IITIALIZED(初始化完成状态)
    try {
        // start前的状态设置
        setStateInternal(LifecycleState.STARTIG_PREP, null, false);
        // start逻辑,抽象方法,由组件自行实现
        startInternal();
        // start过程中,可能因为某些原因失败,这时需要stop操作
        if ((LifecycleState.FAILED)) {
            stop();
        } else if (!(LifecycleState.STARTIG)) {
        	// 抛出异常
            invalidTransition(Lifecycle.AFTER_START_EVET);
        } 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;
.2、StandardServer#start
  • 更正当前组件状态为STARTIG(启动过程中状态)
  • 核心内容启动所有service组件
代码语言:javascript代码运行次数:0运行复制
@Override
protected void startInternal() throws LifecycleException {
    // 通知当前组件触发 COFIGURE_START_EVET事件
    fireLifecycleEvent(COFIGURE_START_EVET, null);
    
    // 更正当前组件状态为STARTIG(启动过程中状态)
    setState(LifecycleState.STARTIG);
    
    // 启动JDI服务
    globalamingResources.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组件
代码语言:javascript代码运行次数:0运行复制
@Override
protected void stopInternal() throws LifecycleException {
    // 通知当前组件触发 COFIGURE_STOP_EVET事件
    fireLifecycleEvent(COFIGURE_STOP_EVET, null);
    
    // 更正当前组件状态为STOPPIG
    setState(LifecycleState.STOPPIG);
    
    // 关闭所有service组件
    for (int i = 0; i < services.length; i++) {
        services[i].stop();
    }

    // 关闭JDI服务
    globalamingResources.stop();

    // 停止监听 shutdown命令 Socket服务
    stopAwait();
}
  • 设置stopAwait标识为true,跳出阻塞SHUTDOW的socket服务
  • 设置awaitSocket为null,关闭Socket服务,不在监听SHUTDOW命令
代码语言:javascript代码运行次数:0运行复制
public void stopAwait() {
    stopAwait=true;
    Thread t = awaitThread;
    if (t != null) {
        ServerSocket s = awaitSocket;
        if (s != null) {
            awaitSocket = null;
            try {
                ();
            } 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方法
代码语言:javascript代码运行次数:0运行复制
@Override
protected void destroyInternal() throws LifecycleException {
    // 调用所有Service子组件启动方法destroy 
    for (int i = 0; i < services.length; i++) {
        services[i].destroy();
    }
    // 销毁JD全局资源
    globalamingResources.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,同个容器可以支持不同协议和端口的部署访问
代码语言:javascript代码运行次数:0运行复制
<!--
    每个Service元素只能有一个Engine元素
    元素处理在同一个<Service>中所有<Connector>元素接收到的客户请求
-->

<!-- 1. Service
	name:Service的名称
-->
<Service name="Catalina">
 
    <!--2. 一个或多个excecutors -->
    <!--
    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
        maxThreads="150" minSpareThreads="4"/>
    -->
 
    <!--
		.Connector
		主要作用是接受连接请求,创建Request和Respe对象用于和请求端交换数据
		然后分配线程让Engine来处理这个请求,并把产生的Request和Respe对象传给Engine
    -->
    
    <!--
		客户端可以通过8080端口使用http协议访问tomcat
		protocol属性规定了请求的协议,port规定了请求的端口号
		redirectPort表示强制要求https而请求是http时,重定向至端口号为844的Connector。
    -->
    <Connector port="8080" protocol="HTTP/1.1" 
    	connectionTimeout="20000" redirectPort="844" />
    <!--
		客户端可以通过8009端口使用AJP协议访问Tomcat
		AJP协议负责和其他的HTTP服务器(如Apache)建立连接
		在把Tomcat与其他HTTP服务器集成时,就需要这个连接器
    -->
    <Connector port="8009" protocol="AJP/1." redirectPort="844" />
	
    <!--
		4. Engine:作用是处理接受进来的请求
    -->
    <Engine name="Catalina" defaultHost="localhost">
    
    </Engine>
</Service>
1.、解析<Service>标签
  • 标签内容用来实例化StandardServer组件
  • addService将创建的StandardService对象设置到Server对象下的services集合
代码语言:javascript代码运行次数:0运行复制
# Catalina#createStartDigester方法
/** 解析<Service>标签实例化StandardService对象 **/
digester.addObjectCreate("Server/Service",
                         "org.StandardService",
                         "classame");
                         
/** 解析<Service>标签将标签中属性值映射到StandardService对象中 **/       
digester.addSetProperties("Server/Service");

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

2、init初始化

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

2.1、StandardService#initInternal
  • StandardService和StandardServer一样也是继承自LifecycleMBeanBase
  • 初始化具体实现留给子类也就是StandardService#initInternal
  • 顶级容器engine、请求url映射Mapper、连接器Connector初始化内容后面章节单独讲
代码语言:javascript代码运行次数:0运行复制
@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) {
	...
            }
        }
    }
}

、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方法
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2024-04-2,如有侵权请联系 cloudcommunity@tencent 删除源码tomcat容器对象服务

#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格

本文地址:http://www.dnpztj.cn/biancheng/1161371.html

相关标签:无
上传时间: 2025-07-20 16:34:02
留言与评论(共有 16 条评论)
本站网友 上海最好的白癜风医院
22分钟前 发表
将忽略start()逻辑 if (LifecycleState.STARTIG_(state) || LifecycleState.(state) || LifecycleState.(state)) { return; } // `EW`状态时
本站网友 南沙新区规划
7分钟前 发表
这个端口负责监听关闭Tomcat的请求 shutdown
本站网友 沙发效果图
28分钟前 发表
请求url映射Mapper
本站网友 擦护肤品的正确步骤
10分钟前 发表
不允许调用init()方法 if (!(LifecycleState.EW)) { // 抛出异常 invalidTransition(Lifecycle.BEFORE_IIT_EVET); } try { // 初始化逻辑之前
本站网友 手纹线
2分钟前 发表
初始化当前Server下的所有ServicesServer里的service是在server.xml里定义的
本站网友 夜叉乐队
26分钟前 发表
包含Host
本站网友 深圳周边旅游景点
27分钟前 发表
然后调用Server的init和start方法
本站网友 中专学校排名
29分钟前 发表
service属性
本站网友 删除系统服务
19分钟前 发表
管理
本站网友 口腔拔牙
1分钟前 发表
创建Server
本站网友 萨摩
12分钟前 发表
重定向至端口号为844的Connector
本站网友 御姐很哀伤
26分钟前 发表
右边部分为jmx内容
本站网友 汉丽轩团购
5分钟前 发表
解析server.xml大概可以分为4个部分
本站网友 目标群体分析
9分钟前 发表
null
本站网友 羚羊角的作用
1分钟前 发表
向以上端口发送的关闭服务器的命令字符串 --> <Server port="8005" shutdown="SHUTDOW"> <!-- 2.Listener 相关 --> <Listener classame="org.AprLifecycleListener" /> <Listener classame="org.ServerLifecycleListener" /> <Listener classame="org.GlobalResourcesLifecycleListener" /> <Listener classame="org.storeconfig.StoreConfigLifecycleListener"/> <!-- .GlobalamingResources 相关 --> <GlobalamingResources> <Environment name="simpleValue" type="java.lang.Integer" value="0"/> <Resource name="UserDatabase" auth="Container" type="org.UserDatabase" description="User database that can be updated and saved" factory="org.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" /> </GlobalamingResources> <!-- 4.service 相关 --> <Service name="Catalina"> ... </Service> </Server>1.