Spring源码------手写体验MVC(升级版)

Spring------手写体验MVC(升级版)

目录

Spring------手写体验MVC(升级版)

1、前言

2、构建思想

2.1 Spring MVC的大致工作流程

2.2 Spring MVC的九大组件

2.3 Spring MVC的核心执行流程

3、核心代码

4、总结


1、前言

本篇博客并非是对Spring源码的深入研究。而是对上一篇博客《Spring源码------手写体验MVC》结构的优化:进行职责对的解耦。过程中主要是体验Spring IOC和DI的初始化过程。那么这篇博客涉及到的知识点大致有以下几点:

  • 如何自定义注解,如何通过反射机制去赋予注解强大的功能(说白了,就是体验在反射机制下,注解功能是多么的强大)
  • Spring Ioc容器的实现原理
  • Spring DI 注解注入
  • Java反射机制
  • Java I/O流(加载配置文件,读取配置文件信息) 
  • 正则表达式
     

2、构建思想

2.1 Spring MVC的大致工作流程

img

  • 用户发送请求至前端控制器DispatcherServlet;
  •  DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;
  • 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;
  • DispatcherServlet 调用 HandlerAdapter处理器适配器;
  • HandlerAdapter 经过适配调用 具体处理器(Handler,也叫后端控制器);
  • Handler执行完成返回ModelAndView;
  • HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
  • DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
  • ViewResolver解析后返回具体View;
  • DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
  • DispatcherServlet响应用户。

2.2 Spring MVC的九大组件

SpringMVC九大组件
序号组件名解释
1MultipartResolver多文件上传组件
2LocaleResolver本地语言环境
3ThemeResolver主题模板处理器
4HandlerMapping保存Url映射关系
5HandlerAdapter动态参数适配器
6HandlerExceptiomResolver异常拦截器
7RequestToViewNameTransltor视图读取器,从request中获取viewname
8ViewResolvers视图转换器,模板引擎
9FlashMapManager参数缓存器

 

 

 

 

 

 

 

 

 

2.3 Spring MVC的核心执行流程

3、核心代码

3.1 核心类结构图

      

3.2 核心代码

/**
 * @description: 委派模式,职责:负责任务调度,请求分发
 * @author: zps
 * @create: 2020-05-09 8:25
 **/
public class ZPSDispatcherServlet extends HttpServlet {

    private ZPSApplicationContext applicationContext;

    private List<ZPSHandlerMapping> handlerMappings = new ArrayList<ZPSHandlerMapping>();

    private Map<ZPSHandlerMapping, ZPSHandlerAdapter> handlerAdapters = new HashMap<ZPSHandlerMapping, ZPSHandlerAdapter>();

    private List<ZPSViewResolver> viewResolvers = new ArrayList<ZPSViewResolver>();

    @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 {

        //委派,根据URL去找到一个对应的Method并通过response返回
        try {
            doDispatch(req,resp);
        } catch (Exception e) {
            try {
                processDispatchResult(req,resp,new ZPSModelAndView("500"));
            } catch (Exception e1) {
                e1.printStackTrace();
                resp.getWriter().write("500 Exception,Detail : " + Arrays.toString(e.getStackTrace()));
            }
        }

    }
    @Override
    public void init(ServletConfig config) throws ServletException {

        //初始化Spring核心IoC容器
        applicationContext = new ZPSApplicationContext(config.getInitParameter("contextConfigLocation"));

        //初始化SpringMVC的九大组件
        initStrategies(applicationContext);

        System.out.println("GP Spring framework is init.");
    }

    //核心处理
    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        //完成了对HandlerMapping的封装
        //完成了对方法返回值的封装ModelAndView

        //通过URL获得一个HandlerMapping
        ZPSHandlerMapping handler = getHandler(req);
        if(handler == null){
            processDispatchResult(req,resp,new ZPSModelAndView("404"));
            return;
        }
        
        //根据一个HandlerMaping获得一个HandlerAdapter
        ZPSHandlerAdapter ha = getHandlerAdapter(handler);

        //解析某一个方法的形参和返回值之后,统一封装为ModelAndView对象
        ZPSModelAndView mv = ha.handler(req,resp,handler);

