Tomcat源码解析五(容器的启动过程解析)

目录

1. 逻辑分析

2. 源码分析

2.1 引擎启动

2.2 启动Host 

2.2.1 初始化Host

2.2.2 启动Host

2.2.3 Host生命周期监听

2.2.4 部署webApps

2.2.5 创建Context

2.3 触发启动Context

2.4 触发Wrapper初始化

2.4.1 启动Wrapper

2.4.2 初始化"启动时加载"的Servlet


1. 逻辑分析

容器的层次结构

Tomcat 设计了 4 种容器,分别是 EngineHostContext Wrapper。这 4 种容器不是平行关系,而是父子关系

Context 表示一个 Web 应用程序;Wrapper 表示一个 Servlet,一个 Web 应用程序中可能会有多个 ServletHost 代表的是一个虚拟主机,或者说一个站点,可以给 Tomcat 配置多个虚拟主机地址,而一个虚拟主机下可以部署多个 Web 应用程序;Engine 表示引擎,用来管理多个虚拟站点,一个 Service 最多只能有一个 Engine

 

Tomcat 是如何将一个 URL 定位到指定的Servlet 呢?

 1. 根据协议和端口号选定 Service Engine

我们知道 Tomcat 的每个连接器都监听不同的端口,比如 Tomcat 默认的 HTTP 连接器监听 8080 端口、默认的 AJP 连接器监听 8009 端口。上面例子中的 URL 访问的是 8080 端口,因此这个请求会被 HTTP 连接器接收,而一个连接器是属于一个 Service 组件的,这样 Service 组件就确定了。我们还知道一个 Service 组件里除了有多个连接器,还有一个容器组件,具体来说就是一个 Engine 容器,因此 Service 确定了也就意味着 Engine 也确定了。

2. 根据域名选定 Host

Service Engine 确定后,Mapper 组件通过 URL 中的域名去查找相应的 Host 容器,比如例子中的 URL 访问的域名是user.shopping.com,因此 Mapper 会找到 Host2 这个容器。

3. 根据 URL 路径找到 Context 组件。

Host 确定以后,Mapper 根据 URL 的路径来匹配相应的 Web 应用的路径,比如例子中访问的是/order,因此找到了 Context4 这个 Context 容器。

4. 根据 URL 路径找到 WrapperServlet

Context 确定后,Mapper 再根据web.xml中配置的 Servlet 映射路径来找到具体的 Wrapper Servlet 

请求过程如下图: 

2. 源码分析

在StandardService#startInternal()方法中调用engine.start()启动引擎

2.1 引擎启动

StandardEngine#startInternal()方法实现:

    @Override
    protected synchronized void startInternal() throws LifecycleException {

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

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

分析: 调用父类ContainerBase的#startInternal方法, 进行启动相关操作, 并启动子容器(向线程池中添加启动子容器的任务, 由其他线程去启动子容器)

ContainerBase#startInternal()方法实现:

    @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 realm = getRealmInternal();
        if (realm instanceof Lifecycle) {
            ((Lifecycle) realm).start();
        }

        /**
         * 启动子容器(StandardHost)
         * Host, Context, Wrapper容器启动是都会执行startInternal()方法
         */
        Container children[] = findChildren();
        List<Future<Void>> results = new ArrayList<>();
        for (int i = 0; i < children.length; i++) {
            /**
             * 由startStopExecutor线程通过调用LifecycleBase#start()去启动子容器
             * {@link StartChild#call()}
             */
            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());
        }

        //启动pipeline
        if (pipeline instanceof Lifecycle) {
            ((Lifecycle) pipeline).start();
        }

        //生命周期监听
        setState(LifecycleState.STARTING);

        //启动线程
        threadStart();
    }

