[Spring MVC] 理解核心原理 - 實現輕量級Spring MVC框架 (一)

涉及知識點:

第一部分, 工程基礎配置

  1. 建立Dynamic web工程
  2. (僅Eclipse下)爲工程添加runtime librariy. 目的: 爲了實現servlet功能 (主要須要其中的servlet-api等jar文件) 此爲servlet基礎知識.
  3. 建立DispatcherServlet並繼承HttpServlet
  4. web.xml中聲明此dispatcherServlet, 目的: ①表示這是個會被tomcat容器識別的servlet, ②攔截全部請求html

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
      <display-name>SpringSim2</display-name>
      <servlet>
          <servlet-name>springsim2</servlet-name>
          <servlet-class>com.spring.sim.DispatcherServlet</servlet-class>
      </servlet>
      <servlet-mapping>
          <servlet-name>springsim2</servlet-name>
          <url-pattern>/*</url-pattern>
      </servlet-mapping>
    </web-app>
  5. src下建立application.properties, 指定須要被掃描的包java

    path=com.spring.sim
  6. web.xml中將properties文件設置爲啓動時被load web

    ⚠ 此步驟爲可選, 在DispatcherServlet中聲明也能夠spring

    此步完成後, web.xml不須要再改動api

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
      <display-name>SpringSimv1</display-name>
      <servlet>
          <servlet-name>springsim</servlet-name>
          <servlet-class>pro.yizheng.DispatcherServlet</servlet-class>
            <!-- 指定配置文件 -->
          <init-param>
              <param-name>webXmlInitParam-properties</param-name>
              <param-value>application.properties</param-value>
          </init-param>
          <load-on-startup>1</load-on-startup>
      </servlet>
      <servlet-mapping>
          <servlet-name>springsim</servlet-name>
          <url-pattern>/*</url-pattern>
      </servlet-mapping>
    </web-app>
  7. 聲明要用到的Annotationtomcat

    • 涉及到的annotation有: Autowired, Controller, RequestMapping, RequestParam, Service
    • 涉及Annotation知識點
    • 這一步驟
  8. Annotation source code:mvc

    @Documented
    @Retention(RUNTIME)
    @Target(FIELD)
    public @interface SSAutowired {
        String value() default "";
    }
    
    @Documented
    @Retention(RUNTIME)
    @Target({ TYPE})
    public @interface SSController {
        String value() default "";
    }
    
    @Documented
    @Retention(RUNTIME)
    @Target({TYPE,METHOD})
    public @interface SSRequestMapping {
        String value() default "";
    }
    
    @Documented
    @Retention(RUNTIME)
    @Target(PARAMETER)
    public @interface SSRequestParam {
        String value() default "";
    }
    
    @Documented
    @Retention(RUNTIME)
    @Target(TYPE)
    public @interface SSService {
        String value() default "";
    }
  9. 編寫service類, 目的: 模擬spring組件的功能app

    @SSService
    public class Service {
    
        public void get(String name) {
            System.out.println(name);
        }
    }
  10. 編寫Action, 目的: 模擬Springmvc的action, 實際上模擬的Action已經和SpringMVC的相同了this

    @SSController
    @SSRequestMapping("/demo")
    public class DemoAction {
    
        @SSAutowired
        private SSDemoService service;
        
        @SSRequestMapping("/query")
        public void query(HttpServletRequest requeust, HttpServletResponse response,  @SSRequestParam("name") String name) {
            String reString = service.get(name);
            try {
                response.getWriter().write(reString);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        @SSRequestMapping("/add")    
        public void add(HttpServletRequest requeust, HttpServletResponse response, @SSRequestParam("name") String name) {
            try {
                response.getWriter().write("this is add");
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

第二部分, 編寫DispatcherServlet

DispatcherServlet是整個工程的大腦, 它負責整個容器的的初始化, 資源讀取管理和請求分發. url

此工程中, dispatcherServlet分爲如下幾個部分:

  • 初始化容器

    • 遍歷工程全部子節點, 找到並記錄全部Java類型文件, 爲後續解析並獲取annotation註解的方法和變量創造先決條件
    • 從java文件中獲取被Annotation註釋的方法和Field, 並將其記錄
  • 接收並處理請求

    • 根據請求路徑., 找到記錄中對應Action, 經過反射調用Action對應的方法

看起來彷佛很簡單, 但實現起來仍是有一些麻煩的.

下面咱們開始.

  1. 而在init方法中, 第一步須要提取出全部的Java類型文件, 每個文件都要對應一個或多個路徑, 因此咱們先完成遍歷類的方法

    • 新建一個全局map<String, Object>
    private Map<String, Object> javaFiles = new HashMap<>();
    • 遍歷工程, 獲取全部Java類, 此時咱們新建一個方法, 將其從init方法中抽離出來
    // 遍歷全部class文件
    private void scanJavaFiles(String path) {
    
        // 經過application.properties中設定的包名, 找到其下全部的java class文件
        File pathDir = new File(this.getClass().getResource(path).getPath());
        String[] pathList = pathDir.list();
    
        for (String temFile : pathList) {
            File tempFile = new File(pathDir+ "/" + temFile);
            // 若是是目錄的話, 即遞歸操做
            if (tempFile.isDirectory()) {
                scanJavaFiles(path + "/" + temFile);
            }
    
            // 非目錄, 獲得子節點,將其放到全局變量中
            if (temFile.endsWith(".class")) {
                javaFiles.put(path+ "/" + temFile.replace(".class", ""), null);
            }
        }
    }
  2. 編寫初始化方法 - 此方法名沒法更改, 只能是init方法, 這是Servlet規範

    public void init(ServletConfig config) throws ServletException {
        System.out.println("init");
        // 獲取配置文件中的scan package
        InputStream is = this.getClass().getClassLoader().getResourceAsStream(config.getInitParameter("param1"));
        Properties configContext = new Properties();
        try {
            configContext.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
        String scanPackage = configContext.getProperty("path");
    
        // 獲取路徑下的java文件
        scanJavaFiles(scanPackage);
    
        // 第二部分完成
    }
相關文章
相關標籤/搜索