首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

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

  • 25-03-03 07:42
  • 4681
  • 13057
blog.csdn.net

Tomcat源码系列文章

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

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

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

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


文章目录

  • 前言
  • 一、StandardServer
    • 1、StandardServer实例化
      • 1.1、Server接口
      • 1.2、解析server.xml
      • 1.3、解析\标签
    • 2、init初始化
      • 2.1、LifecycleBase#init
      • 2.2、LifecycleMBeanBase#initInternal
      • 3.2、StandServer#initInternal
    • 3、start启动
      • 3.1、LifecycleBase#start
      • 3.2、StandardServer#start
    • 4、stop停止
    • 5、destroy销毁
  • 二、StandardService
    • 1、StandardService实例化
      • 1.1、Service接口
      • 1.2、解析server.xml
      • 1.3、解析\标签
    • 2、init初始化
      • 2.1、StandardService#initInternal
    • 3、start、stop、destroy
  • 总结


前言

  前文Tomcat源码解析(二):Bootstrap和Catalina介绍Tomcat的启动类的加载,在Catalina初始化时加载了server.xml,创建Server、Service、Connector等一些列组件,然后调用Server的init和start方法,启动tomcat。Tomcat源码解析(三):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文件中定义的属性初始化
  
<Server port="8005" shutdown="SHUTDOWN">

  
  <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"/>

  
  <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>

  
  <Service name="Catalina">
  		...
  Service>
Server>
  • 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

1.3、解析标签

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

/** 解析标签将操作栈栈顶对象设置到次栈顶对象属性中**/
//将StandardServer对象设置到Catalina启动类对象的server属性中
digester.addSetNext("Server",
                    "setServer",
                    "org.apache.catalina.Server"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 将标签属性映射到StandardServer对象属性中
/**
 * Tomcat shutdown操作,对应字符串指令
 */
private String shutdown = "SHUTDOWN";

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

/**
 * Tomcat ShutDown执行,服务端监听Socket地址。
 */
private String address = "localhost";
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

在这里插入图片描述

  • 监听SHUTDOWN命令Socket服务在前面Tomcat源码解析(二):Bootstrap和Catalina文章里面有讲

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;
  • 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

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());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

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;
  • 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
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

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();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

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();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 设置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
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

在这里插入图片描述

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内容
	...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

二、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 name="Catalina">
 
    
    
 
    
    
    
    <Connector port="8080" protocol="HTTP/1.1" 
    	connectionTimeout="20000" redirectPort="8443" />
    
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
	
    
    <Engine name="Catalina" defaultHost="localhost">
    
    Engine>
Service>
  • 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

1.3、解析标签

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

/** 将StandardService对象设置到Server对象的service集合中 **/   
digester.addSetNext("Server/Service",
                    "addService",
                    "org.apache.catalina.Service");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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) {
	...
            }
        }
    }
}
  • 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

3、start、stop、destroy

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


总结

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

在这里插入图片描述

文章知识点与官方知识档案匹配,可进一步学习相关知识
Java技能树首页概览147154 人正在系统学习中
注:本文转载自blog.csdn.net的冬天vs不冷的文章"https://blog.csdn.net/qq_35512802/article/details/136480579"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top