1

前言
上篇文章分析了Service的 init 和 start 方法,在这两个方法中关键的是调用 Engine 和 Connector 的 init 和 start 方法,一个 Service 里只有一个 Engine,有多个 Connector。本篇文章分析 Engine 的启动。Engine 的实现类是 StandardEngine,


1 StandardEngine#init 方法

StandardEngine 的父类是 ContainerBase ,而 ContainerBase 的父类是 LifecycleMBeanBase。ContainerBase 和 StandardEngine 都实现了 initInternal 和 startInternal 方法。
1.1 StandardEngine#initInternal 方法

@Override
protected void initInternal() throws LifecycleException {
    // Ensure that a Realm is present before any attempt is made to start
    // one. This will create the default NullRealm if necessary.
    getRealm();
    super.initInternal();
}

StandardEngine 的 initInternal 方法中,先调用了 getRealm() 方法,确保 StandardEngine 的父类 StandardEngine中的 Realm 类型的属性不为空。
Realm 是 Tomcat 的特性功能,跟 NamingResouce,这里先略过。
然后调用了 super.initInternal(),也就是 ContainerBase 的 initInternal 方法

1.2 ContainerBase#initInternal 方法

@Override
protected void initInternal() throws LifecycleException {
    reconfigureStartStopExecutor(getStartStopThreads());
    super.initInternal();
}


/**
 * The number of threads available to process start and stop events for any
 * children associated with this container.
 */
private int startStopThreads = 1;
protected ExecutorService startStopExecutor;


@Override
public int getStartStopThreads() {
    return startStopThreads;
}

private void reconfigureStartStopExecutor(int threads) {
    if (threads == 1) {
        // Use a fake executor
        if (!(startStopExecutor instanceof InlineExecutorService)) {
            startStopExecutor = new InlineExecutorService();
        }
    } else {
        // Delegate utility execution to the Service
        Server server = Container.getService(this).getServer();
        server.setUtilityThreads(threads);
        startStopExecutor = server.getUtilityExecutor();
    }
}

super.initInternal() 是调用的 LifecycleMBeanBase 的 initInternal() 方法。之前的文章里讲过了,这里就略过。
reconfigureStartStopExecutor 方法是设置一个线程池来处理子容器启动和关闭事件,。
可以看出,getStartStopThreads() 返回的是成员变量 startStopThreads,而 startStopThreads 默认为 1 ,所以 reconfigureStartStopExecutor 方法会走 if 语句,而 startStopExecutor 最开始是没有赋值的,startStopExecutor instanceof InlineExecutorService 会返回 false,因此最终会执行 startStopExecutor = new InlineExecutorService(),InlineExecutorService 只是简单地实现了 java.util.concurrent.AbstractExecutorService 类。
最终 reconfigureStartStopExecutor 给 startStopExecutor 这个成员变量设置了,startStopExecutor。


2 StandardEngine#start 方法

StandardEngine 的 start 方法跟它的 init 方法类似。
2.1 StandardEngine#startInternal 方法

