Tomcat6源码解析--Bootstrap
package org.apache.catalina.startup;
src file:http://svn.apache.org/repos/asf/tomcat/tc6.0.x/tags/TOMCAT_6_0_42/java/org/apache/catalina/startup/Bootstrap.java
goal:了解tomcat启动的大致流程
欢迎各位指正其中的错误和不足
入口main方法
1 public static void main(String args[]) { 2 3 if (daemon == null) { 4 daemon = new Bootstrap(); 5 try { 6 daemon.init();//init(完成了加载环境变量和类加载器的工作) 7 } catch (Throwable t) { 8 t.printStackTrace(); 9 return; 10 } 11 } 12 13 try { 14 String command = "start"; 15 if (args.length > 0) { 16 command = args[args.length - 1]; 17 } 18 19 if (command.equals("startd")) { 20 args[args.length - 1] = "start"; 21 daemon.load(args); 22 daemon.start(); 23 } else if (command.equals("stopd")) { 24 args[args.length - 1] = "stop"; 25 daemon.stop(); 26 } else if (command.equals("start")) {// 默认没有参数会进入这里 27 // 设置挂起标志 28 daemon.setAwait(true); 29 // 信息: Initialization processed in 3024454 ms 30 daemon.load(args); 31 // 启动server 32 daemon.start(); 33 } else if (command.equals("stop")) { 34 daemon.stopServer(args); 35 } else { 36 log.warn("Bootstrap: command \"" + command + "\" does not exist."); 37 } 38 } catch (Throwable t) { 39 t.printStackTrace(); 40 } 41 42 }
以上是bootstrap类的main方法,里边逐步调用了一些用于初始化的方法.下面一一解读:
init()方法:
1 /** 2 * Initialize daemon. 3 */ 4 public void init() throws Exception { 5 6 // Set Catalina path 7 setCatalinaHome();// 加载Catalina.Home环境变量(catalina.home) 8 setCatalinaBase();// 加载Catalina.Base环境变量(catalina.base) 9 10 initClassLoaders();// 初始化类加载器 11 12 Thread.currentThread().setContextClassLoader(catalinaLoader); 13 14 SecurityClassLoad.securityClassLoad(catalinaLoader); 15 16 // Load our startup class and call its process() method 17 if (log.isDebugEnabled()) { 18 log.debug("Loading startup class"); 19 } 20 Class startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina"); 21 Object startupInstance = startupClass.newInstance(); 22 23 // Set the shared extensions class loader 24 if (log.isDebugEnabled()) { 25 log.debug("Setting startup class properties"); 26 } 27 String methodName = "setParentClassLoader"; 28 Class paramTypes[] = new Class[1]; 29 paramTypes[0] = Class.forName("java.lang.ClassLoader"); 30 Object paramValues[] = new Object[1]; 31 paramValues[0] = sharedLoader; 32 // 找到org.apache.catalina.startup.Catalina#setParentClassLoader方法 33 Method method = startupInstance.getClass().getMethod(methodName, paramTypes); 34 // 设置java.lang.ClassLoader为父类加载器 35 method.invoke(startupInstance, paramValues); 36 37 catalinaDaemon = startupInstance;// 设置Catalina进程 38 }
- 对环境变量的读取,主要是读取 catalina.home\catalina.base
- 初始化类加载器,默认使用当前类的类加载器 this.getClass().getClassLoader();
- 加载了Catalina类 classLoader.loadClass("org.apache.catalina.startup.Catalina")
- 反射设置父类加载器 org.apache.catalina.startup.Catalina#setParentClassLoader设置java.lang.ClassLoader为ParentClassLoader
daemon.setAwait(true)方法:
1 /** 2 * Set flag. 3 */ 4 public void setAwait(boolean await) throws Exception { 5 6 Class paramTypes[] = new Class[1]; 7 paramTypes[0] = Boolean.TYPE; 8 Object paramValues[] = new Object[1]; 9 paramValues[0] = new Boolean(await); 10 // 获取Catalina类(其实是其父类Embedded)中的setAwait方法 11 Method method = catalinaDaemon.getClass().getMethod("setAwait", paramTypes); 12 // 使用await参数调用 13 method.invoke(catalinaDaemon, paramValues); 14 15 }
- 这个方法并没有具体的深入研究,不过从字面意义上来看,应该是设置了一个锁.欢迎各位指正.
daemon.load(args)方法:
1 /** 2 * Load daemon. 3 */ 4 private void load(String[] arguments) throws Exception { 5 6 // Call the load() method 7 String methodName = "load"; 8 Object param[]; 9 Class paramTypes[]; 10 if (arguments==null || arguments.length==0) { 11 paramTypes = null; 12 param = null; 13 } else { 14 paramTypes = new Class[1]; 15 paramTypes[0] = arguments.getClass(); 16 param = new Object[1]; 17 param[0] = arguments; 18 } 19 // 获取Catalina的load方法 20 Method method = catalinaDaemon.getClass().getMethod(methodName, paramTypes); 21 if (log.isDebugEnabled()) 22 log.debug("Calling startup class " + method); 23 // 调用(启动一个新的服务器实例) 24 method.invoke(catalinaDaemon, param); 25 26 }
通过反射调用Catalina的load方法
1 /** 2 * Start a new server instance. 3 */ 4 public void load() { 5 6 long t1 = System.nanoTime(); 7 8 initDirs();// 读取环境变量 9 10 // Before digester - it may be needed 11 12 initNaming(); 13 14 // Create and execute our Digester 15 Digester digester = createStartDigester(); 16 17 InputSource inputSource = null; 18 InputStream inputStream = null; 19 File file = null; 20 try { 21 file = configFile();//获取server.xml位置 22 inputStream = new FileInputStream(file); 23 inputSource = new InputSource("file://" + file.getAbsolutePath()); 24 } catch (Exception e) { 25 ; 26 } 27 // 如果不能获取server.xml,则使用ClassLoader再查找一次 28 if (inputStream == null) { 29 try { 30 inputStream = getClass().getClassLoader().getResourceAsStream(getConfigFile()); 31 inputSource = new InputSource(getClass().getClassLoader().getResource(getConfigFile()).toString()); 32 } catch (Exception e) { 33 ; 34 } 35 } 36 37 // This should be included in catalina.jar 38 // Alternative: don't bother with xml, just create it manually. 39 if( inputStream==null ) { 40 try { 41 inputStream = getClass().getClassLoader() 42 .getResourceAsStream("server-embed.xml"); 43 inputSource = new InputSource 44 (getClass().getClassLoader() 45 .getResource("server-embed.xml").toString()); 46 } catch (Exception e) { 47 ; 48 } 49 } 50 51 52 if ((inputStream == null) && (file != null)) { 53 log.warn("Can't load server.xml from " + file.getAbsolutePath()); 54 if (file.exists() && !file.canRead()) { 55 log.warn("Permissions incorrect, read permission is not allowed on the file."); 56 } 57 return; 58 } 59 60 try { 61 inputSource.setByteStream(inputStream); 62 digester.push(this); 63 digester.parse(inputSource);// 加载server.xml 64 inputStream.close(); 65 } catch (Exception e) { 66 log.warn("Catalina.start using " 67 + getConfigFile() + ": " , e); 68 return; 69 } 70 71 // Stream redirection 72 initStreams();// 设置log 73 74 // Start the new server 75 if (getServer() instanceof Lifecycle) { 76 try { 77 getServer().initialize(); 78 } catch (LifecycleException e) { 79 if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) 80 throw new java.lang.Error(e); 81 else 82 log.error("Catalina.start", e); 83 84 } 85 } 86 87 long t2 = System.nanoTime(); 88 if(log.isInfoEnabled()) 89 log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms"); 90 91 }
- #initDirs()完成了读取环境变量
- #initNaming()设置命名空间catalina.useNaming\java.naming.factory.url.pkgs\java.naming.factory.initial 这几个命名空间没有具体研究作用,同样欢迎补充
- 创建Digester
- 读取server.xml文件
- #digester.push(this)
- #digester.parse(inputSource)使用digester解析server.xml并按照配置创建Server对象
- #initStreams()设置log
- 调用#getServer().initialize()启动server
daemon.start()方法:
1 /** 2 * Start the Catalina daemon. 3 */ 4 public void start() throws Exception { 5 if (catalinaDaemon == null) 6 init(); 7 8 Method method = catalinaDaemon.getClass().getMethod("start", (Class[]) null); 9 method.invoke(catalinaDaemon, (Object[]) null); 10 11 }
通过反射调用Catalina的start方法
1 /** 2 * Start a new server instance. 3 */ 4 public void start() { 5 6 if (getServer() == null) { 7 load(); 8 } 9 10 if (getServer() == null) { 11 log.fatal("Cannot start server. Server instance is not configured."); 12 return; 13 } 14 15 long t1 = System.nanoTime(); 16 17 // Start the new server 18 if (getServer() instanceof Lifecycle) { 19 try { 20 ((Lifecycle) getServer()).start(); 21 } catch (LifecycleException e) { 22 log.error("Catalina.start: ", e); 23 } 24 } 25 26 long t2 = System.nanoTime(); 27 if(log.isInfoEnabled()) 28 log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms"); 29 30 try { 31 // Register shutdown hook 32 if (useShutdownHook) { 33 if (shutdownHook == null) { 34 shutdownHook = new CatalinaShutdownHook(); 35 } 36 Runtime.getRuntime().addShutdownHook(shutdownHook); 37 38 // If JULI is being used, disable JULI's shutdown hook since 39 // shutdown hooks run in parallel and log messages may be lost 40 // if JULI's hook completes before the CatalinaShutdownHook() 41 LogManager logManager = LogManager.getLogManager(); 42 if (logManager instanceof ClassLoaderLogManager) { 43 ((ClassLoaderLogManager) logManager).setUseShutdownHook( 44 false); 45 } 46 } 47 } catch (Throwable t) { 48 // This will fail on JDK 1.2. Ignoring, as Tomcat can run 49 // fine without the shutdown hook. 50 } 51 52 if (await) { 53 await(); 54 stop(); 55 } 56 57 }
- 逐步启动server的生命周期