美文网首页
tomcat 各个组件初始化及启动流程

tomcat 各个组件初始化及启动流程

作者: 小河土 | 来源:发表于2019-06-23 19:37 被阅读0次

结合源码来探索启动的流程

通过上一章的目录结构和体系结构的研究,我们对tomcat有一个初步的认识
我们先找到入口函数。根据"startd"命令来推导
Bootstrap 下面的main方法就是入口函数
上面图片只截取了启动的时候两个方法一个初始化,一个是开始启动,在初始化之前的 init 方法是初始化一些环境参数。这里就没有详细说明。我们先看

if (command.equals("startd")) {
                args[args.length - 1] = "start";
                //先初始化一个必要的组件 如server connetor service
                //这里的daemon 是就是 Bootstrap自己
                daemon.load(args);
                //开始加载Engine 下面相关东西,像Host Conetxt weapp
                daemon.start();
            }

我们再往下看Bootstrap 的 load函数

private void load(String[] arguments)
        throws Exception {

        // Call the load() method
      
        String methodName = "load";
        Object param[];
        Class<?> paramTypes[];
        if (arguments==null || arguments.length==0) {
           paramTypes = null;
            param = null;
        } else {
            paramTypes = new Class[1];
            paramTypes[0] = arguments.getClass();
            param = new Object[1];
            param[0] = arguments;
        }
      // 反射获取catalina 的对象的 load
        Method method =
            catalinaDaemon.getClass().getMethod(methodName, paramTypes);
        if (log.isDebugEnabled())
            log.debug("Calling startup class " + method);
        //利用反射去调用 catalina的load方法
        method.invoke(catalinaDaemon, param);
 }

然后下一步我们去CatalinaDaemon验证下是不是有一个无参的load方法。
果然有一个load方法(方法代码太多只截取重要的部分)

public void load() {
//创建一个xml解析器
  Digester digester = createStartDigester();
        InputSource inputSource = null;
        InputStream inputStream = null;
        File file = null;
        try {
            //读取conf/server.xml文件
            file = configFile();
            inputStream = new FileInputStream(file);
            inputSource = new InputSource(file.toURI().toURL().toString());
        } catch (Exception e) {
            if (log.isDebugEnabled()) {
                log.debug(sm.getString("catalina.configFail", file), e);
            }
        }
····· //这里的一些代码是保证读到server.xml文件的内容
 try {
            inputSource.setByteStream(inputStream);
            digester.push(this);
            //解析 配置文件流,对配置文件里面的配置进行初始化
            digester.parse(inputSource);
        } catch (SAXParseException spe) {
            log.warn("Catalina.start using " + getConfigFile() + ": " +
                    spe.getMessage());
            return;
        } catch (Exception e) {
            log.warn("Catalina.start using " + getConfigFile() + ": " , e);
            return;
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                // Ignore
            }
        }
       ·············· 下面就是开始 Server的初始化了
  // Start the new server 
        try {
            getServer().init();
        } catch (LifecycleException e) {
            if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
                throw new java.lang.Error(e);
            } else {
                log.error("Catalina.start", e);
            }

        }

        long t2 = System.nanoTime();
        if(log.isInfoEnabled()) {
            log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms");
        }
}

我们跟到里面getServer().init();看看做了什么,进去之后发现到了"Lifecycle" 类的 init()方法 这是一个接口,这个接口有三个实现类
除了 LifecycleBase里面是有现实,其他两个类都没有实现,那就不用肯定是调用LifecycleBase的init方法了。

public final synchronized void init() throws LifecycleException {
        //默认的实现
        if (!state.equals(LifecycleState.NEW)) {
            invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
        }
        setStateInternal(LifecycleState.INITIALIZING, null, false);

        try {
            //争对所有的子类初始化,这个地方调用的是自己的抽象方法。
            initInternal();
        } catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
            setStateInternal(LifecycleState.FAILED, null, false);
            throw new LifecycleException(
                    sm.getString("lifecycleBase.initFail",toString()), t);
        }

        setStateInternal(LifecycleState.INITIALIZED, null, false);
    }

