当前位置:   article > 正文

tomcat-整启动流程-源码解析

tomcat启动流程源码

tomcat-目录&总体架构


Tomcat整体启动流程

    上文了解了大致tomat的相关架构,那么本文是针对tomcat的启动流程进行了解,。tomcat是通过Bootstrap的main方法进行启动,然后通过catalina对象中创建server.xml的解析器,一步到位创建出大部分组件,通过责任链模式进行层层管理。细节可以跟着调试代码关注如下。

源码位置:https://gitee.com/hong99/source-code-learning.git

tomcat整体架构

b53709e58c03ab06d9bc708baa165973.png

tomcat的核心启动入口(所有的启动入口)

6efce38f946bc8ec05e86e6e46ef0e2b.png

代码位置

注意:bootstrap调用顺序main->init->load

org.apache.catalina.startup.Bootstrap#main

  1. /**
  2.  * Main method and entry point when starting Tomcat via the provided
  3.  * scripts.
  4.  *
  5.  * @param args Command line arguments to be processed
  6.  * tomcat 核心启动类 主线程类
  7.  */
  8. public static void main(String args[]) {
  9.     //线程同步方式启动
  10.     synchronized (daemonLock) {
  11.         if (daemon == null) {
  12.             //创建 自身
  13.             Bootstrap bootstrap = new Bootstrap();
  14.             try {
  15.                 //创建 tomcat自身的初始化
  16.                 bootstrap.init();
  17.             } catch (Throwable t) {
  18.                 handleThrowable(t);
  19.                 t.printStackTrace();
  20.                 return;
  21.             }
  22.             daemon = bootstrap;
  23.         } else {
  24.             // When running as a service the call to stop will be on a new
  25.             // thread so make sure the correct class loader is used to
  26.             // prevent a range of class not found exceptions.
  27.             Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
  28.         }
  29.     }
  30.     try {
  31.         //默认为启动 标识
  32.         String command = "start";
  33.         //如果args长度大于0
  34.         if (args.length > 0) {
  35.             //重新赋值
  36.             command = args[args.length - 1];
  37.         }
  38.         if (command.equals("startd")) {
  39.             args[args.length - 1] = "start";
  40.             daemon.load(args);
  41.             daemon.start();
  42.         } else if (command.equals("stopd")) {
  43.             args[args.length - 1] = "stop";
  44.             daemon.stop();
  45.         } else if (command.equals("start")) {
  46.             //线程等待,否则tomcat直接就关闭了;就类似于守护线程
  47.             daemon.setAwait(true);
  48.             //加载
  49.             daemon.load(args);
  50.             daemon.start();
  51.             if (null == daemon.getServer()) {
  52.                 System.exit(1);
  53.             }
  54.         } else if (command.equals("stop")) {
  55.             daemon.stopServer(args);
  56.         } else if (command.equals("configtest")) {
  57.             daemon.load(args);
  58.             if (null == daemon.getServer()) {
  59.                 System.exit(1);
  60.             }
  61.             System.exit(0);
  62.         } else {
  63.             log.warn("Bootstrap: command \"" + command + "\" does not exist.");
  64.         }
  65.     } catch (Throwable t) {
  66.         // Unwrap the Exception for clearer error reporting
  67.         if (t instanceof InvocationTargetException &&
  68.                 t.getCause() != null) {
  69.             t = t.getCause();
  70.         }
  71.         handleThrowable(t);
  72.         t.printStackTrace();
  73.         System.exit(1);
  74.     }
  75. }

main执行中,第一步初始化就是init,通过这个init进行初始化所有下级;

org.apache.catalina.startup.Bootstrap#init()

  1. /**
  2.  * bootstartp 初始化方法
  3.  * Initialize daemon.
  4.  * @throws Exception Fatal initialization error
  5.  */
  6. public void init() throws Exception {
  7.     //初始化类加载器 其中包含 catalinaLoader和sharedLoader
  8.     initClassLoaders();
  9.     //将catalinaLoader 放到当前线上下文中
  10.     Thread.currentThread().setContextClassLoader(catalinaLoader);
  11.     //将catalinaLoader 加载到权限管理中
  12.     SecurityClassLoad.securityClassLoad(catalinaLoader);
  13.     // 是否打印日志开关
  14.     if (log.isDebugEnabled()) {
  15.         log.debug("Loading startup class");
  16.     }
  17.     //通过反射方式调用 catalina方法
  18.     Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
  19.     Object startupInstance = startupClass.getConstructor().newInstance();
  20.     // Set the shared extensions class loader
  21.     if (log.isDebugEnabled()) {
  22.         log.debug("Setting startup class properties");
  23.     }
  24.     //方法名称为:setParentClassLoader
  25.     String methodName = "setParentClassLoader";
  26.     Class<?> paramTypes[] = new Class[1];
  27.     paramTypes[0] = Class.forName("java.lang.ClassLoader");
  28.     Object paramValues[] = new Object[1];
  29.     //类加载器
  30.     paramValues[0] = sharedLoader;
  31.     Method method =
  32.         startupInstance.getClass().getMethod(methodName, paramTypes);
  33.     //通过反射方式调用
  34.     method.invoke(startupInstance, paramValues);
  35.     //将这个对象赋值到 catalinaDaemon
  36.     catalinaDaemon = startupInstance;
  37. }