分析:

  1. 启动集群
  2. 启动Realm
  3. 启动子容器; 在获取到子容器StandardHost后, 将子容器的启动委托给startStopExecutor线程池, 在startStopExecutor线程的call()方法中调用StandardHost的start()方法, 实际上执行的是StandardHost的父类LifecycleBase#start()方法; 在LifecycleBase#start()方法中调用StandardHost的startInternal()方法, 开始启动Host容器  注意: (new StartChild(children[i])) == StandardHost)
  4. 启动pipeline
  5. 启动线程

 StartChild类实现:

    private static class StartChild implements Callable<Void> {

        private Container child;

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

        @Override
        public Void call() throws LifecycleException {
            /**
             * {@link LifecycleBase#start()}
             */
            child.start();
            return null;
        }
    }

调用LifecycleBase#start()方法

2.2 启动Host 

LifecycleBase#start()方法的实现:

    @Override
    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;
        }
       /**
         * 根据this的状态,执行指定的操作(如: this为StandardHost时,此处将执行init()方法去初始化Standard)
         */
        if (state.equals(LifecycleState.NEW)) {
            init();
        } else if (state.equals(LifecycleState.FAILED)) {
            stop();
        } else if (!state.equals(LifecycleState.INITIALIZED) &&
                !state.equals(LifecycleState.STOPPED)) {
            invalidTransition(Lifecycle.BEFORE_START_EVENT);
        }

        try {
            //触发STARTING_PREP事件的监听器
            setStateInternal(LifecycleState.STARTING_PREP, null, false);
            /**
             * 由子类实现
             *    Host启动:   {@link StandardHost#startInternal()}
             */
            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 {
                //触发STARTED事件的监听器
                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());
        }
    }

分析:

  1. 初始化StandardHost; 启动Host之前会获取当前容器的生命状态, 此时Host还没有进行初始化, 因此, 此时state= NEW; 所以会调用LifecycleBase#init方法进行初始化
  2. 通过startInternal()方法启动StandardHost(重要)

2.2.1 初始化Host

1. LifecycleBase#init()方法实现:

    @Override
    public final synchronized void init() throws LifecycleException {
        if (!state.equals(LifecycleState.NEW)) {  //在初始化之前, 状态必须为new, 否则报错
            invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
        }

        try {
            setStateInternal(LifecycleState.INITIALIZING, null, false); //更新生命状态
            initInternal();  //使用模板方法, 交由子类去处理
            setStateInternal(LifecycleState.INITIALIZED, null, false);//更新生命状态
        } catch (Throwable t) {
            handleSubClassException(t, "lifecycleBase.initFail", toString());
        }
    }

LifecycleBase子类ContainerBase#initInternal实现:

@Override
protected void initInternal() throws LifecycleException {
    BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<>();
    //创建线程池, 用于该容器的启动或停止
    startStopExecutor = new ThreadPoolExecutor(
            getStartStopThreadsInternal(),
            getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,
            startStopQueue,
            new StartStopThreadFactory(getName() + "-startStop-"));
    startStopExecutor.allowCoreThreadTimeOut(true);
    super.initInternal();
}

ContainerBase的父类LifecycleMBeanBase#initInternal实现:

@Override
protected void initInternal() throws LifecycleException {
    //如果oname不为null,则已经通过进行了注册
    //preRegister().
    if (oname == null) {
        mserver = Registry.getRegistry(null, null).getMBeanServer();

        oname = register(this, getObjectNameKeyProperties());
    }
}

2.2.2 启动Host

2. StandardHost#startInternal()方法实现:

    @Override
    protected synchronized void startInternal() throws LifecycleException {

        // Set error report valve
        String errorValve = getErrorReportValveClass();
        if ((errorValve != null) && (!errorValve.equals(""))) {
            try {
                boolean found = false;
                Valve[] valves = getPipeline().getValves();
                for (Valve valve : valves) {
                    if (errorValve.equals(valve.getClass().getName())) {
                        found = true;
                        break;
                    }
                }
                if(!found) {
                    Valve valve =
                        (Valve) Class.forName(errorValve).getConstructor().newInstance();
                    getPipeline().addValve(valve);
                }
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                log.error(sm.getString(
                        "standardHost.invalidErrorReportValveClass",
                        errorValve), t);
            }
        }
        /**
         * Host容器启动完成后, 调用父类ContainerBase#startInternal()方法启动Context容器
         */
        super.startInternal();
    }

