SpringMVC执行流程

kyang MVP++

1. Spring常用组件


1.1 DispatcherServlet:前端控制器

DispatcherServlet是Spring MVC框架的核心,相当于整个框架的门面。它负责接收用户的请求,并根据请求类型、URL等信息调用相应的处理器,最后将处理结果返回给用户。

  • 统一处理请求和响应,实现请求的统一入口和出口。
  • 控制整个请求处理流程,协调各个组件协同工作。
  • 提供强大的配置机制,通过配置文件或注解的方式定义请求映射和处理器。
  • 支持多种请求处理方式,如Servlet、Servlet3.0异步、WebFlux等。

1.2 HandlerMapping:处理器映射器

HandlerMapping负责根据请求信息(URL、HTTP方法等)找到对应的处理器。

  • **RequestMappingHandlerMapping**:根据Controller类或方法上的@RequestMapping注解进行映射。
  • **SimpleUrlHandlerMapping**:根据URL进行映射。

HandlerMapping的作用

  • 根据请求信息快速定位处理器,提高请求处理效率。
  • 支持多种映射方式,满足不同的业务需求。
  • 提供灵活的映射规则,如后缀映射、路径匹配等。

1.3 Handler:处理器

Handler是开发者编写的控制器,负责接收请求并处理业务逻辑。在Spring MVC中,处理器通常以Controller、Service、DAO的形式存在。

  • 处理业务逻辑,返回处理结果。
  • 支持多种请求处理方式,如直接返回数据、跳转页面、重定向等。
  • 可以方便地与Spring框架的其他组件(如Service、DAO)集成。

1.4 HandlerAdapter:处理器适配器

HandlerAdapter负责调用处理器的方法,并将处理结果返回给DispatcherServlet。

  • **DispatcherServletHandlerAdapter**:适配Controller接口。
  • **SimpleControllerHandlerAdapter**:适配Servlet。

HandlerAdapter的作用

  • 提供统一的调用接口,方便开发者编写处理器。
  • 支持多种处理器类型,如Controller、Servlet等。
  • 提高代码复用性,降低开发难度。

1.5 ViewResolver:视图解析器

ViewResolver负责将处理结果转换为视图,并将视图渲染给用户。

  • **InternalResourceViewResolver**:解析JSP视图。
  • **ThymeleafViewResolver**:解析Thymeleaf视图。

ViewResolver的作用

  • 将处理结果转换为视图,提供丰富的视图支持。
  • 支持多种视图类型,如JSP、Thymeleaf、Freemarker等。
  • 提高代码复用性,降低开发难度。

1.6 View:视图

View负责将处理结果展示给用户。

  • **JspView**:展示JSP视图。
  • **ThymeleafView**:展示Thymeleaf视图。
  • **RedirectView**:重定向到其他URL。

View的作用

  • 将处理结果展示给用户,提供丰富的视图支持。
  • 支持多种视图类型,如JSP、Thymeleaf、Freemarker等。
  • 提高代码复用性,降低开发难度。

2. DispatcherServlet的初始化与生命周期


DispatcherServlet作为Spring MVC框架的核心,其本质是一个Servlet,因此它遵循Servlet的生命周期。在宏观层面上,其调度过程是依托于Servlet的生命周期来进行的。

在这里插入图片描述

2.1 初始化WebApplicationContext

DispatcherServlet的初始化过程首先涉及到WebApplicationContext的创建。

  • 所在类:org.springframework.web.servlet.FrameworkServlet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;

// ...(省略部分代码)

if (wac == null) {
// No context instance is defined for this servlet -> create a local one
wac = createWebApplicationContext(rootContext);
}

// ...(省略部分代码)

if (!this.refreshEventReceived) {
synchronized (this.onRefreshMonitor) {
// 刷新WebApplicationContext
onRefresh(wac);
}
}

// ...(省略部分代码)

return wac;
}

在上述代码中,首先尝试获取已经存在的WebApplicationContext实例。如果不存在,则创建一个新的WebApplicationContext实例,并通过createWebApplicationContext方法进行初始化。