org.apache.catalina.startup.Bootstrap#load

  1. private void load(String[] arguments) throws Exception {
  2.     // Call the load() method 加载的方法名称为load
  3.     String methodName = "load";
  4.     Object param[];
  5.     Class<?> paramTypes[];
  6.     //当arguments为空或长度为0时将paramTypes和param 赋为空。
  7.     if (arguments==null || arguments.length==0) {
  8.         paramTypes = null;
  9.         param = null;
  10.     } else {
  11.         paramTypes = new Class[1];
  12.         paramTypes[0] = arguments.getClass();
  13.         param = new Object[1];
  14.         param[0] = arguments;
  15.     }
  16.     //通过 server.xml获取org.apache.catalina.startup.Catalina里面的方法为load
  17.     Method method =
  18.         catalinaDaemon.getClass().getMethod(methodName, paramTypes);
  19.     if (log.isDebugEnabled()) {
  20.         log.debug("Calling startup class " + method);
  21.     }
  22.     //通过反射调用 catalina里面的load无参方法
  23.     method.invoke(catalinaDaemon, param);
  24. }

到这里就跳出去调catalina的无参load方法。

那么Catalina的调用顺序是:load()->createStartDigester()->getServer().init()

主要的目的是加载sever.xml然后去初始化server,这里注意所有的加载都是通过责任链进行管理,所以getServer都是通过org.apache.catalina.util.LifecycleBase#init进行加载;

org.apache.catalina.startup.Catalina#load()

  1. public void load() {
  2.     //如果为false则直接返回
  3.     if (loaded) {
  4.         return;
  5.     }
  6.     loaded = true;
  7.     long t1 = System.nanoTime();
  8.     //空方法 该方式不做其他操作
  9.     initDirs();
  10.     // Before digester - it may be needed
  11.     initNaming();
  12.     // Create and execute our Digester
  13.     Digester digester = createStartDigester();
  14.     InputSource inputSource = null;
  15.     InputStream inputStream = null;
  16.     File file = null;
  17.     //以下是通过流的方式进行加载,然后解析
  18.     try {
  19.         try {
  20.             file = configFile();
  21.             inputStream = new FileInputStream(file);
  22.             inputSource = new InputSource(file.toURI().toURL().toString());
  23.         } catch (Exception e) {
  24.             if (log.isDebugEnabled()) {
  25.                 log.debug(sm.getString("catalina.configFail", file), e);
  26.             }
  27.         }
  28.         if (inputStream == null) {
  29.             try {
  30.                 inputStream = getClass().getClassLoader()
  31.                     .getResourceAsStream(getConfigFile());
  32.                 inputSource = new InputSource
  33.                     (getClass().getClassLoader()
  34.                      .getResource(getConfigFile()).toString());
  35.             } catch (Exception e) {
  36.                 if (log.isDebugEnabled()) {
  37.                     log.debug(sm.getString("catalina.configFail",
  38.                             getConfigFile()), e);
  39.                 }
  40.             }
  41.         }
  42.         // This should be included in catalina.jar
  43.         // Alternative: don't bother with xml, just create it manually.
  44.         if (inputStream == null) {
  45.             try {
  46.                 inputStream = getClass().getClassLoader()
  47.                         .getResourceAsStream("server-embed.xml");
  48.                 inputSource = new InputSource
  49.                 (getClass().getClassLoader()
  50.                         .getResource("server-embed.xml").toString());
  51.             } catch (Exception e) {
  52.                 if (log.isDebugEnabled()) {
  53.                     log.debug(sm.getString("catalina.configFail",
  54.                             "server-embed.xml"), e);
  55.                 }
  56.             }
  57.         }
  58.         if (inputStream == null || inputSource == null) {
  59.             if  (file == null) {
  60.                 log.warn(sm.getString("catalina.configFail",
  61.                         getConfigFile() + "] or [server-embed.xml]"));
  62.             } else {
  63.                 log.warn(sm.getString("catalina.configFail",
  64.                         file.getAbsolutePath()));
  65.                 if (file.exists() && !file.canRead()) {
  66.                     log.warn("Permissions incorrect, read permission is not allowed on the file.");
  67.                 }
  68.             }
  69.             return;
  70.         }
  71.         try {
  72.             inputSource.setByteStream(inputStream);
  73.             digester.push(this);
  74.             //最终在这里进行解析;
  75.             digester.parse(inputSource);
  76.         } catch (SAXParseException spe) {
  77.             log.warn("Catalina.start using " + getConfigFile() + ": " +
  78.                     spe.getMessage());
  79.             return;
  80.         } catch (Exception e) {
  81.             log.warn("Catalina.start using " + getConfigFile() + ": " , e);
  82.             return;
  83.         }
  84.     } finally {
  85.         if (inputStream != null) {
  86.             try {
  87.                 //关闭流
  88.                 inputStream.close();
  89.             } catch (IOException e) {
  90.                 // Ignore
  91.             }
  92.         }
  93.     }
  94.     //进行双向绑定 绑定到server中,而catalina也可以获取到server。
  95.     getServer().setCatalina(this);
  96.     getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
  97.     getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
  98.     // Stream redirection
  99.     initStreams();
  100.     // Start the new server
  101.     try {
  102.         //启动服务 这些是通过责任链进行管理 进行初始化操作
  103.         getServer().init();
  104.     } catch (LifecycleException e) {
  105.         if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
  106.             throw new java.lang.Error(e);
  107.         } else {
  108.             log.error("Catalina.start", e);
  109.         }
  110.     }
  111.     long t2 = System.nanoTime();
  112.     if(log.isInfoEnabled()) {
  113.         log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms");
  114.     }
  115. }

