在上一篇中咱们说到Tomcat的启动入口是Bootstrap,那么明天咱们就来钻研一下,Bootstrap类在启动main办法之后是如何进行各项初始化来提供后续程序的运行的。

1. Bootstrap.main()办法

在main办法中咱们能够看到,首先是创立了一个Bootstrap对象,并行初始化了一些相干的类加载器等操作,而后将创立的对象赋值给了 daemon,而后通过运行时附带的参数来抉择它后续对应的操作,这里咱们间接看到 start 这里。(具体参数携带能够查看Tomcat我的项目的bin/startup.sh文件)

public static void main(String args[]) {        // 实例化一个以后Bootstrap疏导类对象,并进行类加载器的初始化,而后把该对象赋值给 daemon        synchronized (daemonLock) {            ...            }        try {            String command = "start";            if (args.length > 0) {                command = args[args.length - 1];            }            // 执行命令分支判断            if (command.equals("startd")) {                ...            } else if (command.equals("stopd")) {                ...            } else if (command.equals("start")) {   // 启动 tomcat 时传入的是 start 命令参数,走此分支                daemon.setAwait(true);                // 加载初始化                daemon.load(args);                // 启动                daemon.start();                if (null == daemon.getServer()) {                    System.exit(1);                }            } else if (command.equals("stop")) {                ...            } else if (command.equals("configtest")) {                ...            } else {                log.warn("Bootstrap: command \"" + command + "\" does not exist.");            }        } catch (Throwable t) {            ...        }    }

2. Bootstrap.load()办法

进入load办法之后,咱们能够看到它外部理论是通过反射来调用 Catalina.load办法来进行的初始化加载。

3. Catalina.load()办法

在这个办法中,他会创立一个用于解析 XML 文件的对象 digester,而后通过 configFile办法失去conf/server.xml文件,并对其进行解析,失去server对象(通过查看conf/server.xml文件,咱们能够看到整个配置文件中,最外层的标签就是server,其外部再一层层的嵌套其余的标签)。

public void load() {    // 用于解析XML配置文件    Digester digester = createStartDigester();    InputSource inputSource = null;    InputStream inputStream = null;    File file = null;    try {        try {            // 定位到配置文件 server.xml            file = configFile();            inputStream = new FileInputStream(file);            inputSource = new InputSource(file.toURI().toURL().toString());        } catch (Exception e) {            ...        }        try {            inputSource.setByteStream(inputStream);            digester.push(this);            // 调用 digester 对象真正的去解析 xml            digester.parse(inputSource);        } catch (Exception e) {            ...        }                try {            // 执行server.init            getServer().init();        } catch (LifecycleException e) {            ...        }    } finally {        ...    }}


拿到server对象之后,调用了一个 init办法,点击该办法跳转到对应实现中

4. LifecycleBase.initInternal()办法

LifecycleBaseTomcat中组件生命周期的对立治理接口的实现类,该类对相干组件的生命周期进行了对立治理,通过刚刚的跳转,咱们找到了LifecycleBase.initInternal办法,该办法为形象办法,须要再跳转到对应的子类中,这是一种典型设计模式《模板模式》,在父类中定义好了整体的步骤,具体的实现由子类本人去实现。

5. StandardServer.initInternal()办法

DEBUG打上断点,再按F7进入办法外部,来到StandardServer.initInternal处。

这办法中有两处中央调用了初始化办法:

globalNamingResources.init()service.init(),别离对应着配置文件中的两处子标签,咱们将重点放在service的初始化操作中,Tomcat中的连接器Connector与容器Engine都在这里。

Tomcat中反对多个service的配置,所以此处须要遍历进行初始化操作。

6. StandardService.initInternal()办法

通过service.init办法,咱们又回到了生命周期根底类中,从新调用initInternal办法进入对应的StandardService类中,在该类的initInternal办法中咱们能够看到有engineconnector的初始化操作。

7. StandardEngine.initInternal()办法

持续套娃,进入StandardEngine查看具体实现。在这里失去对应的Realm,而后返回。

8. Connector.initInternal()办法

持续往下走,来到connector.init()这里,初始化连接器组件。持续往下走,看到了有针对protocolHandler.init()的一个初始化操作。


9. AbstractProtocol.init()办法

先对endpoint对象进行简略的设置,而后再对其进行初始化操作。

10. AbstractEndpoint.init()办法

这里次要是做一个端口的绑定,具体的实现由NioEndpoint来进行实现

11. NioEndpoint.bind()办法

在该办法中咱们能够看到他创立了一个socket通道,绑定了咱们在配置文件中设置的IP地址与端口。

总结

到此Bootstrap.load()办法中的初始化操作根本就完结了,咱们在配置文件中设置的各个组件的参数均已进行初始化。

残缺组件线路如下:

Server    Service        Connector            EndPoint:通信端点(TCP/IP)            Processor:报文解析(HTTP/AJP)            Adapter:转换器        Container            Catalina                Engine:引擎,是Servlet容器Catalina的外围,它反对在其下定义多个虚拟主机                Host:虚拟主机,容许Tomcat引擎在将配置在一台机器上的多个域名宰割开来相互不烦扰                Context:上下文对象                Wrapper:包装组件

俄罗斯套娃:initInternal()

我收集有泛滥的 计算机电子书籍,有须要的小伙伴自提哦~