解析SpringMVC 前端控制器(Dispatcherservlet)

一 SpringMVC 流程图

170203_EVYw_3218528.png

 

DispatcherServlet是前端控制器设计模式的实现,提供Spring Web MVC的集中访问点,而且负责职责的分派,而且与Spring IoC容器无缝集成,从而可以获得Spring的所有好处。

自己实现了一个dispatcherServlet,希望帮助大家理解DispatcherServlet的实现原理。目录如下(后面会重构,结构会有所变化)

构)224534_dsZz_3218528.png

二 注解 

   模仿SpringMVC ,自定义@Controller ,@Service,@AutoWired,@RequestMapping

   @Controller

        225041_9L7d_3218528.png

    @Service

       225059_4uju_3218528.png

    @RequestMapping

      225117_DdBy_3218528.png

    @AutoWired

      225133_dvQO_3218528.png

三 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 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

输出

--------------
---- ******  ---
---*********----
-----------------

转载于:https://my.oschina.net/u/3218528/blog/1615081

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值