您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關SpringBoot嵌入式web容器的啟動原理是什么,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
@SpringBootApplication @EnableAsync //使用異步注解@Async 需要在這里加上@EnableAsync @MapperScan("springboot.dao") //不可或缺作用是掃描dao包下面的所有mapper裝配 public class HelloApplication { public static void main(String[] args) { SpringApplication.run(HelloApplication.class,args); } }
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) { return run(new Class[]{primarySource}, args); }
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return (new SpringApplication(primarySources)).run(args); }
private void refreshContext(ConfigurableApplicationContext context) { this.refresh(context); if (this.registerShutdownHook) { try { context.registerShutdownHook(); } catch (AccessControlException var3) { } }
protected void refresh(ApplicationContext applicationContext) { Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); ((AbstractApplicationContext)applicationContext).refresh(); }
public final void refresh() throws BeansException, IllegalStateException { try { super.refresh(); } catch (RuntimeException var2) { this.stopAndReleaseWebServer(); throw var2; } }
protected void onRefresh() { super.onRefresh(); try { this.createWebServer(); } catch (Throwable var2) { throw new ApplicationContextException("Unable to start web server", var2); } }
private void createWebServer() { WebServer webServer = this.webServer; ServletContext servletContext = this.getServletContext(); if (webServer == null && servletContext == null) { ServletWebServerFactory factory = this.getWebServerFactory(); this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()}); } else if (servletContext != null) { try { this.getSelfInitializer().onStartup(servletContext); } catch (ServletException var4) { throw new ApplicationContextException("Cannot initialize servlet context", var4); } } this.initPropertySources(); }
protected ServletWebServerFactory getWebServerFactory() { String[] beanNames = this.getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class); if (beanNames.length == 0) { throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean."); } else if (beanNames.length > 1) { throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames)); } else { return (ServletWebServerFactory)this.getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class); } }
//配置嵌入式的servlet容器 @Bean public WebServerFactoryCustomizer<ConfigurableWebServerFactory> MyCustomizer(){ return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() { @Override public void customize(ConfigurableWebServerFactory factory) { factory.setPort(8081); } }; }
Spring Boot 2.x 版本的嵌入式Servlet容器自動配置是通過 WebServerFactoryCustomizer定制器 來定制的,而在Spring Boot 1.x 版本中我們是通過 EmbeddedServletContainerCustomizer 嵌入式的Servlet容器定制器來定制的。由于之前看的資料都是1.x的版本,但是我使用的是2.x,所以在這里記錄一下2.x版本的嵌入式Servlet容器自動配置原理以及啟動原理。
嵌入式Servlet容器自動配置原理以及啟動原理有三大步:
步驟:
SpringBoot 根據導入的依賴信息,自動創建對應的 WebServerFactoryCustomizer(web服務工廠定制器);
WebServerFactoryCustomizerBeanPostProcessor(web服務工廠定制器組件的后置處理器)獲取所有類型為web服務工廠定制器的組件(包含實現WebServerFactoryCustomizer接口,自定義的定制器組件),依次調用customize()定制接口,定制Servlet容器配置;
嵌入式的Servlet容器工廠創建tomcat容器,初始化并啟動容器。
1、首先找到 EmbeddedWebServerFactoryCustomizerAutoConfiguration ,在里面我們可以看到SpringBoot支持的 servlet容器
//SprinBoot支持的servlet容器有三個Tomcat、Jetty、Undertow,但是默認配置的是Tomcat //嵌入式的Undertow @Configuration( proxyBeanMethods = false ) @ConditionalOnClass({Undertow.class, SslClientAuthMode.class}) public static class UndertowWebServerFactoryCustomizerConfiguration { public UndertowWebServerFactoryCustomizerConfiguration() { } @Bean public UndertowWebServerFactoryCustomizer undertowWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) { return new UndertowWebServerFactoryCustomizer(environment, serverProperties); } } //嵌入式的Jetty @Configuration( proxyBeanMethods = false ) @ConditionalOnClass({Server.class, Loader.class, WebAppContext.class}) public static class JettyWebServerFactoryCustomizerConfiguration { public JettyWebServerFactoryCustomizerConfiguration() { } @Bean public JettyWebServerFactoryCustomizer jettyWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) { return new JettyWebServerFactoryCustomizer(environment, serverProperties); } } //嵌入式的Tomcat @Configuration( proxyBeanMethods = false ) @ConditionalOnClass({Tomcat.class, UpgradeProtocol.class}) public static class TomcatWebServerFactoryCustomizerConfiguration { public TomcatWebServerFactoryCustomizerConfiguration() { } @Bean public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) { return new TomcatWebServerFactoryCustomizer(environment, serverProperties); } }
2、準備環節
1)在以下位置打一個斷點
2)、點進 TomcatWebServerFactoryCustomizer 也就是上圖 return 的,然后在里面的如下位置打一個斷點
3)、然后在里面debug程序,我們在控制臺就可以看到如下信息
3、按照上圖從下往上分析。我們啟動springboot應用時,都是直接運行主程序的main方法,然后調用里面的run方法,如下圖
4、調用完run方法,回來到 refreshContext 方法,這個方法是幫我們創建IOC容器對象,并且初始化容器,創建容器中的每一個組件
5、在調用了 reflesh 方法刷新剛才的IOC容器后,來到 onreflesh 方法,調用createWebServer()方法,創建WebServer
6、來到createWebServer()方法,該方法最終能夠獲取到一個與當前應用(也就是總結里說的第一步,根據我們導入的依賴來獲取)所導入的Servlet類型相匹配的web服務工廠,通過工廠就可以獲取到相應的 WebServerFactoryCustomizer (Web服務工廠定制器)
注:createWebServer()執行后,我們其實來到了 EmbeddedWebServerFactoryCustomizerAutoConfiguration,然后根據條件(配置的依賴)配置哪一個Web服務器
我們通過查看 ServletWebServerFactory 的子類,可以看到其中三個就是Tomcat、Jetty和Undertow,根據我們的配置,所以這里獲取到的是 TomcatWebServerFactoryCustomizer
至此,TomcatWebServerFactoryCustomizer組件創建完成,對應的服務配置類也已添加到IOC容器。
7、因為容器中某個組件要創建對象就會驚動后置處理器 然后就到 WebServerFactoryCustomizerBeanPostProcessor(web服務工廠定制器組件的后置處理器),該類負責在bean組件初始化之前執行初始化工作。它先從IOC容器中獲取所有類型為WebServerFactoryCustomizerBeans(web服務工廠定制器的組件)
通過后置處理器獲取到的TomcatWebServerFactoryCustomizer調用customize()定制方法,獲取到Servlet容器相關配置類ServerProperties,進行自動配置
至此,嵌入式Servlet容器的自動配置完成。
注:從源碼分析可以得出配置嵌入式Servlet容器的兩種解決方案:
1、在全局配置文件中,通過server.xxx來修改和server有關的配置:
server.port=8081 server.tomcat.xxx...
2、實現WebServerFactoryCustomizer接口,重寫它的customize()方法,對容器進行定制配置:
@FunctionalInterface public interface WebServerFactoryCustomizer<T extends WebServerFactory> { void customize(T factory); }
1、應用啟動后,根據導入的依賴信息,創建了相應的Servlet容器工廠,創建了TomcatServletWebServerFactory,調用getWebServer()方法創建Tomcat容器:(其實就是重寫了ServletWebServerFactory里面的getWebServer方法)
找到下面的getTomcatWebServer方法
2、然后點進去分析TomcatWebServer的有參構造器,執行 initialize() 方法
3、點進去就可以發現,里面通過調用start方法來啟動Tomcat
關于“SpringBoot嵌入式web容器的啟動原理是什么”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。