通过查看分析启动脚本,发现最终调用的入口是org.apache.catalina.startup包下面的Bootstrap#main
public static void main(String args[]) { if (daemon == null) { // Don't set daemon until init() has completed Bootstrap bootstrap = new Bootstrap(); try { // 初始化类加载器(这主要是为了要把开发者编写的各种组件应用(WAR 、EAR 等)部署到容器中,并实现组件应用之间的隔离),创建Catalina实例 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"; 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); // 通过反射调用Catalina的load方法,加载server.xml配置、初始化Server daemon.load(args); // 通过反射调用Catalina的start方法,开启服务、初始化并开启一系列组件、子容器 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); } }
类org.apache.catalina.startup.Catalina#load分析:
public void load() { ...... //初始化临时目录 initDirs(); // Before digester - it may be needed //设置额外的系统属性 initNaming(); // Create and execute our Digester //Digester是apache commons中的一种xml解析器,处理conf/server.xml //在这个方法里,读取serverl.xml时通过反射实例化了standardServer对象 Digester digester = createStartDigester(); ...... try { inputSource.setByteStream(inputStream); digester.push(this); //传入流到digester解析xml拼成对象 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; } ...... getServer().setCatalina(this); getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile()); getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile()); // Stream redirection //自定义了System.out.PrintStream,写了一个子类SystemLogHandler继承PrintStream,便于多线程下的日志处理 initStreams(); // Start the new server try { //初始化Engine,Executor(用来在connector中管理线程池),Connector,mapperListener(用来监听container的变化的) 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"); } }
digester.parse解析xml创建对象的时候相关操作:
1.会绑定HostConfig到StandardHost的lifecycleListeners,然后执行StandardHost.ini时会调用HostConfig.deployApps去查找目录和XML找到Context
类org.apache.catalina.startup.Catalina#start分析:
public void start() { ...... // Start the new server try { //启动Engine,Executor,Connector,mapperListener 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; } ...... // if (await) { //调用StandardServer的await方法 //创建socket连接的服务端对象ServerSocket; //循环等待接收客户端发出的命令,如果接收到的命令与SHUTDOWN匹配(由于使用了equals,所以shutdown命令必须是大写的),那么退出循环等待 //执行shutdown.bat的时候,最终使用java命令执行了org.apache.catalina.startup.Bootstrap类中的main方法,参数是stop, //通过调用Bootstrap的stopServer方法停止Tomcat,其实质是用反射调用catalinaDaemon(类型是Catalina)的stopServer方法。 //catalina通过创建Digester解析server.xml文件(此处只解析<Server>标签),以构造出Server容器(此时Server容器的子容器没有被实例化); //从实例化的Server容器获取Server的socket监听端口和地址,然后创建Socket对象连接启动Tomcat时创建的ServerSocket,最后向ServerSocket发送SHUTDOWN命令。 //ServerSocket循环等待接收到SHUTDOWN命令后,最终调用stop方法停止Tomcat。 await(); stop(); } }