一、生命期控制结构基础
Tomcat的生命期控制是一个两层的结构
1)Lifecycle(org.apache.catalina.Lifecycle):
在前一篇
中看到的各组件(Service、Connector、Engine、Host、Context、Wrapper)都会实现这个接口,我们看看这个接口的定义
public interface Lifecycle {
public static final String INIT_EVENT = "init";
public static final String START_EVENT = "start";
public static final String BEFORE_START_EVENT = "before_start";
public static final String AFTER_START_EVENT = "after_start";
public static final String STOP_EVENT = "stop";
public static final String BEFORE_STOP_EVENT = "before_stop";
public static final String AFTER_STOP_EVENT = "after_stop";
public static final String DESTROY_EVENT = "destroy";
public static final String PERIODIC_EVENT = "periodic";
public void addLifecycleListener(LifecycleListener listener);
public LifecycleListener[] findLifecycleListeners();
public void removeLifecycleListener(LifecycleListener listener);
public void start() throws LifecycleException;
public void stop() throws LifecycleException;
}
2)LifecycleListener (org.apache.catalina.LifecycleListener):
在我们上一篇
看到HostConfig就是输入LifecycleListener。
如下是LifecycleLister的定义
public interface LifecycleListener {
public void lifecycleEvent(LifecycleEvent event);
}
二、Tomcat初始化处理过程
1.下面是上一个范例中涉及到的处理器初始化主要过程,可以看出来,通过类似的结构,实现了层层的初始化过程
1.StandardEngine.start
--StandardEngine.init
--super(ContainerBase).start
--fireLifecycleEvent BEFORE_START_EVENT
--EngineConfig. lifecycleEvent(基本上啥事不干,可忽略)
--initChildren
--StandardHost.start(见2)
--fireLifecycleEvent START_EVENT
--fireLifecycleEvent AFTER_START_EVENT
2.StandardHost.start
--StandardHost.init
--super(ContainerBase).start
--fireLifecycleEvent BEFORE_START_EVENT
--HostConfig. lifecycleEvent (识别出Context,并向StandardHost注册)
--initChildren
--StandardContext.start(见3)
--fireLifecycleEvent START_EVENT
--fireLifecycleEvent AFTER_START_EVENT
3.StandardContext.start
--StandardContext.init
--super(ContainerBase).start
--fireLifecycleEvent BEFORE_START_EVENT
--ContextConfig. lifecycleEvent (解析web.xml,并向StandardContxt注册Wrapper)
--initChildren
--StandardWrapper.start
--fireLifecycleEvent START_EVENT
--fireLifecycleEvent AFTER_START_EVENT
2.我们从StandardEngine为入口,看看几个重要的初始化过程的代码
1)Standard.start
public void start() throws LifecycleException {
if( started ) {
return;
}
if( !initialized ) {
init(); //初始化自己
}
// Look for a realm - that may have been configured earlier.
// If the realm is added after context - it'll set itself.
if( realm == null ) {
ObjectName realmName=null;
try {
realmName=new ObjectName( domain + ":type=Realm");
if( mserver.isRegistered(realmName ) ) {
mserver.invoke(realmName, "init",
new Object[] {},
new String[] {}
);
}
} catch( Throwable t ) {
log.debug("No realm for this engine " + realmName);
}
}
// Log our server identification information
//System.out.println(ServerInfo.getServerInfo());
if(log.isInfoEnabled())
log.info( "Starting Servlet Engine: " + ServerInfo.getServerInfo());
if( mbeans != null ) {
try {
Registry.getRegistry(null, null)
.invoke(mbeans, "start", false);
} catch (Exception e) {
log.error("Error in start() for " + mbeansFile, e);
}
}
//ContainerBase.start
super.start();
}
非常简单明了,初始化自己、注册JMX、super.start三步骤,我们进入下一步
2)ContainerBase.start
public synchronized void start() throws LifecycleException {
// Validate and update our current component state
if (started) {
if(log.isInfoEnabled())
log.info(sm.getString("containerBase.alreadyStarted", logName()));
return;
}
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
started = true;
// Start our subordinate components, if any
if ((loader != null) && (loader instanceof Lifecycle))
((Lifecycle) loader).start();
logger = null;
getLogger();
if ((logger != null) && (logger instanceof Lifecycle))
((Lifecycle) logger).start();
if ((manager != null) && (manager instanceof Lifecycle))
((Lifecycle) manager).start();
if ((cluster != null) && (cluster instanceof Lifecycle))
((Lifecycle) cluster).start();
if ((realm != null) && (realm instanceof Lifecycle))
((Lifecycle) realm).start();
if ((resources != null) && (resources instanceof Lifecycle))
((Lifecycle) resources).start();
// Start our child containers, if any
Container children[] = findChildren();
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof Lifecycle)
((Lifecycle) children[i]).start();
}
// Start the Valves in our pipeline (including the basic), if any
if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start();
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(START_EVENT, null);
// Start our thread
threadStart();
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}
如我们上面所说,也是几个简单的过程:触发初始化事件、初始化各组件、初始化children(层次间的关系通过children实现)。注意,ContainerBase本身会继承Lifecycle接口和Container接口,而StandardEngine、StandardHost、StandardContext、StandardWrapper都继承自ContainerBase,因此初始化方式非常类似。
3)HostConfig,HostConfig是一个LifecycleListener,如我们上一篇的DEMO代码,作为LifecycleListener注册到StandardHost中,在ContainerBase初始化开始阶段,会触发一个BEFORE_START_EVENT,触发HostConfig的初始化,HostConfig初始化过程是:HostConfig. lifecycleEvent-->HostConfig.start-->HostConfig. deployApps,我们看看HostConfig. deployApps是如何实现的
protected void deployApps() {
File appBase = appBase();
File configBase = configBase();
// Deploy XML descriptors from configBase
deployDescriptors(configBase, configBase.list());
// Deploy WARs, and loop if additional descriptors are found
deployWARs(appBase, appBase.list());
// Deploy expanded folders
deployDirectories(appBase, appBase.list());
}
可以看到,是3种类型,分别是{tomcat}/conf/{hostname}/目录下的{context.xml}、{tomcat}/{appBase}/下的war和{tomcat}/{appBase}下的目录。我们再看看HostConfig. deployDirectory是如何实现的
protected void deployDirectory(String contextPath, File dir, String file) {
DeployedApplication deployedApp = new DeployedApplication(contextPath);
if (deploymentExists(contextPath))
return;
// Deploy the application in this directory
if( log.isDebugEnabled() )
log.debug(sm.getString("hostConfig.deployDir", file));
try {
Context context = (Context) Class.forName(contextClass).newInstance();
if (context instanceof Lifecycle) {
Class clazz = Class.forName(host.getConfigClass());
LifecycleListener listener =
(LifecycleListener) clazz.newInstance();
((Lifecycle) context).addLifecycleListener(listener);
}
context.setPath(contextPath);
context.setDocBase(file);
File configFile = new File(dir, Constants.ApplicationContextXml);
if (deployXML) {
context.setConfigFile(configFile.getAbsolutePath());
}
host.addChild(context);
deployedApp.redeployResources.put(dir.getAbsolutePath(),
new Long(dir.lastModified()));
if (deployXML) {
deployedApp.redeployResources.put(configFile.getAbsolutePath(),
new Long(configFile.lastModified()));
}
addWatchedResources(deployedApp, dir.getAbsolutePath(), context);
} catch (Throwable t) {
log.error(sm.getString("hostConfig.deployDir.error", file), t);
}
deployed.put(contextPath, deployedApp);
}
实际上也没有太多复杂的东西,需要更细节的了解可以看org.apache.catalina.startup.HostConfig的代码
4)ContextConfig,与HostConfig类似,我们这里直接进入ContextConfig.start
protected synchronized void start() {
...略
// Set properties based on DefaultContext
Container container = context.getParent();
...略
// Process the default and application web.xml files
defaultWebConfig();
applicationWebConfig();
if (!context.getIgnoreAnnotations()) {
applicationAnnotationsConfig();
}
if (ok) {
validateSecurityRoles();
}
// Configure an authenticator if we need one
if (ok)
authenticatorConfig();
...略
}
其中defaultWebConfig解析{tomcat}/config/web.xml(提供JSP和welcome file的支持),而applicationWebConfig当然是每个应用的WEB-INF/web.xml了。解析的全过程不再细节描述,可以参见org.apache.catalina.startup.ContextConfig
5)在初始化过程当中,向Container(Engine、Host、Context、Config)注册child(addChild方法)的过程是需要重点关注的地方,由于跟后续请求处理的过程相关联,因此放在后面再做解析
三、通过如上层层初始化,我们的StandardEngine创建完毕,一切准备就绪,可以等待请求接入
分享到:
相关推荐
这个资源包包含了Tomcat的源码、文档以及源码解析,对于深入理解Tomcat的工作原理、优化应用性能以及进行二次开发具有极大的帮助。 首先,让我们深入探讨Tomcat的源码。源码是软件的基石,通过阅读源码,我们可以...
【标题】"Tomcat源码分析系列文档"深入解析了Apache Tomcat服务器的内部工作原理,涵盖了一系列关键知识点,如HTTP协议、类加载机制、容器设计模式等。这些文档为理解Tomcat的运行机制提供了宝贵的资源。 【描述】...
### tomcat源码解析 #### 简介与概览 Tomcat作为一款开源的Servlet容器,被广泛应用于Java Web应用的开发与部署环境中。它不仅支持Servlet API,还支持JSP规范,使得开发者能够轻松地构建动态网页。本文旨在深入...
Tomcat源码剖析 : 整体架构 层层分析 源码解析 架构分析 (Http服务器功能:Socket通信(TCP/IP)、解析Http报文 Servlet容器功能:有很多Servlet(自带系统级Servlet+自定义Servlet),Servlet处理具体的业务逻辑...
Apache Tomcat源码分析 Apache Tomcat是一款广泛应用的开源Java Servlet容器,它是Java EE Web应用程序的标准实现。Tomcat源码的深入理解对于Java Web开发者来说是至关重要的,它可以帮助我们了解HTTP服务器的工作...
### Tomcat源码解析知识点概览 #### 一、Tomcat概述 - **定义**:Apache Tomcat是一款开源的Servlet容器,它实现了Servlet规范,并且提供了作为Web服务器的一些特性,但其提供的性能远不及专业的Web服务器,如...
然后在"Select root directory"中找到解压后的Tomcat源码目录,MyEclipse会识别出项目的结构并导入。确保勾选"Copy projects into workspace"以便在MyEclipse中进行编辑。 导入完成后,你可能需要对项目进行一些...
2. **获取源码**:从Tomcat官方网站下载源码压缩包,解压后得到源代码目录。 3. **创建项目**:在MyEclipse中创建一个新的Java工程,命名为Tomcat源码的版本号。 4. **添加源码**:将解压后的源码目录导入到...
一、Tomcat7源码结构解析 Tomcat7的源代码结构清晰,主要包含以下几个核心模块: 1. catalina:这是Tomcat的核心模块,负责处理Servlet容器的主要功能,如Servlet和Context的生命周期管理,请求处理等。 2. ...
2. Tomcat启动遇到的常见问题:在研究Tomcat源码的过程中,我们会遇到许多启动时常见的问题。这些问题可能包括端口被占用、配置文件错误、类加载器相关问题等。通过对这些问题的分析,我们可以更加深入地理解Tomcat...
3. **Servlet生命周期**:Servlet在Tomcat中的生命周期包括加载、初始化、服务、销毁四个阶段。Tomcat通过Servlet容器管理Servlet实例,确保其正确地创建、初始化和销毁。 4. **请求处理**:当一个HTTP请求到达时,...
6. **Commons Components**:包含一系列可重用的Java组件,如池、线程、数据结构等,这些组件在Tomcat的不同部分被广泛使用。 7. **Lifecycle and Manager Interfaces**:定义了组件的生命周期方法,如初始化、启动...
源码中,这些生命周期方法的实现有助于理解Tomcat的内部工作流程。 4. **部署与加载**:Tomcat可以自动或手动部署Web应用程序。源码中的`Host`和`Context`类展示了如何解析WAR文件并加载应用到服务器。 5. **JMX...
《深入剖析Tomcat7源码》 Tomcat7是一款广泛使用的开源Java Servlet容器,它实现了Java EE中的Servlet和JSP规范。源码分析是提升开发者对服务器内部运作机制理解的重要途径,尤其对于Tomcat这样的核心组件,源码的...
本文将深入探讨“编译Tomcat源码所需jar包”这一主题,帮助开发者了解如何从源码构建Tomcat,以及在这个过程中需要用到的关键jar包。 首先,我们来了解一下为什么要从源码编译Tomcat。直接下载预编译的二进制版本...
《深入理解Tomcat源码:必备依赖包解析》 Tomcat作为一款广泛应用的开源Java Servlet容器,其源码的编译与理解对于开发者来说具有重要的价值。为了能够顺利地编译Tomcat源码,了解并掌握相关的依赖包是至关重要的。...
Apache Tomcat 8.5.23 源码分析 Apache Tomcat 是一个开源的、免费的Web服务器和Servlet容器,它实现了Java Servlet和JavaServer Pages(JSP)规范,是开发和部署Java Web应用的重要平台。深入理解Tomcat的源码有助...
手把手教你搭建Tomcat7源码开发环境,如果有了如下说明还搭建不成功,建议考虑下自己的理解能力,能不能走编码这条路。附近包括Tomcat源码、Tomcat源码开发环境依赖的包、Tomcat的环境编译工具ant 1、建立如下...