org.apache.catalina.startup.Catalina#createStartDigester

  1. protected Digester createStartDigester() {
  2.     long t1=System.currentTimeMillis();
  3.     // Initialize the digester 初始化解析器
  4.     Digester digester = new Digester();
  5.     //解析器标志为false
  6.     digester.setValidating(false);
  7.     //执行标记为成
  8.     digester.setRulesValidation(true);
  9.     //用于存放对象信息 其中包含 类名 来源 端口编移配置
  10.     Map<Class<?>, List<String>> fakeAttributes = new HashMap<>();
  11.     // Ignore className on all elements
  12.     List<String> objectAttrs = new ArrayList<>();
  13.     objectAttrs.add("className");
  14.     fakeAttributes.put(Object.class, objectAttrs);
  15.     // Ignore attribute added by Eclipse for its internal tracking
  16.     List<String> contextAttrs = new ArrayList<>();
  17.     contextAttrs.add("source");
  18.     fakeAttributes.put(StandardContext.class, contextAttrs);
  19.     // Ignore Connector attribute used internally but set on Server
  20.     List<String> connectorAttrs = new ArrayList<>();
  21.     connectorAttrs.add("portOffset");
  22.     fakeAttributes.put(Connector.class, connectorAttrs);
  23.     digester.setFakeAttributes(fakeAttributes);
  24.     digester.setUseContextClassLoader(true);
  25.     // Configure the actions we will be using
  26.     //以下这些都是在xml的类型
  27.     digester.addObjectCreate("Server",
  28.                              "org.apache.catalina.core.StandardServer",
  29.                              "className");
  30.     digester.addSetProperties("Server");
  31.     digester.addSetNext("Server",
  32.                         "setServer",
  33.                         "org.apache.catalina.Server");
  34.     digester.addObjectCreate("Server/GlobalNamingResources",
  35.                              "org.apache.catalina.deploy.NamingResourcesImpl");
  36.     digester.addSetProperties("Server/GlobalNamingResources");
  37.     digester.addSetNext("Server/GlobalNamingResources",
  38.                         "setGlobalNamingResources",
  39.                         "org.apache.catalina.deploy.NamingResourcesImpl");
  40.     digester.addObjectCreate("Server/Listener",
  41.                              null, // MUST be specified in the element
  42.                              "className");
  43.     digester.addSetProperties("Server/Listener");
  44.     digester.addSetNext("Server/Listener",
  45.                         "addLifecycleListener",
  46.                         "org.apache.catalina.LifecycleListener");
  47.     digester.addObjectCreate("Server/Service",
  48.                              "org.apache.catalina.core.StandardService",
  49.                              "className");
  50.     digester.addSetProperties("Server/Service");
  51.     digester.addSetNext("Server/Service",
  52.                         "addService",
  53.                         "org.apache.catalina.Service");
  54.     digester.addObjectCreate("Server/Service/Listener",
  55.                              null, // MUST be specified in the element
  56.                              "className");
  57.     digester.addSetProperties("Server/Service/Listener");
  58.     digester.addSetNext("Server/Service/Listener",
  59.                         "addLifecycleListener",
  60.                         "org.apache.catalina.LifecycleListener");
  61.     //Executor 该线程池在最新版本中被屏蔽了 可查看server.xml <Connector executor="tomcatThreadPool"
  62.     digester.addObjectCreate("Server/Service/Executor",
  63.                      "org.apache.catalina.core.StandardThreadExecutor",
  64.                      "className");
  65.     digester.addSetProperties("Server/Service/Executor");
  66.     digester.addSetNext("Server/Service/Executor",
  67.                         "addExecutor",
  68.                         "org.apache.catalina.Executor");
  69.     digester.addRule("Server/Service/Connector",
  70.                      new ConnectorCreateRule());
  71.     digester.addRule("Server/Service/Connector",
  72.                      new SetAllPropertiesRule(new String[]{"executor", "sslImplementationName"}));
  73.     digester.addSetNext("Server/Service/Connector",
  74.                         "addConnector",
  75.                         "org.apache.catalina.connector.Connector");
  76.     digester.addRule("Server/Service/Connector", new AddPortOffsetRule());
  77.     digester.addObjectCreate("Server/Service/Connector/SSLHostConfig",
  78.                              "org.apache.tomcat.util.net.SSLHostConfig");
  79.     digester.addSetProperties("Server/Service/Connector/SSLHostConfig");
  80.     digester.addSetNext("Server/Service/Connector/SSLHostConfig",
  81.             "addSslHostConfig",
  82.             "org.apache.tomcat.util.net.SSLHostConfig");
  83.     digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate",
  84.                      new CertificateCreateRule());
  85.     digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate",
  86.                      new SetAllPropertiesRule(new String[]{"type"}));
  87.     digester.addSetNext("Server/Service/Connector/SSLHostConfig/Certificate",
  88.                         "addCertificate",
  89.                         "org.apache.tomcat.util.net.SSLHostConfigCertificate");
  90.     digester.addObjectCreate("Server/Service/Connector/SSLHostConfig/OpenSSLConf",
  91.                              "org.apache.tomcat.util.net.openssl.OpenSSLConf");
  92.     digester.addSetProperties("Server/Service/Connector/SSLHostConfig/OpenSSLConf");
  93.     digester.addSetNext("Server/Service/Connector/SSLHostConfig/OpenSSLConf",
  94.                         "setOpenSslConf",
  95.                         "org.apache.tomcat.util.net.openssl.OpenSSLConf");
  96.     digester.addObjectCreate("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd",
  97.                              "org.apache.tomcat.util.net.openssl.OpenSSLConfCmd");
  98.     digester.addSetProperties("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd");
  99.     digester.addSetNext("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd",
  100.                         "addCmd",
  101.                         "org.apache.tomcat.util.net.openssl.OpenSSLConfCmd");
  102.     digester.addObjectCreate("Server/Service/Connector/Listener",
  103.                              null, // MUST be specified in the element
  104.                              "className");
  105.     digester.addSetProperties("Server/Service/Connector/Listener");
  106.     digester.addSetNext("Server/Service/Connector/Listener",
  107.                         "addLifecycleListener",
  108.                         "org.apache.catalina.LifecycleListener");
  109.     digester.addObjectCreate("Server/Service/Connector/UpgradeProtocol",
  110.                               null, // MUST be specified in the element
  111.                               "className");
  112.     digester.addSetProperties("Server/Service/Connector/UpgradeProtocol");
  113.     digester.addSetNext("Server/Service/Connector/UpgradeProtocol",
  114.                         "addUpgradeProtocol",
  115.                         "org.apache.coyote.UpgradeProtocol");
  116.     // Add RuleSets for nested elements
  117.     digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));
  118.     digester.addRuleSet(new EngineRuleSet("Server/Service/"));
  119.     digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
  120.     digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
  121.     addClusterRuleSet(digester, "Server/Service/Engine/Host/Cluster/");
  122.     digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));
  123.     // When the 'engine' is found, set the parentClassLoader.
  124.     digester.addRule("Server/Service/Engine",
  125.                      new SetParentClassLoaderRule(parentClassLoader));
  126.     addClusterRuleSet(digester, "Server/Service/Engine/Cluster/");
  127.     long t2=System.currentTimeMillis();
  128.     if (log.isDebugEnabled()) {
  129.         log.debug("Digester for server.xml created " + ( t2-t1 ));
  130.     }
  131.     return digester;
  132. }

