摘要:Spring Boot是由Pivotal團隊提供的全新框架,其設計目的是用來簡化新Spring應用的初始搭建以及開發過程。
本文分享自華為云社區《SpringBoot到底是什么?如何理解parent、starter、引導類以及內嵌Tomcat?》,作者:我是一棵卷心菜 。
Spring Boot是由Pivotal團隊提供的全新框架,其設計目的是用來簡化新Spring應用的初始搭建以及開發過程。該框架使用了特定的方式來進行配置,從而使開發人員不再需要定義樣板化的配置。通過這種方式,Spring Boot致力于在蓬勃發展的快速應用開發領域(rapid application development)成為領導者。
從百度百科中可以看出,其目的是用來簡化Spring!那么到底簡化在什么地方呢?
讓我們想想在學習SSM時,做過原始SpringMVC程序的小伙伴應該知道,寫SpringMVC程序,最基礎的spring-web和spring-webmvc這兩個坐標是必須的,這些還不包含我們使用的json啊等等坐標,現在呢?一個坐標搞定!
以前寫配置類或者配置文件,然后用什么東西就要自己寫加載bean這些東西,現在呢?什么都沒寫,照樣能用。
有以下優點:
別著急,讓我們慢慢來探討探討其中的奧秘~
打開創建好的springboot程序,可以看見pom.xml文件中的<parent> </parent>
????<parent> ????????<groupId>org.springframework.boot</groupId> ????????<artifactId>spring-boot-starter-parent</artifactId> ????????<version>2.6.4</version> ????????<relativePath/> ????</parent>
這里的<version>2.6.4<version>就是自己使用的springboot版本,打開后可以發現其中又繼承了一個坐標,引入了很多依賴
<parent> ????<groupId>org.springframework.boot</groupId> ????<artifactId>spring-boot-dependencies</artifactId> ????<version>2.6.4</version> ??</parent>
再次點擊打開,就可以找到其中的奧秘了。
從下圖我們可以發現各式各樣的依賴版本號屬性,下面列出依賴版本屬性的局部,可以看的出來,定義了若干個技術的依賴版本號
再看看下圖,各式各樣的的依賴坐標信息,可以看出依賴坐標定義中沒有具體的依賴版本號,而是引用了第一組信息中定義的依賴版本屬性值
注意:上面的依賴坐標定義是出現在<dependencyManagement>標簽中的,其實是對引用坐標的依賴管理,并不是實際使用的坐標。因此當我們的項目中繼承了這組parent信息后,在不使用對應坐標的情況下,前面的這組定義是不會具體導入某個依賴的
最后來看看使用不同的springboot版本時,其對應的pom依賴文件有什么不同。我這里對比的是springboot2.5.6版本和springboot2.6.4
從圖中可以清楚的看到,當我們使用不同的springboot版本時,他們的依賴版本就會不同。這也確保了,在使用springboot時,我們可以在某種程度上避免版本沖突的復雜問題,方便了程序員們的開發!
SpringBoot關注到開發者在實際開發時,對于依賴坐標的使用往往都有一些固定的組合方式,比如使用spring-webmvc就一定要使用spring-web。每次都要固定搭配著寫,非常繁瑣,而且格式固定,沒有任何技術含量。
SpringBoot一看這種情況,把所有的技術使用的固定搭配格式都給開發出來,以后我們使用某個技術,就不用一次寫一堆依賴了,直接用springboot做好的這個東西就好了,對于這樣的固定技術搭配,SpringBoot給它起了個名字叫做starter。
starter定義了使用某種技術時對于依賴的固定搭配格式,也是一種最佳解決方案,使用starter可以幫助開發者減少依賴配置
?<dependency>????????<groupId>org.springframework.boot</groupId> ????????????<artifactId>spring-boot-starter-web</artifactId> </dependency>
比如我想開發web應用,就需要引入上面的web對應的starter依賴,并沒有寫SpringMVC的坐標,點擊spring-boot-starter-web
我們會發現在spring-boot-starter-web中又定義了若干個具體依賴的坐標
通過上圖我們可以細心的發現叫做spring-boot-starter-json的名字中也有starter,打開看看里面有什么?
我們可以發現,這個starter中又包含了若干個坐標,其實就是使用SpringMVC開發通常都會使用到Json,使用json又離不開這里面定義的這些坐標,看來還真是方便,SpringBoot把我們開發中使用的東西能用到的都給提前做好了。仔細看完會發現,里面有一些我們沒用過的。的確會出現這種過量導入的可能性,不過沒關系,可以通過maven中的排除依賴剔除掉一部分。不過你不管它也沒事,大不了就是過量導入唄。
到這里基本上得到了一個信息,使用starter可以幫開發者快速配置依賴關系
朦朦朧朧中感覺starter與parent好像都是幫助我們簡化配置的,但是功能又不一樣:
starter是一個坐標中定了若干個坐標,以前寫多個的,現在寫一個,是用來減少依賴配置的書寫量的
parent是定義了幾百個依賴版本號,以前寫依賴需要自己手工控制版本,現在由SpringBoot統一管理,這樣就不存在版本沖突了,是用來減少依賴沖突的
溫馨提示
SpringBoot官方給出了好多個starter的定義,方便我們使用,而且名稱都是如下格式
命名規則:spring-boot-starter-技術名稱
配置說完了,我們發現SpringBoot確實幫助我們減少了很多配置工作,下面說一下程序是如何運行的。目前程序運行的入口就是SpringBoot工程創建時自帶的那個類了,帶有main方法的那個類,運行這個類就可以啟動SpringBoot工程的運行,我的是這個:
@SpringBootApplication public?class?Springboot0101Application?{ ????public?static?void?main(String[]?args)?{ SpringApplication.run(Springboot0101Application.class,?args); }
寫代碼測試一下,先創建一個User類,把它放在容器中
@Component public?class?User?{ }
然后再寫一個BookController類,也把它放在容器中
@RestController @RequestMapping("/books") public?class?BookController?{ ????@GetMapping("/getBooks") ????public?String?getBooks()?{ ????????System.out.println("springboot程序正在運行呢~"); ????????return?"Hello,SpringBoot?is?running"; ????} }
看看我對應類的目錄結構:
最后寫代碼測試一下:
@SpringBootApplication public?class?Springboot0101Application?{ ????public?static?void?main(String[]?args)?{ ????????ConfigurableApplicationContext?applicationContext ????????????????=?SpringApplication.run(Springboot0101Application.class,?args); ????????BookController?bookBean?=?applicationContext.getBean(BookController.class); ????????System.out.println("The?message?of?bookBean?:?"?+?bookBean); ????????User?userBean?=?applicationContext.getBean(User.class); ????????System.out.println("The?message?of?userBean?:?"?+?userBean); ????} }
運行結果:
看到結果,小伙伴們不難猜想了——SpringBoot程序啟動是創建了一個Spring容器對象吧?答案就是如此!
Springboot0101Application這個類在SpringBoot程序中是所有功能的入口,稱這個類為引導類。
作為一個引導類最典型的特征就是當前類上方聲明了一個注解@SpringBootApplication
點擊進入@SpringBootApplication,我們可以看到:
這里面有我們之前學習SSM時用到的包掃描注解,再點擊進入@SpringBootConfiguration內:
我們可以發現,它最終使用了@Configuration注解,所以,歸根到底,我們使用的引用類,也是一個配置類。
程序現在已經運行了,通過引導類的main方法運行了起來。但是運行java程序不應該是執行完就結束了嗎?但是我們現在明顯是啟動了一個web服務器啊,不然網頁怎么能正常訪問呢?這個服務器是在哪里寫的呢?
認真想一想,它就在我們引入的spring-boot-starter-web場景starter中,我們打開它來看一看:
這里面有一個核心的坐標,tomcat-embed-core,叫做tomcat內嵌核心。就是這個東西把tomcat功能引入到了我們的程序中。
再來說第二個問題,這個服務器是怎么運行的?
Tomcat服務器是一款軟件,而且是一款使用java語言開發的軟件,既然是使用java語言開發的,運行的時候肯定符合java程序運行的原理,java程序運行靠的是什么?對象呀,一切皆對象,萬物皆對象。那tomcat運行起來呢?也是對象。
如果是對象,那Spring容器是用來管理對象的,這個對象能不能交給Spring容器管理呢?答案是可以的!tomcat服務器運行其實是以對象的形式在Spring容器中運行的,怪不得我們沒有安裝這個tomcat,而且還能用。鬧了白天這東西最后是以一個對象的形式存在,保存在Spring容器中悄悄運行的。具體運行的是什么呢?其實就是上前面提到的那個tomcat內嵌核心
具體內嵌核心依賴如下:
<dependency> ??????<groupId>org.apache.tomcat.embed</groupId> ??????<artifactId>tomcat-embed-core</artifactId> ??????<version>9.0.58</version> ??????<scope>compile</scope> ??????<exclusions> ????????<exclusion> ??????????<artifactId>tomcat-annotations-api</artifactId> ??????????<groupId>org.apache.tomcat</groupId> ????????</exclusion> ??????</exclusions> </dependency>
那既然是個對象,如果把這個對象從Spring容器中去掉是不是就沒有web服務器的功能呢?當然可以,通過依賴排除可以去掉這個web服務器功能。根據SpringBoot的工作機制,用什么技術,加入什么依賴就行了。我選擇的是SpringBoot提供的內置服務器jetty
更換代碼如下:
?<dependency> ????????????<groupId>org.springframework.boot</groupId> ????????????<artifactId>spring-boot-starter-web</artifactId> ????????????<exclusions> ????????????????<exclusion> ????????????????????<groupId>org.springframework.boot</groupId> ????????????????????<artifactId>spring-boot-starter-tomcat</artifactId> ????????????????</exclusion> ????????????</exclusions> </dependency> <dependency> ????????????<groupId>org.springframework.boot</groupId> ????????????<artifactId>spring-boot-starter-jetty</artifactId> </dependency>
讓我們運行一下看看是什么樣的結果:
輸出結果是沒有問題的,但是服務器就不是默認的Tomcat了,而是我選擇的jetty服務器。
?
|