`
ayufox
  • 浏览: 276175 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

[Tomcat源码系列]结构解析 2)生命期控制结构

阅读更多

一、生命期控制结构基础
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创建完毕,一切准备就绪,可以等待请求接入

2
0
分享到:
评论

相关推荐

    tomcat源码+文档pdf+源码解析

    这个资源包包含了Tomcat的源码、文档以及源码解析,对于深入理解Tomcat的工作原理、优化应用性能以及进行二次开发具有极大的帮助。 首先,让我们深入探讨Tomcat的源码。源码是软件的基石,通过阅读源码,我们可以...

    tomcat 源码分析系列文档

    【标题】"Tomcat源码分析系列文档"深入解析了Apache Tomcat服务器的内部工作原理,涵盖了一系列关键知识点,如HTTP协议、类加载机制、容器设计模式等。这些文档为理解Tomcat的运行机制提供了宝贵的资源。 【描述】...

    tomcat源码解析

    ### tomcat源码解析 #### 简介与概览 Tomcat作为一款开源的Servlet容器,被广泛应用于Java Web应用的开发与部署环境中。它不仅支持Servlet API,还支持JSP规范,使得开发者能够轻松地构建动态网页。本文旨在深入...

    「Tomcat源码剖析」.pdf

    Tomcat源码剖析 : 整体架构 层层分析 源码解析 架构分析 (Http服务器功能:Socket通信(TCP/IP)、解析Http报文 Servlet容器功能:有很多Servlet(自带系统级Servlet+自定义Servlet),Servlet处理具体的业务逻辑...

    tomcat源码

    Apache Tomcat源码分析 Apache Tomcat是一款广泛应用的开源Java Servlet容器,它是Java EE Web应用程序的标准实现。Tomcat源码的深入理解对于Java Web开发者来说是至关重要的,它可以帮助我们了解HTTP服务器的工作...

    Tomcat源码解析.pdf

    ### Tomcat源码解析知识点概览 #### 一、Tomcat概述 - **定义**:Apache Tomcat是一款开源的Servlet容器,它实现了Servlet规范,并且提供了作为Web服务器的一些特性,但其提供的性能远不及专业的Web服务器,如...

    Ant编译Tomcat源码、MyEclipse导入Tomcat源码、执行Tomcat源码启动Tomcat

    然后在"Select root directory"中找到解压后的Tomcat源码目录,MyEclipse会识别出项目的结构并导入。确保勾选"Copy projects into workspace"以便在MyEclipse中进行编辑。 导入完成后,你可能需要对项目进行一些...

    tomcat源码导入myeclipse

    2. **获取源码**:从Tomcat官方网站下载源码压缩包,解压后得到源代码目录。 3. **创建项目**:在MyEclipse中创建一个新的Java工程,命名为Tomcat源码的版本号。 4. **添加源码**:将解压后的源码目录导入到...

    tomcat7源码下载

    一、Tomcat7源码结构解析 Tomcat7的源代码结构清晰,主要包含以下几个核心模块: 1. catalina:这是Tomcat的核心模块,负责处理Servlet容器的主要功能,如Servlet和Context的生命周期管理,请求处理等。 2. ...

    Tomcat源码研究.pdf

    2. Tomcat启动遇到的常见问题:在研究Tomcat源码的过程中,我们会遇到许多启动时常见的问题。这些问题可能包括端口被占用、配置文件错误、类加载器相关问题等。通过对这些问题的分析,我们可以更加深入地理解Tomcat...

    tomcat源码资源包

    6. **Commons Components**:包含一系列可重用的Java组件,如池、线程、数据结构等,这些组件在Tomcat的不同部分被广泛使用。 7. **Lifecycle and Manager Interfaces**:定义了组件的生命周期方法,如初始化、启动...

    tomcat6的源码

    源码中,这些生命周期方法的实现有助于理解Tomcat的内部工作流程。 4. **部署与加载**:Tomcat可以自动或手动部署Web应用程序。源码中的`Host`和`Context`类展示了如何解析WAR文件并加载应用到服务器。 5. **JMX...

    tomcat7源码

    《深入剖析Tomcat7源码》 Tomcat7是一款广泛使用的开源Java Servlet容器,它实现了Java EE中的Servlet和JSP规范。源码分析是提升开发者对服务器内部运作机制理解的重要途径,尤其对于Tomcat这样的核心组件,源码的...

    编译tomcat源码所需jar包

    本文将深入探讨“编译Tomcat源码所需jar包”这一主题,帮助开发者了解如何从源码构建Tomcat,以及在这个过程中需要用到的关键jar包。 首先,我们来了解一下为什么要从源码编译Tomcat。直接下载预编译的二进制版本...

    tomcat源码依赖包

    《深入理解Tomcat源码:必备依赖包解析》 Tomcat作为一款广泛应用的开源Java Servlet容器,其源码的编译与理解对于开发者来说具有重要的价值。为了能够顺利地编译Tomcat源码,了解并掌握相关的依赖包是至关重要的。...

    tomcat8源码

    Apache Tomcat 8.5.23 源码分析 Apache Tomcat 是一个开源的、免费的Web服务器和Servlet容器,它实现了Java Servlet和JavaServer Pages(JSP)规范,是开发和部署Java Web应用的重要平台。深入理解Tomcat的源码有助...

    Tomcat源码开发环境搭建

    手把手教你搭建Tomcat7源码开发环境,如果有了如下说明还搭建不成功,建议考虑下自己的理解能力,能不能走编码这条路。附近包括Tomcat源码、Tomcat源码开发环境依赖的包、Tomcat的环境编译工具ant 1、建立如下...

    eclipse运行tomcat源码:修改源码:重新编译:重新打包

    文件描述: 1.tomcat源码文件 2.tomcat程序文件 3.Ant程序文件 4.tomcat源码在eclipse运行,重新编译,重新打包步骤文件 5.一个tomcat源码在eclipse上运行的java工程...2.学习如何修改tomcat源码后如何重新编译,打包。

Global site tag (gtag.js) - Google Analytics