简单设计实践spring框架(手写spring)

目录

1 应用spring的流程

2 梳理设计思路

3 coding spring实战

核心流程:

Step1 配置依赖(仅仅依赖servlet-api包)

Step2 定义一个核心控制器

Step3 自定义一些类spring的注解

Step4 配置容器启动时的初始化

Step5 执行请求,请求分发

Step6 启动

Step7 验证功能

4 源码?just do it 动手实践吧

公众号搜索:DeanKano

企鹅群号: 561932405


应用spring的流程

 

简单设计实践spring框架(手写spring)_第1张图片

 


 

梳理设计思路

 

简单设计实践spring框架(手写spring)_第2张图片

 

coding spring实战

 

核心流程:

Step1 配置依赖(仅仅依赖servlet-api包)


    javax.servlet
    servlet-api
    2.4

Step2 定义一个核心控制器

DkDispatcherServlet extends HttpServlet {...}

在web.xml配置核心控制器

 
    
        dkDispatcher
        com.dean.framework.DkDispatcherServlet
        
            contextConfigLocation
            classpath:application.properties
        
        1
    
    
        dkDispatcher
        /*
    

Step3 自定义一些类spring的注解

@DkController

@DkService

@DkAutowired

@DkRequestMapping

@DkRequestParam

Step4 配置容器启动时的初始化

// 启动DkDispatcherServlet做初始化@Overridepublic void init(ServletConfig config) throws ServletException {    // 1 加载配置文件    doLoadConfig(config.getInitParameter("contextConfigLocation"));    // 2 扫描配置包路径    doScanner(contextConfig.getProperty("scanPackage"));    // 3 反射实例化加载到IOC容器中    doInstance();    // 4 DI依赖注入,针对IOC容器中加载到的类,自动对需要赋值的属性进行初始化操作    doAutowired();    // 5 初始化HandlerMapping    initHandlerMapping();}
privatevoid doLoadConfig(String contextConfigLocation) {    contextConfigLocation = contextConfigLocation.replace("classpath:", EMPTY_STRING);    try (InputStream resourceAsStream = this.getClass().getClassLoader()            .getResourceAsStream(contextConfigLocation)) {        contextConfig.load(resourceAsStream);    } catch (Exception e) {        e.printStackTrace();    }}
private void doScanner(String scanPackage) {    URL url = this.getClass().getClassLoader().getResource(            SLASH_STRING + scanPackage.replaceAll("\\.", SLASH_STRING));    if (url == null) return;    File classDir = new File(url.getFile());    for (File file : classDir.listFiles()) {        if (file.isDirectory()) {            doScanner(scanPackage + SPOT_STRING + file.getName());        } else {            String className = scanPackage + SPOT_STRING +                    file.getName().replace(".class", EMPTY_STRING);            classNames.add(className);        }    }}
private void doInstance() {
  if (classNames.isEmpty()) return;
  for (String className : classNames) {
      try {
          Class clazz = Class.forName(className);
          if (clazz.isInterface()) continue;
          // 针对指定扫描到的包进行实例化
          // 默认bean名称是类名的首字母小写
          String beanName = getFirstLower(clazz.getName());
          Object newInstance = clazz.newInstance();
          if (clazz.isAnnotationPresent(DkController.class)) {
              // 指定了bean名称
              DkController dkController = clazz.getAnnotation(DkController.class);
              if (!EMPTY_STRING.equals(dkController.value())) {
                  beanName = dkController.value();
              }

          } else if (clazz.isAnnotationPresent(DkService.class)) {
              // 指定bean名称
              DkService dkService = clazz.getAnnotation(DkService.class);
              if (!EMPTY_STRING.equals(dkService.value())) {
                  beanName = dkService.value();
              }

              // 针对接口的,bean名称用接口的名称
              Class[] interfaces = clazz.getInterfaces();
              if (interfaces.length == 1) {
                  for (Class anInterface : interfaces) {
                      beanName = getFirstLower(anInterface.getName());
                  }
              } else if (interfaces.length > 1) {
                  // TODO 多接口
              }

          } else {
              continue;
          }
          ioc.put(beanName, newInstance);
      } catch (Exception e) {
          e.printStackTrace();
      }
  }
}
private void doAutowired() {
  if (ioc.isEmpty()) return;
  for (Map.Entry entry : ioc.entrySet()) {
      Field[] declaredFields = entry.getValue().getClass().getDeclaredFields();
      for (Field declaredField : declaredFields) {
          if (!declaredField.isAnnotationPresent(DkAutowired.class)) {
              continue;
          }
          String beanName = getFirstLower(declaredField.getType().getName());
          DkAutowired annotation = declaredField.getAnnotation(DkAutowired.class);
          if (!EMPTY_STRING.equals(annotation.value())) {
              beanName = annotation.value();
          }
          try {
              declaredField.setAccessible(true);
              declaredField.set(entry.getValue(), ioc.get(beanName));
          } catch (IllegalAccessException e) {
              e.printStackTrace();
              continue;
          }
      }
  }
}
private void initHandlerMapping() {
  if (ioc.isEmpty()) return;
  for (Map.Entry entry : ioc.entrySet()) {
      Class clazz = entry.getValue().getClass();
      if (!clazz.isAnnotationPresent(DkController.class)) {
          continue;
      }
      String baseUrl = EMPTY_STRING;
      if (clazz.isAnnotationPresent(DkRequestMapping.class)) {
          DkRequestMapping dkRequestMapping = clazz.getAnnotation(DkRequestMapping.class);
          baseUrl = dkRequestMapping.value();
      }

      for (Method method : clazz.getMethods()) {
          if (!method.isAnnotationPresent(DkRequestMapping.class)) {
              continue;
          }
          DkRequestMapping dkRequestMapping = method.getAnnotation(DkRequestMapping.class);
          String regexUrl = (SLASH_STRING + baseUrl + dkRequestMapping.value()).replaceAll("/+", SLASH_STRING);
          Pattern pattern = Pattern.compile(regexUrl);
          handlerMapping.add(new Handler(method, entry.getValue(), pattern));
          System.out.println("Mapping: [" + regexUrl + "] ==>" + method);
      }
  }
}

Step5 执行请求,请求分发

private voiddoDispatcher(HttpServletRequest req, HttpServletResponse resp) throws InvocationTargetException, IllegalAccessException, IOException {
    Handler handler = retrieveHandler(req);
    if (handler == null) {
        resp.getWriter().write("404 NOT FOUND");
        return;
    }

    Object[] paramValues = new Object[handler.method.getParameterTypes().length];
    // String[]可能多个参数,例如:?name=tom&name=jaine
    Map reqParams = req.getParameterMap();
    for (Map.Entry stringEntry : reqParams.entrySet()) {
        String paramName = stringEntry.getKey();
        if (!handler.paramsIndexMapping.keySet().contains(paramName)) {
            continue;
        }

        int paramIndex = handler.paramsIndexMapping.get(paramName);
        paramValues[paramIndex] = Arrays.toString(stringEntry.getValue()).replaceAll("\\[|\\]", EMPTY_STRING);
    }

    int respIndex = handler.paramsIndexMapping.get(HttpServletResponse.class.getName());
    int reqIndex = handler.paramsIndexMapping.get(HttpServletRequest.class.getName());
    paramValues[reqIndex] = req;
    paramValues[respIndex] = resp;
    handler.method.invoke(handler.controller, paramValues);
}

doDispatcher(req, resp);

Step6 启动

一 直接运行maven 插件 jetty:run

二 命令行启动,在cmd窗口执行:

  `$mvn jetty:run`

Step7 验证功能

启动日志:

...
[INFO] Starting jetty 6.1.7 ...
[INFO] jetty-6.1.7
[INFO] No Transaction manager found - if your webapp requires one, please configure one.
Mapping: [/sample/query.do] ==>public void com.dean.framework.sample.UserAction.query(java.lang.String,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
Mapping: [/sample/add.do] ==>public void com.dean.framework.sample.UserAction.addUser(java.lang.String,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
Mapping: [/sample/remove.do] ==>public void com.dean.framework.sample.UserAction.removeUser(java.lang.String,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
[INFO] Started [email protected]:8080
[INFO] Started Jetty Server

 

请求示例:

http://localhost:8080/sample/query.do?name=Tom

 

源码?just do it 动手实践吧

源码地址: https://github.com/lingqibaobei/rangers-framework-spring

公众号搜索:DeanKano

简单设计实践spring框架(手写spring)_第3张图片

企鹅群号: 561932405

简单设计实践spring框架(手写spring)_第4张图片

 

你可能感兴趣的:(架构师之路,spring,手写,造轮子,coding,coding,spring)