不可错过的SpringMVC工作原理详解

MVC 的原理图如下:


SpringMVC 简单介绍

SpringMVC 框架是以请求为驱动,围绕 Servlet 设计,将请求发给控制器,然后通过模型对象,分派器来展示请求结果视图。其中核心类是 DispatcherServlet,它是一个 Servlet,顶层是实现的Servlet接口。

SpringMVC 使用

需要在 web.xml 中配置 DispatcherServlet 。并且需要配置 Spring 监听器ContextLoaderListener

<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener

</listener-class>

</listener>

<servlet>

<servlet-name>springmvc</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet

</servlet-class>

<!-- 如果不设置init-param标签,则必须在/WEB-INF/下创建xxx-servlet.xml文件,其中xxx是servlet-name中配置的名称。 -->

<init-param>

<param-name>contextConfigLocation</param-name>

<param-value>classpath:spring/springmvc-servlet.xml</param-value>

</init-param>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>springmvc</servlet-name>

<url-pattern>/</url-pattern>

</servlet-mapping>

SpringMVC 工作原理(重要)

简单来说:

客户端发送请求-> 前端控制器 DispatcherServlet 接受客户端请求 -> 找到处理器映射 HandlerMapping 解析请求对应的 Handler-> HandlerAdapter 会根据 Handler 来调用真正的处理器开处理请求,并处理相应的业务逻辑 -> 处理器返回一个模型视图 ModelAndView -> 视图解析器进行解析 -> 返回一个视图对象->前端控制器 DispatcherServlet 渲染数据(Moder)->将得到视图对象返回给用户

如下图所示:


图片发自简书App

上图的一个笔误的小问题:Spring MVC 的入口函数也就是前端控制器 DispatcherServlet 的作用是接收请求,响应结果。

流程说明(重要):

(1)客户端(浏览器)发送请求,直接请求到 DispatcherServlet。

(2)DispatcherServlet 根据请求信息调用 HandlerMapping,解析请求对应的 Handler。

(3)解析到对应的 Handler(也就是我们平常说的 Controller 控制器)后,开始由 HandlerAdapter 适配器处理。

(4)HandlerAdapter 会根据 Handler 来调用真正的处理器开处理请求,并处理相应的业务逻辑。

(5)处理器处理完业务后,会返回一个 ModelAndView 对象,Model 是返回的数据对象,View 是个逻辑上的 View。

(6)ViewResolver 会根据逻辑 View 查找实际的 View。

(7)DispaterServlet 把返回的 Model 传给 View(视图渲染)。

(8)把 View 返回给请求者(浏览器)

SpringMVC 重要组件说明

1、前端控制器DispatcherServlet(不需要工程师开发),由框架提供(重要)

作用:Spring MVC 的入口函数。接收请求,响应结果,相当于转发器,中央处理器。有了 DispatcherServlet 减少了其它组件之间的耦合度。用户请求到达前端控制器,它就相当于mvc模式中的c,DispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,DispatcherServlet的存在降低了组件之间的耦合性。

2、处理器映射器HandlerMapping(不需要工程师开发),由框架提供

作用:根据请求的url查找Handler。HandlerMapping负责根据用户请求找到Handler即处理器(Controller),SpringMVC提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。

3、处理器适配器HandlerAdapter

作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler

通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。

4、处理器Handler(需要工程师开发)

注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler

Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。

由于Handler涉及到具体的用户业务请求,所以一般情况需要工程师根据业务需求开发Handler。

5、视图解析器View resolver(不需要工程师开发),由框架提供

作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)

View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。 springmvc框架提供了很多的View视图类型,包括:jstlView、freemarkerView、pdfView等。

一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由工程师根据业务需求开发具体的页面。

6、视图View(需要工程师开发)

View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf…)

注意:处理器Handler(也就是我们平常说的Controller控制器)以及视图层view都是需要我们自己手动开发的。其他的一些组件比如:前端控制器DispatcherServlet、处理器映射器HandlerMapping、处理器适配器HandlerAdapter等等都是框架提供给我们的,不需要自己手动开发。

DispatcherServlet详细解析

首先看下源码:

package org.springframework.web.servlet;

@SuppressWarnings("serial")

public class DispatcherServlet extends FrameworkServlet {

public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";

public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";

public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver";

public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";

public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter";

public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver";

public static final String REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator";

public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";

public static final String FLASH_MAP_MANAGER_BEAN_NAME = "flashMapManager";

public static final String WEB_APPLICATION_CONTEXT_ATTRIBUTE = DispatcherServlet.class.getName() + ".CONTEXT";

public static final String LOCALE_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".LOCALE_RESOLVER";

public static final String THEME_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_RESOLVER";

public static final String THEME_SOURCE_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_SOURCE";

public static final String INPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".INPUT_FLASH_MAP";

public static final String OUTPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".OUTPUT_FLASH_MAP";

public static final String FLASH_MAP_MANAGER_ATTRIBUTE = DispatcherServlet.class.getName() + ".FLASH_MAP_MANAGER";

public static final String EXCEPTION_ATTRIBUTE = DispatcherServlet.class.getName() + ".EXCEPTION";

public static final String PAGE_NOT_FOUND_LOG_CATEGORY = "org.springframework.web.servlet.PageNotFound";

private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";

protected static final Log pageNotFoundLogger = LogFactory.getLog(PAGE_NOT_FOUND_LOG_CATEGORY);

private static final Properties defaultStrategies;

static {

try {

ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);

defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);

}

