首先就是啟動springboot項目,即執行主函數,這個主函數的類通常帶有SpingBootApplication注解,類中的main方法就是程序的入口。
啟動主函數后,SpringBoot會按特定順序加載配置文件,如application.properties或application.yml,這兩種格式的文件都行,還能根據不同的環境加載不同的加載文件,如生產環境,測試環境等。配置文件里一般包含數據庫連接的信息,服務端接口,日志級別等。
接著main函數中的run方法會創建一個Spring容器負責管理項目中的Bean,具體過程就是在調用SpingApplication.run方法時,會先創建一個SpringApplication實例,該實例會進行如下工作:
? ?1.推斷應用類型,判斷時Web應用還是非Web應用。
? ?2.查找并加載初始化器(ApplicationContextInitializer),這些初始化器可以在? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ApplicationContext(應用上下文,是一個管理Spring應用中各種組件如Bean,配置信息,時間等的高級容器)刷新之前進行自定義配置。
? 3.查找并加載監聽器,監聽器會監聽應用啟動過程中的各種時間,如應用啟動,上下文刷新等。
? 4.推斷主應用類,即包含main方法的類
然后SpringApplition實例會根據應用類型創建相應的ApplicationContext實例。
接下來就是加載Bean定義,ApplicationContext會加載所有的Bean定義,這些Bean定義可以來自多個地方:
? ?1.通過@ComponentScan掃描指定路徑下的帶有@Component,@Service,@Repository,? ? ? ? ? @Controller等注解的類
? ?2.@Configuration注解的配置類中使用@Bean注解定義的類
?接著就是在Applicationtext刷新的過程中,會根據Bean定義創建Bean實例,并進行依賴注入和生命周期管理。Spring容器會確保Bean的單例性(默認情況下,也可以指定為多例),并處理Bean的初始化和銷毀方法。
在Sping容器和Bean加載完成后,還會啟動服務器,執行命令運行器和應用啟動運行器(對實現了CommandLineRunner或ApplicationRunner接口的Bean在應用啟動后執行一些初始化操作),最后發布應用啟動完成事件。
講完了springboot的啟動后下面就是交互過程了。
客戶端發起請求,這個請求是HTTP請求,它包括如下方法:
? 1.請求方法:常見的有GET(用于獲取資源),POST(用于提交數據),PUT(用于更新資源),DELETE(用于更新資源),DELETE(用于刪除資源)等
? 2.請求URL:指明要訪問的資源地址
? 3.請求頭:攜帶關于請求的額外信息,包含很多信息,如客戶端類型,請求體的數據格式,請求發送的日期時間,身份驗證(例如把token放到請求頭中)等等
? 4.請求體:POST,PUT等方法可能會攜帶請求體,用于傳遞數據,數據格式可以是JSON,XML等
? 接著請求到達了SpringBoot應用所監聽的端口,在請求到達之前,服務器一直在監聽該端口,端口一般是8080。
嵌入式服務器接收到請求后,會進行如下操作:
? 1.將原始的HTTP請求封裝成HttpServletRequest對象,該對象提供了一系列方法用于獲取請求的各種信息,如請求方法,請求URL,請求頭,請求體等。
? 2.同時創建一個HttpServletResponse響應對象,用于后續后端向前端返回消息
請求在到達DispatcherServlet之前,會經過一系列過濾器,過濾器可以實現編碼轉換,請求日志,權限驗證等功能,通過實現Filter接口來定義過濾器。
DispatcherServlet作為SpringMVC的核心調度器,繼承自HttpServlet,在SpringBoot啟動時自動配置和初始化,接受經過過濾器鏈處理后的請求。
在查找處理器(三層架構中的controller)之前,DispatcherServlet會進行一些預處理操作:
? 1.檢查請求是否為文件上傳請求,若為文件上傳請求,則將請求包裝成MultipartHttpServletRequest。
? 2.根據請求的Accept頭確定合適的消息轉換器,用于后續處理響應數據的格式轉換
(這里的Accept頭是HTTP請求頭中的一個字段,他用于告知服務器客戶端能夠接受的響應內容類型)
HandlerMapping根據請求的URL和請求方法,從被@Controller或@RestController注解標記的類中查找對應的處理器方法。常見的HandlerMapping實現是RequestMappingHandlerMapping,它依據@RequestMapping,@GetMappingdeng等注解來匹配處理器方法。
在確定請求對應的處理器之后,調用處理器方法之前,會執行攔截器的preHandle方法。攔截器是SpringMVC提供的功能,可用于對處理器方法進行增強,如權限驗證,日志記錄,性能監控等。
示例:
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 權限驗證if (request.getSession().getAttribute("user") == null) {response.sendRedirect("/login");return false;}// 記錄請求開始時間request.setAttribute("startTime", System.currentTimeMillis());return true;}
}
若攔截器的preHandle方法返回true,HandlerAdapter會將請求中的參數(如URL參數,請求體參數等)綁定到處理器方法的參數上,并調用處理器方法。在這個過程中,控制器可能會調用服務層的方法來處理業務邏輯。
服務層主要負責處理業務規則,數據訪問和事務管理等操作。控制器調用服務層的方法,服務層再調用數據訪問層(DAO)來與數據庫或其他數據源進行交互。
數據訪問層負責與底層數據源進行交互,執行數據的增刪改查,通常用mybatis或者mybatisplus進行實現。
處理器方法執行完成后,在視圖渲染之前,會執行攔截器的postHandle方法。此方法可用于對處理器方法的執行結果進行修改或補充。
處理器方法處理完業務邏輯后,返回一個結果。結果可以是視圖名稱(用于視圖渲染),也可以是數據對象(如JSON,XML等)。如果使用@RequestController注解,默認會將返回的對象轉換為JSON格式返回給客戶端。
若處理器方法返回的是視圖名稱,DispatcherServlet會使用ViewResolver解析視圖,將模型數據傳遞給視圖模版進行渲染。
視圖模板將模型數據和視圖模版合并,生成最終的HTML頁面。(如果有)
在整個請求處理完成后,包括視圖渲染完成,會執行攔截器的afterComletion方法。此方法主要用于進行資源清理操作,如關閉數據庫連接,記錄請求處理的總時長等。
處理器方法返回的結果(視圖或數據)被封裝到HttpServletResponse對象中,DispatcherServlet設置響應的狀態碼,響應頭和響應體。
響應在返回客戶端之前,再次經過過濾器,過濾器可對響應進行后置處理,如添加響應頭,壓縮響應數據等。
嵌入式服務器將HttpServletResponse對象中的響應數據返回給客戶端,客戶端根據響應內容進行相應處理。