org.apache.catalina.util.LifecycleBase#init

通过责任链管理生命周期;

  1. @Override
  2. public final synchronized void init() throws LifecycleException {
  3.     if (!state.equals(LifecycleState.NEW)) {
  4.         invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
  5.     }
  6.     try {
  7.         //设置生命周期状态
  8.         setStateInternal(LifecycleState.INITIALIZING, null, false);
  9.         initInternal();
  10.         setStateInternal(LifecycleState.INITIALIZED, null, false);
  11.     } catch (Throwable t) {
  12.         handleSubClassException(t, "lifecycleBase.initFail", toString());
  13.     }
  14. }

通过以上的initInternal()进入StandardServer#initInternal方法;

这里注意:StandardServer的执行顺序是:initInterna->NamingResourcesImpl#initInternal->service.init();

通过initInterna 为初始化server容器然后通过初始化NamingResourcesImpl#initInternal是JNIDI的数据连接服务,然后再初始多个service

org.apache.catalina.core.StandardServer#initInternal

  1. @Override
  2. protected void initInternal() throws LifecycleException {
  3.     super.initInternal();
  4.     // Register global String cache
  5.     // Note although the cache is global, if there are multiple Servers
  6.     // present in the JVM (may happen when embedding) then the same cache
  7.     // will be registered under multiple names
  8.     onameStringCache = register(new StringCache(), "type=StringCache");
  9.     // Register the MBeanFactory
  10.     MBeanFactory factory = new MBeanFactory();
  11.     factory.setContainer(this);
  12.     onameMBeanFactory = register(factory, "type=MBeanFactory");
  13.     // Register the naming resources
  14.     globalNamingResources.init();
  15.     // Populate the extension validator with JARs from common and shared
  16.     // class loaders
  17.     if (getCatalina() != null) {
  18.         ClassLoader cl = getCatalina().getParentClassLoader();
  19.         // Walk the class loader hierarchy. Stop at the system class loader.
  20.         // This will add the shared (if present) and common class loaders
  21.         while (cl != null && cl != ClassLoader.getSystemClassLoader()) {
  22.             if (cl instanceof URLClassLoader) {
  23.                 URL[] urls = ((URLClassLoader) cl).getURLs();
  24.                 for (URL url : urls) {
  25.                     if (url.getProtocol().equals("file")) {
  26.                         try {
  27.                             File f = new File (url.toURI());
  28.                             if (f.isFile() &&
  29.                                     f.getName().endsWith(".jar")) {
  30.                                 ExtensionValidator.addSystemResource(f);
  31.                             }
  32.                         } catch (URISyntaxException | IOException e) {
  33.                             // Ignore
  34.                         }
  35.                     }
  36.                 }
  37.             }
  38.             cl = cl.getParent();
  39.         }
  40.     }
  41.     // Initialize our defined Services 初始化service
  42.     for (Service service : services) {
  43.         service.init();
  44.     }
  45. }

