SpringMVC運行流程:
1) 用戶向伺服器發送請求, 請求被SpringMVC 前端控制器 DispatcherServlet捕獲;
2) DispatcherServlet對請求URL進行解析, 得到請求資源識別字(URI):
判斷請求URI對應的映射
① 不存在:
a) 再判斷是否配置了mvc:default-servlet-handler:
b) 如果沒配置, 則控制台報映射查找不到, 用戶端展示404錯誤
c) 如果有配置, 則執行目標資源(一般為靜態資源, 如:JSP,HTML)
② 存在:
a) 執行下面流程
3) 根據該URI, 調用HandlerMapping獲得該Handler配置的所有相關的物件(包括Handler物件以及Handler物件對應的攔截器), 最後以HandlerExecutionChain物件的形式返回;
4) DispatcherServlet 根據獲得的Handler, 選擇一個合適的HandlerAdapter。
5) 如果成功獲得HandlerAdapter後, 此時將開始執行攔截器的preHandler(...)方法【正向】
6) 提取Request中的模型資料, 填充Handler入參, 開始執行Handler(Controller)方法, 處理請求。 在填充Handler的入參過程中, 根據你的配置, Spring將幫你做一些額外的工作:
① HttpMessageConveter: 將請求消息(如Json、xml等資料)轉換成一個物件, 將物件轉換為指定的響應資訊
② 資料轉換:對請求消息進行資料轉換。 如String轉換成Integer、Double等
③ 資料根式化:對請求消息進行資料格式化。
④ 資料驗證: 驗證資料的有效性(長度、格式等), 驗證結果存儲到BindingResult或Error中
7) Handler執行完成後, 向DispatcherServlet 返回一個ModelAndView物件;
8) 此時將開始執行攔截器的postHandle(...)方法【逆向】
9) 根據返回的ModelAndView(此時會判斷是否存在異常:如果存在異常, 則執行HandlerExceptionResolver進行異常處理)選擇一個適合的ViewResolver(必須是已經註冊到Spring容器中的ViewResolver)返回給DispatcherServlet, 根據Model和View, 來渲染視圖
10) 在返回給用戶端時需要執行攔截器的AfterCompletion方法【逆向】
11) 將渲染結果返回給用戶端
@RequestMapping("testResponseEntity")
public ResponseEntity testResponseEntity(HttpSession session) throws IOException{
ServletContext servletContext = session.getServletContext();
InputStream resourceAsStream = servletContext.getResourceAsStream("/files/abc.txt");
byte[] body = new byte[resourceAsStream.available()] ;
resourceAsStream.read(body);
MultiValueMap headers = new HttpHeaders ();
headers.add ("Content-Disposition ", "attachment;filename=abc.txt");
HttpStatus statusCode = HttpStatus.OK;
ResponseEntity responseEntity = new ResponseEntity(body, headers, statusCode);
return responseEntity ;
}
橫切性關注點
AOP程式設計也就是基於上述描述推演開來。
1) 橫切性關注點
我們加在主線業務前後的這些內容稱為“橫切性關注點”。 根據OOP程式設計的原則, 提供給多個地方調用的內容需要將它封裝為一個方法, 方法也不可能單獨存在,
2) 通知(advice)
將橫向業務內容也即橫切性關注點的內容封裝為一個方法, 這個方法稱為“通知”advice
,它可以放在主方法的前面(比如User裡面的add方法是主方法而checkSecurity可以放在add方法前面後面等, 均可)也可以放在後面。 除此外還有異常通知、環繞通知和最終通知。
即被方法化的橫切性關注點稱為通知, 它可以放在前後等多個地方。
3) 連接點(joinpoint)
就是那些被攔截到的點, spring這些點就是方法。 也就是主線業務中的主要方法, 每一
方法就是一個連接點, 比如User類的CRUD四個方法, 就是4個連接點。
4) 切入點(pointcut)
就是要對那些方法進行攔截, 是對需要攔截的jonitpoint的定義。
5) 切面(aspect)
一個個封裝了的方法稱為advice, 每一個方法均應該封裝在一個類中;此外,
這些advice上也需要定義將這些通知用於那些方法前面或者後面, 這些定義也封裝在這個類中, 稱為切入點, 它們以後就作用於joinpoint將這些統一封裝起來的類稱為切面。 公式表達:aspect=pointcut+advice
6) 織入(weave)
將aspect運用到代理的目標物件上並導致proxy創建的過程稱為織入。