Tomcat源码解析(四):StandardServer和StandardService
Tomcat源码解析(四):StandardServer和StandardService
Tomcat源码系列文章
Tomcat源码解析(一):Tomcat整体架构
Tomcat源码解析(二):Bootstrap和Catalina
Tomcat源码解析(三):LifeCycle生命周期管理
Tomcat源码解析(四):StandardServer和StandardService
前文Tomcat源码解析(二):Bootstrap和Catalina介绍Tomcat的启动类的加载,在Catalina初始化时加载了server.xml
,创建Server
、Service
、Connector
等一些列组件,然后调用Server
的init
和start
方法,启动tomcat
。Tomcat源码解析(三):LifeCycle生命周期管理介绍了组件init、start、stop等共同生命周期方法,使用模板方法设计模式,具体的实现类由子类去实现。
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="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组件
# 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对象属性中
/**
* 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使用模板模式将初始化的具体操作留给了每个容器自己实现
@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了
@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使用某些通用的资源(不常用,不做过多介绍了)
@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方法的实现
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
组件
@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
组件
@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命令
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
方法
@Override
protected void destroyInternal() throws LifecycleException {
// 调用所有Service子组件启动方法destroy
for (int i = 0; i < services.length; i++) {
services[i].destroy();
}
// 销毁JD全局资源
globalamingResources.destroy();
// 省略jmx内容
...
}
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"/>
-->
<!--
.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
集合
# 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初始化内容后面章节单独讲
@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
组件通过调用init
和start
方法来启动tomcat
的- 而Server的init方法和start方法则是调用
多个Service
的init
和start
方法 - 而一个Service的init方法和start方法则是调用
一个顶级容器engine、一个请求url映射Mapper、多个执行器Executor、多个连接器Connector
的init
和start
方法
#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格
推荐阅读
留言与评论(共有 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. |