DispatcherServlet是前端控制器设计模式的实现,提供Spring Web MVC的集中访问点,并且负责职责的分派,并且与Spring IoC容器无缝集成,从而能够得到Spring的全部好处。前端
本身实现了一个dispatcherServlet,但愿帮助你们理解DispatcherServlet的实现原理。目录以下(后面会重构,结构会有所变化)java
构)web
模仿SpringMVC ,自定义@Controller ,@Service,@AutoWired,@RequestMapping设计模式
@Controller浏览器
@Serviceapp
@RequestMappingide
@AutoWired测试
SpringMVC 一样要遵循JAVA EE 规范。因此DispatcherServlet 要继承HttpServlet。this
实现代码以下url
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 List<String> classNameList = new ArrayList<>(); private volatile Map<String, Object> instanceMap = new HashMap<>(); /** * @throws ServletException 1 扫描基包 */ @Override public void init() throws ServletException { String baseScan = "com.dsk.controller,com.dsk.service"; // 扫描基包 获取包名加类名 Map<String, List<String>> packageMap = scanFile(baseScan); try { for(Map.Entry<String,List<String>> entry : packageMap.entrySet()){ String packageName = entry.getKey(); List<String> classNames = entry.getValue(); // 4 实例化(包名+类名) Class.forName() newInstance(packageName,classNames); } // 实现IOC 注入 Ioc(instanceMap); }catch (Exception e){ throw new RuntimeException(e.getMessage()); } } private Map<String, List<String>> scanFile(String baseScan) { Map<String, List<String>> 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<String> 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<String> 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<String> 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<String, Object> instanceMap) throws IllegalAccessException { if (instanceMap == null || instanceMap.size() == 0) { return; } for (Map.Entry<String, Object> 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<String, Object> 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----"); } }
配置文件
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <servlet> <servlet-name>myservlet</servlet-name> <servlet-class>servlet.Dispatcherservlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>myservlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
浏览器输入
http://localhost:8080/test/test
输出
-------------- ---- ****** --- ---*********---- -----------------