catch (IOException ex) {

throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());

}

}

/** Detect all HandlerMappings or just expect "handlerMapping" bean? */

private boolean detectAllHandlerMappings = true;

/** Detect all HandlerAdapters or just expect "handlerAdapter" bean? */

private boolean detectAllHandlerAdapters = true;

/** Detect all HandlerExceptionResolvers or just expect "handlerExceptionResolver" bean? */

private boolean detectAllHandlerExceptionResolvers = true;

/** Detect all ViewResolvers or just expect "viewResolver" bean? */

private boolean detectAllViewResolvers = true;

/** Throw a NoHandlerFoundException if no Handler was found to process this request? **/

private boolean throwExceptionIfNoHandlerFound = false;

/** Perform cleanup of request attributes after include request? */

private boolean cleanupAfterInclude = true;


/** MultipartResolver used by this servlet */


private MultipartResolver multipartResolver;


/** LocaleResolver used by this servlet */


private LocaleResolver localeResolver;


/** ThemeResolver used by this servlet */


private ThemeResolver themeResolver;


/** List of HandlerMappings used by this servlet */


private List<HandlerMapping> handlerMappings;


/** List of HandlerAdapters used by this servlet */


private List<HandlerAdapter> handlerAdapters;


/** List of HandlerExceptionResolvers used by this servlet */


private List<HandlerExceptionResolver> handlerExceptionResolvers;


/** RequestToViewNameTranslator used by this servlet */


private RequestToViewNameTranslator viewNameTranslator;


private FlashMapManager flashMapManager;


/** List of ViewResolvers used by this servlet */


private List<ViewResolver> viewResolvers;


public DispatcherServlet() {


super();


}


public DispatcherServlet(WebApplicationContext webApplicationContext) {


super(webApplicationContext);


}


@Override


protected void onRefresh(ApplicationContext context) {


initStrategies(context);


}


protected void initStrategies(ApplicationContext context) {


initMultipartResolver(context);


initLocaleResolver(context);


initThemeResolver(context);


initHandlerMappings(context);


initHandlerAdapters(context);


initHandlerExceptionResolvers(context);


initRequestToViewNameTranslator(context);


initViewResolvers(context);


initFlashMapManager(context);


}


}


DispatcherServlet类中的属性beans:


HandlerMapping:用于handlers映射请求和一系列的对于拦截器的前处理和后处理,大部分用@Controller注解。


HandlerAdapter:帮助DispatcherServlet处理映射请求处理程序的适配器,而不用考虑实际调用的是 哪个处理程序。- - -

ViewResolver:根据实际配置解析实际的View类型。

ThemeResolver:解决Web应用程序可以使用的主题,例如提供个性化布局。

MultipartResolver:解析多部分请求,以支持从HTML表单上传文件。-

FlashMapManager:存储并检索可用于将一个请求属性传递到另一个请求的input和output的FlashMap,通常用于重定向。

在Web MVC框架中,每个DispatcherServlet都拥自己WebApplicationContext,它继承了ApplicationContext。WebApplicationContext包含了其上下文和Servlet实例之间共享的所有的基础框架beans。

HandlerMapping


HandlerMapping接口处理请求的映射HandlerMapping接口的实现类:


SimpleUrlHandlerMapping类通过配置文件把URL映射到Controller类。

DefaultAnnotationHandlerMapping类通过注解把URL映射到Controller类。

HandlerAdapter


HandlerAdapter接口-处理请求映射


AnnotationMethodHandlerAdapter:通过注解,把请求URL映射到Controller类的方法上。

HandlerExceptionResolver

HandlerExceptionResolver接口-异常处理接口

SimpleMappingExceptionResolver通过配置文件进行异常处理。

AnnotationMethodHandlerExceptionResolver:通过注解进行异常处理。

ViewResolver接口解析View视图。

UrlBasedViewResolver类 通过配置文件,把一个视图名交给到一个View来处理。

打个广告,本人博客地址是:风吟个人博客

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

推荐阅读更多精彩内容

  • 1.内存泄露 内存泄漏两种情况: 在堆中申请的空间没有被释放(虚拟机gc可以解决) 对象已不在使用,但仍然在内存中...
    Aimerwhy阅读 575评论 0 0
  • SpringMVC的工作原理图: SpringMVC的工作原理图: SpringMVC流程 1、 用户发送请求至前...
    我不饿我不想吃东西阅读 840评论 0 1
  • 对于必然的解读思绪万千,其实典型的实例就是计算机在社会生存中的应用,注意是计算机而不是kk说的网络。 计算机的国内...
    秦家炎阅读 98评论 0 2
  • 2018年3月9号星期五天气晴亲子日记29篇昨天开完家长会回来,晚上躺在床上想了很多,明宇假期的古诗和开学后第一课...
    明天有宇阅读 150评论 0 0
  • 20190220 星期三 天气晴朗 昨晚,我做了一个美梦,早上起来仍记得那些情节,心情美美哒~
    海伦_Helen阅读 192评论 0 0