分析:

  1. 错误信息输出设置
  2. 调用父类的ContainerBase#startInternal()方法启动相关子容器以及生命周期更新设置

ContainerBase#startInternal实现:

@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 realm = getRealmInternal();
    if (realm instanceof Lifecycle) {
        ((Lifecycle) realm).start();
    }

    /**
     * 启动子容器
     * Host, Context容器启动是都会执行startInternal()方法
     */
    Container children[] = findChildren();
    List<Future<Void>> results = new ArrayList<>();
    for (int i = 0; i < children.length; i++) {
        /**
         * 由startStopExecutor线程通过调用LifecycleBase#start()去启动子容器
         * {@link StartChild#call()}
         * Engine启动子容器Host是通过此方法启动的, 但是Context并不是通过此处启动的
         */
        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());
    }

    //启动pipeline
    if (pipeline instanceof Lifecycle) {
        ((Lifecycle) pipeline).start();
    }

    //生命周期监听
    setState(LifecycleState.STARTING);

    //启动线程
    threadStart();
}

分析: 在Host启动完成后, 进行生命周期更新, 这是会有监听器进行监听, 开始接下来的操作;

2.2.3 Host生命周期监听

LifecycleBase#setState(org.apache.catalina.LifecycleState) 

       ==> LifecycleBase#setStateInternal实现:

private synchronized void setStateInternal(LifecycleState state, Object data, boolean check) throws LifecycleException {
    . . . 
    this.state = state;
    //获取生命周期事件
    String lifecycleEvent = state.getLifecycleEvent();
    if (lifecycleEvent != null) {
        //发送生命周期事件通知
        fireLifecycleEvent(lifecycleEvent, data);
    }
}

分析: 发布生命周期事件通知

LifecycleBase#fireLifecycleEvent实现:

protected void fireLifecycleEvent(String type, Object data) {
    LifecycleEvent event = new LifecycleEvent(this, type, data);
    //lifecycleListeners: 事件监听者
    for (LifecycleListener listener : lifecycleListeners) {
        /**
         * {@link EngineConfig#lifecycleEvent(LifecycleEvent)}
         * {@link ContextConfig#lifecycleEvent(LifecycleEvent)}
         * {@link HostConfig#lifecycleEvent(LifecycleEvent)}
         */
        listener.lifecycleEvent(event);
    }
}

HostConfig#lifecycleEvent实现:

@Override
public void lifecycleEvent(LifecycleEvent event) {
    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());
        }
    } 
    ...
    // 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();
    }
}

2.2.4 部署webApps

HostConfig#start实现:

public void start() {
    try {
        ObjectName hostON = host.getObjectName();
        oname = new ObjectName
            (hostON.getDomain() + ":type=Deployer,host=" + host.getName());
        Registry.getRegistry(null, null).registerComponent
            (this, oname, this.getClass().getName());
    } 
    . . .
    if (!host.getAppBaseFile().isDirectory()) {
        host.setDeployOnStartup(false);
        host.setAutoDeploy(false);
    }
    if (host.getDeployOnStartup())
        /**
         * 部署webApp
         **/
        deployApps();
}

HostConfig#deployApps()实现:

protected void deployApps() {
    File appBase = host.getAppBaseFile();
    File configBase = host.getConfigBaseFile();
    String[] filteredAppPaths = filterAppPaths(appBase.list());
    //部署xml
    deployDescriptors(configBase, configBase.list());
    //部署war包
    deployWARs(appBase, filteredAppPaths);
    /部署扩展文件
    deployDirectories(appBase, filteredAppPaths);
}

HostConfig#deployDirectories实现:

