手把手写Spring框架

目录
  • 初始化阶段
  • 运行阶段
    • HandlerAdapter
      • 形参列表:编译后就能拿到值
      • 实参列表:要运行时才能拿到值
      • 最后反射
  • 总结:

    这部分目标是MVC!

    主要完成3个重要组件:

    HandlerMapping:保存URL映射关系

    HandlerAdapter:动态参数适配器

    ViewResolvers:视图转换器,模板引擎

    SpringMVC核心组件执行流程:



    相对应的,用以下几个类来实现上述的功能:

    初始化阶段

    在DispatcherServlet这个类的init方法中,将mvc部分替换为initStrategies(context):


    并且调用初始化三个组件的方法。

    分别完善这几个方法:

    private void initViewResolvers(PigApplicationContext context) {
            //模板引擎的根路径
            String tempateRoot = context.getConfig().getProperty("templateRoot");
            String templateRootPath = this.getClass().getClassLoader().getResource(tempateRoot).getFile();
            File templateRootDir = new File(templateRootPath);
            for (File file : templateRootDir.listFiles()) {
                this.viewResolvers.add(new PIGViewResolver(tempateRoot));
            }
        }
        private void initHandlerAdapters(PigApplicationContext context) {
            for (PIGHandlerMapping handlerMapping : handlerMappings) {
                this.handlerAdapters.put(handlerMapping,new PIGHandlerAdapter());
            }
        }
        private void initHandlerMappings(PigApplicationContext context) {
            if(context.getBeanDefinitionCount() == 0){ return; }
            String [] beanNames = context.getBeanDefinitionNames();
            for (String beanName : beanNames) {
                Object instance = context.getBean(beanName);
                Class<?> clazz = instance.getClass();
                if(!clazz.isAnnotationPresent(PIGController.class)){ continue; }
                String baseUrl = "";
                if(clazz.isAnnotationPresent(PIGRequestMapping.class)){
                    PIGRequestMapping requestMapping = clazz.getAnnotation(PIGRequestMapping.class);
                    baseUrl = requestMapping.value();
                }
                //默认只获取public方法
                for (Method method : clazz.getMethods()) {
                    if(!method.isAnnotationPresent(PIGRequestMapping.class)){continue;}
                    PIGRequestMapping requestMapping = method.getAnnotation(PIGRequestMapping.class);
                    //   //demo//query
                    String regex = ("/" + baseUrl + "/" + requestMapping.value().replaceAll("\\*",".*")).replaceAll("/+","/");
                    Pattern pattern = Pattern.compile(regex);
                    handlerMappings.add(new PIGHandlerMapping(pattern,instance,method));
                    System.out.println("Mapped " + regex + "," + method);
                }
            }
        }
    

    全局变量:

    private List<PIGHandlerMapping> handlerMappings = new ArrayList<PIGHandlerMapping>();

    private Map<PIGHandlerMapping,PIGHandlerAdapter> handlerAdapters = new HashMap<PIGHandlerMapping, PIGHandlerAdapter>();

    private List<PIGViewResolver> viewResolvers = new ArrayList<PIGViewResolver>();

    HandlerMapping与HandlerAdapter是一一对应的关系。

    运行阶段

    整体思路:


    getHandler就是通过请求拿到URI,并与handlerMappings中存好的模板进行匹配:

        private PIGHandlerMapping getHandler(HttpServletRequest req) {
            String url = req.getRequestURI();
            String contextPath = req.getContextPath();
            url = url.replaceAll(contextPath,"").replaceAll("/+","/");
            for (PIGHandlerMapping handlerMapping : this.handlerMappings) {
                Matcher matcher = handlerMapping.getPattern().matcher(url);
                if(!matcher.matches()){continue;}
                return handlerMapping;
            }
            return null;
        }
    

    HandlerAdapter

    HandlerAdapter的handle方法负责反射调用具体方法。需要匹配参数,那么需要先保存好实参和形参列表。

    形参列表:编译后就能拿到值

    Map<String,Integer> paramIndexMapping = new HashMap<String, Integer>();
            //提取加了PIGRequestParam注解的参数的位置
            Annotation[][] pa = handler.getMethod().getParameterAnnotations();
            for (int i = 0; i < pa.length; i ++){
                for (Annotation a : pa[i]) {
                    if(a instanceof PIGRequestParam){
                        String paramName = ((PIGRequestParam) a).value();
                        if(!"".equals(paramName.trim())){
                            paramIndexMapping.put(paramName,i);
                        }
                    }
                }
            }
            //提取request和response的位置
            Class<?> [] paramTypes = handler.getMethod().getParameterTypes();
            for (int i = 0; i < paramTypes.length; i++) {
                Class<?> type = paramTypes[i];
                if(type == HttpServletRequest.class || type == HttpServletResponse.class){
                    paramIndexMapping.put(type.getName(),i);
                }
            }
    

    实参列表:要运行时才能拿到值

     Map<String,String[]> paramsMap = req.getParameterMap();
            //声明实参列表
            Object [] parameValues = new Object[paramTypes.length];
            for (Map.Entry<String,String[]> param : paramsMap.entrySet()) {
                String value = Arrays.toString(paramsMap.get(param.getKey()))
                        .replaceAll("\\[|\\]","")
                        .replaceAll("\\s","");
                if(!paramIndexMapping.containsKey(param.getKey())){continue;}
                int index = paramIndexMapping.get(param.getKey());
                parameValues[index] = caseStringVlaue(value,paramTypes[index]);
            }
            if(paramIndexMapping.containsKey(HttpServletRequest.class.getName())){
                int index = paramIndexMapping.get(HttpServletRequest.class.getName());
                parameValues[index] = req;
            }
            if(paramIndexMapping.containsKey(HttpServletResponse.class.getName())){
                int index = paramIndexMapping.get(HttpServletResponse.class.getName());
                parameValues[index] = resp;
            }
    

    最后反射


    总结:

    本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注的更多内容!

    本文转自网络,如有侵权请联系客服删除。