一,当启动Tomcat后,各个组件都做了什么
当执行 startup.sh脚本来启动Tomcat后,
1,Tomcat本质上是一个Java程序,所以 startup.sh脚本会启动一个JVM来运行Tomcat的启动类 Bootstrap
2,Bootstrap是初始化 Tomcat 的类加载器,并且创建Catalina
3,Catalina 是一个启动类,它可以解析 server.xml,创建相应的组件,并且调用 Server 的 start 方法。
4,Server组件用来管理 Service组件,它可以调用Service的start方法
5,Service组件的职责就是管理连接器和顶层容器Engine,它可以调用连接器 和 Engine的start方法
二,Catalina
Catalina的任务就是创建 Server,它通过解析 server.xml ,把在 server.xml 中配置的各个组件创建出来,然后调用Server组件的init方法和start方法,这样Tomcat就启动了。
public void start() { //1. 如果持有的 Server 实例为空,就解析 server.xml 创建出来 if (getServer() == null) { load(); } //2. 如果创建失败,报错退出 if (getServer() == null) { log.fatal(sm.getString("catalina.noServer")); return; } //3. 启动 Server try { getServer().start(); } catch (LifecycleException e) { return; } // 创建并注册关闭钩子 if (useShutdownHook) { if (shutdownHook == null) { shutdownHook = new CatalinaShutdownHook(); } Runtime.getRuntime().addShutdownHook(shutdownHook); } // 用 await 方法监听停止请求 if (await) { await(); stop(); } }
那么,Tomcat是如何停止和清理资源的呢?
首先,Catalina在JVM中注册一个 “关闭钩子”,这个钩子可以在关闭时做一些清理操作,比如将缓存数据刷到磁盘上。这个钩子其实就是一个线程,JVM在停止之前会尝试执行这个线程的run方法。
CatalinaShutdownHook:
protected class CatalinaShutdownHook extends Thread { @Override public void run() { try { if (getServer() != null) { Catalina.this.stop(); } } catch (Throwable ex) { ... } } }
Tomcat的 “关闭钩子” 实际上就执行了 Server的stop方法,Server的stop方法会释放和清理所有的资源。
三,Server组件
具体实现类:StandardServer。
Server的子组件是Service,所以它要管理Service的生命周期。在Server启动时,需要调用Service组件的启动方法,在停止时调用它们的停止方法。Server在内部维护了Service组件,通过数组来保存。Server如何添加一个Service到数组中?
@Override public void addService(Service service) { service.setServer(this); synchronized (servicesLock) { // 创建一个长度 +1 的新数组 Service results[] = new Service[services.length + 1]; // 将老的数据复制过去 System.arraycopy(services, 0, results, 0, services.length); results[services.length] = service; services = results; // 启动 Service 组件 if (getState().isAvailable()) { try { service.start(); } catch (LifecycleException e) { // Ignore } } // 触发监听事件 support.firePropertyChange("service", null, service); } }
四,Service组件
Service组件的具体实现类:StandardService。
public class StandardService extends LifecycleBase implements Service { // 名字 private String name = null; //Server 实例 private Server server = null; // 连接器数组 protected Connector connectors[] = new Connector[0]; private final Object connectorsLock = new Object(); // 对应的 Engine 容器 private Engine engine = null; // 映射器及其监听器 protected final Mapper mapper = new Mapper(); protected final MapperListener mapperListener = new MapperListener(this);
可以看到StandardService中的组件有:Connector,Engine,Mapper,MapperListener(这是一个监听器,当Web应用的部署发生变化时,把信息更新到Mapper中,热部署时用到)。
StandardService中的启动方法:
protected void startInternal() throws LifecycleException { //1. 触发启动监听器 setState(LifecycleState.STARTING); //2. 先启动 Engine,Engine 会启动它子容器 if (engine != null) { synchronized (engine) { engine.start(); } } //3. 再启动 Mapper 监听器 mapperListener.start(); //4. 最后启动连接器,连接器会启动它子组件,比如 Endpoint synchronized (connectorsLock) { for (Connector connector: connectors) { if (connector.getState() != LifecycleState.FAILED) { connector.start(); } } } }
注意启动顺序:先启动Engine组件,再启动Mapper监听器,最后才是启动连接器。(符合先内层,后外层)
五,Engine组件
具体实现类:StandardEngine,Engine本质是一个容器,它继承了ContainerBase基类,并实现Engine接口
public class StandardEngine extends ContainerBase implements Engine { }
Engine的子容器是Host,它持有一个Host容器的数组,
CatalinaShutdownHook
极客时间版权所有: https://time.geekbang.org/column/article/97603: