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

前言

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

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

DispatcherServlet的设计

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

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

下面我们来看源码:

DispatcherServlet的初始化

publicfinalvoidinit() 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 +"]");

}        }returnwac;

}//创建    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);returnwac;

}    }

上边代码展示了对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的核心组件

MultipartResolver:文件解析器,用于支持服务器的文件上传

LocaleResolver:国际化解析器,可以提供国际化的功能

ThemeResolver:主题解析器,类似于软件皮肤的转换功能

HandlerMappings:处理器映射器,它会包装用户提供一个控制器的方法和它的一些拦截器

HandlerAdapters:处理器适配器,因为处理器会在不同的上下文运行,所以Spring MVC会找到合适的适配器,然后运行处理器服务方法

HandlerExceptionResolvers:处理器异常解析器,处理器有可能产生异常,如果产生异常,则通过异常解析器来处理它

RequestToViewNameTranslator:视图逻辑名称转换器,在控制器中返回一个视图的名称,通过它可以找到实际的视图。当处理器没有返回逻辑视图名等相关信息时,自动请求URL映射为逻辑视图名

ViewResolvers:视图解析器,当控制器返回后,通过视图解析器会把逻辑视图名称进行解析,然后定位实际视图

Spring MVC流程

用户发送请求至前端控制器DispatcherServlet

DispatcherServlet收到请求调用HandlerMapping处理器映射器

处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet

DispatcherServlet通过HandlerAdapter处理器适配器调用处理器

执行处理器(Controller,也叫后端控制器)

Controller执行完成返回ModelAndView

HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet

DispatcherServlet将ModelAndView传给ViewReslover视图解析器

ViewReslover解析后返回具体View

DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)

DispatcherServlet响应用户

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

欢迎观看~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353