用300行代码手写提炼Spring的核心原理(V3)

实现V3 版本

在V2 版本中,基本功能以及完全实现,但代码的优雅程度还不如人意。譬如HandlerMapping 还不能像SpringMVC
一样支持正则,url 参数还不支持强制类型转换,在反射调用前还需要重新获取beanName,在V3 版本中,下面我们
继续优化。
首先,改造HandlerMapping,在真实的Spring 源码中,HandlerMapping 其实是一个List 而非Map。List 中的元
素是一个自定义的类型。现在我们来仿真写一段代码,先定义一个内部类Handler 类:

package com.hezhiqin.hand;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.hezhiqin.mvcframework.annotation.HZQRequestParam;

public class HandlerMapping {
	
	public Object controller;//保存方法对应的实例
	public Method method;//保存映射的方法
	public Pattern pattern;
	public Map<String,Integer> paramIndexMapping;//参数顺序
	
	
	
	/**
	*构造一个Handler基本的参数
	* @param controller
	* @param method
	*/
	public HandlerMapping(Object controller, Method method, Pattern pattern) {
		
		this.controller = controller;
		this.method = method;
		this.pattern = pattern;
		paramIndexMapping = new HashMap<String,Integer>();
		putParamIndexMapping(method);

	}



	private void putParamIndexMapping(Method method) {
		// TODO Auto-generated method stub
		//提取方法中加了注解的参数
		Annotation [] [] pa = method.getParameterAnnotations();
		
		for (int i = 0; i < pa.length; i++) {
			
			for (Annotation a : pa[i]) {
				if(a instanceof HZQRequestParam){
					String paramName = ((HZQRequestParam) 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);
			}

		}


	}



	public Class<?>[] getParamTypes() {
		Class<?> [] paramsTypes = method.getParameterTypes();
		return paramsTypes;
	}

}

然后,优化HandlerMapping 的结构,代码如下:

//保存 url 和 Method 的对应关系
//	private Map<String,Method> handlerMapping = new HashMap<String,Method>();
	
	private List<HandlerMapping> handlerMapping = new ArrayList<HandlerMapping>();

修改initHandlerMapping()方法:

private void initHandlerMapping() {
		if(ioc.isEmpty()){ return; }
		for (Entry<String, Object> entry : ioc.entrySet()) {
			Class<?> clazz = entry.getValue().getClass();
			if(!clazz.isAnnotationPresent(HZQController.class)){ continue; }
			String url = "";
			if(clazz.isAnnotationPresent(HZQRequestMapping.class)){
				HZQRequestMapping requestMapping = clazz.getAnnotation(HZQRequestMapping.class);
				url = requestMapping.value();
			}
			
			//获取 Method 的 url 配置
			Method [] methods = clazz.getMethods();
			
			for (Method method : methods) {
				
				//没有加 RequestMapping 注解的直接忽略
				if(!method.isAnnotationPresent(HZQRequestMapping.class)){ continue; }
				//映射 URL
				HZQRequestMapping requestMapping = method.getAnnotation(HZQRequestMapping.class);
				String regex = ("/" + url + requestMapping.value()).replaceAll("/+", "/");
				Pattern pattern = Pattern.compile(regex);
				handlerMapping.add(new HandlerMapping(entry.getValue(),method,pattern));
				System.out.println("mapping " + regex + "," + method);

			}



		}

		
	}

修改doDispatch()方法:

	private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
		 HandlerMapping handler = getHandler(req);
		 if (handler==null) {
			 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());




		
	}


	private HandlerMapping getHandler(HttpServletRequest req) {
		if(handlerMapping.isEmpty()){ return null; }
		String url = req.getRequestURI();
		String contextPath = req.getContextPath();
		url = url.replace(contextPath, "").replaceAll("/+", "/");
		System.out.println("我草拟大爷"+url);
		for (HandlerMapping  handler : handlerMapping) {
			Matcher matcher = handler.pattern.matcher(url);
			System.out.println(matcher.matches());
			//如果没有匹配上继续下一个匹配
			if(!matcher.matches()){ continue; }
			return handler;
		}
		return null;
		

	}


	private Object convert(Class<?> type,String value){
		if(Integer.class == type){
			return Integer.valueOf(value);
		}
		return value;
	}

在以上代码中,增加了两个方法,一个是getHandler()方法,主要负责处理url 的正则匹配;一个是
convert()方法,主要负责url 参数的强制类型转换。
至此,手写Mini 版SpringMVC 框架就已全部完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值