2.2 创建WebApplicationContext

创建WebApplicationContext的过程涉及到反射和配置设置。

  • 所在类:org.springframework.web.servlet.FrameworkServlet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
Class<?> contextClass = getContextClass();
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException(
"Fatal initialization error in servlet with name '" + getServletName() +
"': custom WebApplicationContext class [" + contextClass.getName() +
"] is not of type ConfigurableWebApplicationContext");
}
// 通过反射创建 IOC 容器对象
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

// 设置环境、父容器、配置位置等
wac.setEnvironment(getEnvironment());
wac.setParent(parent);
String configLocation = getContextConfigLocation();
if (configLocation != null) {
wac.setConfigLocation(configLocation);
}
configureAndRefreshWebApplicationContext(wac);

return wac;
}

在此步骤中,通过反射创建一个ConfigurableWebApplicationContext实例,并设置其环境、父容器和配置位置等信息。

2.3 DispatcherServlet初始化策略

在创建并初始化WebApplicationContext之后,DispatcherServlet会调用initStrategies方法来初始化其各个组件。

  • 所在类:org.springframework.web.servlet.DispatcherServlet
1
2
3
4
5
6
7
8
9
10
11
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}

在这段代码中,DispatcherServlet会依次初始化以下策略:

  • 文件上传解析器(MultipartResolver)
  • 区域设置解析器(LocaleResolver)
  • 主题解析器(ThemeResolver)
  • 处理器映射器(HandlerMappings)
  • 处理器适配器(HandlerAdapters)
  • 异常处理器(HandlerExceptionResolvers)
  • 请求到视图名转换器(RequestToViewNameTranslator)
  • 视图解析器(ViewResolvers)
  • FlashMap管理器(FlashMapManager)

3. DispatcherServlet请求处理流程详解


3.1 processRequest()

FrameworkServlet 类继承自 HttpServlet,并重写了 service()doXxx() 方法。这些方法最终会调用 processRequest(request, response) 来处理请求。

  • 所在类:org.springframework.web.servlet.FrameworkServlet
1
2
3
4
5
6
7
8
9
10
11
12
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// ...(省略初始化和上下文设置代码)

try {
// 执行服务,doService()是一个抽象方法,在DispatcherServlet中进行了重写
doService(request, response);
}
finally {
// ...(省略清理和日志记录代码)
}
}

在这个方法中,DispatcherServlet会初始化一些必要的上下文,如Locale、RequestAttributes等,并最终调用 doService() 方法来处理实际的请求。

3.2 doService()

doService() 方法是DispatcherServlet处理请求的核心方法,它负责将请求映射到合适的处理器(Handler),并执行处理器逻辑。

  • 所在类:org.springframework.web.servlet.DispatcherServlet
1
2
3
4
5
6
7
8
9
10
11
12
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
// ...(省略请求日志和属性设置代码)

try {
// 处理请求和响应
doDispatch(request, response);
}
finally {
// ...(省略清理代码)
}
}

doService() 方法中,首先会设置一些框架对象,如WebApplicationContext、LocaleResolver、ThemeResolver等,然后调用 doDispatch() 方法来执行实际的请求处理。

3.3 doDispatch()

doDispatch() 方法负责将请求分发给相应的处理器,并处理返回的 ModelAndView 对象。

  • 所在类:org.springframework.web.servlet.DispatcherServlet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// ...(省略检查文件上传和解析请求路径代码)

try {
// Determine handler for the current request.
HandlerExecutionChain mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}

// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// 调用拦截器的preHandle()
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}

// Actually invoke the handler.
ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

// 调用拦截器的postHandle()
mappedHandler.applyPostHandle(processedRequest, response, mv);

// 后续处理:处理模型数据和渲染视图
processDispatchResult(processedRequest, response, mappedHandler, mv, null);
}
catch (Exception ex) {
processDispatchResult(processedRequest, response, null, null, ex);
}
catch (Throwable err) {
processDispatchResult(processedRequest, response, null, null, new NestedServletException("Handler processing failed", err));
}
}

