[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, ②拦截所有请求

    
    
      SpringSim2
      
          springsim2
          com.spring.sim.DispatcherServlet
      
      
          springsim2
          /*
      
    
  5. src下创建application.properties, 指定需要被扫描的包

    path=com.spring.sim
  6. web.xml中将properties文件设置为启动时被load

    ⚠ 此步骤为可选, 在DispatcherServlet中声明也可以

    此步完成后, web.xml不需要再改动

    
    
      SpringSimv1
      
          springsim
          pro.yizheng.DispatcherServlet
            
          
              webXmlInitParam-properties
              application.properties
          
          1
      
      
          springsim
          /*
      
    
  7. 声明要用到的Annotation

    • 涉及到的annotation有: Autowired, Controller, RequestMapping, RequestParam, Service
    • 涉及Annotation知识点
    • 这一步骤
  8. Annotation source code:

    @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组件的功能

    @SSService
    public class Service {
    
        public void get(String name) {
            System.out.println(name);
        }
    }
  10. 编写Action, 目的: 模拟Springmvc的action, 实际上模拟的Action已经和SpringMVC的相同了

    @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是整个工程的大脑, 它负责整个容器的的初始化, 资源读取管理和请求分发.

此工程中, dispatcherServlet分为以下几个部分:

  • 初始化容器

    • 遍历工程所有子节点, 找到并记录所有Java类型文件, 为后续解析并获取annotation注解的方法和变量创造先决条件
    • 从java文件中获取被Annotation注释的方法和Field, 并将其记录
  • 接收并处理请求

    • 根据请求路径., 找到记录中对应Action, 通过反射调用Action对应的方法

看起来似乎很简单, 但实现起来还是有一些麻烦的.

下面我们开始.

  1. 而在init方法中, 第一步需要提取出所有的Java类型文件, 每一个文件都要对应一个或多个路径, 所以我们先完成遍历类的方法

    • 新建一个全局map
    private Map 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);
    
        // 第二部分完成
    }

你可能感兴趣的:(spring-mvc)