赞
踩
Tomcat整体启动流程
上文了解了大致tomat的相关架构,那么本文是针对tomcat的启动流程进行了解,。tomcat是通过Bootstrap的main方法进行启动,然后通过catalina对象中创建server.xml的解析器,一步到位创建出大部分组件,通过责任链模式进行层层管理。细节可以跟着调试代码关注如下。
源码位置:https://gitee.com/hong99/source-code-learning.git
tomcat整体架构
tomcat的核心启动入口(所有的启动入口)
代码位置
注意:bootstrap调用顺序main->init->load
org.apache.catalina.startup.Bootstrap#main
- /**
- * Main method and entry point when starting Tomcat via the provided
- * scripts.
- *
- * @param args Command line arguments to be processed
- * tomcat 核心启动类 主线程类
- */
- public static void main(String args[]) {
- //线程同步方式启动
- synchronized (daemonLock) {
- if (daemon == null) {
- //创建 自身
- Bootstrap bootstrap = new Bootstrap();
- try {
- //创建 tomcat自身的初始化
- bootstrap.init();
- } catch (Throwable t) {
- handleThrowable(t);
- t.printStackTrace();
- return;
- }
- daemon = bootstrap;
- } else {
- // When running as a service the call to stop will be on a new
- // thread so make sure the correct class loader is used to
- // prevent a range of class not found exceptions.
- Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
- }
- }
-
- try {
- //默认为启动 标识
- String command = "start";
- //如果args长度大于0
- if (args.length > 0) {
- //重新赋值
- command = args[args.length - 1];
- }
-
- if (command.equals("startd")) {
- args[args.length - 1] = "start";
- daemon.load(args);
- daemon.start();
- } else if (command.equals("stopd")) {
- args[args.length - 1] = "stop";
- daemon.stop();
- } else if (command.equals("start")) {
- //线程等待,否则tomcat直接就关闭了;就类似于守护线程
- daemon.setAwait(true);
- //加载
- daemon.load(args);
- daemon.start();
- if (null == daemon.getServer()) {
- System.exit(1);
- }
- } else if (command.equals("stop")) {
- daemon.stopServer(args);
- } else if (command.equals("configtest")) {
- daemon.load(args);
- if (null == daemon.getServer()) {
- System.exit(1);
- }
- System.exit(0);
- } else {
- log.warn("Bootstrap: command \"" + command + "\" does not exist.");
- }
- } catch (Throwable t) {
- // Unwrap the Exception for clearer error reporting
- if (t instanceof InvocationTargetException &&
- t.getCause() != null) {
- t = t.getCause();
- }
- handleThrowable(t);
- t.printStackTrace();
- System.exit(1);
- }
- }
main执行中,第一步初始化就是init,通过这个init进行初始化所有下级;
org.apache.catalina.startup.Bootstrap#init()
- /**
- * bootstartp 初始化方法
- * Initialize daemon.
- * @throws Exception Fatal initialization error
- */
- public void init() throws Exception {
- //初始化类加载器 其中包含 catalinaLoader和sharedLoader
- initClassLoaders();
- //将catalinaLoader 放到当前线上下文中
- Thread.currentThread().setContextClassLoader(catalinaLoader);
- //将catalinaLoader 加载到权限管理中
- SecurityClassLoad.securityClassLoad(catalinaLoader);
-
- // 是否打印日志开关
- if (log.isDebugEnabled()) {
- log.debug("Loading startup class");
- }
- //通过反射方式调用 catalina方法
- Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
- Object startupInstance = startupClass.getConstructor().newInstance();
-
- // Set the shared extensions class loader
- if (log.isDebugEnabled()) {
- log.debug("Setting startup class properties");
- }
- //方法名称为:setParentClassLoader
- String methodName = "setParentClassLoader";
- Class<?> paramTypes[] = new Class[1];
- paramTypes[0] = Class.forName("java.lang.ClassLoader");
- Object paramValues[] = new Object[1];
- //类加载器
- paramValues[0] = sharedLoader;
- Method method =
- startupInstance.getClass().getMethod(methodName, paramTypes);
- //通过反射方式调用
- method.invoke(startupInstance, paramValues);
- //将这个对象赋值到 catalinaDaemon
- catalinaDaemon = startupInstance;
- }
org.apache.catalina.startup.Bootstrap#load
- private void load(String[] arguments) throws Exception {
-
- // Call the load() method 加载的方法名称为load
- String methodName = "load";
- Object param[];
- Class<?> paramTypes[];
- //当arguments为空或长度为0时将paramTypes和param 赋为空。
- 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;
- }
- //通过 server.xml获取org.apache.catalina.startup.Catalina里面的方法为load
- Method method =
- catalinaDaemon.getClass().getMethod(methodName, paramTypes);
- if (log.isDebugEnabled()) {
- log.debug("Calling startup class " + method);
- }
- //通过反射调用 catalina里面的load无参方法
- method.invoke(catalinaDaemon, param);
- }
到这里就跳出去调catalina的无参load方法。
那么Catalina的调用顺序是:load()->createStartDigester()->getServer().init()
主要的目的是加载sever.xml然后去初始化server,这里注意所有的加载都是通过责任链进行管理,所以getServer都是通过org.apache.catalina.util.LifecycleBase#init进行加载;
org.apache.catalina.startup.Catalina#load()
- public void load() {
- //如果为false则直接返回
- if (loaded) {
- return;
- }
- loaded = true;
-
- long t1 = System.nanoTime();
- //空方法 该方式不做其他操作
- initDirs();
-
- // Before digester - it may be needed
- initNaming();
-
- // Create and execute our Digester
- Digester digester = createStartDigester();
-
- InputSource inputSource = null;
- InputStream inputStream = null;
- File file = null;
- //以下是通过流的方式进行加载,然后解析
- try {
- try {
- 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);
- }
- }
- if (inputStream == null) {
- try {
- inputStream = getClass().getClassLoader()
- .getResourceAsStream(getConfigFile());
- inputSource = new InputSource
- (getClass().getClassLoader()
- .getResource(getConfigFile()).toString());
- } catch (Exception e) {
- if (log.isDebugEnabled()) {
- log.debug(sm.getString("catalina.configFail",
- getConfigFile()), e);
- }
- }
- }
-
- // This should be included in catalina.jar
- // Alternative: don't bother with xml, just create it manually.
- if (inputStream == null) {
- try {
- inputStream = getClass().getClassLoader()
- .getResourceAsStream("server-embed.xml");
- inputSource = new InputSource
- (getClass().getClassLoader()
- .getResource("server-embed.xml").toString());
- } catch (Exception e) {
- if (log.isDebugEnabled()) {
- log.debug(sm.getString("catalina.configFail",
- "server-embed.xml"), e);
- }
- }
- }
-
-
- if (inputStream == null || inputSource == null) {
- if (file == null) {
- log.warn(sm.getString("catalina.configFail",
- getConfigFile() + "] or [server-embed.xml]"));
- } else {
- log.warn(sm.getString("catalina.configFail",
- file.getAbsolutePath()));
- if (file.exists() && !file.canRead()) {
- log.warn("Permissions incorrect, read permission is not allowed on the file.");
- }
- }
- return;
- }
-
- 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 {
- if (inputStream != null) {
- try {
- //关闭流
- inputStream.close();
- } catch (IOException e) {
- // Ignore
- }
- }
- }
- //进行双向绑定 绑定到server中,而catalina也可以获取到server。
- getServer().setCatalina(this);
- getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
- getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
-
- // Stream redirection
- initStreams();
-
- // 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");
- }
- }
org.apache.catalina.startup.Catalina#createStartDigester
- protected Digester createStartDigester() {
- long t1=System.currentTimeMillis();
- // Initialize the digester 初始化解析器
- Digester digester = new Digester();
- //解析器标志为false
- digester.setValidating(false);
- //执行标记为成
- digester.setRulesValidation(true);
- //用于存放对象信息 其中包含 类名 来源 端口编移配置
- Map<Class<?>, List<String>> fakeAttributes = new HashMap<>();
- // Ignore className on all elements
- List<String> objectAttrs = new ArrayList<>();
- objectAttrs.add("className");
- fakeAttributes.put(Object.class, objectAttrs);
- // Ignore attribute added by Eclipse for its internal tracking
- List<String> contextAttrs = new ArrayList<>();
- contextAttrs.add("source");
- fakeAttributes.put(StandardContext.class, contextAttrs);
- // Ignore Connector attribute used internally but set on Server
- List<String> connectorAttrs = new ArrayList<>();
- connectorAttrs.add("portOffset");
- fakeAttributes.put(Connector.class, connectorAttrs);
- digester.setFakeAttributes(fakeAttributes);
- digester.setUseContextClassLoader(true);
-
- // Configure the actions we will be using
- //以下这些都是在xml的类型
- digester.addObjectCreate("Server",
- "org.apache.catalina.core.StandardServer",
- "className");
- digester.addSetProperties("Server");
- digester.addSetNext("Server",
- "setServer",
- "org.apache.catalina.Server");
-
- digester.addObjectCreate("Server/GlobalNamingResources",
- "org.apache.catalina.deploy.NamingResourcesImpl");
- digester.addSetProperties("Server/GlobalNamingResources");
- digester.addSetNext("Server/GlobalNamingResources",
- "setGlobalNamingResources",
- "org.apache.catalina.deploy.NamingResourcesImpl");
-
- digester.addObjectCreate("Server/Listener",
- null, // MUST be specified in the element
- "className");
- digester.addSetProperties("Server/Listener");
- digester.addSetNext("Server/Listener",
- "addLifecycleListener",
- "org.apache.catalina.LifecycleListener");
-
- digester.addObjectCreate("Server/Service",
- "org.apache.catalina.core.StandardService",
- "className");
- digester.addSetProperties("Server/Service");
- digester.addSetNext("Server/Service",
- "addService",
- "org.apache.catalina.Service");
-
- digester.addObjectCreate("Server/Service/Listener",
- null, // MUST be specified in the element
- "className");
- digester.addSetProperties("Server/Service/Listener");
- digester.addSetNext("Server/Service/Listener",
- "addLifecycleListener",
- "org.apache.catalina.LifecycleListener");
-
- //Executor 该线程池在最新版本中被屏蔽了 可查看server.xml <Connector executor="tomcatThreadPool"
- digester.addObjectCreate("Server/Service/Executor",
- "org.apache.catalina.core.StandardThreadExecutor",
- "className");
- digester.addSetProperties("Server/Service/Executor");
-
- digester.addSetNext("Server/Service/Executor",
- "addExecutor",
- "org.apache.catalina.Executor");
-
- digester.addRule("Server/Service/Connector",
- new ConnectorCreateRule());
- digester.addRule("Server/Service/Connector",
- new SetAllPropertiesRule(new String[]{"executor", "sslImplementationName"}));
- digester.addSetNext("Server/Service/Connector",
- "addConnector",
- "org.apache.catalina.connector.Connector");
-
- digester.addRule("Server/Service/Connector", new AddPortOffsetRule());
-
- digester.addObjectCreate("Server/Service/Connector/SSLHostConfig",
- "org.apache.tomcat.util.net.SSLHostConfig");
- digester.addSetProperties("Server/Service/Connector/SSLHostConfig");
- digester.addSetNext("Server/Service/Connector/SSLHostConfig",
- "addSslHostConfig",
- "org.apache.tomcat.util.net.SSLHostConfig");
-
- digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate",
- new CertificateCreateRule());
- digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate",
- new SetAllPropertiesRule(new String[]{"type"}));
- digester.addSetNext("Server/Service/Connector/SSLHostConfig/Certificate",
- "addCertificate",
- "org.apache.tomcat.util.net.SSLHostConfigCertificate");
-
- digester.addObjectCreate("Server/Service/Connector/SSLHostConfig/OpenSSLConf",
- "org.apache.tomcat.util.net.openssl.OpenSSLConf");
- digester.addSetProperties("Server/Service/Connector/SSLHostConfig/OpenSSLConf");
- digester.addSetNext("Server/Service/Connector/SSLHostConfig/OpenSSLConf",
- "setOpenSslConf",
- "org.apache.tomcat.util.net.openssl.OpenSSLConf");
-
- digester.addObjectCreate("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd",
- "org.apache.tomcat.util.net.openssl.OpenSSLConfCmd");
- digester.addSetProperties("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd");
- digester.addSetNext("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd",
- "addCmd",
- "org.apache.tomcat.util.net.openssl.OpenSSLConfCmd");
-
- digester.addObjectCreate("Server/Service/Connector/Listener",
- null, // MUST be specified in the element
- "className");
- digester.addSetProperties("Server/Service/Connector/Listener");
- digester.addSetNext("Server/Service/Connector/Listener",
- "addLifecycleListener",
- "org.apache.catalina.LifecycleListener");
-
- digester.addObjectCreate("Server/Service/Connector/UpgradeProtocol",
- null, // MUST be specified in the element
- "className");
- digester.addSetProperties("Server/Service/Connector/UpgradeProtocol");
- digester.addSetNext("Server/Service/Connector/UpgradeProtocol",
- "addUpgradeProtocol",
- "org.apache.coyote.UpgradeProtocol");
-
- // Add RuleSets for nested elements
- digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));
- digester.addRuleSet(new EngineRuleSet("Server/Service/"));
- digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
- digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
- addClusterRuleSet(digester, "Server/Service/Engine/Host/Cluster/");
- digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));
-
- // When the 'engine' is found, set the parentClassLoader.
- digester.addRule("Server/Service/Engine",
- new SetParentClassLoaderRule(parentClassLoader));
- addClusterRuleSet(digester, "Server/Service/Engine/Cluster/");
-
- long t2=System.currentTimeMillis();
- if (log.isDebugEnabled()) {
- log.debug("Digester for server.xml created " + ( t2-t1 ));
- }
- return digester;
-
- }
org.apache.catalina.util.LifecycleBase#init
通过责任链管理生命周期;
- @Override
- public final synchronized void init() throws LifecycleException {
- if (!state.equals(LifecycleState.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());
- }
- }
通过以上的initInternal()进入StandardServer#initInternal方法;
这里注意:StandardServer的执行顺序是:initInterna->NamingResourcesImpl#initInternal->service.init();
通过initInterna 为初始化server容器然后通过初始化NamingResourcesImpl#initInternal是JNIDI的数据连接服务,然后再初始多个service
org.apache.catalina.core.StandardServer#initInternal
- @Override
- 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
- globalNamingResources.init();
-
- // Populate the extension validator with JARs from common and shared
- // class loaders
- if (getCatalina() != null) {
- ClassLoader cl = getCatalina().getParentClassLoader();
- // Walk the class loader hierarchy. Stop at the system class loader.
- // This will add the shared (if present) and common class loaders
- while (cl != null && cl != ClassLoader.getSystemClassLoader()) {
- if (cl instanceof URLClassLoader) {
- URL[] urls = ((URLClassLoader) cl).getURLs();
- for (URL url : urls) {
- if (url.getProtocol().equals("file")) {
- try {
- File f = new File (url.toURI());
- if (f.isFile() &&
- f.getName().endsWith(".jar")) {
- ExtensionValidator.addSystemResource(f);
- }
- } catch (URISyntaxException | IOException e) {
- // Ignore
- }
- }
- }
- }
- cl = cl.getParent();
- }
- }
- // Initialize our defined Services 初始化service
- for (Service service : services) {
- service.init();
- }
- }
org.apache.catalina.deploy.NamingResourcesImpl#initInternal
- //加载 web.xml 中<resource-ref> 的资源配置
- @Override
- protected void initInternal() throws LifecycleException {
- super.initInternal();
-
- // Set this before we register currently known naming resources to avoid
- // timing issues. Duplication registration is not an issue.
- resourceRequireExplicitRegistration = true;
- //循环创建
- for (ContextResource cr : resources.values()) {
- try {
- MBeanUtils.createMBean(cr);
- } catch (Exception e) {
- log.warn(sm.getString(
- "namingResources.mbeanCreateFail", cr.getName()), e);
- }
- }
- //循环创建多个
- for (ContextEnvironment ce : envs.values()) {
- try {
- MBeanUtils.createMBean(ce);
- } catch (Exception e) {
- log.warn(sm.getString(
- "namingResources.mbeanCreateFail", ce.getName()), e);
- }
- }
-
- for (ContextResourceLink crl : resourceLinks.values()) {
- try {
- MBeanUtils.createMBean(crl);
- } catch (Exception e) {
- log.warn(sm.getString(
- "namingResources.mbeanCreateFail", crl.getName()), e);
- }
- }
- }
org.apache.catalina.core.StandardService#initInternal
执行顺序:initInternal->org.apache.catalina.core.StandardEngine#initInternal->connector.init();
- @Override
- protected void initInternal() throws LifecycleException {
-
- super.initInternal();
-
- if (engine != null) {
- //初始化engine的角色信息
- engine.init();
- }
-
- // Initialize any Executors 在tomcat8后以后在web.xml中被屏蔽了
- for (Executor executor : findExecutors()) {
- if (executor instanceof JmxEnabled) {
- ((JmxEnabled) executor).setDomain(getDomain());
- }
- executor.init();
- }
-
- // Initialize mapper listener 初始化生命周期bean中
- mapperListener.init();
-
- // Initialize our defined Connectors 同步对象锁
- synchronized (connectorsLock) {
- //初始化多个connector
- for (Connector connector : connectors) {
- try {
- connector.init();
- } catch (Exception e) {
- String message = sm.getString(
- "stxandardService.connector.initFailed", connector);
- log.error(message, e);
-
- if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
- throw new LifecycleException(message);
- }
- }
- }
- }
- }
#注册到bean
org.apache.catalina.util.LifecycleMBeanBase#initInternal
- @Override
- protected void initInternal() throws LifecycleException {
- // If oname is not null then registration has already happened via
- // preRegister().
- if (oname == null) {
- mserver = Registry.getRegistry(null, null).getMBeanServer();
-
- oname = register(this, getObjectNameKeyProperties());
- }
- }
org.apache.catalina.connector.Connector#initInternal
- @Override
- protected void initInternal() throws LifecycleException {
-
- super.initInternal();
-
- // Initialize adapter
- adapter = new CoyoteAdapter(this);
- protocolHandler.setAdapter(adapter);
-
- // Make sure parseBodyMethodsSet has a default
- if (null == parseBodyMethodsSet) {
- setParseBodyMethods(getParseBodyMethods());
- }
-
- if (protocolHandler.isAprRequired() && !AprLifecycleListener.isInstanceCreated()) {
- throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprListener",
- getProtocolHandlerClassName()));
- }
- if (protocolHandler.isAprRequired() && !AprLifecycleListener.isAprAvailable()) {
- throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprLibrary",
- getProtocolHandlerClassName()));
- }
- if (AprLifecycleListener.isAprAvailable() && AprLifecycleListener.getUseOpenSSL() &&
- protocolHandler instanceof AbstractHttp11JsseProtocol) {
- AbstractHttp11JsseProtocol<?> jsseProtocolHandler =
- (AbstractHttp11JsseProtocol<?>) protocolHandler;
- if (jsseProtocolHandler.isSSLEnabled() &&
- jsseProtocolHandler.getSslImplementationName() == null) {
- // OpenSSL is compatible with the JSSE configuration, so use it if APR is available
- jsseProtocolHandler.setSslImplementationName(OpenSSLImplementation.class.getName());
- }
- }
-
- try {
- protocolHandler.init();
- } catch (Exception e) {
- throw new LifecycleException(
- sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
- }
- }
#初始化httpnio
org.apache.coyote.http11.AbstractHttp11Protocol#init
- @Override
- public void init() throws Exception {
- // Upgrade protocols have to be configured first since the endpoint
- // init (triggered via super.init() below) uses this list to configure
- // the list of ALPN protocols to advertise
- for (UpgradeProtocol upgradeProtocol : upgradeProtocols) {
- configureUpgradeProtocol(upgradeProtocol);
- }
-
- super.init();
-
- // Set the Http11Protocol (i.e. this) for any upgrade protocols once
- // this has completed initialisation as the upgrade protocols may expect this
- // to be initialised when the call is made
- for (UpgradeProtocol upgradeProtocol : upgradeProtocols) {
- if (upgradeProtocol instanceof Http2Protocol) {
- ((Http2Protocol) upgradeProtocol).setHttp11Protocol(this);
- }
- }
- }
shutdownhook关闭钩子(优雅关闭)
- protected class CatalinaShutdownHook extends Thread {
-
- @Override
- public void run() {
- try {
- if (getServer() != null) {
- Catalina.this.stop();
- }
- } catch (Throwable ex) {
- ExceptionUtils.handleThrowable(ex);
- log.error(sm.getString("catalina.shutdownHookFail"), ex);
- } finally {
- // If JULI is used, shut JULI down *after* the server shuts down
- // so log messages aren't lost
- LogManager logManager = LogManager.getLogManager();
- if (logManager instanceof ClassLoaderLogManager) {
- ((ClassLoaderLogManager) logManager).shutdown();
- }
- }
- }
- public void load() {
-
- if (loaded) {
- return;
- }
- loaded = true;
-
- long t1 = System.nanoTime();
-
- initDirs();
-
- // Before digester - it may be needed
- initNaming();
-
- // Set configuration source
- ConfigFileLoader.setSource(new CatalinaBaseConfigurationSource(Bootstrap.getCatalinaBaseFile(), getConfigFile()));
- File file = configFile();
-
- // 创建解析器(核心方法)
- Digester digester = createStartDigester();
-
- try (ConfigurationSource.Resource resource = ConfigFileLoader.getSource().getServerXml()) {
- InputStream inputStream = resource.getInputStream();
- InputSource inputSource = new InputSource(resource.getURI().toURL().toString());
- inputSource.setByteStream(inputStream);
- digester.push(this);
- digester.parse(inputSource);
- } catch (Exception e) {
- log.warn(sm.getString("catalina.configFail", file.getAbsolutePath()), e);
- if (file.exists() && !file.canRead()) {
- log.warn(sm.getString("catalina.incorrectPermissions"));
- }
- return;
- }
- //进行双向绑定 绑定到server中,而catalina也可以获取到server。
- getServer().setCatalina(this);
- getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
- getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
-
- // Stream redirection
- initStreams();
-
- // 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(sm.getString("catalina.initError"), e);
- }
- }
-
- long t2 = System.nanoTime();
- if(log.isInfoEnabled()) {
- log.info(sm.getString("catalina.init", Long.valueOf((t2 - t1) / 1000000)));
- }
- }}
org.apache.catalina.startup.Catalina#initNaming
- protected void initNaming() {
- // Setting additional variables
- if (!useNaming) {
- log.info(sm.getString("catalina.noNaming"));
- System.setProperty("catalina.useNaming", "false");
- } else {
- //设置系统属性catalina.useNaming 为true
- System.setProperty("catalina.useNaming", "true");
- String value = "org.apache.naming";
- String oldValue =
- System.getProperty(javax.naming.Context.URL_PKG_PREFIXES);
- //如果系统属性中该值已存在 则将新值:老值这样拼上;
- if (oldValue != null) {
- value = value + ":" + oldValue;
- }
- //设置java.naming.factory.url.pkgs 为 org.apache.naming
- System.setProperty(javax.naming.Context.URL_PKG_PREFIXES, value);
- if( log.isDebugEnabled() ) {
- log.debug("Setting naming prefix=" + value);
- }
- //获取系统属性java.naming.factory.initial
- value = System.getProperty
- (javax.naming.Context.INITIAL_CONTEXT_FACTORY);
- if (value == null) {
- System.setProperty
- (javax.naming.Context.INITIAL_CONTEXT_FACTORY,
- "org.apache.naming.java.javaURLContextFactory");
- } else {
- log.debug( "INITIAL_CONTEXT_FACTORY already set " + value );
- }
- }
- }
所有的生命期都在lifecyclebase进行管理
org.apache.catalina.util.LifecycleBase#init
- @Override
- public final synchronized void init() throws LifecycleException {
- if (!state.equals(LifecycleState.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());
- }
- }
位置:org.apache.catalina.connector.Connector#setProtocol(用于设置协议 tomcat高版本默认为nio,而协议为http 1.1)
- public void setProtocol(String protocol) {
-
- boolean aprConnector = AprLifecycleListener.isAprAvailable() &&
- AprLifecycleListener.getUseAprConnector();
-
- if ("HTTP/1.1".equals(protocol) || protocol == null) {
- if (aprConnector) {
- setProtocolHandlerClassName("org.apache.coyote.http11.Http11AprProtocol");
- } else {
- setProtocolHandlerClassName("org.apache.coyote.http11.Http11NioProtocol");
- }
- } else if ("AJP/1.3".equals(protocol)) {
- if (aprConnector) {
- setProtocolHandlerClassName("org.apache.coyote.ajp.AjpAprProtocol");
- } else {
- setProtocolHandlerClassName("org.apache.coyote.ajp.AjpNioProtocol");
- }
- } else {
- setProtocolHandlerClassName(protocol);
- }
- }
最终进入方法:org.apache.catalina.startup.Catalina#start ,那么整个启动就完毕了。但是要注意下面的这个await(); ,启动到这里就一直阻塞了,每隔10秒就检测一次,当stopAwait为true时,线程才结束。
- /**
- * Start a new server instance.
- */
- 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();
-
- // 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;
- }
-
- long t2 = System.nanoTime();
- if(log.isInfoEnabled()) {
- log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms");
- }
-
- // Register shutdown hook
- if (useShutdownHook) {
- if (shutdownHook == null) {
- shutdownHook = new CatalinaShutdownHook();
- }
- Runtime.getRuntime().addShutdownHook(shutdownHook);
-
- // If JULI is being used, disable JULI's shutdown hook since
- // shutdown hooks run in parallel and log messages may be lost
- // if JULI's hook completes before the CatalinaShutdownHook()
- LogManager logManager = LogManager.getLogManager();
- if (logManager instanceof ClassLoaderLogManager) {
- ((ClassLoaderLogManager) logManager).setUseShutdownHook(
- false);
- }
- }
- //await就是主线程的守护,否则就直接关闭了
- if (await) {
- await();
- //当上面的结束后,才会执行下面的关闭,如果没有就一直等待中,当关闭线程的时候,不会直接就关闭,因为tomcat使用卫钩子函数,通过这个可以优雅关闭。
- stop();
- }
- }
最后
以上为tomcat启动的核心流程,只挑了一些重点的了解,其实tomcat还有很多非常细节没有涉及到,由于篇幅有限所以,在后续如果需要的时候再标出,还有原因上传gitee上面有需要同步可以拉源码了解。
参考:《Tomcat架构解析》
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。