手把手寫Spring框架
這部分目標是MVC!
主要完成3個重要組件:
HandlerMapping:保存URL映射關系
HandlerAdapter:動態(tài)參數適配器
ViewResolvers:視圖轉換器,模板引擎
SpringMVC核心組件執(zhí)行流程:
相對應的,用以下幾個類來實現(xiàn)上述的功能:
初始化階段
在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; }
最后反射
總結:
本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關注腳本之家的更多內容!
相關文章
Spring中ApplicationEventPublisher發(fā)布訂閱模式的實現(xiàn)
本文主要介紹了Spring中ApplicationEventPublisher發(fā)布訂閱模式的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-07-07maven項目中<scope>provided</scope>的作用及說明
這篇文章主要介紹了maven項目中<scope>provided</scope>的作用及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12