protected void deployDirectories(File appBase, String[] files) {
    if (files == null)
        return;
    ExecutorService es = host.getStartStopExecutor();
    List<Future<?>> results = new ArrayList<>();

    for (int i = 0; i < files.length; i++) {

        if (files[i].equalsIgnoreCase("META-INF"))
            continue;
        if (files[i].equalsIgnoreCase("WEB-INF"))
            continue;
        File dir = new File(appBase, files[i]);
        if (dir.isDirectory()) {
            ContextName cn = new ContextName(files[i], false);

            if (isServiced(cn.getName()) || deploymentExists(cn.getName()))
                continue;
            //
            //   ====重点======
            //
            results.add(es.submit(new DeployDirectory(this, cn, dir)));
        }
    }

    for (Future<?> result : results) {
        try {
            result.get();
        } catch (Exception e) {
            log.error(sm.getString(
                    "hostConfig.deployDir.threaded.error"), e);
        }
    }
}


 分析: 将webapps目录下所有的文件夹(META-INF和WEB-INF除外)交给线程池去进行处理, 线程池拿到任务后, 调用HostConfig.DeployDirectory#run的run方法, 进行部署

2.2.5 创建Context

HostConfig.DeployDirectory类实现:

private static class DeployDirectory implements Runnable {

    private HostConfig config;
    private ContextName cn;
    private File dir;

    public DeployDirectory(HostConfig config, ContextName cn, File dir) {
        this.config = config;
        this.cn = cn;
        this.dir = dir;
    }

    @Override
    public void run() {
        config.deployDirectory(cn, dir);
    }
}

分析: 当线程执行run方法时, 开始部署应用...

HostConfig#deployDirectory实现:

protected void deployDirectory(ContextName cn, File dir) {
    long startTime = 0;
    // Deploy the application in this directory
    if( log.isInfoEnabled() ) {
        startTime = System.currentTimeMillis();
        log.info(sm.getString("hostConfig.deployDir",
                dir.getAbsolutePath()));
    }
    Context context = null;
    File xml = new File(dir, Constants.ApplicationContextXml);
    File xmlCopy = new File(host.getConfigBaseFile(), cn.getBaseName() + ".xml");

    DeployedApplication deployedApp;
    boolean copyThisXml = isCopyXML();
    boolean deployThisXML = isDeployThisXML(dir, cn);

    try {
        if (deployThisXML && xml.exists()) {
            synchronized (digesterLock) {
                try {
                    context = (Context) digester.parse(xml);
                } catch (Exception e) {
                    log.error(sm.getString(
                            "hostConfig.deployDescriptor.error",
                            xml), e);
                    context = new FailedContext();
                } finally {
                    digester.reset();
                    if (context == null) {
                        context = new FailedContext();
                    }
                }
            }

            if (copyThisXml == false && context instanceof StandardContext) {
                // Host is using default value. Context may override it.
                copyThisXml = ((StandardContext) context).getCopyXML();
            }

            if (copyThisXml) {
                Files.copy(xml.toPath(), xmlCopy.toPath());
                context.setConfigFile(xmlCopy.toURI().toURL());
            } else {
                context.setConfigFile(xml.toURI().toURL());
            }
        } else if (!deployThisXML && xml.exists()) {
            // Block deployment as META-INF/context.xml may contain security
            // configuration necessary for a secure deployment.
            log.error(sm.getString("hostConfig.deployDescriptor.blocked",
                    cn.getPath(), xml, xmlCopy));
            context = new FailedContext();
        } else {
            context = (Context) Class.forName(contextClass).getConstructor().newInstance();
        }

        Class<?> clazz = Class.forName(host.getConfigClass());
        LifecycleListener listener = (LifecycleListener) clazz.getConstructor().newInstance();
        context.addLifecycleListener(listener);

        context.setName(cn.getName());
        context.setPath(cn.getPath());
        context.setWebappVersion(cn.getVersion());
        context.setDocBase(cn.getBaseName());
        host.addChild(context);
    } 
    ...
}

分析: 根据web应用生成Context对象, 并添加到Host容器中