org.apache.catalina.deploy.NamingResourcesImpl#initInternal

  1. //加载 web.xml 中<resource-ref> 的资源配置
  2. @Override
  3. protected void initInternal() throws LifecycleException {
  4.     super.initInternal();
  5.     // Set this before we register currently known naming resources to avoid
  6.     // timing issues. Duplication registration is not an issue.
  7.     resourceRequireExplicitRegistration = true;
  8.     //循环创建
  9.     for (ContextResource cr : resources.values()) {
  10.         try {
  11.             MBeanUtils.createMBean(cr);
  12.         } catch (Exception e) {
  13.             log.warn(sm.getString(
  14.                     "namingResources.mbeanCreateFail", cr.getName()), e);
  15.         }
  16.     }
  17.     //循环创建多个
  18.     for (ContextEnvironment ce : envs.values()) {
  19.         try {
  20.             MBeanUtils.createMBean(ce);
  21.         } catch (Exception e) {
  22.             log.warn(sm.getString(
  23.                     "namingResources.mbeanCreateFail", ce.getName()), e);
  24.         }
  25.     }
  26.     for (ContextResourceLink crl : resourceLinks.values()) {
  27.         try {
  28.             MBeanUtils.createMBean(crl);
  29.         } catch (Exception e) {
  30.             log.warn(sm.getString(
  31.                     "namingResources.mbeanCreateFail", crl.getName()), e);
  32.         }
  33.     }
  34. }

