对于读过我Tomcat启动流程的小伙伴们应该清楚,在Host容器启动的过程中会激发HostConfig监听器,从而使得HostConfig可以根据对应的web.xml文件构建Context容器并加入Host中,那么HostConfig监听器到底是如何激发的呢?

没有看过启动源码的小伙伴可以移步下文梳理一下过程:

Tomcat启动源码流程分析(图解及源码注释) (三)

Tomcat启动源码流程分析(图解及源码注释) (四)

首先我们要知道无论是Engine,Host,Context,Server等等都是继承于ContainerBase容器,在ContainerBase的start方法中,在调用子容器的start方法后,都会调用一个名为setState(LifecycleState.STARTING)的方法设置当前容器的状态为start状态.

protected synchronized void startInternal() throws LifecycleException {

        .....

        //获取所有子容器,并交给线程池进行启动(线程池在Engine初始化阶段以及被初始化)
        //实际上在StartChild线程启动时,启动子容器的startInternal方法
        Container children[] = findChildren();
        List<Future<Void>> results = new ArrayList<>();
        for (Container child : children) {
            results.add(startStopExecutor.submit(new StartChild(child)));
        }

        MultiThrowable multiThrowable = null;

        .....
        
        //设置管线
        if (pipeline instanceof Lifecycle) {
            ((Lifecycle) pipeline).start();
        }

        //***激发STARTING状态的监听
        setState(LifecycleState.STARTING);

        // Start our thread
        threadStart();
    }

那么为什么这个方法能触发监听器的监听呢?我们点进此方法中,

protected synchronized void setState(LifecycleState state) throws LifecycleException {
        setStateInternal(state, null, true);
    }
private synchronized void setStateInternal(LifecycleState state, Object data, boolean check)
            throws LifecycleException {
        ....

        this.state = state;
        String lifecycleEvent = state.getLifecycleEvent();
        //设置容器的监听器用于start或stop容器
        if (lifecycleEvent != null) {
            fireLifecycleEvent(lifecycleEvent, data);
        }
    }

可以发现一个名为fireLifecycleEvent(lifecycleEvent, data)的方法,这个方法就非常有意思了,在这个方法中容器调用了当前容器中所有监听器的lifecycleEvent方法.

protected void fireLifecycleEvent(String type, Object data) {
        LifecycleEvent event = new LifecycleEvent(this, type, data);
        for (LifecycleListener listener : lifecycleListeners) {
            listener.lifecycleEvent(event);
        }
    }

那么当我们随便打开一个监听器,比如HostConfig类,会发现HostConfig类的接口LifecycleListener中存在一个方法lifecycleEvent(LifecycleEvent event),打开HostConfig中该方法的实现,我们可以发现:

public void lifecycleEvent(LifecycleEvent event) {

        // Identify the host we are associated with
        try {
            host = (Host) event.getLifecycle();
            if (host instanceof StandardHost) {
                setCopyXML(((StandardHost) host).isCopyXML());
                setDeployXML(((StandardHost) host).isDeployXML());
                setUnpackWARs(((StandardHost) host).isUnpackWARs());
                setContextClass(((StandardHost) host).getContextClass());
            }
        } catch (ClassCastException e) {
            log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e);
            return;
        }

        // Process the event that has occurred
        if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) {
            check();
        } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
            beforeStart();
        } else if (event.getType().equals(Lifecycle.START_EVENT)) {
            start();
        } else if (event.getType().equals(Lifecycle.STOP_EVENT)) {
            stop();
        }
    }

就是在这个方法中是的HostConfig监听器调用了HostConfig.start()方法(注:这里状态的判断用的是Lifecycle接口中的一个String对象START_EVENT,实际上就是字符串"start",而一开始LifeCycleState.STARTING是个枚举类,对应的就是Lifecycle接口中的START_EVENT对象,两者在此时是等价的)

public enum LifecycleState {
    ....
    STARTING(true, Lifecycle.START_EVENT),
    ....

    private final boolean available;
    private final String lifecycleEvent;

    private LifecycleState(boolean available, String lifecycleEvent) {
        this.available = available;
        this.lifecycleEvent = lifecycleEvent;
    }
    
    public boolean isAvailable() {
        return available;
    }

    public String getLifecycleEvent() {
        return lifecycleEvent;
    }
}

在让我们来深入理解一下Tomcat容器的构建,所有Tomcat的容器都继承于LifecycleBase抽象类

该抽象类中存在当前容器的状态,以及所有监听器的List集合

   /**
     * The list of registered LifecycleListeners for event notifications.
     */
    private final List<LifecycleListener> lifecycleListeners = new CopyOnWriteArrayList<>();

    /**
     * The current state of the source component.
     */
    private volatile LifecycleState state = LifecycleState.NEW;

 

同时setState方法是LifecycleBase中的一个确定的方法

protected synchronized void setState(LifecycleState state) throws LifecycleException {
        setStateInternal(state, null, true);
    }

他调用了LifecycleBase类中的setStateInternal方法

private synchronized void setStateInternal(LifecycleState state, Object data, boolean check)
            throws LifecycleException {

        ....
        this.state = state;
        String lifecycleEvent = state.getLifecycleEvent();
        //设置容器的监听器用于start或stop容器
        if (lifecycleEvent != null) {
            fireLifecycleEvent(lifecycleEvent, data);
        }
    }

setStateInternal方法调用了fireLifecycleEvent方法

protected void fireLifecycleEvent(String type, Object data) {
        LifecycleEvent event = new LifecycleEvent(this, type, data);
        for (LifecycleListener listener : lifecycleListeners) {
            listener.lifecycleEvent(event);
        }
    }

此方法则如上文中所说的,调用了容器内部所有Listener的lifecycleEvent方法,

由此可以达到当状态改变时,容器能够自主的通过Listener进行操作,实际上这就是观察者模式的一大运用.

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