点开 LifecycleBase类的 initInternal()方法,发现也是有很多实现,其实到这里我们应该去看哪个实现类了,肯定是跟Server有关的。于是乎我们就找到了
StandardServer 这个类的initInternal() 方法

  protected void initInternal() throws LifecycleException {
    //调用父类的 方法
     super.initInternal();

    // Register global String cache
    // Note although the cache is global, if there are multiple Servers
    // present in the JVM (may happen when embedding) then the same cache
    // will be registered under multiple names
    onameStringCache = register(new StringCache(), "type=StringCache");

    // Register the MBeanFactory
    MBeanFactory factory = new MBeanFactory();
    factory.setContainer(this);
    onameMBeanFactory = register(factory, "type=MBeanFactory");

    // Register the naming resources
  //结合之前的tomcat 体系结构图中来看  globalNamingResources资源文件组件进行初始化
      globalNamingResources.init();
   ··············· 此处代码省略
    //这个地方就验证了官网说的 Server下面有多个Service 这的调
         //service 里面的init方法
        // Initialize our defined Services 初始化多个services
        for (int i = 0; i < services.length; i++) {
              services[i].init();
        }
      }
这里Service 调用的init 方法是 Lifecycle的,
之前我们说Lifecycle init      是LifecycleBase实现了
我们看下LifecycleBase 的init 方法
public final synchronized void init() throws LifecycleException {
    //默认的实现
    if (!state.equals(LifecycleState.NEW)) {
        invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
    }
    setStateInternal(LifecycleState.INITIALIZING, null, false);

    try {
        //初始化  Service 组件
        initInternal();
    } catch (Throwable t) {
        ExceptionUtils.handleThrowable(t);
        setStateInternal(LifecycleState.FAILED, null, false);
        throw new LifecycleException(
                sm.getString("lifecycleBase.initFail",toString()), t);
    }
  setStateInternal(LifecycleState.INITIALIZED, null, false);
}

我们发现这个initInternal() 方法又是 LifecycleBase的,所以我们在找对应的实现类的时候,就可以参照之前方法,找跟service 相关的,如果只有一个StandardService类

protected void initInternal() throws LifecycleException{
······此处代码省略
//这里是线程池的初始化,这个可以对照上面的图来看
 for (Executor executor : findExecutors()) {
            if (executor instanceof JmxEnabled) {
                ((JmxEnabled) executor).setDomain(getDomain());
            }
            //线程池 初始化
            executor.init();
        }
 // 初始化 mapper listener
        mapperListener.init();

        // Initialize our defined Connectors
       //可以看到这里的connector 是多个的,用加锁来保证线程安全
        synchronized (connectorsLock) {
            for (Connector connector : connectors) {
                try {
                    //connector就开始初始化了
                    connector.init();
                } catch (Exception e) {
                    String message = sm.getString(
                            "standardService.connector.initFailed", connector);
                    log.error(message, e);

                    if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"))
                        throw new LifecycleException(message);
                }
            }
        }
}

这里调用每个 Connector的init方法,再一步步跟进去,发现还是之前的套路,
在Connector 的init 方法里面又会去调用 LifecycleBase 的 initInternal() 方法,这次我们还是去找Connector里面的实现
还是贴代码

protected void initInternal() throws LifecycleException {
            //其实到这里必要的组件在这个方法里面已经初始化完了
        //bootstarp 方法 load 方法已经完成了
      //这里还是老样子调用父类LifecycleMBeanBase 去注册bean
        super.initInternal();

        // Initialize adapter 这里就是初始化处理器
        adapter = new CoyoteAdapter(this);
          //绑定处理器 然后就是到下面 init 方法再去绑定
        protocolHandler.setAdapter(adapter);
        ·········此处代码省略
        try {
            //决定是用bio 还是nio  nio2 apr 这些组件去处理请求
          //我们看看这个里面做了些什么 
            protocolHandler.init();
        } catch (Exception e) {
            throw new LifecycleException
                (sm.getString
                 ("coyoteConnector.protocolHandlerInitializationFailed"), e);
        }
    }

protocolHandler 这个类是一个接口,有两个实现类,我们肯定是找
AbstractProtocol这个实现类 的init 方法,在这个方法里面有一段代码也就是最后

try {
            //在这里去调用,这里就是具体的绑定用 Apr 还是JIo 还是NIo
            endpoint.init();
        } catch (Exception ex) {
            getLog().error(sm.getString("abstractProtocolHandler.initError",
                    getName()), ex);
            throw ex;
        }

那么到这里初始化的工作就全部做完了,看到这里肯定晕了。


image.png

Connector 、StandardService、StandardServer 他们都是Lifecycle的子类,其实到最后才发现整个 初始化过程都是围绕着 Lifecycle init() 和 LifecycleBase initInternal() 方法来实现的。
其实这个初始化的过程,就是用 责任链的调用模式来实现的, 一个链接着一个链来的任务来,最终完成所有的初始化。


