国产成人精品亚洲777人妖,欧美日韩精品一区视频,最新亚洲国产,国产乱码精品一区二区亚洲

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

分析SpringBoot的啟動(dòng)原理

瀏覽:6日期:2023-04-25 18:52:28

背景

1> 大家都知道SpringBoot是通過(guò)main函數(shù)啟動(dòng)的,這里面跟蹤代碼到處都沒(méi)有找到while(true),為什么啟動(dòng)后可以一直跑?

2> SpringBoot默認(rèn)使用tomcat作為web容器。大家也可以通過(guò)在pom文件中exclusion掉tomcat,denpendency jetty 的方法來(lái)使用jetty。那SpringBoot是怎么做到在不同web容器之間切換的呢?

3> 傳統(tǒng)的web容器比如jetty本質(zhì)上是直接通過(guò)java start.jar 來(lái)啟動(dòng),之后來(lái)加載spring上下文的,SpringBoot通過(guò)main函數(shù)是怎么來(lái)啟動(dòng)web容器的呢?

本文就這三個(gè)問(wèn)題展開(kāi)論述。

問(wèn)題1分析

問(wèn)題1很簡(jiǎn)單,啟動(dòng)后一直跑是因?yàn)閱?dòng)了線(xiàn)程池。原理就是有非deamon的線(xiàn)程在跑。Java虛擬機(jī)規(guī)范定義要等所有用戶(hù)線(xiàn)程都運(yùn)行完才會(huì)退出。

所以這個(gè)原理就和下面啟動(dòng)線(xiàn)程池一樣

分析SpringBoot的啟動(dòng)原理

程序員修煉之道教我們:不要假定,要證明。雖然jetty使用線(xiàn)程池是常識(shí),我們也來(lái)跟蹤下源碼,看看線(xiàn)程池是在哪里初始化的:

org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory類(lèi)里,創(chuàng)建Server的使用使用線(xiàn)程池作為初始化參數(shù)。然后創(chuàng)建了socket連接來(lái)監(jiān)聽(tīng)端口。(對(duì)于socket連接有之前沒(méi)接觸過(guò)的,可以自己查一下。建議動(dòng)手實(shí)踐。《Java異常處理總結(jié)》這篇文章里有不錯(cuò)的簡(jiǎn)單小例子可以實(shí)操下。)

分析SpringBoot的啟動(dòng)原理

到這里,大家應(yīng)該都明白了為什么啟動(dòng)后一直不停。但是又有疑問(wèn)了:JettyServletWebServerFactory是個(gè)什么東東?

問(wèn)題2分析

關(guān)于問(wèn)題2,我們寫(xiě)個(gè)最簡(jiǎn)單的類(lèi)來(lái)debug一下:

分析SpringBoot的啟動(dòng)原理

進(jìn)入SpringAppication.run的源碼可以看到,里面創(chuàng)建了一個(gè)context,默認(rèn)是AnnotationConfigServletWebServerApplicationContext。一初始化,在Bean定義里就加載了spring開(kāi)天辟地的5個(gè)Bean。

分析SpringBoot的啟動(dòng)原理

繼續(xù)向下執(zhí)行走到AbstractApplicationContext的refresh方法,執(zhí)行到onRefresh時(shí),你進(jìn)入方法里發(fā)現(xiàn)實(shí)際上執(zhí)行的是

ServletWebServerApplicationContext的onFresh

分析SpringBoot的啟動(dòng)原理

這里面實(shí)際只做了一件事:創(chuàng)建web服務(wù)。

分析SpringBoot的啟動(dòng)原理

進(jìn)入這個(gè)方法,debug到getWebServerFactory

分析SpringBoot的啟動(dòng)原理

來(lái)看一下:

分析SpringBoot的啟動(dòng)原理

獲取的正式JettyServletWebServerFactory。為啥不是TomcatServlet呢?ServletWebServerFactoryAutoConfiguration的源碼很好的說(shuō)明了這個(gè)問(wèn)題。源碼的大意是當(dāng)tomcat依賴(lài)存在就用tomcat,不然就按順序找jetty存不存在,不存在再找Undertow存不存在。找到了就返回這個(gè)bean作為Servlet的工廠(chǎng)類(lèi)。

