SpringMVC执行流程
文章目录
- SpringMVC执行流程
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
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
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
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
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
@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
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
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框架的执行流程是自动化且高度可配置的
-
请求捕获与解析
用户向服务器发送请求,该请求首先被Spring MVC的前端控制器 DispatcherServlet 捕获。 -
URL映射解析
DispatcherServlet解析请求的URL,获取请求资源标识符(URI)。然后,系统判断该URI是否已经配置了映射关系:a. 映射不存在
- 如果没有配置映射,系统会检查是否启用了
mvn:default-servlet-handler
。 - 如果没有配置
default-servlet-handler
,则控制台会显示映射找不到的错误,客户端会收到404错误。 - 如果启用了
default-servlet-handler
,DispatcherServlet会将请求转发到默认的Servlet处理静态资源(如JS、CSS、HTML文件),如果资源不存在,客户端同样会收到404错误。
- 如果没有配置映射,系统会检查是否启用了
-
HandlerMapping查找
如果存在映射,DispatcherServlet会调用 HandlerMapping 获取与请求URI对应的处理器(Handler)配置信息,包括处理器对象及其关联的拦截器。这些信息被封装成 HandlerExecutionChain 对象返回。 -
HandlerAdapter选择
根据获取到的处理器,DispatcherServlet会选择一个合适的 HandlerAdapter。HandlerAdapter负责调用处理器的方法,并处理返回的结果。 -
拦截器预处理
如果配置了拦截器,DispatcherServlet会先执行拦截器的preHandle()
方法。 -
处理器方法调用
DispatcherServlet提取请求中的模型数据,填充处理器(Controller)的入参。在这个过程中,Spring MVC会自动处理以下任务:- 消息转换:将请求消息(如JSON、XML等)转换为Java对象。
- 数据转换:对请求消息进行数据转换,如将字符串转换为整数或双精度浮点数。
- 数据格式化:对请求消息进行格式化处理,如将字符串转换为格式化的数字或日期。
- 数据验证:验证数据的有效性,如长度、格式等,并将验证结果存储到
BindingResult
或Error
对象中。
-
ModelAndView生成
处理器(Controller)方法执行完成后,向DispatcherServlet返回一个ModelAndView
对象。该对象包含视图名称和模型数据。 -
拦截器后处理
此时,系统会执行拦截器的postHandle()
方法。 -
视图解析与渲染
根据返回的ModelAndView
,系统选择一个合适的 ViewResolver 进行视图解析。ViewResolver负责将视图名称解析为具体的视图对象,并根据模型数据渲染视图。 -
拦截器完成处理
渲染视图完成后,执行拦截器的afterCompletion()
方法。 -
响应客户端
最后,将渲染结果返回给客户端。