        //就把ModelAndView变成一个ViewResolver
        processDispatchResult(req,resp,mv);

    }

    private ZPSHandlerAdapter getHandlerAdapter(ZPSHandlerMapping handler) {
        if(this.handlerAdapters.isEmpty()){return null;}
        return this.handlerAdapters.get(handler);
    }

    private void processDispatchResult(HttpServletRequest req, HttpServletResponse resp, ZPSModelAndView mv) throws Exception {
        if(null == mv){return;}
        if(this.viewResolvers.isEmpty()){return;}

        for (ZPSViewResolver viewResolver : this.viewResolvers) {
            ZPSView view = viewResolver.resolveViewName(mv.getViewName());
            //直接往浏览器输出
            view.render(mv.getModel(),req,resp);
            return;
        }
    }

    private ZPSHandlerMapping getHandler(HttpServletRequest req) {
        if(this.handlerMappings.isEmpty()){return  null;}
        String url = req.getRequestURI();
        String contextPath = req.getContextPath();
        url = url.replaceAll(contextPath,"").replaceAll("/+","/");

        for (ZPSHandlerMapping mapping : handlerMappings) {
            Matcher matcher = mapping.getPattern().matcher(url);
            if(!matcher.matches()){continue;}
            return mapping;
        }
        return null;
    }


    //这里主要是进行九大主键的初始化
    private void initStrategies(ZPSApplicationContext context) {
//        //多文件上传的组件
//        initMultipartResolver(context);
//        //初始化本地语言环境
//        initLocaleResolver(context);
//        //初始化模板处理器
//        initThemeResolver(context);

        //c初始化处理器映射器
        initHandlerMappings(context);

        //初始化参数适配器
        initHandlerAdapters(context);

//        //初始化异常拦截器
//        initHandlerExceptionResolvers(context);
//        //初始化视图预处理器
//        initRequestToViewNameTranslator(context);

        //初始化视图转换器
        initViewResolvers(context);
//        //FlashMap管理器
//        initFlashMapManager(context);
    }

    //初始化视图转换器
    private void initViewResolvers(ZPSApplicationContext context) {
        String templateRoot = context.getConfig().getProperty("templateRoot");
        String templateRootPath = this.getClass().getClassLoader().getResource(templateRoot).getFile();

        File templateRootDir = new File(templateRootPath);
        for (File file : templateRootDir.listFiles()) {
            this.viewResolvers.add(new ZPSViewResolver(templateRoot));
        }
    }

    private void initHandlerAdapters(ZPSApplicationContext context) {
        for (ZPSHandlerMapping handlerMapping : handlerMappings) {
            this.handlerAdapters.put(handlerMapping,new ZPSHandlerAdapter());
        }
    }
    //初始化处理器映射器
    private void initHandlerMappings(ZPSApplicationContext context) {
        if(this.applicationContext.getBeanDefinitionCount() == 0){ return;}

        for (String beanName : this.applicationContext.getBeanDefinitionNames()) {
            Object instance = applicationContext.getBean(beanName);
            Class<?> clazz = instance.getClass();

            if(!clazz.isAnnotationPresent(ZPSController.class)){ continue; }

            //相当于提取 class上配置的url
            String baseUrl = "";
            if(clazz.isAnnotationPresent(ZPSRequestMapping.class)){
                ZPSRequestMapping requestMapping = clazz.getAnnotation(ZPSRequestMapping.class);
                baseUrl = requestMapping.value();
            }

            //只获取public的方法
            for (Method method : clazz.getMethods()) {
                if(!method.isAnnotationPresent(ZPSRequestMapping.class)){continue;}
                //提取每个方法上面配置的url
                ZPSRequestMapping requestMapping = method.getAnnotation(ZPSRequestMapping.class);

                // //demo//query
                String regex = ("/" + baseUrl + "/" + requestMapping.value().replaceAll("\\*",".*")).replaceAll("/+","/");
                Pattern pattern = Pattern.compile(regex);
                //handlerMapping.put(url,method);
                handlerMappings.add(new ZPSHandlerMapping(pattern,instance,method));
                System.out.println("Mapped : " + regex + "," + method);
            }

        }
    }

}
/**
 * @description: 处理器映射器,由相应的url找到相应的handler
 * @author: zps
 * @create: 2020-05-09 8:30
 **/
