自定義SpringMVC部分實現

自定義SpringMVC

1.SpringMVC執行流程

1.1 執行流程圖
複製代碼

091846_FTTR_3577599.png

1.2 執行過程
複製代碼
  1. 前端發送Http請求到DispatcherServlet;
  2. DispatcherServlet收到請求調用HandlerMapping處理映射器,處理映射器根據請求的url找到具體的處理器,生成處理器對象以及處理器攔截器(若是有則生成),一併返回給DispatcherServlet;
  3. DispatcherServlet經過HandlerAdapter處理器適配器調用處理器;
  4. 執行處理器(Controlle,也叫後端控制器),返回ModelAndView(數據模型和視圖名稱);
  5. HandlerAdapter將ModelAndView傳給DispatcherServlet;
  6. DispatcherServlet將ModelAndView傳給ViewResolver視圖解析器,解析後返回具體的View;
  7. DispatcherServlet對View進行渲染,將數據模型填充到View中;
  8. DispatcherServlet響應用戶;

2.設計思路

  1. 讀取配置文件前端

    SpringMVC本質上是一個Servlet,爲了讀取web.xml配置,這裏用到了ServletConfig 這個類,它表明當前Servlet在web.xml中的配置信息,經過 [^ config.getInitParameter("contextConfigLocation");//讀取啓動參數],讀取application.properties。java

    <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>application.properties</param-value>
            </init-param>
    複製代碼
  2. 初始化階段git

    @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();
        }
    複製代碼
  3. 運行階段github

    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.代碼實現

github.com/gnng/MySpri…web

4.自我總結

  1. 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>
    複製代碼
  2. Java元註解api

    /** * java中元註解有四個: @Retention @Target @Document @Inherited; * &emsp;&emsp;@Retention:註解的保留位置 * &emsp;&emsp;&emsp;&emsp;@Retention(RetentionPolicy.SOURCE)   //註解僅存在於源碼中,在class字節碼文件中不包含 * &emsp;&emsp;&emsp;&emsp;@Retention(RetentionPolicy.CLASS)     // 默認的保留策略,註解會在class字節碼文件中存在,但運行時沒法得到, * &emsp;&emsp;&emsp;&emsp;@Retention(RetentionPolicy.RUNTIME)  // 註解會在class字節碼文件中存在,在運行時能夠經過反射獲取到 * * &emsp;&emsp;@Target:註解的做用目標 * &emsp;&emsp;&emsp;&emsp;@Target(ElementType.TYPE)   //接口、類、枚舉、註解 * &emsp;&emsp;&emsp;&emsp;@Target(ElementType.FIELD) //字段、枚舉的常量 * &emsp;&emsp;&emsp;&emsp;@Target(ElementType.METHOD) //方法 * &emsp;&emsp;&emsp;&emsp;@Target(ElementType.PARAMETER) //方法參數 * &emsp;&emsp;&emsp;&emsp;@Target(ElementType.CONSTRUCTOR)  //構造函數 * &emsp;&emsp;&emsp;&emsp;@Target(ElementType.LOCAL_VARIABLE)//局部變量 * &emsp;&emsp;&emsp;&emsp;@Target(ElementType.ANNOTATION_TYPE)//註解 * &emsp;&emsp;&emsp;&emsp;@Target(ElementType.PACKAGE) ///包    *   *     @Document:說明該註解將被包含在javadoc中 *   * &emsp;  @Inherited:說明子類能夠繼承父類中的該註解 */
    複製代碼
相關文章
相關標籤/搜索