org.apache.catalina.core.StandardService#initInternal

执行顺序:initInternal->org.apache.catalina.core.StandardEngine#initInternal->connector.init();

  1. @Override
  2. protected void initInternal() throws LifecycleException {
  3.     super.initInternal();
  4.     if (engine != null) {
  5.         //初始化engine的角色信息
  6.         engine.init();
  7.     }
  8.     // Initialize any Executors 在tomcat8后以后在web.xml中被屏蔽了
  9.     for (Executor executor : findExecutors()) {
  10.         if (executor instanceof JmxEnabled) {
  11.             ((JmxEnabled) executor).setDomain(getDomain());
  12.         }
  13.         executor.init();
  14.     }
  15.     // Initialize mapper listener 初始化生命周期bean中
  16.     mapperListener.init();
  17.     // Initialize our defined Connectors 同步对象锁
  18.     synchronized (connectorsLock) {
  19.         //初始化多个connector
  20.         for (Connector connector : connectors) {
  21.             try {
  22.                 connector.init();
  23.             } catch (Exception e) {
  24.                 String message = sm.getString(
  25.                         "stxandardService.connector.initFailed", connector);
  26.                 log.error(message, e);
  27.                 if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
  28.                     throw new LifecycleException(message);
  29.                 }
  30.             }
  31.         }
  32.     }
  33. }

#注册到bean

org.apache.catalina.util.LifecycleMBeanBase#initInternal

  1. @Override
  2. protected void initInternal() throws LifecycleException {
  3.     // If oname is not null then registration has already happened via
  4.     // preRegister().
  5.     if (oname == null) {
  6.         mserver = Registry.getRegistry(null, null).getMBeanServer();
  7.         oname = register(this, getObjectNameKeyProperties());
  8.     }
  9. }

org.apache.catalina.connector.Connector#initInternal

  1. @Override
  2. protected void initInternal() throws LifecycleException {
  3.     super.initInternal();
  4.     // Initialize adapter
  5.     adapter = new CoyoteAdapter(this);
  6.     protocolHandler.setAdapter(adapter);
  7.     // Make sure parseBodyMethodsSet has a default
  8.     if (null == parseBodyMethodsSet) {
  9.         setParseBodyMethods(getParseBodyMethods());
  10.     }
  11.     if (protocolHandler.isAprRequired() && !AprLifecycleListener.isInstanceCreated()) {
  12.         throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprListener",
  13.                 getProtocolHandlerClassName()));
  14.     }
  15.     if (protocolHandler.isAprRequired() && !AprLifecycleListener.isAprAvailable()) {
  16.         throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprLibrary",
  17.                 getProtocolHandlerClassName()));
  18.     }
  19.     if (AprLifecycleListener.isAprAvailable() && AprLifecycleListener.getUseOpenSSL() &&
  20.             protocolHandler instanceof AbstractHttp11JsseProtocol) {
  21.         AbstractHttp11JsseProtocol<?> jsseProtocolHandler =
  22.                 (AbstractHttp11JsseProtocol<?>) protocolHandler;
  23.         if (jsseProtocolHandler.isSSLEnabled() &&
  24.                 jsseProtocolHandler.getSslImplementationName() == null) {
  25.             // OpenSSL is compatible with the JSSE configuration, so use it if APR is available
  26.             jsseProtocolHandler.setSslImplementationName(OpenSSLImplementation.class.getName());
  27.         }
  28.     }
  29.     try {
  30.         protocolHandler.init();
  31.     } catch (Exception e) {
  32.         throw new LifecycleException(
  33.                 sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
  34.     }
  35. }

#初始化httpnio

org.apache.coyote.http11.AbstractHttp11Protocol#init

  1. @Override
  2. public void init() throws Exception {
  3.     // Upgrade protocols have to be configured first since the endpoint
  4.     // init (triggered via super.init() below) uses this list to configure
  5.     // the list of ALPN protocols to advertise
  6.     for (UpgradeProtocol upgradeProtocol : upgradeProtocols) {
  7.         configureUpgradeProtocol(upgradeProtocol);
  8.     }
  9.     super.init();
  10.     // Set the Http11Protocol (i.e. this) for any upgrade protocols once
  11.     // this has completed initialisation as the upgrade protocols may expect this
  12.     // to be initialised when the call is made
  13.     for (UpgradeProtocol upgradeProtocol : upgradeProtocols) {
  14.         if (upgradeProtocol instanceof Http2Protocol) {
  15.             ((Http2Protocol) upgradeProtocol).setHttp11Protocol(this);
  16.         }
  17.     }
  18. }
