Tomcat源码分析(八) -- Engine

641 阅读3分钟

Tomcat 中的 Engine

Engine 定义

public interface Engine extends Container {

    public String getDefaultHost();

    public void setDefaultHost(String defaultHost);

    public String getJvmRoute();

    public void setJvmRoute(String jvmRouteId);

    public Service getService();

    public void setService(Service service);
}

从定义中可以看出

  • Engine 继承了 container 接口。注意 Container 接口继承了 Lifecycle 接口
  • Engine 的实现类是 StandardEngine

StandardEngine 的构造方法

public StandardEngine() {

    super();
    //这里为 pipeline 设置了一个基础阀 StandardEngineValve
    pipeline.setBasic(new StandardEngineValve());
    /* Set the jmvRoute using the system property jvmRoute */
    try {
        setJvmRoute(System.getProperty("jvmRoute"));
    } catch(Exception ex) {
        log.warn(sm.getString("standardEngine.jvmRouteFail"));
    }
    // By default, the engine will hold the reloading thread
    backgroundProcessorDelay = 10;
}
  • 这里需要补充一点 容器对象的创建是在 Catalina 的 load 方法中通过 Digester 对象的 parse 方法解析xml文件时创建的,后面的添加子容器也是在 Digester 对象解析xml文件时完成的

StandardEngine 的 initInternal 方法

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.
    //注意这里并没有初始化Host、Context、Wrapper等
    getRealm();
    //在父类中创建了一个 startStopExecutor 的线程池
    super.initInternal();
}
  • 这里需要注意的是,初始化init过程到这就结束了。后面的Host、Context、Wrapper的初始化是在start中进行的

StandardEngine 的 startInternal 方法

protected synchronized void startInternal() throws LifecycleException {

    // Log our server identification information
    if(log.isInfoEnabled())
        log.info( "Starting Servlet Engine: " + ServerInfo.getServerInfo());

    // Standard container startup
    //调用父类的方法,去看看父类ContainerBase的 startInternal 方法做了什么
    super.startInternal();
}

ContainerBase的 startInternal 方法

protected synchronized void startInternal() throws LifecycleException {
    //这里是分层调用 每个容器都会来这里寻找子容器然后调用 start 方法
    //直到找到最后的 Wrapper 才结束
    // 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++) {
        //这里直接跳转到 org.apache.catalina.core.ContainerBase.StartChild 的 call 方法
        //这里要注意看 StartChild 的 call 方法,这个 call 方法中会调用 children 的 start 方法
        //注意这里的 children 是 LifeCycle 的实现类,所以会进入LifeCycleBase 的start 方法
        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
    //启动 pipeline
    if (pipeline instanceof Lifecycle) {
        ((Lifecycle) pipeline).start();
    }

    //这里会激发监听器HostConfig
    //进入 HostConfig 的 start 方法
    setState(LifecycleState.STARTING);

    // Start our thread
    threadStart();
}

再看 LifecycleBase 的 start 方法

public final synchronized void start() throws LifecycleException {

    if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) ||
        LifecycleState.STARTED.equals(state)) {

        if (log.isDebugEnabled()) {
            Exception e = new LifecycleException();
            log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e);
        } else if (log.isInfoEnabled()) {
            log.info(sm.getString("lifecycleBase.alreadyStarted", toString()));
        }

        return;
    }

    if (state.equals(LifecycleState.NEW)) {
        //注意如果没有初始化,会先进入这里初始化以后再执行下面的start方法
        init();
    } else if (state.equals(LifecycleState.FAILED)) {
        stop();
    } else if (!state.equals(LifecycleState.INITIALIZED) &&
               !state.equals(LifecycleState.STOPPED)) {
        invalidTransition(Lifecycle.BEFORE_START_EVENT);
    }

    try {
        setStateInternal(LifecycleState.STARTING_PREP, null, false);
        //子类实现,跟 init 一样
        startInternal();
        if (state.equals(LifecycleState.FAILED)) {
            // This is a 'controlled' failure. The component put itself into the
            // FAILED state so call stop() to complete the clean-up.
            stop();
        } else if (!state.equals(LifecycleState.STARTING)) {
            // Shouldn't be necessary but acts as a check that sub-classes are
            // doing what they are supposed to.
            invalidTransition(Lifecycle.AFTER_START_EVENT);
        } else {
            setStateInternal(LifecycleState.STARTED, null, false);
        }
    } catch (Throwable t) {
        // This is an 'uncontrolled' failure so put the component into the
        // FAILED state and throw an exception.
        handleSubClassException(t, "lifecycleBase.startFail", toString());
    }
}
  • 这里要注意的是,如果没有初始化,会在这里先执行初始化再start
  • 在StandardEngine 的start方法中,会初始化所有的子容器,并执行所有子容器的start方法
  • 默认只有一个子容器 Host

StandardEngine 的 基础阀 -- StandardEngineValve

public final void invoke(Request request, Response response)
        throws IOException, ServletException {
    // Select the Host to be used for this Request
    //从 request 中获取 Host 对象
    Host host = request.getHost();
    if (host == null) {
        response.sendError
            (HttpServletResponse.SC_BAD_REQUEST,
             sm.getString("standardEngine.noHost",
                          request.getServerName()));
        return;
    }
    if (request.isAsyncSupported()) {
        request.setAsyncSupported(host.getPipeline().isAsyncSupported());
    }

    // Ask this Host to process this request
    //调用 Host 对象Pipeline 中的 Valve
    host.getPipeline().getFirst().invoke(request, response);

}
  • 这里只关注 invoke 方法
  • StandardEngineValve 中直接从 request 对象获取了 Host 对象然后调用 Host 对象的 Pipeline

小结

  • 这里能看到第一篇 tomcat 源码分析最后的流程图是错误的。Host、Context、Wrapper的 init 并不是在 Engine 的 init 中调用的,而是在 Engine 的start 方法中调用的