doDispatch() 方法中,首先通过 getHandler() 方法找到对应的处理器,然后通过 getHandlerAdapter() 方法获取处理器适配器。接着,调用拦截器的 preHandle() 方法,执行处理器方法,并获取 ModelAndView 对象。之后,调用拦截器的 postHandle() 方法,最后通过 processDispatchResult() 方法处理模型数据和渲染视图。

3.4 processDispatchResult()

processDispatchResult() 方法负责处理 ModelAndView 对象,包括渲染视图和处理异常。

  • 所在类:org.springframework.web.servlet.DispatcherServlet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
// ...(省略异常处理代码)

if (mv != null && !mv.wasCleared()) {
// 处理模型数据和渲染视图
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("No view rendering, null ModelAndView returned.");
}
}

// 调用拦截器的afterCompletion()
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}

processDispatchResult() 方法中,如果 ModelAndView 对象不为空且未被清除,则会处理模型数据和渲染视图。如果发生异常,则会进行处理,并清理错误请求属性。最后,调用拦截器的 afterCompletion() 方法。

4. SpringMVC执行流程解析


Spring MVC框架的执行流程是自动化且高度可配置的

  1. 请求捕获与解析
    用户向服务器发送请求,该请求首先被Spring MVC的前端控制器 DispatcherServlet 捕获。

  2. URL映射解析
    DispatcherServlet解析请求的URL,获取请求资源标识符(URI)。然后,系统判断该URI是否已经配置了映射关系:

    a. 映射不存在

    • 如果没有配置映射,系统会检查是否启用了 mvn:default-servlet-handler
    • 如果没有配置 default-servlet-handler,则控制台会显示映射找不到的错误,客户端会收到404错误。
    • 如果启用了 default-servlet-handler,DispatcherServlet会将请求转发到默认的Servlet处理静态资源(如JS、CSS、HTML文件),如果资源不存在,客户端同样会收到404错误。
  3. HandlerMapping查找
    如果存在映射,DispatcherServlet会调用 HandlerMapping 获取与请求URI对应的处理器(Handler)配置信息,包括处理器对象及其关联的拦截器。这些信息被封装成 HandlerExecutionChain 对象返回。

  4. HandlerAdapter选择
    根据获取到的处理器,DispatcherServlet会选择一个合适的 HandlerAdapter。HandlerAdapter负责调用处理器的方法,并处理返回的结果。

  5. 拦截器预处理
    如果配置了拦截器,DispatcherServlet会先执行拦截器的 preHandle() 方法。

  6. 处理器方法调用
    DispatcherServlet提取请求中的模型数据,填充处理器(Controller)的入参。在这个过程中,Spring MVC会自动处理以下任务:

    • 消息转换:将请求消息(如JSON、XML等)转换为Java对象。
    • 数据转换:对请求消息进行数据转换,如将字符串转换为整数或双精度浮点数。
    • 数据格式化:对请求消息进行格式化处理,如将字符串转换为格式化的数字或日期。
    • 数据验证:验证数据的有效性,如长度、格式等,并将验证结果存储到 BindingResultError 对象中。
  7. ModelAndView生成
    处理器(Controller)方法执行完成后,向DispatcherServlet返回一个 ModelAndView 对象。该对象包含视图名称和模型数据。

  8. 拦截器后处理
    此时,系统会执行拦截器的 postHandle() 方法。

  9. 视图解析与渲染
    根据返回的 ModelAndView,系统选择一个合适的 ViewResolver 进行视图解析。ViewResolver负责将视图名称解析为具体的视图对象,并根据模型数据渲染视图。

  10. 拦截器完成处理
    渲染视图完成后,执行拦截器的 afterCompletion() 方法。

  11. 响应客户端
    最后,将渲染结果返回给客户端。

  • 标题: SpringMVC执行流程
  • 作者: kyang
  • 创建于 : 2024-10-18 11:17:42
  • 更新于 : 2025-07-11 16:56:12
  • 链接: https://blog.kyang.top/2024/10/18/SpringMVC执行流程/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论