package cn.nosum.framework.mvc.v3.servlet; import cn.nosum.framework.annotation.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.URL; import java.util.*; public class GPDispatcherServlet extends HttpServlet { //保存application.properties配置文件中的内容 private Properties contextConfig = new Properties(); //保存扫描的所有的类名 private List classNames = new ArrayList(); // IOC容器 private Map ioc = new HashMap(); // 保存url和Method的对应关系 private List handlerMapping = new ArrayList(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //6、调用,运行阶段 try { doDispatch(req, resp); } catch (Exception e) { e.printStackTrace(); resp.getWriter().write("500 Exection,Detail : " + Arrays.toString(e.getStackTrace())); } } private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception { Handler handler = getHandler(req); if (handler == null) { resp.getWriter().write("404 Not Found!!!"); return; } //获得方法的形参列表 Class[] paramTypes = handler.getParamTypes(); Object[] paramValues = new Object[paramTypes.length]; Map params = req.getParameterMap(); for (Map.Entry 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 Handler getHandler(HttpServletRequest req) { if (handlerMapping.isEmpty()) { return null; } // 绝对路径 String url = req.getRequestURI(); // 处理成相对路径 String contextPath = req.getContextPath(); url = url.replaceAll(contextPath, "").replaceAll("/+", "/"); for (Handler handler : this.handlerMapping) { Matcher matcher = handler.getPattern().matcher(url); if (!matcher.matches()) { continue; } return handler; } return null; } //url传过来的参数都是String类型的,HTTP是基于字符串协议 //只需要把String转换为任意类型就好 private Object convert(Class type, String value) { //如果是int if (Integer.class == type) { return Integer.valueOf(value); } else if (Double.class == type) { return Double.valueOf(value); } //如果还有double或者其他类型,继续加if //这时候,我们应该想到策略模式了 //在这里暂时不实现,希望小伙伴自己来实现 return value; } //初始化阶段 @Override public void init(ServletConfig config) throws ServletException { //1、加载配置文件 doLoadConfig(config.getInitParameter("contextConfigLocation")); //2、扫描相关的类 doScanner(contextConfig.getProperty("scanPackage")); //3、初始化扫描到的类,并且将它们放入到ICO容器之中 doInstance(); //4、完成依赖注入 doAutowired(); //5、初始化HandlerMapping initHandlerMapping(); System.out.println("Spring framework is init."); } //初始化url和Method的一对一对应关系 private void initHandlerMapping() { if (ioc.isEmpty()) { return; } for (Map.Entry entry : ioc.entrySet()) { Class clazz = entry.getValue().getClass(); if (!clazz.isAnnotationPresent(Controller.class)) { continue; } //保存写在类上面的@GPRequestMapping("/demo") String baseUrl = ""; if (clazz.isAnnotationPresent(RequestMapping.class)) { RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class); baseUrl = requestMapping.value(); } //默认获取所有的 public方法 for (Method method : clazz.getMethods()) { if (!method.isAnnotationPresent(RequestMapping.class)) { continue; } RequestMapping requestMapping = method.getAnnotation(RequestMapping.class); //优化 String regex = ("/" + baseUrl + "/" + requestMapping.value()).replaceAll("/+", "/"); Pattern pattern = Pattern.compile(regex); this.handlerMapping.add(new Handler(pattern, entry.getValue(), method)); System.out.println("Mapped :" + pattern + "," + method); } } } //自动依赖注入 private void doAutowired() { if (ioc.isEmpty()) { return; } for (Map.Entry entry : ioc.entrySet()) { //Declared 所有的,特定的 字段,包括 private/protected/default //正常来说,普通的OOP编程只能拿到public的属性 Field[] fields = entry.getValue().getClass().getDeclaredFields(); for (Field field : fields) { if (!field.isAnnotationPresent(Autowired.class)) { continue; } Autowired autowired = field.getAnnotation(Autowired.class); //如果用户没有自定义beanName,默认就根据类型注入 //这个地方省去了对类名首字母小写的情况的判断,这个作为课后作业 //小伙伴们自己去完善 String beanName = autowired.value().trim(); if ("".equals(beanName)) { //获得接口的类型,作为key待会拿这个key到ioc容器中去取值 beanName = field.getType().getName(); } //如果是public以外的修饰符,只要加了@Autowired注解,都要强制赋值 //反射中叫做暴力访问, 强吻 field.setAccessible(true); try { //用反射机制,动态给字段赋值 field.set(entry.getValue(), ioc.get(beanName)); } catch (IllegalAccessException e) { e.printStackTrace(); } } } } private void doInstance() { //初始化,为DI做准备 if (classNames.isEmpty()) { return; } try { for (String className : classNames) { Class clazz = Class.forName(className); if (clazz.isAnnotationPresent(Controller.class)) { Object instance = clazz.newInstance(); String beanName = toLowerFirstCase(clazz.getSimpleName()); ioc.put(beanName, instance); } else if (clazz.isAnnotationPresent(Service.class)) { Service service = clazz.getAnnotation(Service.class); String beanName = service.value(); if ("".equals(beanName.trim())) { beanName = toLowerFirstCase(clazz.getSimpleName()); } Object instance = clazz.newInstance(); ioc.put(beanName, instance); for (Class i : clazz.getInterfaces()) { if (ioc.containsKey(i.getName())) { throw new Exception("The “" + i.getName() + "” is exists!!"); } ioc.put(i.getName(), instance); } } else { continue; } } } catch (Exception e) { e.printStackTrace(); } } //扫描出相关的类 private void doScanner(String scanPackage) { URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.", "/")); File classPath = new File(url.getFile()); for (File file : classPath.listFiles()) { if (file.isDirectory()) { doScanner(scanPackage + "." + file.getName()); } else { if (!file.getName().endsWith(".class")) { continue; } String className = (scanPackage + "." + file.getName().replace(".class", "")); classNames.add(className); } } } //加载配置文件 private void doLoadConfig(String contextConfigLocation) { // 直接从类路径下找到Spring主配置文件所在的路径 // 并且将其读取出来放到Properties对象中 // 相对于scanPackage=cn.nosum.demo 从文件中保存到了内存中 InputStream fis = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation); try { contextConfig.load(fis); } catch (IOException e) { e.printStackTrace(); } finally { if (null != fis) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } public class Handler { private Pattern pattern; //正则 private Method method; private Object controller; private Class[] paramTypes; // 形参列表 // 参数的名字作为key,参数的顺序,位置作为值 private Map paramIndexMapping; public Handler(Pattern pattern, Object controller, Method method) { this.pattern = pattern; this.method = method; this.controller = controller; paramTypes = method.getParameterTypes(); paramIndexMapping = new HashMap(); putParamIndexMapping(method); } /** * 提取方法中加了注解的参数并且保存 */ private void putParamIndexMapping(Method method) { // 取得方法中参数的注解,得到的是一个二维数组 // 一个方法有多个参数,一个参数可以有多个注解 Annotation[][] pa = method.getParameterAnnotations(); for (int i = 0; i < pa.length; i++) { for (Annotation annotation : pa[i]) { if (annotation instanceof RequestParam) { String paramName = ((RequestParam) annotation).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 Pattern getPattern() { return pattern; } public Method getMethod() { return method; } public Object getController() { return controller; } public Class[] getParamTypes() { return paramTypes; } } private String toLowerFirstCase(String simpleName) { char[] chars = simpleName.toCharArray(); chars[0] += 32; return String.valueOf(chars); } }