华丽的分割线

初始化完成了,那我们再去看看启动,回到 Bootstrap 的main 方法

不说废话直接上图

if (command.equals("startd")) {
                args[args.length - 1] = "start";
                //先初始化一个必要的组件 如server connetor service
                //这里的daemon 是就是 Bootstrap自己
                daemon.load(args);
                //开始加载Engine 下面相关东西,像Host Conetxt weapp
                daemon.start();
            }
public void start()
        throws Exception {
        //还是跟之前是一样的方法 反射调用catalina里面的start 方法
        if( catalinaDaemon==null ) init();

        Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
        method.invoke(catalinaDaemon, (Object [])null);

    }

我们再看 catalina 里面的start 方法

 public void start() {

        if (getServer() == null) {
            load();
        }

        if (getServer() == null) {
            log.fatal("Cannot start server. Server instance is not configured.");
            return;
        }

        long t1 = System.nanoTime();
        //前面都是做一些判空的操作,下面server 开始启动
        // Start the new server
        try {
            getServer().start();
        } catch (LifecycleException e) {
            log.fatal(sm.getString("catalina.serverStartFail"), e);
            try {
                getServer().destroy();
            } catch (LifecycleException e1) {
                log.debug("destroy() failed for failed Server ", e1);
            }
            return;
        }
    }

我们按照之前的思维来分析 这个start 方法肯定又是Lifecycle 接口的一个方法,我们再去找相关的实现类 LifecycleBase,在代码中又调用了自己的startInternal方法,所以我们还是找相关的实现类StandardServer

protected void startInternal() throws LifecycleException {

        fireLifecycleEvent(CONFIGURE_START_EVENT, null);
        setState(LifecycleState.STARTING);
        //加载一些资源文件
        globalNamingResources.start();

        // Start our defined Services
        synchronized (servicesLock) {
            for (int i = 0; i < services.length; i++) {
                // 跟之前的方式一样 ,开始每一个service启动
                services[i].start();
            }
        }
    }

我们跟到StandardService 的 startInternal方法

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) {
              //这个地方就是 启动Engine、Host、context 这些组件
                container.start();
            }
        }

        synchronized (executors) {
            for (Executor executor: executors) {
                //启动线程池
                executor.start();
            }
        }

        //以及一些监听器
        mapperListener.start();

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

我们可以看到 connector 和 executor 的组件启动。
这里我们继续 Connector 的 startInternal() 方法

protected void startInternal() throws LifecycleException {

        // Validate settings before starting
        if (getPort() < 0) {
            throw new LifecycleException(sm.getString(
                    "coyoteConnector.invalidPort", Integer.valueOf(getPort())));
        }

        setState(LifecycleState.STARTING);

        try {
            //这里就跟处理请求的,模式 是Bio NIO ···等方式, 这个在之前初始化的时候就已经选择好了
            protocolHandler.start();
        } catch (Exception e) {
            String errPrefix = "";
            if(this.service != null) {
                errPrefix += "service.getName(): \"" + this.service.getName() + "\"; ";
            }

            throw new LifecycleException
                (errPrefix + " " + sm.getString
                 ("coyoteConnector.protocolHandlerStartFailed"), e);
        }
    }

上面代码中 我们先看下 container.start() 这里,点进去发现这里是调用的ContainerBase 这个类startInternal()方法

protected synchronized void startInternal() throws LifecycleException {

        // Start our subordinate components, if any
        logger = null;
        getLogger();
        Cluster cluster = getClusterInternal();
        if ((cluster != null) && (cluster instanceof Lifecycle))
            ((Lifecycle) cluster).start();
        Realm realm = getRealmInternal();
        if ((realm != null) && (realm instanceof Lifecycle))
            ((Lifecycle) realm).start();

        // Start our child containers, if any
        Container children[] = findChildren();
        List<Future<Void>> results = new ArrayList<>();
        //通过责任链的 调用  不同的调用子类的start
        //这里的子类 有 Engine、Host、context 这些
        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();

    }

关注 new StartChild(children[i] )这段代码
这里会调用 engine 子容器的 start 方法。也就是Host,Host 会将一个一个的项目编译后的class 文件加进来

 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).newInstance();
                    getPipeline().addValve(valve);
                }
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                log.error(sm.getString(
                        "standardHost.invalidErrorReportValveClass",
                        errorValve), t);
            }
        }
        super.startInternal();
    }