@Configuration@AutoConfigureOrder(-2147483648)@ConditionalOnClass({ServletRequest.class})@ConditionalOnWebApplication( type = Type.SERVLET)@EnableConfigurationProperties({ServerProperties.class})@Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, EmbeddedTomcat.class, EmbeddedJetty.class, EmbeddedUndertow.class})public class ServletWebServerFactoryAutoConfiguration { public ServletWebServerFactoryAutoConfiguration() { } @Bean public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) { return new ServletWebServerFactoryCustomizer(serverProperties); } @Bean @ConditionalOnClass( name = {'org.apache.catalina.startup.Tomcat'} ) public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(ServerProperties serverProperties) { return new TomcatServletWebServerFactoryCustomizer(serverProperties); } public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware { private ConfigurableListableBeanFactory beanFactory; public BeanPostProcessorsRegistrar() { } public void setBeanFactory(BeanFactory beanFactory) throws BeansException { if (beanFactory instanceof ConfigurableListableBeanFactory) {this.beanFactory = (ConfigurableListableBeanFactory)beanFactory; } } public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { if (this.beanFactory != null) {this.registerSyntheticBeanIfMissing(registry, 'webServerFactoryCustomizerBeanPostProcessor', WebServerFactoryCustomizerBeanPostProcessor.class);this.registerSyntheticBeanIfMissing(registry, 'errorPageRegistrarBeanPostProcessor', ErrorPageRegistrarBeanPostProcessor.class); } } private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name, Class<?> beanClass) { if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) {RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);beanDefinition.setSynthetic(true);registry.registerBeanDefinition(name, beanDefinition); } } }}

至此第二個(gè)問(wèn)題也真相大白。

問(wèn)題3分析

第三個(gè)問(wèn)題是傳統(tǒng)的web容器比如jetty本質(zhì)上是直接通過(guò)java start.jar 來(lái)啟動(dòng),之后來(lái)加載spring上下文的,SpringBoot通過(guò)main函數(shù)是怎么來(lái)啟動(dòng)web容器。

這個(gè)問(wèn)題在前面問(wèn)題分析過(guò)程中也給了很多線(xiàn)索。我們來(lái)回顧下:SpringApplication.run里會(huì)創(chuàng)建Spring的應(yīng)用上下文,默認(rèn)是AnnotationConfigServletWebServerApplicationContext。首先會(huì)加載Spring開(kāi)天辟地的5個(gè)Bean。然后它初始化各種Bean工廠(chǎng)。

SpringBoot在ServletWebServerApplicationContext中重載了onRefresh方法,除了以前Spring默認(rèn)的onRefresh方法外還增加了createWebServer方法,在這個(gè)方法中對(duì)Web容器進(jìn)行了初始化工作。

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>${spring.boot.version}</version> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> <exclusion> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </exclusion> </exclusions></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> <version>${spring.boot.version}</version> <exclusions> <exclusion> <groupId>org.eclipse.jetty.aggregate</groupId> <artifactId>jetty-all</artifactId> </exclusion> </exclusions></dependency>

因?yàn)檫x擇servlet容器是類(lèi)似于使用基于條件的注解方式。因?yàn)楫?dāng)exclusion掉tomcat后,只有jetty滿(mǎn)足條件,所以會(huì)加載JettyServletWebServerFactory。

通過(guò)getWebServer方法會(huì)new一個(gè)WebServer對(duì)象,new對(duì)象的方法會(huì)調(diào)用initialize方法,在這個(gè)方法中會(huì)對(duì)容器進(jìn)行初始化并啟動(dòng)。

而容器啟動(dòng)的基本原理就是創(chuàng)建個(gè)線(xiàn)程池和網(wǎng)絡(luò)套接字。用線(xiàn)程去處理套接字讀寫(xiě)的內(nèi)容。

總結(jié)

文本用帶有少許說(shuō)明的三個(gè)問(wèn)題開(kāi)場(chǎng)展開(kāi)論述,實(shí)際是使用了麥肯錫大法中的SCQA架構(gòu)。

SCQA架構(gòu)是金字塔模型里面突出的一個(gè)論述方法,即“情境(Situation)、沖突(Complication)、問(wèn)題(Question)、答案(Answer)”。可以幫助我們?cè)陉愂鍪聦?shí)時(shí)條理更為清晰、有效。

SCQA其實(shí)只是麥肯錫做了總結(jié)。這個(gè)方法李清照都在用:

昨夜雨疏風(fēng)驟,濃睡不消殘酒 (情境)

試問(wèn)卷簾人,渠道海棠依舊(沖突)

知否,知否(問(wèn)題)

應(yīng)是綠肥紅瘦(答案)

文章正文看似一步步回答問(wèn)題,實(shí)際上在講述怎樣去看spring源碼,了解spring原理的一個(gè)過(guò)程。即:帶著問(wèn)題去看,debug跟蹤源碼驗(yàn)證 的方法。

以上就是分析SpringBoot的啟動(dòng)原理的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot 啟動(dòng)原理的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Spring
相關(guān)文章:
主站蜘蛛池模板: 南通市| 黄骅市| 朝阳区| 勃利县| 华安县| 美姑县| 宜都市| 金平| 易门县| 麻江县| 淮北市| 图片| 雷山县| 汕尾市| 贡山| 甘孜县| 旺苍县| 丹凤县| 苏州市| 海伦市| 崇信县| 广水市| 荔浦县| 肥乡县| 兴安县| 滦南县| 太白县| 额济纳旗| 高清| 苏州市| 蒙山县| 彭山县| 介休市| 达拉特旗| 大石桥市| 北票市| 漾濞| 黄浦区| 灵寿县| 七台河市| 嵊州市|