一 SpringMVC 流程图
DispatcherServlet是前端控制器设计模式的实现,提供Spring Web MVC的集中访问点,而且负责职责的分派,而且与Spring IoC容器无缝集成,从而可以获得Spring的所有好处。
自己实现了一个dispatcherServlet,希望帮助大家理解DispatcherServlet的实现原理。目录如下(后面会重构,结构会有所变化)
构)
二 注解
模仿SpringMVC ,自定义 ,,@AutoWired,@RequestMapping
@Service
@RequestMapping
@AutoWired
三 DispatcherServlet
SpringMVC 同样要遵循JAVA EE 规范。所以DispatcherServlet 要继承HttpServlet。
实现代码如下
package servlet;import com.dsk.annotation.Autowired;import com.dsk.annotation.Controller;import com.dsk.annotation.RequestMapping;import com.dsk.annotation.Service;import com.dsk.controller.ControllerTest;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;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.lang.reflect.Field;import java.lang.reflect.Method;import java.net.URL;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/** * Created by dingshuangkun on 2018/1/29. */public class Dispatcherservlet extends HttpServlet { private volatile ListclassNameList = new ArrayList<>(); private volatile Map instanceMap = new HashMap<>(); /** * @throws ServletException 1 扫描基包 */ @Override public void init() throws ServletException { String baseScan = "com.dsk.controller,com.dsk.service"; // 扫描基包 获取包名加类名 Map > packageMap = scanFile(baseScan); try { for(Map.Entry > entry : packageMap.entrySet()){ String packageName = entry.getKey(); List classNames = entry.getValue(); // 4 实例化(包名+类名) Class.forName() newInstance(packageName,classNames); } // 实现IOC 注入 Ioc(instanceMap); }catch (Exception e){ throw new RuntimeException(e.getMessage()); } } private Map > scanFile(String baseScan) { Map > packageMap = new HashMap<>(); // 分割 com.dsk.controller 和 com.dsk.service String[] paths = baseScan.split(","); // 替换为 com/dsk/controller for (String path : paths) { String filePath = "/" + path.replaceAll("\\.", "\\/"); // 1 加载资源 URL url = this.getClass().getClassLoader().getResource(filePath); // 2 获取全路径名 String urlPath = url.getFile(); // 3 处理路径 得到包下面的类 List classNames = handleFile(urlPath); // 4 分组 根据包名分组 for(String className : classNames){ packageMap.putIfAbsent(path,new ArrayList<>()); packageMap.get(path).add(className); } classNameList.clear(); } return packageMap; } /** * 处理路径 * * @param urlPath */ private List handleFile(String urlPath) { File file = new File(urlPath); if (file.isDirectory()) { String[] paths = file.list(); for (String path : paths) { // 可能是文件也可能是文件夹 递归处理 handleFile(urlPath + path); } } else { classNameList.add(file.getName().replace(".class", "")); } return classNameList; } /** * 实例化 * 1 通过包名+类名 获取Class 对象 * 2 获取注解信息@Controller 和 @Service * 3 实例化 放入容器Map中 */ private void newInstance(String packageName, List classNames) throws Exception { if (classNames != null && classNames.size() != 0) { for (String className : classNames) { String name = packageName + "." + className; Class cc = Class.forName(packageName + "." + className); // 判断类上是否有@Controller if (cc.isAnnotationPresent(Controller.class)) { Controller controller = (Controller) cc.getAnnotation(Controller.class); // 获取注解的值 String value = controller.value(); if (value != null && value.length() > 0) { // 把实例存放到容器中 instanceMap.put(value, cc.newInstance()); } else { // 第一个字母转小写(还没实现) instanceMap.put(className, cc.newInstance()); } } else if (cc.isAnnotationPresent(Service.class)) { Service service = (Service) cc.getAnnotation(Service.class); String value = service.value(); if (value != null && value.length() > 0) { // 把实例存放到容器中 instanceMap.put(value, cc.newInstance()); } else { // 第一个字母转小写(还没实现) instanceMap.put(className, cc.newInstance()); } } } } } /** * IOC 注入 * 1 遍历 Map 获取对象 * 2 反射 获取字段 * 3 给带有@Autowired 注解的字段实例化 */ private void Ioc(Map instanceMap) throws IllegalAccessException { if (instanceMap == null || instanceMap.size() == 0) { return; } for (Map.Entry entry : instanceMap.entrySet()) { Object obj = entry.getValue(); // 获取Class 对象 Class cc = obj.getClass(); // 获取声明的字段 Field[] fields = cc.getDeclaredFields(); if (fields != null && fields.length > 0) { for (Field field : fields) { // 判读是否带有注解 Autowired if (field.isAnnotationPresent(Autowired.class)) { field.setAccessible(true); Autowired autowired = field.getAnnotation(Autowired.class); // 从容器中获取对象 Object instance = instanceMap.get(autowired.value()); field.set(obj, instance); } } } } } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String url = req.getServletPath(); try { parseUrl(url); } catch (Exception e) { throw new RuntimeException(e.getMessage()); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("-----doPost------"); } private void parseUrl(String url) throws Exception { String path = url.subSequence(1, url.length()).toString(); String[] params = path.split("/"); if (params.length != 2) { return; } for (Map.Entry entry : instanceMap.entrySet()) { Class cc = entry.getValue().getClass(); // 判读类上是否有@Controller 和 @RequestMapping 注解 if (cc.isAnnotationPresent(Controller.class) && cc.isAnnotationPresent(RequestMapping.class)) { RequestMapping requestMapping = (RequestMapping) cc.getAnnotation(RequestMapping.class); // 获取@RequestMapping 的值 String paramValue = requestMapping.value(); if (paramValue != null && paramValue.length() > 0) { // localhost:8080/test/test params=test,test // 判读 类上 @RequestMapping的值是否和 params[0] 相等 if (paramValue.equals(params[0])) { // 获取该类的方法 Method[] methods = cc.getMethods(); if (methods != null && methods.length > 0) { for (Method method : methods) { // 判读方法上是否有@RequestMapping 注解 if (method.isAnnotationPresent(RequestMapping.class)) { RequestMapping rem = method.getAnnotation(RequestMapping.class); // 获取方法上@RequestMapping 的值 String methodParam = rem.value(); if (methodParam != null && methodParam.length() > 0) { // 方法上@RequestMapping 的值methodParam 和 params[1] 是否相等 if (methodParam.equals(params[1])) { method.invoke(entry.getValue(), null); } } } } } } } } } }}
测试类
package com.dsk.controller;import com.dsk.annotation.Autowired;import com.dsk.annotation.Controller;import com.dsk.annotation.RequestMapping;import com.dsk.service.MyService;/** * Created by dingshuangkun on 2018/1/29. */@Controller("controllerTest")@RequestMapping("test")public class ControllerTest { @Autowired("myService") private MyService myService; @RequestMapping("test") public void test(){ System.out.println("--------------"); System.out.println("---- ****** ---"); System.out.println("---*********----"); System.out.println("-----------------"); }}
package com.dsk.service;import com.dsk.annotation.Service;/** * Created by dingshuangkun on 2018/1/29. */@Service("myService")public class MyService { public void test(){ System.out.println("----serviceTest----"); }}
配置文件
myservlet servlet.Dispatcherservlet myservlet /
浏览器输入
http://localhost:8080/test/test
输出
--------------
---- ****** --- ---*********---- -----------------