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
輸出
-------------- ---- ****** --- ---*********---- -----------------