public class ZPSHandlerMapping {
    private Pattern pattern;     //URL
    private Method method;  //对应的Method
    private Object controller;//Method对应的实例对象

    public ZPSHandlerMapping(Pattern pattern, Object controller, Method method) {
        this.pattern = pattern;
        this.method = method;
        this.controller = controller;
    }

    public Pattern getPattern() {
        return pattern;
    }

    public void setPattern(Pattern pattern) {
        this.pattern = pattern;
    }

    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }

    public Object getController() {
        return controller;
    }

    public void setController(Object controller) {
        this.controller = controller;
    }
}
/**
 * @description: 处理器适配器,这里主要是完成请求方法与处理方法的参数转换
 * @author: zps
 * @create: 2020-05-09 9:30
 **/
public class ZPSHandlerAdapter {

    public ZPSModelAndView handler(HttpServletRequest req, HttpServletResponse resp, ZPSHandlerMapping handler) throws Exception{

        //保存形参列表
        //将参数名称和参数的位置,这种关系保存起来
        Map<String,Integer> paramIndexMapping = new HashMap<String, Integer>();

        //通过运行时的状态
        Annotation[] [] pa = handler.getMethod().getParameterAnnotations();
        for (int i = 0; i < pa.length ; i ++) {
            for(Annotation a : pa[i]){
                if(a instanceof ZPSRequestParam){
                    String paramName = ((ZPSRequestParam) a).value();
                    if(!"".equals(paramName.trim())){
//                        String value = Arrays.toString(params.get(paramName))
//                                .replaceAll("\\[|\\]","")
//                                .replaceAll("\\s+",",");
//                        paramValues[i] = value;
                        paramIndexMapping.put(paramName,i);
                    }
                }
            }
        }

        //初始化一下
        Class<?> [] paramTypes = handler.getMethod().getParameterTypes();
        for (int i = 0; i < paramTypes.length; i++) {
            Class<?> paramterType = paramTypes[i];
            if(paramterType == HttpServletRequest.class || paramterType == HttpServletResponse.class){
                paramIndexMapping.put(paramterType.getName(),i);
            }
        }


        //去拼接实参列表
        Map<String,String[]> params = req.getParameterMap();

        Object [] paramValues = new Object[paramTypes.length];

        for (Map.Entry<String,String[]> param : params.entrySet()) {
            String value = Arrays.toString(params.get(param.getKey()))
                    .replaceAll("\\[|\\]","")
                    .replaceAll("\\s+",",");

            if(!paramIndexMapping.containsKey(param.getKey())){continue;}

            int index = paramIndexMapping.get(param.getKey());

            //允许自定义的类型转换器Converter,这里硬编码
            paramValues[index] = castStringValue(value,paramTypes[index]);
        }

        if(paramIndexMapping.containsKey(HttpServletRequest.class.getName())){
            int index = paramIndexMapping.get(HttpServletRequest.class.getName());
            paramValues[index] = req;
        }

        if(paramIndexMapping.containsKey(HttpServletResponse.class.getName())){
            int index = paramIndexMapping.get(HttpServletResponse.class.getName());
            paramValues[index] = resp;
        }

        Object result = handler.getMethod().invoke(handler.getController(),paramValues);
        if(result == null || result instanceof Void){return null;}

        boolean isModelAndView = handler.getMethod().getReturnType() == ZPSModelAndView.class;
        if(isModelAndView){
            return (ZPSModelAndView)result;
        }
        return null;
    }

    private Object castStringValue(String value, Class<?> paramType) {
        if(String.class == paramType){
            return value;
        }else if(Integer.class == paramType){
            return Integer.valueOf(value);
        }else if(Double.class == paramType){
            return Double.valueOf(value);
        }else {
            if(value != null){
                return value;
            }
            return null;
        }

    }
}
/**
 * @description: 返回结果封装
 * @author: zps
 * @create: 2020-05-09 11:30
 **/
public class ZPSModelAndView {
    private String viewName;   //视图名
    private Map<String,?> model;  //返回结果