StandardHost#addChild

    ==> ContainerBase#addChild

            ==> ContainerBase#addChildInternal

                    ==> LifecycleBase#start实现:

2.3 触发启动Context

 

LifecycleBase#start实现:

@Override
public final synchronized void start() throws LifecycleException {
    ...
    /**
     * 根据this的状态,执行指定的操作(如: this为StandardHost时,此处将执行init()方法去初始化Standard)
     */
    if (state.equals(LifecycleState.NEW)) {
        init();
    } else if (state.equals(LifecycleState.FAILED)) {
        stop();
    } else if (!state.equals(LifecycleState.INITIALIZED) &&
            !state.equals(LifecycleState.STOPPED)) {
        invalidTransition(Lifecycle.BEFORE_START_EVENT);
    }

    try {
        //触发STARTING_PREP事件的监听器
        setStateInternal(LifecycleState.STARTING_PREP, null, false);
        /**
         * 由子类实现
         * 容器:
         *    Engine启动: {@link StandardEngine#startInternal()}
         *    Host启动:   {@link StandardHost#startInternal()}
         *    Context启动: {@link StandardContext#startInternal()}
         *    Wrapper启动: {@link StandardWrapper#startInternal()}
         *
         * 连接器:
         *    Connector启动: {@link Connector#startInternal()}
         */
        startInternal();
        ...
}

分析: 当前容器Context还没有进行初始化, 因此state = NEW, 所以会先去初始化Context, 然后再启动Context容器;

StandardContext#startInternal实现:

@Override
protected synchronized void startInternal() throws LifecycleException {
    ...
    /**
     * Notify our interested LifecycleListeners   <=====重点
     */
    fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);

    // Start our child containers, if not already started
    for (Container child : findChildren()) {
        if (!child.getState().isAvailable()) {
            /**
             * 启动子容器(Wrapper不是通过此处启动的)
             */
            child.start();
        }
    }
    ...
    /**
     * 启动pipeline中的valve(包括基本管道)
     */
    if (pipeline instanceof Lifecycle) {
        ((Lifecycle) pipeline).start();
    }
    ...
    /**
      * 加载并初始化所有“启动时加载” servlet
      * 注意: 对于SpringMvc中的DispatchServlet就是由此触发初始化操作的
      * {@link StandardContext#loadOnStartup(org.apache.catalina.Container[]){
      */
    if (ok) {
        if (!loadOnStartup(findChildren())){
            log.error(sm.getString("standardContext.servletFail"));
            ok = false;
        }
    }
}

分析:

  1. 发布事件
  2. 将未启动的子容器启动
  3. 启动Valve
  4. 加载并初始化所有"启动时加载"的Servlet

2.4 触发Wrapper初始化

2.4.1 启动Wrapper

LifecycleBase#fireLifecycleEvent实现:

protected void fireLifecycleEvent(String type, Object data) {
    LifecycleEvent event = new LifecycleEvent(this, type, data);
    //lifecycleListeners: 事件监听者
    for (LifecycleListener listener : lifecycleListeners) {
        /**
         * {@link EngineConfig#lifecycleEvent(LifecycleEvent)}
         * {@link ContextConfig#lifecycleEvent(LifecycleEvent)}
         * {@link HostConfig#lifecycleEvent(LifecycleEvent)}
         */
        listener.lifecycleEvent(event);
    }
}

ContextConfig#lifecycleEvent

          ==> ContextConfig#configureStart

                  ==> ContextConfig#webConfig

                         ==>  ContextConfig#configureContext

                                 ==> StandardContext#addChild

                                          ==> ContainerBase#addChild

                                                  ==> ContainerBase#addChildInternal

                                                          ==> LifecycleBase#start

                                                                  ==> StandardWrapper#startInternal实现:

