SpringBoot内置源码解析WebServer初始化过程( 二 )


protected ServletWebServerFactory getWebServerFactory() {//使用 Bean name 数组的好处是可以不用考虑层级关系String[] beanNames = getBeanF actory() . getBeanNamesForType(ServletWebServer-Factory.class);if (beanNames.length == 0) {throw new ApplicationContextException("Unable to start ServletWebServe-rApplicationContext due to missing" +"ServletWebServerFactory bean.");if (beanNames . length > 1) {throw new ApplicationContextException("Unable to start ServletwebServer-ApplicationContext due to multiple”+ "ServletWebServerFactory beans :”+StringUtils.arrayToCommaDelimitedString(beanNames));}return getBeanFactory(). getBean(beanNames[0], ServletWebServerFactory.class);}getWebServerFactory 方法中通过 BeanFactory 获得类型为 ServletWebServerFactory 类的 beanNames 数组 , 然后判断数组长度 。 当 beanNames 长度为 0 时 , 说明容器中没有对应的 Bean 存在 , 则抛出异常;当 beanNames 长度大于 1 时 , 说明存在多个对应的 Bean,也就是说有可能同时存在多个 Web 容器的工厂方法 , 同样抛出异常;只有 beanNames 长度等于 1 时 , 说明恰好存在一个对应的 Bean, 才会获取对应的 Bean 并返回 。
如果一层层向上追溯 TomcatServletWebServerFactory 的类结构 , 我们就会发现 , 它先是继承了抽象类AbstractServletWebServerFactory,而抽象类AbstractServletWebServerFactory 又实现了口 ConfigurableServletWebServerFactory 接口ConfigurableServletWebServer-Factory又继承接口ServletWebServerFactory.这里获得的 ServletWebServerFactory 的具体实现类 , 正是我们在上一节中通过自动配置实例化的TomcatServletWebServerFactory 对象的 Bean 名称 。
当获得 ServletWebServerFactory 之后 , 便调用了它的 getWebServer 方法 , 以 Tomcat 为例 , 其实也就是调用了 TomcatServletWebServerFactory 的 getWebServer 方法 。
@Overridepublic WebServer getWebServer(ServletContextInitializer... initializers)//内置 Tomcat 包中提供的类Tomcat tomcat = new Tomcat();//获取并没置 baseDir 路径 , 不存在则创建一个 ltomcat 为前缀的临时文件File baseDir = (this. baseDirectory != null) ? this. baseDirectorycreateTempDir("tomcat");tomcat . setBaseDir(baseDir . getAbsolutePath());/创建 ConnectorConnector connector = new Connector(this . protocol);tomcat . getService(). addConnector(connector);// Connector 定制化customi zeConnector(connector);tomcat. setConnector( connector);tomcat. . getHost(). setAutoDeploy(false);configureEngine(tomcat. getEngine());for (Connector additionalConnector : this . additionalTomcatConnectors) {tomcat . getService() . addConnector ( additionalConnector);prepareContext(tomcat . getHost(), initializers);//创建 omcatWebServerreturn getTomcatwebServer(tomcat);}}TomcatServletWebServerFactory 的 getWebServer 方法中实现了 Tomcat 的创建、BaseDir的设置 、Connector 的初始化和定制化等一系 列初始化操作 。
至此 , 上面代码中依旧没有 体现 TomcatServer 的创建和初始化 ,不要着急 , 它们就在getWebServer 方法的最后- -行代码调用的 getTomcatWebServer 方法中 。
protected TomcatWebServer getTomcatWebServer (Tomcat tomcat) {return new TomcatWebServer(tomcat, getPort() >=getTomcatWebServer 方法的实现很简单 , 将 getWebServer 中创建的 Tomcat 对象和当前类中 port 值是否大于等于 0 的判断结果作为 TomcatWebServer 构造方法的参数传入 , 创建 TomcatWebServer 对象 。
针 对 getTomcatWebServer 方 法,子 类 可 以 重 写 该 方 法,返 回 一 个 不 同 的Tomcat-WebServer 或者添加针对 Tomcat Server 的一些额外操作 。
先看 TomcatWebServer 的构造方法源码 。
public class TomcatWebServer implements WebServer {private final Tomcat tomcat;private final boolean autoStart;public TomcatWebServer(Tomcat tomcat, boolean autoStart) {Assert . notNull(tomcat, "Tomcat Server must not be null");this. tomcat = tomcat;this. autoStart = autoStart;initialize();}}构造方法接收 Tomcat tomcat 和 boolean autoStart 两个参数 , 并将其赋值给对应的成员变量 。 其中 Tomcat 参数不能为 null, autoStart 参 数则根据端口是否大于等于 0 来决定是否启动服务 。 在构造方法的最后 , 调用了 nitialize 方法来进行初始化操作 。
SpringBoot内置源码解析WebServer初始化过程文章插图
omcatWebServern 的 initialize 方法源代码如下 。
【SpringBoot内置源码解析WebServer初始化过程】public class TomcatWebServer implements WebServer {private final Tomcat tomcat;private final boolean autoStart;privatevolatile boolean started;logger. info("Tomcat initialized with port(s): ”+ getPortsDescription(fsynchronized (this .monitor) {// 将 实 例 id 添 加 到 tomcat 引 擎 名 字 中,格 式 为 “ 原 引 / 擎 名 字 实 例 id”Contextcontext=findContext()://添加生命周期的监昕事件context . addL ifecyclelistener((event) -> {if (context . equals(event. getSource()) /可以直接在主线程中重新抛出失败异常 ,TomcatStarter 不存在或状态错误均会抛出异常rethrowDeferredStartupExceptions();try/绑定一个命名的 context.到类加载器(), getClass().getClassLoader());sLoader(context, context. getNamingTokencatch (NamingException ex)// 当命名不可用时(抛异常) ,直接跳过并继续// 与 Jetty 不同 ,所有 Tomcat 线程都是守护程序线程 。 创建一 一个阻止非守护程序止立即关闭startDaemonAwaitThread();} catch (Exception ex) {stopSilently();destroySilently();throw new WebServerException("Unable to start embedded Tomcat", e x);}}}}