tomcat的启动过程与Lifecycle

本文主要介绍tomcat启动过程中,从server到context这一部分,主要涉及Lifecycle。

public interface Lifecycle {
    public static final String BEFORE_INIT_EVENT = "before_init";
    public static final String AFTER_INIT_EVENT = "after_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 AFTER_DESTROY_EVENT = "after_destroy";
    public static final String BEFORE_DESTROY_EVENT = "before_destroy";
    public static final String PERIODIC_EVENT = "periodic";
    public static final String CONFIGURE_START_EVENT = "configure_start";
    public static final String CONFIGURE_STOP_EVENT = "configure_stop";

    public void addLifecycleListener(LifecycleListener listener);
    public LifecycleListener[] findLifecycleListeners();
    public void removeLifecycleListener(LifecycleListener listener);
    public void init() throws LifecycleException;
    public void start() throws LifecycleException;
    public void stop() throws LifecycleException;
    public void destroy() throws LifecycleException;
    public LifecycleState getState();
    public String getStateName();
}

上面是Lifecycle接口,我把注释都去掉了,接口定义中开始部分的static域(如:BEFORE_INIT_EVENT)是Lifecycle中支持的各种事件。之前我们提到过,Lifecycle实现了一个观察者模式,而上面这些事件就代表了tomcat中各个组件生命周期中的各个事件,当这些事件发生的时候,会通知感兴趣的观察者(LifecycleListener)。

Lifecycletomcat中被使用的很多,用来管理tomcat中各个组件的生命周期,之前的博文中我们提到过的serverserviceconnectorenginehostcontext等,他们都派生了Lifecycle接口。

Lifecycle中还声明了几个很重要的方法:initstartstopdestroy。这几个方法共同构成了组件的生命周期,init-初始化,start-启动,stop-停止,destroy-销毁。再看看上面的那些事件,实际上都是和这里的几个生命周期对应的,每个生命周期XXX,都包括beforeXXXXXXafterXXX这三个事件。各个组件在tomcat启动之后,到shutdown之前,就会经历这样的生命周期过程,从一开始初始化,最后被销毁,中间可能会经历startstopstartstop,起起落落。就像人诞生下来,不管中间过得多么精彩,但最终的结果还是会死亡。

Tomcat分成很多的组件,这些组件需要分别启动,我们已经知道Lifecycle中声明的start的方法就是用来完成这项工作的。这些组件都派生了Lifecycle接口,分别实现了Lifecycle里的方法,也就拥有了管理自己生命周期(初始化、启动、停止、销毁)的能力。

接下来,我们分析下各个组件是怎么样完成启动过程的。

一个Server就代表了整个catalina servlet容器。因此,他的属性,也能代表了整个servlet容器的特性。整个servlet的生命周期都由server控制。

我们在启动tomcat的时候,首先会创建一个单例的server对象(实际上是StandardServer对象,我们之前提到过,一个tomcat中,只会有一个server),然后进行初始化(init),之后会调用serverstart方法,用来启动server

我们也提到过server中包含service,可能是一个或者多个。

/**
     * The set of Services associated with this Server.
     */
    private Service services[] = new Service[0];

    /**
     * Start nested components ({@link Service}s) and implement the requirements
     * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
     *
     * @exception LifecycleException if this component detects a fatal error
     *  that prevents this component from being used
     */
    @Override
    protected void startInternal() throws LifecycleException {

        fireLifecycleEvent(CONFIGURE_START_EVENT, null);
        setState(LifecycleState.STARTING);

        globalNamingResources.start();
        
        // Start our defined Services
        synchronized (services) {
            for (int i = 0; i < services.length; i++) {
                services[i].start();
            }
        }
    }

Serverstart方法中,会调用上面的startInternal()方法。在startInternal()方法中,我们可以看到,server会将自己所拥有的service全部给start-启动。

Service中,有2tomcat中最重要的组件:connectorcontainerConnector用来接收浏览器的请求,一个service中可以有多个connectorContainer主要有3种,分别是enginehostcontextservice直接包含的是engineengine包含hosthost包含context,一个service只能有一个engine

/**
     * The set of Connectors associated with this Service.
     */
    protected Connector connectors[] = new Connector[0];

    /**
     * The Container associated with this Service. (In the case of the
     * org.apache.catalina.startup.Embedded subclass, this holds the most
     * recently added Engine.)
     */
    protected Container container = null;

    /**
     * Start nested components ({@link Executor}s, {@link Connector}s and
     * {@link Container}s) and implement the requirements of
     * {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
     *
     * @exception LifecycleException if this component detects a fatal error
     *  that prevents this component from being used
     */
    @Override
    protected void startInternal() throws LifecycleException {

        if(log.isInfoEnabled())
            log.info(sm.getString("standardService.start.name", this.name));
        setState(LifecycleState.STARTING);

        // Start our defined Container first
        if (container != null) {
            synchronized (container) {
                container.start();
            }
        }

        synchronized (executors) {
            for (Executor executor: executors) {
                executor.start();
            }
        }

        // Start our defined Connectors second
        synchronized (connectors) {
            for (Connector connector: connectors) {
                try {
                    // If it has already failed, don't try and start it
                    if (connector.getState() != LifecycleState.FAILED) {
                        connector.start();
                    }
                } catch (Exception e) {
                    log.error(sm.getString(
                            "standardService.connector.startFailed",
                            connector), e);
                }
            }
        }
    }

server一样,servicestart方法会调用他所拥有的containerconnectorstart方法。

如此一来,就相当于形成了一条链,server启动的时候会去启动serviceservice启动的时候又会顺道把containerconnector启动了。

剩下的就是container的启动了,service启动的container,实际上就是engineStandardEngin)。

容器的start方法和serverservice的有点不一样,因为容器有一个包含关系,父容器包含子容器。父容器启动的时候,会顺道将自己所有的子容器启动,顶层的容器是engine,他的子容器是一个或多个hostengine启动的时候,会将他拥有的所有host启动,然后host启动的时候,又会将context启动。

    /**
     * Start this component and implement the requirements
     * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
     *
     * @exception LifecycleException if this component detects a fatal error
     *  that prevents this component from being used
     */
    @Override
    protected synchronized void startInternal() throws LifecycleException {

        // Start our subordinate components, if any
        if ((loader != null) && (loader instanceof Lifecycle))
            ((Lifecycle) loader).start();
        logger = null;
        getLogger();
        if ((manager != null) && (manager instanceof Lifecycle))
            ((Lifecycle) manager).start();
        if ((cluster != null) && (cluster instanceof Lifecycle))
            ((Lifecycle) cluster).start();
        Realm realm = getRealmInternal();
        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();
        List<Future<Void>> results = new ArrayList<Future<Void>>();
        for (int i = 0; i < children.length; i++) {
            results.add(startStopExecutor.submit(new StartChild(children[i])));
        }

        boolean fail = false;
        for (Future<Void> result : results) {
            try {
                result.get();
            } catch (Exception e) {
                log.error(sm.getString("containerBase.threadedStartFailed"), e);
                fail = true;
            }

        }
        if (fail) {
            throw new LifecycleException(
                    sm.getString("containerBase.threadedStartFailed"));
        }

        // Start the Valves in our pipeline (including the basic), if any
        if (pipeline instanceof Lifecycle)
            ((Lifecycle) pipeline).start();


        setState(LifecycleState.STARTING);

        // Start our thread
        threadStart();

    }

如是, tomcat 启动过程中各个组件的启动流程。



转载于:https://my.oschina.net/u/227422/blog/66965

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值