@Override
protected synchronized void startInternal() throws LifecycleException {
    // Send j2ee.state.starting notification
    if (this.getObjectName() != null) {
        Notification notification = new Notification("j2ee.state.starting",this.getObjectName(),sequenceNumber++);
        broadcaster.sendNotification(notification);
    }
    // Start up this component
    super.startInternal();
    setAvailable(0L);
    // Send j2ee.state.running notification
    if (this.getObjectName() != null) {
        Notification notification =
            new Notification("j2ee.state.running", this.getObjectName(),
                            sequenceNumber++);
        broadcaster.sendNotification(notification);
    }
}

2.4.2 初始化"启动时加载"的Servlet

StandardContext#loadOnStartup实现:

public boolean loadOnStartup(Container children[]) {
    /**
     * 遍历Context中所有子容器, 收集需要初始化的“启动时加载” servlet
     */
    TreeMap<Integer, ArrayList<Wrapper>> map = new TreeMap<>();
    for (int i = 0; i < children.length; i++) {
        Wrapper wrapper = (Wrapper) children[i];
        int loadOnStartup = wrapper.getLoadOnStartup();
        if (loadOnStartup < 0)
            continue;
        Integer key = Integer.valueOf(loadOnStartup);
        ArrayList<Wrapper> list = map.get(key);
        if (list == null) {
            list = new ArrayList<>();
            map.put(key, list);
        }
        list.add(wrapper);
    }
    /**
     * 遍历加载 "启动时加载"Servlet
     */
    for (ArrayList<Wrapper> list : map.values()) {
        for (Wrapper wrapper : list) {
            try {
                /**
                 * {@link StandardWrapper#load()}
                 */
                wrapper.load();
            } catch (ServletException e) {
              ...
            }
        }
    }
    return true;
}

分析:

  1. 遍历Context中所有子容器, 收集需要初始化的“启动时加载” servlet
  2. 遍历加载 "启动时加载"Servlet

StandardWrapper#load实现:

@Override
public synchronized void load() throws ServletException {
    /**
     * 加载Servlet
     */
    instance = loadServlet();
    if (!instanceInitialized) {
        initServlet(instance);
    }
    if (isJspServlet) {
        StringBuilder oname = new StringBuilder(getDomain());
        oname.append(":type=JspMonitor");
        oname.append(getWebModuleKeyProperties());
        oname.append(",name=");
        oname.append(getName());
        oname.append(getJ2EEKeyProperties());
        try {
            jspMonitorON = new ObjectName(oname.toString());
            Registry.getRegistry(null, null).registerComponent(instance, jspMonitorON, null);
        } catch (Exception ex) {
            log.warn("Error registering JSP monitoring with jmx " + instance);
        }
    }
}

StandardWrapper#loadServlet

     ==> StandardWrapper#initServlet实现:

private synchronized void initServlet(Servlet servlet) throws ServletException {
    if (instanceInitialized && !singleThreadModel) return;
    // 调用此Servlet的初始化方法
    try {
        if( Globals.IS_SECURITY_ENABLED) {
            boolean success = false;
            try {
                Object[] args = new Object[] { facade };
                /**
                 * 通过反射执行该Servlet的init()方法  <==== 重点
                 * 对于SpringMvc中的DispatchServlet就是在此时触发初始化操作的
                 */
                SecurityUtil.doAsPrivilege("init", servlet, classType, args);
                success = true;
            } finally {
                if (!success) {
                    SecurityUtil.remove(servlet);
                }
            }
        } else {
            servlet.init(facade);
        }
        instanceInitialized = true;
    } 
    ...
}

   分析: 该方法中通过反射执行GenericServlet的init()方法,  进行自定义Servlet的初始化操作;  例如: SpringMVC中的HttpServletBean#init()


继承关系如下:

流程图如下:

至此, 容器的启动过程解析完成;

 

相关文章:

      Tomcat源码解析一(Tomcat整体架构解析)

      Tomcat源码解析二(Tomcat初始化过程解析)

      Tomcat源码解析三(Tomcat启动过程解析)

      Tomcat源码解析四(连接器启动过程解析)

      Tomcat源码解析五(容器的启动过程解析)

      Tomcat源码解析六(Http请求过程解析_基于NIO)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值