/**
 * 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 {

    // Log our server identification information
    if (log.isInfoEnabled()) {
        log.info(sm.getString("standardEngine.start", ServerInfo.getServerInfo()));
    }

    // Standard container startup
    super.startInternal();
}

StandardEngine#startInternal 方法只是简单地调用了 ContainerBase 的startInternal 方法。

2.2 ContainerBase#startInternal 方法

/**
 * 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
    logger = null;
    getLogger();
    Cluster cluster = getClusterInternal();
    if (cluster instanceof Lifecycle) {
        ((Lifecycle) cluster).start();
    }
    Realm realm = getRealmInternal();
    if (realm instanceof Lifecycle) {
        ((Lifecycle) realm).start();
    }

    // Start our child containers, if any
    Container children[] = findChildren();
    List<Future<Void>> results = new ArrayList<>();
    for (int i = 0; i < children.length; i++) {
        results.add(startStopExecutor.submit(new StartChild(children[i])));
    }

    MultiThrowable multiThrowable = null;

    for (Future<Void> result : results) {
        try {
            result.get();
        } catch (Throwable e) {
            log.error(sm.getString("containerBase.threadedStartFailed"), e);
            if (multiThrowable == null) {
                multiThrowable = new MultiThrowable();
            }
            multiThrowable.add(e);
        }

    }
    if (multiThrowable != null) {
        throw new LifecycleException(sm.getString("containerBase.threadedStartFailed"),
                multiThrowable.getThrowable());
    }

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

    setState(LifecycleState.STARTING);

    // Start our thread
    if (backgroundProcessorDelay > 0) {
        monitorFuture = Container.getService(ContainerBase.this).getServer()
                .getUtilityExecutor().scheduleWithFixedDelay(
                        new ContainerBackgroundProcessorMonitor(), 0, 60, TimeUnit.SECONDS);
    }
}

首先调用了 getClusterInternal() 和 getRealmInternal() 方法分别获取了,Cluster 和 Realm 对象,然后调用这两个对象的 start 方法啊,如果这两个对象是继承自 Lifecycle 的话。
Cluster 和 Realm 是 tomcat 新增的特性,这里就先略过不讲。

其次,用 findChildren() 方法获取子容器
并将子容器的启动封装在一个 StartChild 对象里,
然后将这个 StartChild 对象丢到 startStopExecutor 中,这个 startStopExecutor 就是在文中上面介绍到的,
并等待执行结果,如果执行中出现异常,则将收集到 MultiThrowable 对象了,并抛出 LifecycleException 异常。

private static class StartChild implements Callable<Void> {

    private Container child;

    public StartChild(Container child) {
        this.child = child;
    }

    @Override
    public Void call() throws LifecycleException {
        child.start();
        return null;
    }
}

StartChild 类就只是简单执行 Container 对象的 start 方法。
Engine 的子容器是 Host,而 Host 的子容器是 Context,Context 的子容器是 Wrapper。
所以 Host#start,Context#start,Wrapper#start 会被依次调用。
Host#start,Context#start,Wrapper#start 会在后面的文章中介绍,这里先略过。

调用完子容器的 start 方法之后,就开始调用 Pipeline 的 start 方法。
Pipeline 是 Container 用来处理请求的,上篇文章提到 Container 是处理请求的,Container 处理请求实际上是交给 Pipeline 处理的,Pipeline 串联了一个或多个 Valve,用 Value 去处理请求。
Pipeline 和 Valve 是处理Http请求非常重要的组件,后面的文章会专门讲解。

最后,根据 backgroundProcessorDelay 判断是否需要在后台处理一些任务,如果需要就使用 Server 里的 utilityExecutorWrapper 线程池去执行 ContainerBackgroundProcessorMonitor 任务。utilityExecutorWrapper 在这篇文章中介绍过。
backgroundProcessorDelay 的默认值是 -1,但是在 StandardEngine 里被赋值为 10。

protected class ContainerBackgroundProcessorMonitor implements Runnable {
    @Override
    public void run() {
        if (getState().isAvailable()) {
            threadStart();
        }
    }
}

ContainerBackgroundProcessorMonitor 任务很简单,就是执行 threadStart() 方法。

2.3 ContainerBase#threadStart() 方法

/**
 * Start the background thread that will periodically check for
 * session timeouts.
 */
protected void threadStart() {
    if (backgroundProcessorDelay > 0
            && (getState().isAvailable() || LifecycleState.STARTING_PREP.equals(getState()))
            && (backgroundProcessorFuture == null || backgroundProcessorFuture.isDone())) {
        if (backgroundProcessorFuture != null && backgroundProcessorFuture.isDone()) {
            // There was an error executing the scheduled task, get it and log it
            try {
                backgroundProcessorFuture.get();
            } catch (InterruptedException | ExecutionException e) {
                log.error(sm.getString("containerBase.backgroundProcess.error"), e);
            }
        }
        backgroundProcessorFuture = Container.getService(this).getServer().getUtilityExecutor()
                .scheduleWithFixedDelay(new ContainerBackgroundProcessor(),
                        backgroundProcessorDelay, backgroundProcessorDelay,
                        TimeUnit.SECONDS);
    }
}