最后又去调用父类的startInternal(),然后 调用 父类里面的threadStart() 方法

protected void threadStart() {

        if (thread != null)
            return;
        if (backgroundProcessorDelay <= 0)
            return;

        threadDone = false;
        String threadName = "ContainerBackgroundProcessor[" + toString() + "]";
        //每个子类的run方法  任务
        thread = new Thread(new ContainerBackgroundProcessor(), threadName);
        thread.setDaemon(true);
        thread.start();

    }

ContainerBackgroundProcessor 是实现了 Runnable d 线程类
processChildren 方法 里面去处理 各个子类的线程
container.backgroundProcess(); 这个是各个子类的事件的触发器
这个方法最后 fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null)
这一段是调用LifecycleSupport 类

public void fireLifecycleEvent(String type, Object data) {

        LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
        LifecycleListener interested[] = listeners;
        for (int i = 0; i < interested.length; i++)
            interested[i].lifecycleEvent(event);

    }

然后又会用调用 LifecycleListener lifecycleEvent这个接口的方法
这个接口里面我们看到有很多实现


image.png

其实可以看出很多子类的具体任务都是在这里处理的。
我们找一下实现 HostConfig 里面的实现 lifecycleEvent方法
的check()方法

protected void check() {

        if (host.getAutoDeploy()) {
            // Check for resources modification to trigger redeployment
            DeployedApplication[] apps =
                deployed.values().toArray(new DeployedApplication[0]);
            for (int i = 0; i < apps.length; i++) {
                if (!isServiced(apps[i].name))
                    checkResources(apps[i]);
            }

            // Check for old versions of applications that can now be undeployed
            if (host.getUndeployOldVersions()) {
                checkUndeploy();
            }

            // Hotdeploy applications
            //开始部署应用
            deployApps();
        }
    }

这个地方就是开始部署应用了。

protected void deployApps() {
        //部署web 项目
        File appBase = host.getAppBaseFile();
        //找到config的配置文件路径
        File configBase = host.getConfigBaseFile();
        String[] filteredAppPaths = filterAppPaths(appBase.list());
        // Deploy XML descriptors from configBase
        deployDescriptors(configBase, configBase.list());
        // Deploy WARs
        //这个filteredAppPaths 是返回这个路径下面 所有的文件夹及文件名
        deployWARs(appBase, filteredAppPaths);
        // Deploy expanded folders
        deployDirectories(appBase, filteredAppPaths);

    }

到这个地方 整个tomcat 的启动流程就完了。

相关文章

  • tomcat 各个组件初始化及启动流程

    结合源码来探索启动的流程 通过上一章的目录结构和体系结构的研究,我们对tomcat有一个初步的认识我们先找到入口函...

  • Tomcat的生命周期

    前言:本文是基于Tomcat架构中各个组件及组件间关系的基础上,继续深挖Tomcat中各个组件在“动态”的情况下是...

  • Tomcat 监听初始化流程

    开篇  这篇博文的主要目的是为了理清楚Tomcat监听的初始化流程,所谓的监听初始化流程是指Tomcat启动后直至...

  • Tomcat 监听初始化流程

    开篇  这篇博文的主要目的是为了理清楚Tomcat监听的初始化流程,所谓的监听初始化流程是指Tomcat启动后直至...

  • Tomcat请求处理分析(一) - Processor

    在分析了Tomcat的启动过程和各个组件后,本文开始分析Tomcat是如何处理请求的。让我们回到Tomcat启动分...

  • Tomcat请求处理分析(一) - 从套接字到容器组件

    在分析了Tomcat的启动过程和各个组件后,本文开始分析Tomcat是如何处理请求的。让我们回到Tomcat启动分...

  • tomcat-4-Lifecycle

    什么是Lifecycle 组件tomcat启动时初始化依赖的下层组件父组件管理子组件 Servlet加载和实例化(...

  • tomcat-5-Pipeline

    什么是Lifecycle 组件tomcat启动时初始化依赖的下层组件父组件管理子组件 Servlet加载和实例化(...

  • 源码系列-Activiti7流程启动和命令执行

    启动流程 下面的流程是针对于springboot启动器的启动流程 activiti 流程引擎组件初始化 拦截器链初...

  • Tomcat学习——server.xml配置文件

    学习了tomcat的启动流程,我们来学习一下tomcat的配置文件server.xml 顶级组件Server 代表...

网友评论

      本文标题:tomcat 各个组件初始化及启动流程

      本文链接:https://www.haomeiwen.com/subject/hvaiqctx.html