    public ZPSModelAndView(String viewName, Map<String, ?> model) {
        this.viewName = viewName;
        this.model = model;
    }

    public ZPSModelAndView(String viewName) {
        this.viewName = viewName;
    }

    public String getViewName() {
        return viewName;
    }

    public Map<String, ?> getModel() {
        return model;
    }
}
/**
 * @description: 视图解析器
 * @author: zps
 * @create: 2020-05-09 11:40
 **/
public class ZPSViewResolver {
    private final String DEFAULT_TEMPLATE_SUFFIX = ".html";
    private File tempateRootDir;
    public ZPSViewResolver(String templateRoot) {
        String templateRootPath = this.getClass().getClassLoader().getResource(templateRoot).getFile();
        tempateRootDir = new File(templateRootPath);
    }

    public ZPSView resolveViewName(String viewName){
        if(null == viewName || "".equals(viewName.trim())){return null;}
        viewName = viewName.endsWith(DEFAULT_TEMPLATE_SUFFIX)? viewName : (viewName + DEFAULT_TEMPLATE_SUFFIX);
        File templateFile = new File((tempateRootDir.getPath() + "/" + viewName).replaceAll("/+","/"));
        return new ZPSView(templateFile);
    }

}
/**
 * @description: 视图渲染
 * @author: zps
 * @create: 2020-05-09 12:40
 **/
public class ZPSView {

    private File viewFile;
    public ZPSView(File templateFile) {
        this.viewFile = templateFile;
    }

    //渲染
    public void render(Map<String, ?> model, HttpServletRequest req, HttpServletResponse resp) throws Exception {
        StringBuffer sb = new StringBuffer();
        RandomAccessFile ra = new RandomAccessFile(this.viewFile,"r");

        String line = null;
        while (null != (line = ra.readLine())){
            line = new String(line.getBytes("ISO-8859-1"),"utf-8");
            Pattern pattern = Pattern.compile("¥\\{[^\\}]+\\}",Pattern.CASE_INSENSITIVE);
            Matcher matcher = pattern.matcher(line);
            while (matcher.find()){
                String paramName = matcher.group();
                paramName = paramName.replaceAll("¥\\{|\\}","");
                Object paramValue = model.get(paramName);
                line = matcher.replaceFirst(makeStringForRegExp(paramValue.toString()));
                matcher = pattern.matcher(line);
            }
            sb.append(line);
        }
        resp.setCharacterEncoding("utf-8");
        resp.getWriter().write(sb.toString());
    }

    //处理特殊字符
    public static String makeStringForRegExp(String str) {
        return str.replace("\\", "\\\\").replace("*", "\\*")
                .replace("+", "\\+").replace("|", "\\|")
                .replace("{", "\\{").replace("}", "\\}")
                .replace("(", "\\(").replace(")", "\\)")
                .replace("^", "\\^").replace("$", "\\$")
                .replace("[", "\\[").replace("]", "\\]")
                .replace("?", "\\?").replace(",", "\\,")
                .replace(".", "\\.").replace("&", "\\&");
    }
}

4、总结

结合前面三篇博客,大致可以得出Spring框架的初始化过程和原理:

  • 首先就是初始化Spring IoC 容器  (Ioc和DI)

       1. 根据配置文件的信息,扫描相关的包,然后将类信息封装成BeanDefinition对象

       2.  把BeanDefinition进行缓存,如果是延迟加载,则在进行getBean()时获取相关的BeanDefinition进行实例化

       3.当调用getBean()方法时,创建Bean实例,并对创建的实例进行一层包装,封装成BeanWrapper对象进行缓存

       4.进行bean的一个属性依赖注入 

  • Spring MVC启动时调用init()方法,进行九大组件的初始化(这里只介绍三个)

       1.初始化处理器映射器,即把处理器的url与handler(也就是我们常用的RequestMapping注解方法)进行绑定

       2.初始化处理器适配器,主要是进行handler请求与用户请求中参数的适配

       3.初始化视图解析器,主要是对相应视图模板进行初始化

  • 初始化后,便可以进行请求的处理了

 

个人一点小结,若有误,希望指出!!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值