1、常規(guī)springmvc的流程
1.1springmvc的啟動過程
首先,對于一個web應(yīng)用,其部署在web容器中保屯,web容器提供其一個全局的上下文環(huán)境,這個上下文就是ServletContext涤垫,其為后面的spring IoC容器提供宿主環(huán)境姑尺;
其次,在web.xml中會提供有contextLoaderListener蝠猬。在web容器啟動時切蟋,會觸發(fā)容器初始化事件,此時contextLoaderListener會監(jiān)聽到這個事件吱雏,其contextInitialized方法會被調(diào)用敦姻,在這個方法中,spring會初始化一個啟動上下文歧杏,這個上下文被稱為根上下文,即WebApplicationContext迷守,這是一個接口類犬绒,確切的說,其實際的實現(xiàn)類是XmlWebApplicationContext兑凿。這個就是spring的IoC容器凯力,其對應(yīng)的Bean定義的配置由web.xml中的context-param標(biāo)簽指定。在這個IoC容器初始化完畢后礼华,spring以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE為屬性Key咐鹤,將其存儲到ServletContext中,便于獲仁バ酢祈惶;
再次,contextLoaderListener監(jiān)聽器初始化完畢后,開始初始化web.xml中配置的Servlet捧请,這個servlet可以配置多個凡涩,以最常見的DispatcherServlet為例,這個servlet實際上是一個標(biāo)準(zhǔn)的前端控制器疹蛉,用以轉(zhuǎn)發(fā)活箕、匹配、處理每個servlet請求可款。DispatcherServlet上下文在初始化的時候會建立自己的IoC上下文育韩,用以持有spring mvc相關(guān)的bean。在建立DispatcherServlet自己的IoC上下文時闺鲸,會利用WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE先從ServletContext中獲取之前的根上下文(即WebApplicationContext)作為自己上下文的parent上下文座慰。有了這個parent上下文之后,再初始化自己持有的上下文翠拣。這個DispatcherServlet初始化自己上下文的工作在其initStrategies方法中可以看到版仔,大概的工作就是初始化處理器映射、視圖解析等误墓。這個servlet自己持有的上下文默認實現(xiàn)類也是mlWebApplicationContext蛮粮。初始化完畢后,spring以與servlet的名字相關(guān)(此處不是簡單的以servlet名為Key谜慌,而是通過一些轉(zhuǎn)換然想,具體可自行查看源碼)的屬性為屬性Key,也將其存到ServletContext中欣范,以便后續(xù)使用变泄。這樣每個servlet就持有自己的上下文,即擁有自己獨立的bean空間恼琼,同時各個servlet共享相同的bean妨蛹,即根上下文(第2步中初始化的上下文)定義的那些bean。
1.2spring mvc工作流程圖
Spring工作流程描述
1.用戶向服務(wù)器發(fā)送請求晴竞,請求被Spring前端控制Servelt DispatcherServlet捕獲蛙卤;
2.?DispatcherServlet對請求URL進行解析,得到請求資源標(biāo)識符(URI)噩死。然后根據(jù)該URI颤难,調(diào)用HandlerMapping獲得該Handler配置的所有相關(guān)的對象(包括Handler對象以及Handler對象對應(yīng)的攔截器),最后以HandlerExecutionChain對象的形式返回已维;
3.?DispatcherServlet根據(jù)獲得的Handler行嗤,選擇一個合適的HandlerAdapter。(附注:如果成功獲得HandlerAdapter后垛耳,此時將開始執(zhí)行攔截器的preHandler(...)方法)
4.提取Request中的模型數(shù)據(jù)栅屏,填充Handler入?yún)⑵В_始執(zhí)行Handler(Controller)。 在填充Handler的入?yún)⑦^程中既琴,根據(jù)你的配置占婉,Spring將幫你做一些額外的工作:
HttpMessageConveter:將請求消息(如Json、xml等數(shù)據(jù))轉(zhuǎn)換成一個對象甫恩,將對象轉(zhuǎn)換為指定的響應(yīng)信息
數(shù)據(jù)轉(zhuǎn)換:對請求消息進行數(shù)據(jù)轉(zhuǎn)換逆济。如String轉(zhuǎn)換成Integer、Double等
數(shù)據(jù)根式化:對請求消息進行數(shù)據(jù)格式化磺箕。如將字符串轉(zhuǎn)換成格式化數(shù)字或格式化日期等奖慌;
數(shù)據(jù)驗證: 驗證數(shù)據(jù)的有效性(長度、格式等)松靡,驗證結(jié)果存儲到BindingResult或Error中简僧;
5. ?Handler執(zhí)行完成后,向DispatcherServlet返回一個ModelAndView對象雕欺;
6.根據(jù)返回的ModelAndView岛马,選擇一個適合的ViewResolver(必須是已經(jīng)注冊到Spring容器中的ViewResolver)返回給DispatcherServlet;
7.?ViewResolver結(jié)合Model和View屠列,來渲染視圖
8.將渲染結(jié)果返回給客戶端啦逆。
2springboot搭建
2.1選取ide工具
下圖是spring官網(wǎng)提供的ide工具
要創(chuàng)建springboot項目可以下載spring官網(wǎng)提供的sts這款I(lǐng)DE笛洛,自動集成了創(chuàng)建boot項目所需的插件,當(dāng)然對使用eclipse的開發(fā)者也可以安裝對應(yīng)系統(tǒng)的插件進行構(gòu)建boot項目沟蔑。
2.2創(chuàng)建項目
File> New > Spring Starter Project
Next> Finish
項目創(chuàng)建完成:
可以看出瘦材,項目源碼就一個Java類,在pom.xml中有spring-boot-starter-web的依賴宇色。
SpringBootSampleApplication.java
packageorg.springboot.sample;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
publicclass SpringBootSampleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootSampleApplication.class,args);
}
}
pom.xml
4.0.0
org.springboot.sample
spring-boot-sample
0.0.1-SNAPSHOT
jar
spring-boot-sample
Spring Boot Sample WebApplication
org.springframework.boot
spring-boot-starter-parent
1.3.1.RELEASE
UTF-8
1.8
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
這樣就完成了項目的創(chuàng)建颁湖,下面我們創(chuàng)建一個HelloController.java定義3個方法
packageorg.springboot.sample.controller;
importjava.util.ArrayList;
importjava.util.HashMap;
importjava.util.List;
importjava.util.Map;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestParam;
importorg.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/hello")
publicclass HelloController {
@RequestMapping
public String hello() {
return "Hello Spring-Boot";
}
@RequestMapping("/info")
public Map getInfo(@RequestParamString name) {
Map map = newHashMap<>();
map.put("name", name);
return map;
}
@RequestMapping("/list")
public List>getList() {
List> list= new ArrayList<>();
Map map = null;
for (int i = 1; i <= 5; i++) {
map = new HashMap<>();
map.put("name", "Shanhy-"+ i);
list.add(map);
}
return list;
}
}
然后現(xiàn)在可以直接運行SpringBootSampleApplication的main方法例隆,和執(zhí)行普通java程序一樣。
然后可以看到spring-boot內(nèi)置server容器(默認為Tomcat)镰禾,這一切spring-boot都幫我們做好了皿曲。
控制臺輸出內(nèi)容Started SpringBootSampleApplication in 7.358 seconds (JVM running
for 9.154)表示服務(wù)已經(jīng)啟動。
在瀏覽器輸入我們3個請求便可看到結(jié)果吴侦。http://localhost:8080/hello
輸出:HelloSpring-Boothttp://localhost:8080/hello/info?name=shanhy
輸出:{“name”:”shanhy”}http://localhost:8080/hello/list
輸出:[{“name”:”Shanhy-1”},{“name”:”Shanhy-2”},{“name”:”Shanhy-3”},{“name”:”Shanhy-4”},{“name”:”Shanhy-5”}]
通過我們的Hello實例屋休,相信大家一目了然,可謂spring-boot創(chuàng)建一個項目如此簡單备韧,完全可以在幾分鐘內(nèi)將服務(wù)啟動劫樟。spring-boot拋棄繁瑣的配置,讓開發(fā)人員更專注與業(yè)務(wù)邏輯的實現(xiàn)织堂。后面幾篇文章將會對spring-boot的多個方面通過實例的方式呈現(xiàn)給大家叠艳。
3springboot的運行原理
系統(tǒng)啟動類視圖如下:
可以發(fā)現(xiàn)啟動類有個@SpringBootApplication注解,這是一個組合注解易阳,結(jié)構(gòu)如下圖:
@SpringBootApplication注解的功能主要由@ EnableAutoCongiguration附较、@componentScan組成。
@EnableAutoCongiguration負責(zé)啟動自動配置功能潦俺,在main方法中的SpringApplication啟動的方法中拒课,如下圖:
在SpringApplication啟動時,依據(jù)@ EnableAutoCongiguration設(shè)定的自動配置功能事示,有一部分功能是去掃描maven內(nèi)所有jar包下的spring.factories文件早像,構(gòu)建成一個配置文件鏈表,如果系統(tǒng)有引用很魂,則根據(jù)條件注解去初始化bean扎酷,例如:
@componentScan負責(zé)掃描啟動類所在package下子package的所有需要實例化的bean的IOC,比如@controller遏匆、@service法挨、@Component、@Configuration幅聘、@bean等凡纳。
boot提供了默認的配置文件:application.xml,集成了各類starter服務(wù)的配置屬性定制化帝蒿,簡單舉幾個例子:
日志配置
web服務(wù)器配置
模板配置
http編碼、json和微服務(wù)配置
mvc交互配置
認證配置
還有spring.data.*和spring.datasource.*的異構(gòu)數(shù)據(jù)源的配置等等,具體詳情參考
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/
4springmvc遷移springboot
4.1零配置
常規(guī)springmvc的整體結(jié)構(gòu)如下圖:
springboot的整體結(jié)構(gòu)如下圖:
綜合對比答渔,springmvc要遷移springboot沼撕,首當(dāng)其中的就是springboot是如何去XML(web.xml和applicationcontext.xml)的务豺。
去web.xml:依賴內(nèi)置web服務(wù)器啟動初始化應(yīng)用的上下文笼沥;
去applicationcontext.xml:依賴java注解和條件注解技術(shù)敬拓,使用自動配置功能實現(xiàn)。
4.2web.xml
對于一些springboot
application.xml中沒有的服務(wù)厕诡,有三種解決方式:
1灵嫌、自定義starter pom
2寿羞、原始方式自己編寫服務(wù)
3绪穆、原始引用XML
對于springboot服務(wù)不好用玖院,想進行變更的第岖,boot設(shè)計中為它的任何一個服務(wù)都提供了可擴展性的方式進行變更蔑滓,比如如何解決web.xml內(nèi)配置的filter键袱、Listener蹄咖、Interceptor等,可通過注解方式(比如@Component比藻、@Configuration)自行擴展對應(yīng)的服務(wù)银亲。
5樣例
5.1pom文件配置
5.2application.xml配置
環(huán)境分流配置
開啟shutdown功能
配置內(nèi)容
5.3平滑升級
6總結(jié)
使用springboot馏段,首選需要判斷boot是否提供了服務(wù)院喜,boot有一些服務(wù)是自動配置加載的,有一些服務(wù)是需要enable*打開才能用的砍濒,比如定時@EnableScheduling硫麻、異步@EnableAsync服務(wù)等拿愧,如果boot目前還無法定制某項目的個性化服務(wù),可自行擴展券敌,擴展方式參考4.2小節(jié)描述內(nèi)容陪白。
對于jar包版本一致性問題也是同理咱士,先判斷boot是否提供了對應(yīng)的jar服務(wù)序厉,決定是否需要自行擴展弛房。
springboot可以導(dǎo)出jar包也可以導(dǎo)出war包文捶,war包基本依賴外部應(yīng)用服務(wù)器,可以利用外部應(yīng)用服務(wù)器的shutdown功能平滑升級种远。但jar包形式依賴linux sh腳本的運行坠敷,基本都會使用kill去暴力殺線程膝迎,這是會影響線上業(yè)務(wù)的胰耗,所以為了保證線上線程不會突然崩潰影響業(yè)務(wù)宪郊,sringboot也考慮了這一點,在監(jiān)控Actuator中提供了優(yōu)雅的shutdown功能懊亡,只要我們在sh腳本中訪問線上服務(wù)的shutdown地址店枣,即可優(yōu)雅的關(guān)閉線上服務(wù)鸯两,平滑升級了钧唐。