threadStart() 的重点是使用 Server 里的 utilityExecutorWrapper 去执行 ContainerBackgroundProcessor 任务。

2.4 ContainerBackgroundProcessor的 run 方法

/**
 * Private runnable class to invoke the backgroundProcess method
 * of this container and its children after a fixed delay.
 */
protected class ContainerBackgroundProcessor implements Runnable {

    @Override
    public void run() {
        processChildren(ContainerBase.this);
    }

    protected void processChildren(Container container) {
        ClassLoader originalClassLoader = null;

        try {
            if (container instanceof Context) {
                Loader loader = ((Context) container).getLoader();
                // Loader will be null for FailedContext instances
                if (loader == null) {
                    return;
                }

                // Ensure background processing for Contexts and Wrappers
                // is performed under the web app's class loader
                originalClassLoader = ((Context) container).bind(false, null);
            }
            container.backgroundProcess();
            Container[] children = container.findChildren();
            for (int i = 0; i < children.length; i++) {
                if (children[i].getBackgroundProcessorDelay() <= 0) {
                    processChildren(children[i]);
                }
            }
        } catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
            log.error(sm.getString("containerBase.backgroundProcess.error"), t);
        } finally {
            if (container instanceof Context) {
                ((Context) container).unbind(false, originalClassLoader);
            }
        }
    }
}

ContainerBackgroundProcessor 的一个重点是调用 Container 的 backgroundProcess() 方法,然后递归处理调用 ContainerBackgroundProcessor#processChildren 来调用子容器的 backgroundProcess(),另外,如果 Container 是 Context 的实现来的话,还会调用 Context#bind 方法。

StandardEngine 没有重载 ContainerBase 的 backgroundProcess() 方法,而 StandardHost、StandardContext、StandardWrapper 都没有重新给 backgroundProcessorDelay 赋值,所以这些类的 getBackgroundProcessorDelay() 返回的值是 -1,因此都这些类的 backgroundProcess() 都将会执行。

2.5 ContainerBase#backgroundProcess() 方法

/**
 * Execute a periodic task, such as reloading, etc. This method will be
 * invoked inside the classloading context of this container. Unexpected
 * throwables will be caught and logged.
 */
@Override
public void backgroundProcess() {

    if (!getState().isAvailable())
        return;

    Cluster cluster = getClusterInternal();
    if (cluster != null) {
        try {
            cluster.backgroundProcess();
        } catch (Exception e) {
            log.warn(sm.getString("containerBase.backgroundProcess.cluster",
                    cluster), e);
        }
    }
    Realm realm = getRealmInternal();
    if (realm != null) {
        try {
            realm.backgroundProcess();
        } catch (Exception e) {
            log.warn(sm.getString("containerBase.backgroundProcess.realm", realm), e);
        }
    }
    Valve current = pipeline.getFirst();
    while (current != null) {
        try {
            current.backgroundProcess();
        } catch (Exception e) {
            log.warn(sm.getString("containerBase.backgroundProcess.valve", current), e);
        }
        current = current.getNext();
    }
    fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null);
}

可以看出 ContainerBase 的 backgroundProcess() 方法依次调用 Cluster、Realm、Valve 的 backgroundProcess() 方法,然后触发一个 Lifecycle.PERIODIC_EVENT 事件。
Cluster、Realm、Valve 不是本文的重点,这里就不细讲了。


小结
本文介绍了 Engine 的 initInternal 和 startInternal 方法。在这两个方法里 StandardEngine 主要做的事情就是调用父类 ContainerBase 的重载方法,在 ContainerBase 的 startInternal 方法里,依次调用了 Container 里有的 Cluster 对象、Realm对象、子Container对象、Pipeline对象的 start 方法,并且异步调用了 Container 自身的 backgroundProcess 方法,以及递归调用了子类的 backgroundProcess 方法。


客官
36 声望25 粉丝