`
haitaoandroid
  • 浏览: 27484 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Tomcat源码分析(七)--单一启动/关闭机制(生命周期)

 
阅读更多

在前面的大部分文章都是讲连接器和容器的,以后的内容会偏向写一些Tomcat的其他组件以及一些细节的东西。

Tomcat有很多组件,要一个一个启动组件难免有点麻烦。由于Tomcat的包含关系是Catalina->Server->Service->容器/连接器/日志器等,于是可通过父组件负责启动/关闭它的子组件,这样只要启动Catalina,其他的都自动启动了。这种单一启动和关闭的机制是通过实现Lifecycle接口来实现的。下面是Lifecycle接口的定义:

 

public interface Lifecycle {
    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 void addLifecycleListener(LifecycleListener listener);//在此组件中添加一个监听器
    public LifecycleListener[] findLifecycleListeners();
    public void removeLifecycleListener(LifecycleListener listener);
    public void start() throws LifecycleException;//组件启动方法
    public void stop() throws LifecycleException;
}


当组件实现了Lifecycle接口,父组件启动的时候,即调用start方法时,只要在父组件的start方法中也调用子组件的start方法即可(只有实现统一的接口Lifecycle才能实现统一调用,如以下调用方式:(Lifecycle)子组件.start()),下面一步一步来看源代码,首先在Catalina启动start,部分代码如下:

 

 

// Start the new server
        if (server instanceof Lifecycle) {
            try {
                server.initialize();
                ((Lifecycle) server).start();//启动server
                try {
                    // Register shutdown hook
                    Runtime.getRuntime().addShutdownHook(shutdownHook);
                } catch (Throwable t) {
                    // This will fail on JDK 1.2. Ignoring, as Tomcat can run
                    // fine without the shutdown hook.
                }
                // Wait for the server to be told to shut down
                server.await();
            } catch (LifecycleException e) {
                System.out.println("Catalina.start: " + e);
                e.printStackTrace(System.out);
                if (e.getThrowable() != null) {
                    System.out.println("----- Root Cause -----");
                    e.getThrowable().printStackTrace(System.out);
                }
            }
        }

关键看((Lifecycle) server).start();这样便在启动Catalina的时候启动了Server,再看StandardServer的start方法:

 

 

    public void start() throws LifecycleException {

        // Validate and update our current component state
        if (started)
            throw new LifecycleException
                (sm.getString("standardServer.start.started"));
        // Notify our interested LifecycleListeners
        //发送这个事件
        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);//发送生命周期事件。

        lifecycle.fireLifecycleEvent(START_EVENT, null);
        started = true;

        // Start our defined Services
        synchronized (services) {   //由这里也可以看出一个server可以有多个services
            for (int i = 0; i < services.length; i++) {
                if (services[i] instanceof Lifecycle)
                    ((Lifecycle) services[i]).start();
            }
        }

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);

    }

主要做了两件事,1:发送生命周期事件给监听者;2:启动子组件services(至于server怎么关联上services请看前面的几篇文章,以后都不再题怎么关联上的了)。

 

这里先岔开一下,说一下监听器,lifecycle是一个工具类LifecycleSupport的实例,每一个组件都有这样一个工具类,这个工具类的作用就是帮助管理该组件上的监听器,包括添加监听器和群发事件给监听器,看LifecycleSupport类的一些关键代码:

 

public final class LifecycleSupport {
public LifecycleSupport(Lifecycle lifecycle) {

        super();
        this.lifecycle = lifecycle;

    }
  private LifecycleListener listeners[] = new LifecycleListener[0];
 public void addLifecycleListener(LifecycleListener listener) { //向listeners添加监听器

      synchronized (listeners) {
          LifecycleListener results[] =
            new LifecycleListener[listeners.length + 1];
          for (int i = 0; i < listeners.length; i++)
              results[i] = listeners[i];
          results[listeners.length] = listener;
          listeners = results;
      }

    }
 public void fireLifecycleEvent(String type, Object data) {//群发事件给监听器

        LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
        LifecycleListener interested[] = null;
        synchronized (listeners) {
            interested = (LifecycleListener[]) listeners.clone();
        }
        for (int i = 0; i < interested.length; i++)
            interested[i].lifecycleEvent(event);//发送组件生命周期事件。

    }
}

先看构造方法,传入一个lifecycle,因为每个组件都实现了lifecycle,所以这里传入的实际上是一个组件,即每个组件都有一个LifecycleSupport与之关联,当要在组件中添加一个监听器的时候,实际上是添加进工具类LifecycleSupport的一个监听器数组listeners中,当要发送一个组件生命周期的事件时,工具类就会遍历监听器数组,然后再一个一个的发送事件。这里需要先实现我们自己的监听器类并且添加进我们需要监听的组件当中。实现监听器类只要实现LifecycleListener接口就行,这个接口只有一个方法:

 

 

public interface LifecycleListener {
    public void lifecycleEvent(LifecycleEvent event);
}

我们需要做的就是实现LifecycleListener接口来拥有自己的监听器,在lifecycleEvent方法里写自己监听到事件后该做的事情,然后添加进要监听的组件就行,比如当我们要看StandardServer是否启动了,在上面StandardServer的start方法有一句这样的代码:lifecycle.fireLifecycleEvent(START_EVENT, null);即发送StandardServer启动的事件给跟它关联的监听器。接下来回到一开始,当server启动后,接着启动它的子组件service,即调用StandardService的start方法,这个方法跟StandardServer的start方法差不多,只是启动了连接器和容器,连接器的start方法在前面的文章已经讲过了,主要是启动了n个处理器HttpProcessor组件。顶级容器是StandardEngine,它的start方法仅仅调用了父类ContainerBase的start方法,下面看ContainerBase的start方法:

 

   public synchronized void start() throws LifecycleException {

        // Validate and update our current component state
        if (started)
            throw new LifecycleException
                (sm.getString("containerBase.alreadyStarted", logName()));

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);

        addDefaultMapper(this.mapperClass);
        started = true;

        // Start our subordinate components, if any
        if ((loader != null) && (loader instanceof Lifecycle)) //启动所有其他的组件
            ((Lifecycle) loader).start();
        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 Mappers, if any
        Mapper mappers[] = findMappers();
        for (int i = 0; i < mappers.length; i++) {
            if (mappers[i] instanceof Lifecycle)
                ((Lifecycle) mappers[i]).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);

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);

    }


这里代码比较丰富,由它启动了Tomcat其他所有的组件,包括加载器,映射器,日志记录器,管道等等,由这里也可以看出,他们都实现了Lifecycle接口。统一关闭跟统一启动的逻辑差不多,这里就不再说了。至此,我们对Tomcat怎么实现统一启动/关闭应该有一个比较清晰的认识了!

分享到:
评论

相关推荐

    tomcat-redis-session-manager源码

    通过源码分析,我们可以看到它在设计上的灵活性和实用性,以及在处理高并发场景时的优秀性能。无论是开发者还是运维人员,理解并掌握这套解决方案的内在机制,都能在构建大型Web应用时提供有力支持。

    tomcat架构的源码分析

    ### Tomcat架构的源码分析 #### 一、Tomcat的架构概述 Tomcat作为一款广泛使用的开源Java Servlet容器,其内部架构设计简洁而高效。本文档将对Tomcat的架构进行详细介绍,并从源码层面深入分析其核心组成部分。...

    cas源码.....

    【标题】:“CAS源码分析” 【描述】:CAS(Central Authentication Service)是 Yale 大学发起的一个开源项目,主要用于实现单点登录(Single Sign-On, SSO)。它是一个基于 Web 的身份验证系统,允许用户通过单一...

    J2EE课程总结

    - 用于监听应用程序的不同生命周期事件,如ServletContextListener监听上下文的启动和关闭。 #### JSP (JavaServer Pages) **1. JSP的工作原理** - JSP页面会被编译成Servlet,然后由Servlet引擎执行。 **2. JSP...

    单点登入--CAS3.0

    2. **会话管理**:正确处理TGT和ST的生命周期,防止会话固定攻击。 3. **防止重放攻击**:票证只能使用一次,不能被重复使用。 4. **多因素认证**:考虑增加额外的安全层,如短信验证码或生物识别。 通过了解和实践...

    Expert One-on-One J2EE Design & Development

    掌握这些工具的使用能够提高开发效率并简化整个软件开发生命周期。 压缩文件“ticket.ear”可能是一个J2EE应用程序的部署单元,通常包含一个或多个EJB模块、Web模块以及其他资源文件。.EAR文件是Enterprise Archive...

    30天学通Java Web项目案例开发(源码.rar

    5. **Web容器**:如Tomcat,用于运行Java Web应用,管理Servlet的生命周期,处理请求和响应。 6. **JSP标签库**:例如JSTL和Struts Tags,可以简化JSP页面的编写,减少Java代码的嵌入,使页面更清晰。 7. **Maven...

    基于Jsp的仓库管理系统源码.zip

    2. **Servlet**:理解Servlet生命周期,以及它与JSP的关系,如何通过Servlet处理HTTP请求和响应。 3. **MVC模式**:JSP通常结合Model-View-Controller模式进行开发,了解模型、视图、控制器各自的角色。 4. **...

    spring2与quartz在Web整合

    IoC 通过容器管理对象的生命周期和依赖关系,而 AOP 则允许在不修改代码的情况下,通过切面来实现横切关注点,如日志、事务管理等。 2. **Quartz 工作原理**:Quartz 是基于 JDBC 或内存的数据存储方式来管理作业和...

    使用portal实现个人工作台

    开发portlet需要理解Portlet API,包括初始化、渲染、事件处理等生命周期方法。 8. **权限管理**: 在个人工作台上,权限管理至关重要。这涉及到用户角色的定义,以及基于角色的访问控制(RBAC),确保用户只能...

    Portal技术实现[实例]

    容器负责加载Portlet并管理其生命周期。 3. **Portlet通信**:Portlets通过门户服务器进行通信,避免了直接的跨Portlet交互,保证了系统的稳定性和安全性。 4. **个性化配置**:用户可以通过Portal提供的界面,...

    SpringBoot+Vue前后端分离型图书管理系统.zip

    总的来说,"SpringBoot+Vue前后端分离型图书管理系统"是一个综合性的项目,涵盖了软件开发的全生命周期,对于学习者来说,不仅可以深入了解SpringBoot和Vue.js的使用,还能体验到从需求分析到系统上线的完整流程,...

    会员管理系统代码java编写

    Servlet的生命周期包括加载、初始化、服务和销毁四个阶段。 2. JSP:JavaServer Pages(JSP)是Java EE的一部分,它允许开发人员将静态内容(HTML、CSS、JavaScript)与动态Java代码结合,方便创建交互式的Web应用...

Global site tag (gtag.js) - Google Analytics