當前位置:
首頁 >
前端技术
> javascript
>内容正文
javascript
Spring容器初始化实现V3 版本
生活随笔
收集整理的這篇文章主要介紹了
Spring容器初始化实现V3 版本
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
在V2 版本中,基本功能以及完全實現,但代碼的優雅程度還不如人意。譬如HandlerMapping 還不能像SpringMVC一樣支持正則,url 參數還不支持強制類型轉換,在反射調用前還需要重新獲取beanName,在V3 版本中,下面我們繼續優化。
首先,改造HandlerMapping,在真實的Spring 源碼中,HandlerMapping 其實是一個List 而非Map。List 中的元素是一個自定義的類型。現在我們來仿真寫一段代碼,先定義一個內部類Handler 類:
//保存一個url和一個Method的關系 public class Handler {//必須把url放到HandlerMapping才好理解吧private Pattern pattern; //正則private Method method;private Object controller;private Class<?> [] paramTypes;public Pattern getPattern() {return pattern;}public Method getMethod() {return method;}public Object getController() {return controller;}public Class<?>[] getParamTypes() {return paramTypes;}//形參列表//參數的名字作為key,參數的順序,位置作為值private Map<String,Integer> paramIndexMapping;public Handler(Pattern pattern, Object controller, Method method) {this.pattern = pattern;this.method = method;this.controller = controller;paramTypes = method.getParameterTypes();paramIndexMapping = new HashMap<String, Integer>();putParamIndexMapping(method);}private void putParamIndexMapping(Method method){//提取方法中加了注解的參數//把方法上的注解拿到,得到的是一個二維數組//因為一個參數可以有多個注解,而一個方法又有多個參數Annotation [] [] pa = method.getParameterAnnotations();for (int i = 0; i < pa.length ; i ++) {for(Annotation a : pa[i]){if(a instanceof GPRequestParam){String paramName = ((GPRequestParam) a).value();if(!"".equals(paramName.trim())){paramIndexMapping.put(paramName, i);}}}}//提取方法中的request和response參數Class<?> [] paramsTypes = method.getParameterTypes();for (int i = 0; i < paramsTypes.length ; i ++) {Class<?> type = paramsTypes[i];if(type == HttpServletRequest.class ||type == HttpServletResponse.class){paramIndexMapping.put(type.getName(),i);}}}// private }然后,優化HandlerMapping 的結構,代碼如下:
//思考:為什么不用Map //你用Map的話,key,只能是url //Handler 本身的功能就是把url和method對應關系,已經具備了Map的功能 //根據設計原則:冗余的感覺了,單一職責,最少知道原則,幫助我們更好的理解 private List<Handler> handlerMapping = new ArrayList<Handler>();修改initHandlerMapping()方法:
//初始化url和Method的一對一對應關系 private void initHandlerMapping() {if(ioc.isEmpty()){ return; }for (Map.Entry<String, Object> entry : ioc.entrySet()) {Class<?> clazz = entry.getValue().getClass();if(!clazz.isAnnotationPresent(GPController.class)){continue;}//保存寫在類上面的@GPRequestMapping("/demo")String baseUrl = "";if(clazz.isAnnotationPresent(GPRequestMapping.class)){GPRequestMapping requestMapping = clazz.getAnnotation(GPRequestMapping.class);baseUrl = requestMapping.value();}//默認獲取所有的public方法for (Method method : clazz.getMethods()) {if(!method.isAnnotationPresent(GPRequestMapping.class)){continue;}GPRequestMapping requestMapping = method.getAnnotation(GPRequestMapping.class);//優化// //demo///queryString regex = ("/" + baseUrl + "/" + requestMapping.value()).replaceAll("/+","/");Pattern pattern = Pattern.compile(regex);this.handlerMapping.add(new Handler(pattern,entry.getValue(),method)); // handlerMapping.put(url,method);System.out.println("Mapped :" + pattern + "," + method);}}}修改doDispatch()方法:
private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {Handler handler = getHandler(req);if(handler == null){ // if(!this.handlerMapping.containsKey(url)){resp.getWriter().write("404 Not Found!!!");return;}//獲得方法的形參列表Class<?> [] paramTypes = handler.getParamTypes();Object [] paramValues = new Object[paramTypes.length];Map<String,String[]> params = req.getParameterMap();for (Map.Entry<String, String[]> parm : params.entrySet()) {String value = Arrays.toString(parm.getValue()).replaceAll("\\[|\\]","").replaceAll("\\s",",");if(!handler.paramIndexMapping.containsKey(parm.getKey())){continue;}int index = handler.paramIndexMapping.get(parm.getKey());paramValues[index] = convert(paramTypes[index],value);}if(handler.paramIndexMapping.containsKey(HttpServletRequest.class.getName())) {int reqIndex = handler.paramIndexMapping.get(HttpServletRequest.class.getName());paramValues[reqIndex] = req;}if(handler.paramIndexMapping.containsKey(HttpServletResponse.class.getName())) {int respIndex = handler.paramIndexMapping.get(HttpServletResponse.class.getName());paramValues[respIndex] = resp;}Object returnValue = handler.method.invoke(handler.controller,paramValues);if(returnValue == null || returnValue instanceof Void){ return; }resp.getWriter().write(returnValue.toString()); }在以上代碼中,增加了兩個方法,一個是getHandler()方法,主要負責處理url 的正則匹配;一個是convert()方法,主要負責url 參數的強制類型轉換。至此,手寫Mini 版SpringMVC 框架就已全部完成。
?
總結
以上是生活随笔為你收集整理的Spring容器初始化实现V3 版本的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring容器初始化实现V2 版本
- 下一篇: 再谈IOC 与DI