波及知识点:

  • slf4j
  • java annotation如何定义
  • 通过classloader获取java文件的门路等信息 - https://www.cnblogs.com/seven...
  • map遍历 https://blog.csdn.net/tjcyjd/... 办法二
  • class.forname实例化 https://www.cnblogs.com/shosk...
  • java 反射中的调用办法 - https://www.cnblogs.com/qingc...
  • java 获取我的项目门路的形式

第一局部, 工程根底配置

  1. 创立Dynamic web工程
  2. 为工程增加runtime librariy. 目标: 为了实现servlet性能 (次要须要其中的servlet-api等jar文件) 此为servlet基础知识.

  3. 创立DispatcherServlet并继承HttpServlet
  4. web.xml中申明此dispatcherServlet, 目标: ①示意这是个会被tomcat容器辨认的servlet, ②拦挡所有申请

    <?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, 指定须要被扫描的包

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

    ⚠ 此步骤为可选, 在DispatcherServlet中申明也能够

    此步实现后, web.xml不须要再改变

    <?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. 申明要用到的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组件的性能

    @SSServicepublic 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办法, 这是Servlet标准

    而在init办法中, 第一步须要提取出所有的Java类型文件, 每一个文件都要对应一个或多个门路, 所以咱们

    • 新建一个全局map<String, Object>
    private Map<String, Object> javaFiles = new HashMap<>();
    • 遍历工程, 获取所有Java类, 此时咱们新建一个办法, 将其从init办法中抽离进去
     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);         }     } }