shutdownhook关闭钩子(优雅关闭)
  1. protected class CatalinaShutdownHook extends Thread {
  2.     @Override
  3.     public void run() {
  4.         try {
  5.             if (getServer() != null) {
  6.                 Catalina.this.stop();
  7.             }
  8.         } catch (Throwable ex) {
  9.             ExceptionUtils.handleThrowable(ex);
  10.             log.error(sm.getString("catalina.shutdownHookFail"), ex);
  11.         } finally {
  12.             // If JULI is used, shut JULI down *after* the server shuts down
  13.             // so log messages aren't lost
  14.             LogManager logManager = LogManager.getLogManager();
  15.             if (logManager instanceof ClassLoaderLogManager) {
  16.                 ((ClassLoaderLogManager) logManager).shutdown();
  17.             }
  18.         }
  19.     }
  20. public void load() {
  21.     if (loaded) {
  22.         return;
  23.     }
  24.     loaded = true;
  25.     long t1 = System.nanoTime();
  26.     initDirs();
  27.     // Before digester - it may be needed
  28.     initNaming();
  29.     // Set configuration source
  30.     ConfigFileLoader.setSource(new CatalinaBaseConfigurationSource(Bootstrap.getCatalinaBaseFile(), getConfigFile()));
  31.     File file = configFile();
  32.     // 创建解析器(核心方法)
  33.     Digester digester = createStartDigester();
  34.     try (ConfigurationSource.Resource resource = ConfigFileLoader.getSource().getServerXml()) {
  35.         InputStream inputStream = resource.getInputStream();
  36.         InputSource inputSource = new InputSource(resource.getURI().toURL().toString());
  37.         inputSource.setByteStream(inputStream);
  38.         digester.push(this);
  39.         digester.parse(inputSource);
  40.     } catch (Exception e) {
  41.         log.warn(sm.getString("catalina.configFail", file.getAbsolutePath()), e);
  42.         if (file.exists() && !file.canRead()) {
  43.             log.warn(sm.getString("catalina.incorrectPermissions"));
  44.         }
  45.         return;
  46.     }
  47.     //进行双向绑定 绑定到server中,而catalina也可以获取到server。
  48.     getServer().setCatalina(this);
  49.     getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
  50.     getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
  51.     // Stream redirection
  52.     initStreams();
  53.     // Start the new server
  54.     try {
  55.         //初始化服务操作
  56.         getServer().init();
  57.     } catch (LifecycleException e) {
  58.         if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
  59.             throw new java.lang.Error(e);
  60.         } else {
  61.             log.error(sm.getString("catalina.initError"), e);
  62.         }
  63.     }
  64.     long t2 = System.nanoTime();
  65.     if(log.isInfoEnabled()) {
  66.         log.info(sm.getString("catalina.init", Long.valueOf((t2 - t1) / 1000000)));
  67.     }
  68. }}

org.apache.catalina.startup.Catalina#initNaming

  1. protected void initNaming() {
  2.     // Setting additional variables
  3.     if (!useNaming) {
  4.         log.info(sm.getString("catalina.noNaming"));
  5.         System.setProperty("catalina.useNaming", "false");
  6.     } else {
  7.         //设置系统属性catalina.useNaming 为true
  8.         System.setProperty("catalina.useNaming", "true");
  9.         String value = "org.apache.naming";
  10.         String oldValue =
  11.             System.getProperty(javax.naming.Context.URL_PKG_PREFIXES);
  12.         //如果系统属性中该值已存在 则将新值:老值这样拼上;
  13.         if (oldValue != null) {
  14.             value = value + ":" + oldValue;
  15.         }
  16.         //设置java.naming.factory.url.pkgs 为 org.apache.naming
  17.         System.setProperty(javax.naming.Context.URL_PKG_PREFIXES, value);
  18.         if( log.isDebugEnabled() ) {
  19.             log.debug("Setting naming prefix=" + value);
  20.         }
  21.         //获取系统属性java.naming.factory.initial
  22.         value = System.getProperty
  23.             (javax.naming.Context.INITIAL_CONTEXT_FACTORY);
  24.         if (value == null) {
  25.             System.setProperty
  26.                 (javax.naming.Context.INITIAL_CONTEXT_FACTORY,
  27.                  "org.apache.naming.java.javaURLContextFactory");
  28.         } else {
  29.             log.debug( "INITIAL_CONTEXT_FACTORY already set " + value );
  30.         }
  31.     }
  32. }

