自定義SpringMVC
1.SpringMVC執行流程
1.1 執行流程圖
複製程式碼
1.2 執行過程
複製程式碼
- 前端傳送Http請求到DispatcherServlet;
- DispatcherServlet收到請求呼叫HandlerMapping處理對映器,處理對映器根據請求的url找到具體的處理器,生成處理器物件以及處理器攔截器(如果有則生成),一併返回給DispatcherServlet;
- DispatcherServlet通過HandlerAdapter處理器介面卡呼叫處理器;
- 執行處理器(Controlle,也叫後端控制器),返回ModelAndView(資料模型和檢視名稱);
- HandlerAdapter將ModelAndView傳給DispatcherServlet;
- DispatcherServlet將ModelAndView傳給ViewResolver檢視解析器,解析後返回具體的View;
- DispatcherServlet對View進行渲染,將資料模型填充到View中;
- DispatcherServlet響應使用者;
2.設計思路
-
讀取配置檔案
SpringMVC本質上是一個Servlet,為了讀取web.xml配置,這裡用到了ServletConfig 這個類,它代表當前Servlet在web.xml中的配置資訊,通過 [^ config.getInitParameter("contextConfigLocation");//讀取啟動引數],讀取application.properties。
<init-param> <param-name>contextConfigLocation</param-name> <param-value>application.properties</param-value> </init-param> 複製程式碼
-
初始化階段
@Override public void init(ServletConfig config) throws ServletException { //1.載入配置檔案 doLoadConfig(config.getInitParameter("contextConfigLocation")); //2.初始化相關聯的類,掃描使用者設定包下的所有類 doScanner(properties.getProperty("scanPackage")); //3.拿到掃描到的類,通過反射例項化,並放入IOC容器中,(k-v,beanName-bean),beanName預設首字母小寫 doInstance(); //4.初始化HandlerMapping(將url和method對應上) iniHandlerMapping(); } 複製程式碼
-
執行階段
private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception { if(handlerMapping.isEmpty()){ return; } String url = req.getRequestURI(); String contextPath = req.getContextPath(); url = url.replace(contextPath,"").replaceAll("/+","/"); if(!this.handlerMapping.containsKey(url)){ resp.getWriter().write("404 No Found"); return; } Method method = this.handlerMapping.get(url); //獲取方法的引數列表 Class<?>[] parameterTypes = method.getParameterTypes(); //獲取請求的引數 Map<String, String[]> parameterMap = req.getParameterMap(); //儲存引數值 Object [] paramValues = new Object[parameterTypes.length]; //方法的引數列表 for (int i = 0; i < parameterTypes.length; i++) { //根據引數名稱,做某些處理 String requestParam = parameterTypes[i].getSimpleName(); if("HttpServletRequest".equals(requestParam)){ //引數型別已明確,強轉型別是 paramValues[i] = req; continue; } if("HttpServletResponse".equals(requestParam)){ paramValues[i] = resp; continue; } if("String".equals(requestParam)){ for (Entry<String, String[]> param : parameterMap.entrySet()) { String valuse = Arrays.toString(param.getValue()).replaceAll("\\[|\\]", "").replaceAll(",\\s", ","); paramValues[i] = valuse; } } } //利用反射機制呼叫 try { method.invoke(this.controllerMap.get(url),paramValues);//第一個引數為method所對應的例項,在IOC容器中 }catch (Exception e){ e.printStackTrace(); } 複製程式碼
3.程式碼實現
4.自我總結
-
Maven的依賴範圍provided
<dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <!-- <scope>xxx</scope>依賴範圍 * compile,預設值,適用於所有階段,會隨著專案一起釋出。 * provided,類似compile,期望JDK、容器或使用者會提供這個依賴。如servlet.jar。 * runtime,只在執行時使用,如JDBC驅動,適用執行和測試階段。 * test,只在測試時使用,用於編譯和執行測試程式碼。不會隨專案釋出。 * system,類似provided,需要顯式提供包含依賴的jar,Maven不會在Repository中查詢它。 --> <scope>provided</scope> </dependency> </dependencies> 複製程式碼
-
Java元註解
/** * java中元註解有四個: @Retention @Target @Document @Inherited; *   @Retention:註解的保留位置 *     @Retention(RetentionPolicy.SOURCE) //註解僅存在於原始碼中,在class位元組碼檔案中不包含 *     @Retention(RetentionPolicy.CLASS) // 預設的保留策略,註解會在class位元組碼檔案中存在,但執行時無法獲得, *     @Retention(RetentionPolicy.RUNTIME) // 註解會在class位元組碼檔案中存在,在執行時可以通過反射獲取到 * *   @Target:註解的作用目標 *     @Target(ElementType.TYPE) //介面、類、列舉、註解 *     @Target(ElementType.FIELD) //欄位、列舉的常量 *     @Target(ElementType.METHOD) //方法 *     @Target(ElementType.PARAMETER) //方法引數 *     @Target(ElementType.CONSTRUCTOR) //建構函式 *     @Target(ElementType.LOCAL_VARIABLE)//區域性變數 *     @Target(ElementType.ANNOTATION_TYPE)//註解 *     @Target(ElementType.PACKAGE) ///包 * * @Document:說明該註解將被包含在javadoc中 * *   @Inherited:說明子類可以繼承父類中的該註解 */ 複製程式碼