来来来, 一张图教你看懂Spring MVC执行流程,还不赶紧收

2020-05-09  本文已影响0人  阿博的java技术栈

前言

今天主要给大家分享的是关于Spring MVC的知识内容,刚好是最近用到的知识点,所以今天就来给大家安利安利了!

那么,老规矩,话不多说!上干货.....

DispatcherServlet的设计

DispatcherServlet的父类是FrameworkServletFrameworkServlet的父类则是HttpServletBeanHttpServletBean继承了Web容器所提供的HttpServlet,所以它可以载入Web容器中的Servlet

DispatcherServlet的工作大致可以分为两个部分:一个是初始化部分,由initServletBean()启动,通过initWebApplicationContext()方法最终调用DispatcherServletinitStrategies方法。在这个方法里,DispatcherServlet对MVC模块的其他部分进行了初始化,比如handlerMappingViewResolver等。另一个是对HTTP请求进行相应,作为一个servlet,web容器会调用doGet(),doPost()方法,在经过FrameworkServletprocessRequest简单处理后,会调用DispatcherServletdoService()方法,在这个方法中封装了doDispatch(),这个doDispatch()是Dispatcher实现MVC模式的主要部分。

下边我们来看源码:

DispatcherServlet的初始化

    public final void init() throws ServletException {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Initializing servlet '" + this.getServletName() + "'");
        }

        //根据参数初始化bean的属性
        try {
            PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
            ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());
            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
            this.initBeanWrapper(bw);
            bw.setPropertyValues(pvs, true);
        } catch (BeansException var4) {
            this.logger.error("Failed to set bean properties on servlet '" + this.getServletName() + "'", var4);
            throw var4;
        }
        //调用子类的initServletBean进行具体的初始化
        this.initServletBean();
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Servlet '" + this.getServletName() + "' configured successfully");
        }

    }

FrameworkServlet的initServletBean方法

    protected final void initServletBean() throws ServletException {
        this.getServletContext().log("Initializing Spring FrameworkServlet '" + this.getServletName() + "'");
        if (this.logger.isInfoEnabled()) {
            this.logger.info("FrameworkServlet '" + this.getServletName() + "': initialization started");
        }

        long startTime = System.currentTimeMillis();

        try {
            //初始化Spring Ioc容器
            this.webApplicationContext = this.initWebApplicationContext();
            this.initFrameworkServlet();
        } catch (ServletException var5) {
            this.logger.error("Context initialization failed", var5);
            throw var5;
        } catch (RuntimeException var6) {
            this.logger.error("Context initialization failed", var6);
            throw var6;
        }

        if (this.logger.isInfoEnabled()) {
            long elapsedTime = System.currentTimeMillis() - startTime;
            this.logger.info("FrameworkServlet '" + this.getServletName() + "': initialization completed in " + elapsedTime + " ms");
        }

    }

    protected WebApplicationContext initWebApplicationContext() {
        WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
        WebApplicationContext wac = null;
        //判断是否已经被初始化
        if (this.webApplicationContext != null) {
            //如果Web Ioc容器在启动的时候创建,那么就沿用它
            wac = this.webApplicationContext;
            if (wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)wac;
                if (!cwac.isActive()) {
                    //如果父容器为空的情况
                    if (cwac.getParent() == null) {
                        cwac.setParent(rootContext);
                    }

                    //如果Spring Ioc容器还没有刷新,那么就进行刷新父容器上下文设置id等操作
                    this.configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }

        //没有初始化,则查找是否有存在的Spring Web Ioc容器
        if (wac == null) {
            wac = this.findWebApplicationContext();
        }

        //没有初始化,也没有找到,则自己创建一个
        if (wac == null) {
            wac = this.createWebApplicationContext(rootContext);
        }

        //当onRefresh还没调用过,执行onRefresh方法
        if (!this.refreshEventReceived) {
            this.onRefresh(wac);
        }

        if (this.publishContext) {
            //作为Servlet上下文属性发布到IOC容器
            String attrName = this.getServletContextAttributeName();
            this.getServletContext().setAttribute(attrName, wac);
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Published WebApplicationContext of servlet '" + this.getServletName() + "' as ServletContext attribute with name [" + attrName + "]");
            }
        }

        return wac;
    }

    //创建
    protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
        Class<?> contextClass = this.getContextClass();
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Servlet with name '" + this.getServletName() + "' will try to create custom WebApplicationContext context of class '" + contextClass.getName() + "'" + ", using parent context [" + parent + "]");
        }

        if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
            throw new ApplicationContextException("Fatal initialization error in servlet with name '" + this.getServletName() + "': custom WebApplicationContext class [" + contextClass.getName() + "] is not of type ConfigurableWebApplicationContext");
        } else {
            //初始化MVC
            ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);
            wac.setEnvironment(this.getEnvironment());
            wac.setParent(parent);
            wac.setConfigLocation(this.getContextConfigLocation());
            this.configureAndRefreshWebApplicationContext(wac);
            return wac;
        }
    }

上边代码展示了对Spring Ioc容器的初始化,除了SpringMVC上下文创建外,还需要启动SpringMVC的其他一些配置初始化,通过onRefresh调用来完成。这个方法就在DispatcherServlet当中,实际调用的initStrategies进行配置

    protected void onRefresh(ApplicationContext context) {
        this.initStrategies(context);
    }

    protected void initStrategies(ApplicationContext context) {
        //初始化文件的解析
        this.initMultipartResolver(context);
        //本地初始化
        this.initLocaleResolver(context);
        //主题解析
        this.initThemeResolver(context);
        //处理器映射
        this.initHandlerMappings(context);
        //处理器适配器
        this.initHandlerAdapters(context);
        //handler的异常处理解析器
        this.initHandlerExceptionResolvers(context);
        //当处理器没有返回逻辑视图名等相关信息,自动将请求URL映射为路基视图名
        this.initRequestToViewNameTranslator(context);
        //视图解析器
        this.initViewResolvers(context);
        //flash
        this.initFlashMapManager(context);
    }

Spring MVC的核心组件

Spring MVC流程

  1. 用户发送请求至前端控制器DispatcherServlet
  2. DispatcherServlet收到请求调用HandlerMapping处理器映射器
  3. 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet
  4. DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
  5. 执行处理器(Controller,也叫后端控制器)
  6. Controller执行完成返回ModelAndView
  7. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
  8. DispatcherServlet将ModelAndView传给ViewReslover视图解析器
  9. ViewReslover解析后返回具体View
  10. DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
  11. DispatcherServlet响应用户

DispatcherServlet有接收请求,响应结果,转发等作用。有了DispatcherServlet之后,可以减少组件之间的耦合度

上一篇 下一篇

猜你喜欢

热点阅读