所有的生命期都在lifecyclebase进行管理

org.apache.catalina.util.LifecycleBase#init

  1. @Override
  2. public final synchronized void init() throws LifecycleException {
  3.     if (!state.equals(LifecycleState.NEW)) {
  4.         invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
  5.     }
  6.     try {
  7.         //设置生命周期状态
  8.         setStateInternal(LifecycleState.INITIALIZING, null, false);
  9.         initInternal();
  10.         setStateInternal(LifecycleState.INITIALIZED, null, false);
  11.     } catch (Throwable t) {
  12.         handleSubClassException(t, "lifecycleBase.initFail", toString());
  13.     }
  14. }

位置:org.apache.catalina.connector.Connector#setProtocol(用于设置协议 tomcat高版本默认为nio,而协议为http 1.1)

  1. public void setProtocol(String protocol) {
  2.     boolean aprConnector = AprLifecycleListener.isAprAvailable() &&
  3.             AprLifecycleListener.getUseAprConnector();
  4.     if ("HTTP/1.1".equals(protocol) || protocol == null) {
  5.         if (aprConnector) {
  6.             setProtocolHandlerClassName("org.apache.coyote.http11.Http11AprProtocol");
  7.         } else {
  8.             setProtocolHandlerClassName("org.apache.coyote.http11.Http11NioProtocol");
  9.         }
  10.     } else if ("AJP/1.3".equals(protocol)) {
  11.         if (aprConnector) {
  12.             setProtocolHandlerClassName("org.apache.coyote.ajp.AjpAprProtocol");
  13.         } else {
  14.             setProtocolHandlerClassName("org.apache.coyote.ajp.AjpNioProtocol");
  15.         }
  16.     } else {
  17.         setProtocolHandlerClassName(protocol);
  18.     }
  19. }

最终进入方法:org.apache.catalina.startup.Catalina#start ,那么整个启动就完毕了。但是要注意下面的这个await(); ,启动到这里就一直阻塞了,每隔10秒就检测一次,当stopAwait为true时,线程才结束。

  1. /**
  2.  * Start a new server instance.
  3.  */
  4. public void start() {
  5.     if (getServer() == null) {
  6.         load();
  7.     }
  8.     if (getServer() == null) {
  9.         log.fatal("Cannot start server. Server instance is not configured.");
  10.         return;
  11.     }
  12.     long t1 = System.nanoTime();
  13.     // Start the new server 启动服务
  14.     try {
  15.         getServer().start();
  16.     } catch (LifecycleException e) {
  17.         log.fatal(sm.getString("catalina.serverStartFail"), e);
  18.         try {
  19.             getServer().destroy();
  20.         } catch (LifecycleException e1) {
  21.             log.debug("destroy() failed for failed Server ", e1);
  22.         }
  23.         return;
  24.     }
  25.     long t2 = System.nanoTime();
  26.     if(log.isInfoEnabled()) {
  27.         log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms");
  28.     }
  29.     // Register shutdown hook
  30.     if (useShutdownHook) {
  31.         if (shutdownHook == null) {
  32.             shutdownHook = new CatalinaShutdownHook();
  33.         }
  34.         Runtime.getRuntime().addShutdownHook(shutdownHook);
  35.         // If JULI is being used, disable JULI's shutdown hook since
  36.         // shutdown hooks run in parallel and log messages may be lost
  37.         // if JULI's hook completes before the CatalinaShutdownHook()
  38.         LogManager logManager = LogManager.getLogManager();
  39.         if (logManager instanceof ClassLoaderLogManager) {
  40.             ((ClassLoaderLogManager) logManager).setUseShutdownHook(
  41.                     false);
  42.         }
  43.     }
  44.     //await就是主线程的守护,否则就直接关闭了
  45.     if (await) {
  46.         await();
  47.         //当上面的结束后,才会执行下面的关闭,如果没有就一直等待中,当关闭线程的时候,不会直接就关闭,因为tomcat使用卫钩子函数,通过这个可以优雅关闭。
  48.         stop();
  49.     }
  50. }

最后

    以上为tomcat启动的核心流程,只挑了一些重点的了解,其实tomcat还有很多非常细节没有涉及到,由于篇幅有限所以,在后续如果需要的时候再标出,还有原因上传gitee上面有需要同步可以拉源码了解。

参考:《Tomcat架构解析》

0de1e48da65595eed4d66d874848bd4d.png

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/天景科技苑/article/detail/741649
推荐阅读
相关标签
  

闽ICP备14008679号