Tomcat启动分析(Tomcat7.0)
1)bin目录下的bootstrap.jar中的main方法启动Tomcat
org.apache.catalina.startup.Bootstrap类下的main方法
可以看到Bootstrap类使用单例方式在main方法中初始化Bootstrap对象
private static Bootstrap daemon = null; private Object catalinaDaemon = null; protected ClassLoader commonLoader = null; protected ClassLoader catalinaLoader = null; protected ClassLoader sharedLoader = null;
调用Bootstrap对象的init()方法
public static void main(String[] args) { if (daemon == null) { Bootstrap bootstrap = new Bootstrap(); try { bootstrap.init(); } catch (Throwable t) { handleThrowable(t); t.printStackTrace(); return; } daemon = bootstrap; } try { String command = "start"; 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")) { daemon.setAwait(true); daemon.load(args); daemon.start(); } 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(new StringBuilder().append("Bootstrap: command \"").append(command).append("\" does not exist.").toString()); } } catch (Throwable t) { if (((t instanceof InvocationTargetException)) && (t.getCause() != null)) { t = t.getCause(); } handleThrowable(t); t.printStackTrace(); System.exit(1); } }
Bootstrap对象的init()方法,引导类Bootstrap负责引导,在其init方法内部创建容器启动所需的类加载器,以及用于JMX监控的MBeanServer
public void init() throws Exception { setCatalinaHome(); setCatalinaBase(); initClassLoaders(); Thread.currentThread().setContextClassLoader(this.catalinaLoader); SecurityClassLoad.securityClassLoad(this.catalinaLoader); if (log.isDebugEnabled()) log.debug("Loading startup class"); Class<?> startupClass = this.catalinaLoader.loadClass("org.apache.catalina.startup.Catalina"); Object startupInstance = startupClass.newInstance(); if (log.isDebugEnabled()) log.debug("Setting startup class properties"); String methodName = "setParentClassLoader"; Class<?>[] paramTypes = new Class[1]; paramTypes[0] = Class.forName("java.lang.ClassLoader"); Object[] paramValues = new Object[1]; paramValues[0] = this.sharedLoader; Method method = startupInstance.getClass().getMethod(methodName, paramTypes); method.invoke(startupInstance, paramValues); this.catalinaDaemon = startupInstance; }
仍然在Bootstrap类中,初始化所需要的类加载器
private void initClassLoaders() { try { this.commonLoader = createClassLoader("common", null); if (this.commonLoader == null) { this.commonLoader = getClass().getClassLoader(); } this.catalinaLoader = createClassLoader("server", this.commonLoader); this.sharedLoader = createClassLoader("shared", this.commonLoader); } catch (Throwable t) { handleThrowable(t); log.error("Class loader creation threw exception", t); System.exit(1); } }
我们继续看到main方法中调用了Bootstrap对象的load(args)方法和start()方法
daemon.load(args); daemon.start();
我们看到load(args)方法,Bootstrap调用Catalina的load()方法加载Server的配置(也就是server.xml),将加载的配置信息委托给Digester类进行相关内容的解析。
通过反射调用了Bootstrap对象中catalinaDaemon对象的load()方法,
private void load(String[] arguments) throws Exception { String methodName = "load"; Object[] param; Class<?>[] paramTypes; Object[] param; if ((arguments == null) || (arguments.length == 0)) { Class<?>[] paramTypes = null; param = null; } else { paramTypes = new Class[1]; paramTypes[0] = arguments.getClass(); param = new Object[1]; param[0] = arguments; } Method method = this.catalinaDaemon.getClass().getMethod(methodName, paramTypes); if (log.isDebugEnabled()) log.debug(new StringBuilder().append("Calling startup class ").append(method).toString()); method.invoke(this.catalinaDaemon, param); }
我们可以看到在上面的init()方法中初始化了org.apache.catalina.startup.Catalina对象,通过之前初始化的catalinaLoader类加载器
该类在lib包下的catalina.jar包中
Class<?> startupClass = this.catalinaLoader.loadClass("org.apache.catalina.startup.Catalina"); Object startupInstance = startupClass.newInstance(); if (log.isDebugEnabled()) log.debug("Setting startup class properties"); String methodName = "setParentClassLoader"; Class<?>[] paramTypes = new Class[1]; paramTypes[0] = Class.forName("java.lang.ClassLoader"); Object[] paramValues = new Object[1]; paramValues[0] = this.sharedLoader; Method method = startupInstance.getClass().getMethod(methodName, paramTypes); method.invoke(startupInstance, paramValues); this.catalinaDaemon = startupInstance;
我们看该类中的load方法是如何加载server.xml文件的。
public void load() { long t1 = System.nanoTime(); initDirs(); initNaming(); Digester digester = createStartDigester(); InputSource inputSource = null; InputStream inputStream = null; File file = null; 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", new Object[] { 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", new Object[] { getConfigFile() }), e); } } } 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", new Object[] { "server-embed.xml" }), e); } } } if ((inputStream == null) || (inputSource == null)) { if (file == null) { log.warn(sm.getString("catalina.configFail", new Object[] { getConfigFile() + "] or [server-embed.xml]" })); } else { log.warn(sm.getString("catalina.configFail", new Object[] { 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); try { inputStream.close(); } catch (IOException e) {} getServer().setCatalina(this); } 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) {} } initStreams(); try { getServer().init(); } catch (LifecycleException e) { if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) { throw new Error(e); } log.error("Catalina.start", e); } long t2 = System.nanoTime(); if (log.isInfoEnabled()) { log.info("Initialization processed in " + (t2 - t1) / 1000000L + " ms"); } } public void load(String[] args) { try { if (arguments(args)) { load(); } } catch (Exception e) { e.printStackTrace(System.out); } }
protected boolean arguments(String[] args) { boolean isConfig = false; if (args.length < 1) { usage(); return false; } for (int i = 0; i < args.length; i++) { if (isConfig) { this.configFile = args[i]; isConfig = false; } else if (args[i].equals("-config")) { isConfig = true; } else if (args[i].equals("-nonaming")) { setUseNaming(false); } else { if (args[i].equals("-help")) { usage(); return false; } if (args[i].equals("start")) { this.starting = true; this.stopping = false; } else if (args[i].equals("configtest")) { this.starting = true; this.stopping = false; } else if (args[i].equals("stop")) { this.starting = false; this.stopping = true; } else { usage(); return false; } } } return true; }
看到Catalina类当中的变量,表明解析文件的位置。
protected String configFile = "conf/server.xml";
protected File configFile() { File file = new File(this.configFile); if (!file.isAbsolute()) { file = new File(System.getProperty("catalina.base"), this.configFile); } return file; }
看到configFile方法创建File对象的过程
我们将看到load方法中调用getServer().init()调用 Server对象的init方法。
Catalina获取到Server的配置信息后,执行StandardServer容器的init()方法。Tomcat的所有容器类都实现了统一的Lifecycle接口,由基类LifecycleBase提供统一的init方法来负责处理容器的状态,调用模板方法initInternal来处理各个容器自身所负责的内容。关于Tomcat的容器结构可以参看本系列文章的《Tomcat7源码解读(一)——容器静态结构概述》。StandardServer容器在其initInternal()方法中完成Mbean的设定,GlobalNamingResources的初始化和类加载器的设置。然后执行StandardService容器的init方法。
StandardService同StandardServer容器,由基类LifecycleBase完成容器的生命周期状态设定,而在initInternal()方法中启动Container,Executor,Connector的init方法
StandardService类位于lib包下的catalina.jar包中,
org.apache.catalina.core.StandardService的父类中有init方法,
public final synchronized void init() throws LifecycleException { if (!this.state.equals(LifecycleState.NEW)) { invalidTransition("before_init"); } 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", new Object[] { toString() }), t); } setStateInternal(LifecycleState.INITIALIZED, null, false); }
是在org.apache.catalina.util.LifecycleBase类当中,调用了initInternal()方法。
看到LifecyceBase类的父类中
protected void initInternal() throws LifecycleException { if (this.oname == null) { this.mserver = Registry.getRegistry(null, null).getMBeanServer(); this.oname = register(this, getObjectNameKeyProperties()); } }
protected void initInternal() throws LifecycleException { super.initInternal(); this.onameStringCache = register(new StringCache(), "type=StringCache"); MBeanFactory factory = new MBeanFactory(); factory.setContainer(this); this.onameMBeanFactory = register(factory, "type=MBeanFactory"); this.globalNamingResources.init(); if (getCatalina() != null) { ClassLoader cl = getCatalina().getParentClassLoader(); 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 e) {}catch (IOException e) {} } } } cl = cl.getParent(); } } for (int i = 0; i < this.services.length; i++) { this.services[i].init(); } }
看到Bootstrap类当中调用玩load方法之后,开始调用start方法,方法也是调用Catalina类当中的start方法来启动Tomcat
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(); try { getServer().start(); } catch (LifecycleException e) { log.error("Catalina.start: ", e); } long t2 = System.nanoTime(); if (log.isInfoEnabled()) { log.info("Server startup in " + (t2 - t1) / 1000000L + " ms"); } if (this.useShutdownHook) { if (this.shutdownHook == null) { this.shutdownHook = new CatalinaShutdownHook(); } Runtime.getRuntime().addShutdownHook(this.shutdownHook); LogManager logManager = LogManager.getLogManager(); if ((logManager instanceof ClassLoaderLogManager)) { ((ClassLoaderLogManager)logManager).setUseShutdownHook(false); } } if (this.await) { await(); stop(); } }
看到调用的还是StandardServer类的start方法来启动Tomcat容器
看到类似于init的方式,我们看到也是通过调用org.apache.catalina.util.LifeCycleBase类的start方法调用一系列的startInternal方法来启动的
public final synchronized void start() throws LifecycleException { if ((LifecycleState.STARTING_PREP.equals(this.state)) || (LifecycleState.STARTING.equals(this.state)) || (LifecycleState.STARTED.equals(this.state))) { if (log.isDebugEnabled()) { Exception e = new LifecycleException(); log.debug(sm.getString("lifecycleBase.alreadyStarted", new Object[] { toString() }), e); } else if (log.isInfoEnabled()) { log.info(sm.getString("lifecycleBase.alreadyStarted", new Object[] { toString() })); } return; } if (this.state.equals(LifecycleState.NEW)) { init(); } else if (this.state.equals(LifecycleState.FAILED)) { stop(); } else if ((!this.state.equals(LifecycleState.INITIALIZED)) && (!this.state.equals(LifecycleState.STOPPED))) { invalidTransition("before_start"); } setStateInternal(LifecycleState.STARTING_PREP, null, false); try { startInternal(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); setStateInternal(LifecycleState.FAILED, null, false); throw new LifecycleException(sm.getString("lifecycleBase.startFail", new Object[] { toString() }), t); } if ((this.state.equals(LifecycleState.FAILED)) || (this.state.equals(LifecycleState.MUST_STOP))) { stop(); } else { if (!this.state.equals(LifecycleState.STARTING)) { invalidTransition("after_start"); } setStateInternal(LifecycleState.STARTED, null, false); } }