javascript
Spring容器初始化实现V3 版本
在V2 版本中,基本功能以及完全實(shí)現(xiàn),但代碼的優(yōu)雅程度還不如人意。譬如HandlerMapping 還不能像SpringMVC一樣支持正則,url 參數(shù)還不支持強(qiáng)制類型轉(zhuǎn)換,在反射調(diào)用前還需要重新獲取beanName,在V3 版本中,下面我們繼續(xù)優(yōu)化。
首先,改造HandlerMapping,在真實(shí)的Spring 源碼中,HandlerMapping 其實(shí)是一個(gè)List 而非Map。List 中的元素是一個(gè)自定義的類型。現(xiàn)在我們來(lái)仿真寫一段代碼,先定義一個(gè)內(nèi)部類Handler 類:
//保存一個(gè)url和一個(gè)Method的關(guān)系 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;}//形參列表//參數(shù)的名字作為key,參數(shù)的順序,位置作為值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){//提取方法中加了注解的參數(shù)//把方法上的注解拿到,得到的是一個(gè)二維數(shù)組//因?yàn)橐粋€(gè)參數(shù)可以有多個(gè)注解,而一個(gè)方法又有多個(gè)參數(shù)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參數(shù)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 }然后,優(yōu)化HandlerMapping 的結(jié)構(gòu),代碼如下:
//思考:為什么不用Map //你用Map的話,key,只能是url //Handler 本身的功能就是把url和method對(duì)應(yīng)關(guān)系,已經(jīng)具備了Map的功能 //根據(jù)設(shè)計(jì)原則:冗余的感覺(jué)了,單一職責(zé),最少知道原則,幫助我們更好的理解 private List<Handler> handlerMapping = new ArrayList<Handler>();修改initHandlerMapping()方法:
//初始化url和Method的一對(duì)一對(duì)應(yīng)關(guān)系 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();}//默認(rèn)獲取所有的public方法for (Method method : clazz.getMethods()) {if(!method.isAnnotationPresent(GPRequestMapping.class)){continue;}GPRequestMapping requestMapping = method.getAnnotation(GPRequestMapping.class);//優(yōu)化// //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()); }在以上代碼中,增加了兩個(gè)方法,一個(gè)是getHandler()方法,主要負(fù)責(zé)處理url 的正則匹配;一個(gè)是convert()方法,主要負(fù)責(zé)url 參數(shù)的強(qiáng)制類型轉(zhuǎn)換。至此,手寫Mini 版SpringMVC 框架就已全部完成。
?
總結(jié)
以上是生活随笔為你收集整理的Spring容器初始化实现V3 版本的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Spring容器初始化实现V2 版本
- 下一篇: Spring 核心容器类BeanFact