1. 程式人生 > >springboot原始碼解析-管中窺豹系列之web伺服器(七)

springboot原始碼解析-管中窺豹系列之web伺服器(七)

# 一、前言 - Springboot原始碼解析是一件大工程,逐行逐句的去研究程式碼,會很枯燥,也不容易堅持下去。 - 我們不追求大而全,而是試著每次去研究一個小知識點,最終聚沙成塔,這就是我們的springboot原始碼管中窺豹系列。 ![ 簡介 ](https://zhangbin1989.gitee.io/blog/picture/zb0018_springsour/springboot_source_0.png) # 二、web伺服器 - 以前的的spring專案或者springmvc專案都需要一個web伺服器,tomcat,或者其它的 - 使用springboot之後,我們不再需要配置web伺服器,因為springboot幫我們集成了 - 今天我們來分析一下原始碼,看看在哪裡實現的,知其然知其所以然 # 三、原始碼分析 - 還是從SpringApplication的run方法開始看 - 不熟悉的可以看之前的文章:springboot原始碼解析-管中窺豹系列之總體結構(一) ``` SpringApplication.java public ConfigurableApplicationContext run(String... args) { ... try { ... refreshContext(context); ... } catch (Throwable ex) { ... } ... return context; } ``` - 接著進入到 refreshContext(context) 裡面 ``` AbstractApplicationContext.java @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { ... try { ... // Initialize other special beans in specific context subclasses. onRefresh(); ... } catch (BeansException ex) { ... } finally { ... } } } ``` - 進入到 onRefresh() 方法 ``` protected void onRefresh() throws BeansException { // For subclasses: do nothing by default. } ``` - 注意這個是一個protected方法,我們進入到子實現裡面 - 具體用的哪個context,請看之前的文章:springboot原始碼解析-管中窺豹系列之專案型別(二) ``` public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context." + "annotation.AnnotationConfigApplicationContext"; public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot." + "web.servlet.context.AnnotationConfigServletWebServerApplicationContext"; public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework." + "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext"; protected ConfigurableApplicationContext createApplicationContext() { Class contextClass = this.applicationContextClass; if (contextClass == null) { try { switch (this.webApplicationType) { case SERVLET: contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS); break; case REACTIVE: contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS); break; default: contextClass = Class.forName(DEFAULT_CONTEXT_CLASS); } } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass); } ``` - 最常用的就是普通web專案,我們看這一個 - 我們到org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext裡面找 onRefresh() 方法 - 沒找到,在父類ServletWebServerApplicationContext裡面找到了 ``` ServletWebServerApplicationContext.java @Override protected void onRefresh() { super.onRefresh(); try { createWebServer(); } catch (Throwable ex) { throw new ApplicationContextException("Unable to start web server", ex); } } ``` - 我們到 createWebServer() 方法裡面 ``` private void createWebServer() { WebServer webServer = this.webServer; ServletContext servletContext = getServletContext(); if (webServer == null && servletContext == null) { ServletWebServerFactory factory = getWebServerFactory(); this.webServer = factory.getWebServer(getSelfInitializer()); } else if (servletContext != null) { try { getSelfInitializer().onStartup(servletContext); } catch (ServletException ex) { throw new ApplicationContextException("Cannot initialize servlet context", ex); } } initPropertySources(); } ``` - 用的工廠模式,先找到工廠getWebServerFactory() - 再用工廠生成webServer, factory.getWebServer(getSelfInitializer()) - 先看看 getWebServerFactory() 這個方法 ``` protected ServletWebServerFactory getWebServerFactory() { // Use bean names so that we don't consider the hierarchy String[] beanNames = getBeanFactory() .getBeanNamesForType(ServletWebServerFactory.class); if (beanNames.length == 0) { throw new ApplicationContextException( "Unable to start ServletWebServerApplicationContext due to missing " + "ServletWebServerFactory bean."); } if (beanNames.length > 1) { throw new ApplicationContextException( "Unable to start ServletWebServerApplicationContext due to multiple " + "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames)); } return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class); } ``` - 獲取唯一的工廠:ServletWebServerFactory,多了少了都不行 - 在哪載入進springboot的呢? ``` ``` - spring-boot-starter-web裡面是包含了spring-boot-starter依賴的 - spring-boot-starter裡面包含了spring-boot-autoconfigure依賴 - spring-boot-autoconfigure裡面有一個類:ServletWebServerFactoryConfiguration - 這個類裡面有一個靜態類: EmbeddedTomcat ``` @Configuration(proxyBeanMethods = false) @ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class }) @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT) static class EmbeddedTomcat { @Bean TomcatServletWebServerFactory tomcatServletWebServerFactory( Object