当前位置: 首页 > news >正文

Spring MVC框架中DispatcherServlet详解

1. DispatcherServlet概述

1.1 什么是DispatcherServlet?

DispatcherServlet是Spring MVC框架的核心组件,它本质上是一个Java Servlet,作为前端控制器(Front Controller)负责接收所有HTTP请求,并根据特定规则将请求分发到相应的处理器(Handler)进行处理 。在Spring Web应用中,当用户发送一个HTTP请求时,首先由Servlet容器(如Tomcat)接收并路由到DispatcherServlet,然后由DispatcherServlet协调其他组件完成请求处理。

1.2 核心作用与职责

DispatcherServlet在Spring MVC中扮演着"指挥官"的角色,其核心职责包括:

  1. 请求分发:根据请求的URL、HTTP方法等信息,通过策略接口找到对应的处理器(Handler)
  2. 组件协调:协调Spring MVC框架中的各类组件,如HandlerMapping、HandlerAdapter、ViewResolver等 
  3. 异常处理:捕获处理器执行过程中的异常,并通过HandlerExceptionResolver进行处理 
  4. 拦截器管理:执行HandlerInterceptor拦截器链,进行预处理和后处理 
  5. 上下文管理:创建并维护WebApplicationContext,这是Spring MVC的IoC容器 

前端控制器设计模式是DispatcherServlet实现的核心思想,它将请求处理的流程统一管理,使得具体的业务逻辑可以独立于请求处理流程之外 。这种设计模式使得Spring MVC具有高度的灵活性和可扩展性。

2. 初始化流程解析

2.1 init方法的执行过程

DispatcherServlet的初始化过程是从Servlet容器(Tomcat等)调用其init()方法开始的 。这个方法定义在HttpServletBean父类中,主要完成以下工作:

//摘自HttpServletBean类
public final void init() throws ServletException {if (logger.isDebugEnabled()) {logger.debug("Initializing.servlet '" + getServletName() + "'");  }// 1. 将ServletConfig参数转换为Bean属性try {PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this(requiredProperties));BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());bw.registerCustomEditor(Resource.class,new ResourceEditor(resourceLoader, getEnvironment()));initBeanWrapper(bw);bw.setPropertyValues(pvs, true);  } catch (BeansException ex) {logger.error("Failed to.set bean properties.on Servlet '" +getServletName() + "'", ex);throw ex;}// 2. 执行子类的特定初始化initServletBean();  if (logger.isDebugEnabled()) {logger.debug("Servlet '" + getServletName() + "' configured successfully");}
}

在这个过程中,关键步骤是initServletBean()方法,它由FrameworkServlet实现,负责创建WebApplicationContext并初始化Spring MVC组件 。

2.2 WebApplicationContext的创建与加载

WebApplicationContext是Spring MVC的IoC容器,它继承自ApplicationContext,增加了Web环境相关的功能。创建过程发生在initServletBean()方法中:

//摘自FrameworkServlet类
protected final void initServletBean() throws ServletException {// ... 省略其他代码 ...// 1. 创建WebApplicationContextif (this.webApplicationContext == null) {WebApplicationContext wac = createWebApplicationContext(servletConfig);if (!this焕然一新) {this.webApplicationContext = wac;}// ... 省略其他代码 ...}// 2. 设置上下文属性if (this.webApplicationContext != null) {this.webApplicationContext.set ServletContext(getServletContext());this.webApplicationContext.set ServletConfig(getServletConfig());this.webApplicationContextRefresh();}// ... 省略其他代码 ...
}

创建WebApplicationContext时,会根据contextClass初始化参数决定使用哪个上下文实现类(默认是XmlWebApplicationContext),并根据contextConfigLocation参数加载配置 。

WebApplicationContext与根上下文的关系:如果配置了ContextLoaderListener,则根上下文由它负责创建,而DispatcherServlet的WebApplicationContext会成为根上下文的子上下文,可以访问根上下文中的Bean,但根上下文不能访问Servlet上下文中的Bean。

2.3 策略接口的初始化(HandlerMapping、ViewResolver等)

在完成WebApplicationContext的创建后,DispatcherServlet会调用onRefresh()方法,并在其中执行initStrategies()方法来初始化各种策略接口

//摘自FrameworkServlet类
protected void onRefresh(ApplicationContext context) {// ... 省略其他代码 ...// 1. 初始化各种策略initStrategies(context); [ty-reference](16) // ... 省略其他代码 ...
}//摘自FrameworkServlet类
protected void initStrategies(ApplicationContext context) {// 1. 初始化Multipart解析器  initMultipartResolver(context);// 2. 初始化locale解析器  initLocaleResolver(context);// 3. 初始化theme解析器  initThemeResolver(context);// 4. 初始化HandlerMapping  initHandlerMappings(context);// 5. 初始化HandlerAdapter  initHandlerAdapters(context);// 6. 初始化HandlerExceptionResolver  initHandlerExceptionResolvers(context);// 7. 初始化RequestToViewNameTranslator  initRequestToViewNameTranslator(context);// 8. 初始化ViewResolvers  initViewResolvers(context);// 9. 初始化FlashMapManager  initFlashMapManager(context);
}

策略接口初始化的顺序非常重要,它决定了组件的优先级和协作方式。例如,多个HandlerMapping会被按顺序查询,直到找到匹配的处理器为止 。

2.4 初始化参数详解

在web.xml中配置DispatcherServlet时,可以设置以下关键初始化参数:

参数名描述默认值
contextConfigLocation指定Spring MVC配置文件的位置/WEB-INF/[servlet-name]-servlet.xml
contextClass指定WebApplicationContext的类XmlWebApplicationContext
namespace指定WebApplicationContext的命名空间[servlet-name]-servlet
detectAllHandlerMappings是否检测所有HandlerMappingfalse
detectAllHandlerAdapters是否检测所有HandlerAdapterfalse

示例配置

<!-- web.xml -->
<servlet><servlet-name>mvcdemo</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:mvcdemo-servlet.xml</param-value></init-param><load-on-startup>1</load-on-startup>
</servlet><servlet-mapping><servlet-name>mvcdemo</servlet-name><url-pattern>/</url-pattern>
</servlet-mapping>

3. 请求处理流程详解

3.1 doService方法的职责

doService()是DispatcherServlet处理请求的核心方法,它定义在FrameworkServlet中,根据HTTP方法调用相应的处理方法(如doGet、doPost等),并最终调用doDispatch()**方法进行请求分发。

//摘自FrameworkServlet类
protected void doService(HttpServletRequest request, HttpServletResponse response)throws Exception {// ... 省略其他代码 ...// 1. 设置框架对象到请求中request.setAttribute(WEB_APPLICATION_CONTEXT attribute, getWebApplicationContext());request.setAttribute(LOCALE RESOLVER attribute, this.localeResolver);request.setAttribute(THEME RESOLVER attribute, this.themeResolver);request.setAttribute(THEME Source attribute, getThemeSource());// ... 省略其他代码 ...// 2. 调用doDispatch处理请求doDispatch(request, response); [ty-reference](7) // ... 省略其他代码 ...
}

3.2 doDispatch方法的执行步骤

**doDispatch()**是Spring MVC请求处理的核心方法,它定义在DispatcherServlet中,负责整个请求处理流程 :

//摘自DispatcherServlet类
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null;boolean multipartRequestParsed = false;WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);try {// 1. 检查并处理Multipart请求(如文件上传)  processedRequest = checkMultipart(request);multipartRequestParsed = (processedRequest != request);// 2. 获取HandlerExecutionChain(处理器和拦截器链)  mappedHandler = getHandler(processedRequest);  if (mappedHandler == null || mappedHandler.getHandler() == null) {noHandlerFound(processedRequest, response);  return;}// 3. 获取HandlerAdapter(处理器适配器)  HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());  // 4. 执行拦截器的preHandle方法  if (!mappedHandler.applyPreHandle(processedRequest, response)) {  return;}// 5. 调用处理器处理请求,获取ModelAndView  mv = ha.handle(processedRequest, response, mappedHandler.getHandler());// 6. 处理异步请求  if (asyncManager.isConcurrentHandlingStarted()) {return;}// 7. 应用默认视图名称  applyDefaultViewName(processedRequest, mv);// 8. 执行拦截器的postHandle方法  mappedHandler.applyPostHandle(processedRequest, response, mv);// 9. 渲染视图processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}catch (Exception ex) {// ... 省略其他代码 ...}catch (Throwable err) {// ... 省略其他代码 ...}finally {// ... 省略其他代码 ...}
}

关键执行步骤

  1. Multipart请求处理:检查请求是否包含文件上传,如果是则使用MultipartResolver进行解析
  2. 处理器查找:通过HandlerMapping查找与请求匹配的处理器,返回包含处理器和拦截器链的HandlerExecutionChain
  3. 处理器适配:通过HandlerAdapter获取处理器的执行方式
  4. 拦截器预处理:按顺序执行拦截器链的preHandle方法
  5. 处理器执行:调用处理器处理请求,返回ModelAndView
  6. 拦截器后处理:逆序执行拦截器链的postHandle方法
  7. 视图解析与渲染:通过ViewResolver解析视图名称,渲染模型数据到响应

3.3 拦截器(HandlerInterceptor)的作用与实现

HandlerInterceptor是Spring MVC中的拦截器接口,它定义了三个方法:

public interface HandlerInterceptor {// 1. 预处理(在处理器执行前)boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;// 2. 后处理(在处理器执行后)void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv) throws Exception;// 3. 完成处理(在视图渲染后)void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception;
}

拦截器执行顺序

当有多个拦截器时,preHandle方法按拦截器注册顺序执行,而postHandle和afterCompletion方法则按逆序执行 。

拦截器应用场景

  • 权限验证:检查用户是否有权访问当前请求
  • 日志记录:记录请求处理的开始和结束时间
  • 性能监控:统计处理器执行时间
  • 异常处理:统一处理处理器执行中的异常

示例拦截器

public class SecurityInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {// 1. 获取用户信息Object user = request.getSession()..getAttribute("user");// 2. 检查用户是否登录if (user == null) {// 3. 未登录则重定向到登录页面response.sendRedirect("/login");return false;}// 4. 检查权限String url = request.getRequestURI();if (!userHasPermission(user, url)) {// 5. 无权限则返回错误信息response.setStatus(HttpServletResponse status SC对于BAD对于REQUEST);return false;}// 6. 放行return true;}// 其他方法实现@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv) {// 处理ModelAndView}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {// 处理请求完成}private boolean userHasPermission(Object user, String url) {// 权限验证逻辑return true;}
}

4. 源码级解析

4.1 DispatcherServlet类的继承关系

DispatcherServlet的继承关系体现了Spring框架的设计思想和分层架构:

HttpServlet → HttpServletBean → FrameworkServlet → DispatcherServlet

各层职责

  • HttpServlet:Servlet规范的核心接口,定义了Servlet的基本生命周期方法
  • HttpServletBean:将Servlet配置参数转换为Bean属性的基类
  • FrameworkServlet:提供Spring Web应用的通用功能,如WebApplicationContext的创建和初始化
  • DispatcherServlet:实现请求分发的具体逻辑,是Spring MVC的前端控制器

这种继承结构使得Spring MVC能够无缝集成到Servlet容器中,同时保持高度的可扩展性和灵活性。

4.2 关键方法源码分析(doDispatch、processDispatchResult)

4.2.1 doDispatch方法源码分析

doDispatch()是Spring MVC请求处理的核心方法,其源码(Spring 6.0版本)位于org.springframework.web.servlet.DispatcherServlet类中,大约从第1200行开始:

//摘自DispatcherServlet.java(Spring 6.0)
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {// 1. 处理Multipart请求HttpServletRequest processedRequest = checkMultipart(request);boolean multipartRequestParsed = (processedRequest != request);// 2. 查找处理器HandlerExecutionChain mappedHandler = getHandler(processedRequest);if (mappedHandler == null || mappedHandler.getHandler() == null) {noHandlerFound(processedRequest, response);return;}// 3. 获取处理器适配器HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());// 4. 执行拦截器链的preHandle方法if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}// 5. 调用处理器处理请求MV mv = null;Exception dispatchException = null;try {mv = ha.handle(processedRequest, response, mappedHandler.getHandler());}catch (Exception ex) {dispatchException = ex;if (ex instanceofognl Exception) {// 保存ognl异常信息processedRequest.setAttribute(ognl Exception attribute, ex);}}catch (Throwable err) {// 处理Error异常dispatchException = newServletException("Handler dispatch failed", err);}// 6. 处理异步请求if (asyncManager.isConcurrentHandlingStarted()) {return;}// 7. 应用默认视图名称applyDefaultViewName(processedRequest, mv);// 8. 执行拦截器链的postHandle方法mappedHandler.applyPostHandle(processedRequest, response, mv);// 9. 处理分发结果processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}

关键逻辑点

  • Multipart处理:通过checkMultipart()方法检查并处理文件上传请求
  • 处理器查找:通过getHandler()方法查找与请求匹配的处理器
  • 拦截器链执行:通过applyPreHandle()applyPostHandle()方法执行拦截器链
  • 异常处理:捕获异常并传递给processDispatchResult()方法处理
4.2.2 processDispatchResult方法源码分析

processDispatchResult()方法负责处理处理器返回的结果,包括视图解析和渲染:

//摘自DispatcherServlet.java(Spring 6.0)
protected void processDispatchResult(HttpServletRequest request, HttpServletResponse response,HandlerExecutionChain mappedHandler,ModelAndView mv, Exception exception) throws Exception {// 1. 处理异常if (exception != null) {mv = resolveException(request, response, mappedHandler.getHandler(), exception);}// 2. 渲染视图if (mv != null) {mv = applyViewName Trans later(request, mv, mappedHandler);mv = mappedHandler.applyViewName Trans later(request, mv);mv =暴露Model到请求中(request, mv, mappedHandler);// 3. 解析视图View view = resolveViewName(mv至少视图名, mv至少模型, request);if (view != null) {// 4. 渲染视图view.render(mv至少模型, request, response);}// 5. 执行拦截器链的afterCompletion方法mappedHandler.applyAfterCompletion(request, response, mv至少模型);}
}

关键逻辑点

  • 异常处理:通过resolveException()方法处理处理器执行过程中的异常
  • 视图解析:通过resolveViewName()方法将逻辑视图名解析为具体视图
  • 视图渲染:调用视图的render()方法将模型数据渲染到响应
  • 拦截器完成处理:执行拦截器链的afterCompletion方法
4.2.3 拦截器链执行源码分析

拦截器链的执行逻辑在HandlerExecutionChain类中实现:

//摘自HandlerExecutionChain.java
public boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {// 1. 按注册顺序执行preHandle方法for (HandlerInterceptor interceptor : this.interceptors) {if (!interceptor.preHandle(request, response, this handler)) {triggerAfterCompletion(request, response, this handler, null);return false;}}return true;
}public void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {// 2. 按逆序执行postHandle方法for (int i = this.interceptors.size() - 1; i >= 0; i--) {HandlerInterceptorInterceptor = this.interceptors.get(i);拦截器.postHandle(request, response, this handler, mv);}
}public void applyAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception {// 3. 按逆序执行afterCompletion方法for (int i = this.interceptors.size() - 1; i >= 0; i--) {HandlerInterceptor拦截器 = this.interceptors.get(i);try {拦截器.afterCompletion(request, response, this handler, ex);}catch (Exception err) {// 记录错误但不抛出handleAfterCompletionError(拦截器, err);}}
}

拦截器链执行顺序

  • preHandle:按拦截器注册顺序执行
  • postHandle:按拦截器注册逆序执行
  • afterCompletion:按拦截器注册逆序执行

这种顺序设计确保了拦截器的执行逻辑符合"进入时按顺序,退出时按逆序"的编程模式。

4.3 策略接口设计(HandlerMapping、HandlerAdapter)

4.3.1 HandlerMapping接口设计

HandlerMapping接口定义了如何根据请求找到对应的处理器:

public interface HandlerMapping {// 根据请求查找处理器HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;// 根据处理器查找请求路径String getHandlerPath(Object handler);// 获取支持的请求方法Set<HttpMethod> getHandlerMethods(Object handler);
}

Spring提供了多种HandlerMapping实现,包括:

  • BeanNameUrlHandlerMapping:根据Bean名称与URL路径匹配
  • RequestMappingHandlerMapping:根据@RequestMapping注解匹配(默认实现)
  • SimpleUrlHandlerMapping:根据简单URL模式匹配

策略模式应用:通过HandlerMapping接口,Spring MVC可以轻松支持多种请求到处理器的映射策略,开发者也可以实现自定义的HandlerMapping。

4.3.2 HandlerAdapter接口设计

HandlerAdapter接口定义了如何调用处理器处理请求:

public interface HandlerAdapter {// 判断是否支持某个处理器boolean supports(Object handler);// 调用处理器处理请求ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;// 获取处理器的最后修改时间long最后一次修改时间(HttpServletRequest request, Object handler);
}

Spring提供了多种HandlerAdapter实现,包括:

  • ControllerHandlerAdapter:处理实现Controller接口的处理器
  • HttpRequestHandlerAdapter:处理实现HttpRequestHandler接口的处理器
  • HandlerMethodAdapter:处理基于方法的处理器(如使用@RequestMapping注解的方法)

适配器模式应用:通过HandlerAdapter接口,Spring MVC可以统一处理不同类型的处理器,使得处理器的实现更加灵活。

4.3.3 ViewResolver接口设计

ViewResolver接口定义了如何将逻辑视图名解析为具体视图:

public interface ViewResolver {// 将逻辑视图名解析为具体视图View resolveViewName(String viewName, Locale locale,(HttpServletRequest request, HttpServletResponse response)) throws Exception;// 获取支持的视图名String[]得到视图名();
}

Spring提供了多种ViewResolver实现,包括:

  • InternalResourceViewResolver:解析为JSP视图(默认实现)
  • UrlBasedViewResolver:根据URL解析视图
  • FreeMarkerViewResolver:解析为FreeMarker视图

策略模式应用:通过ViewResolver接口,Spring MVC可以支持多种视图技术,开发者也可以实现自定义的ViewResolver。

4.4 扩展点分析

Spring MVC提供了多个扩展点,允许开发者自定义和增强框架功能:

  1. 自定义HandlerMapping:实现HandlerMapping接口,重写getHandler()方法
  2. 自定义HandlerAdapter:实现HandlerAdapter接口,重写handle()方法
  3. 自定义ViewResolver:实现ViewResolver接口,重写resolveViewName()方法
  4. 自定义拦截器:实现HandlerInterceptor接口,重写preHandle()等方法
  5. 自定义异常处理器:实现HandlerExceptionResolver接口,重写resolveException()方法

示例:自定义HandlerMapping

public class CustomHandlerMapping implements HandlerMapping {@Overridepublic HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {// 自定义处理器查找逻辑String uri = request.getRequestURI();// 1. 查找处理器Object handler = findHandler(uri);// 2. 查找拦截器List<HandlerInterceptor> interceptors = findInterceptors(uri);return new HandlerExecutionChain(handler, interceptors);}@Overridepublic String getHandlerPath(Object handler) {// 自定义处理器路径获取逻辑return null;}@Overridepublic Set<HttpMethod> getHandlerMethods(Object handler) {// 自定义处理器方法获取逻辑return null;}private Object findHandler(String uri) {// 查找处理器逻辑return null;}private List<HandlerInterceptor> findInterceptors(String uri) {// 查找拦截器逻辑return null;}
}

5. 配置方式与示例

5.1 传统web.xml配置

web.xml配置示例

<!-- web.xml -->
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http:// xmlns . jcp . org / xml / ns / javaee http:// xmlns . jcp . org / xml / ns / javaee / web - app _ 4 _ 0 . xsd"version="4.0"><!-- 1. 配置DispatcherServlet --><servlet><servlet-name>mvcdemo</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:mvcdemo-servlet.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><!-- 2. 配置DispatcherServlet的映射路径 --><servlet-mapping><servlet-name>mvcdemo</servlet-name><url-pattern>/</url-pattern></servlet-mapping><!-- 3. 配置根上下文(可选) --><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value></context-param>< listener >< listener-class > org.springframework.web.context.ContextLoaderListener </ listener-class ></ listener >
</web-app>

关键配置参数

  • contextConfigLocation:指定Spring MVC配置文件的位置
  • load-on-startup:指定Servlet的初始化顺序,值大于0表示容器启动时初始化
  • namespace:指定WebApplicationContext的命名空间(默认是servlet-name-servlet)

5.2 Java配置类方式

Java配置类示例

// 1. 创建Web应用上下文
public class WebAppContext implements WebApplicationInitializer {@Overridepublic void onStartup(ServletContext container) {// 1. 创建根上下文ContextLoaderListener listener = new ContextLoaderListener(newAnnotationConfigWebApplicationContext());listener.getApplicationContext().setConfigLocation("com.example.config rootConfig");container.addListener(listener);// 2. 创建DispatcherServlet上下文DispatcherServlet分散器 = new分散器();分散器.setContextClass(AnnotationConfigWebApplicationContext.class);分散器.setContextConfigLocation("com.example.config mvcConfig");// 3. 注册DispatcherServletServletRegistration动态注册 = container.addServlet("mvcdemo",分散器);dynamicRegistration.setLoadOnStartup(1);dynamicRegistration.addMapping("/");// 4. 配置其他Servlet参数分散器.getServletConfig().getInitParameter("namespace", "mvcdemo");}
}

Web MVC配置类

// 1. 配置Spring MVC组件
@Configuration
@EnableWebMvc
@ComponentScan("com.example.controller")
public class桂cConfig implements WebMvcConfigurer {// 2. 配置视图解析器@Overridepublic void configureViewResolvers(List<ViewResolver> viewResolvers) {InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();viewResolver.setPrefix("/WEB-INF/jsp/");  viewResolver.setSuffix(".jsp");  viewResolvers.add(viewResolver);}// 3. 配置静态资源处理器@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");  }// 4. 配置拦截器@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new SecurityInterceptor())  .addPathPatterns("/**")  .excludePathPatterns("/login", "/css/**", "/js/**");  }// 5. 配置异常处理器@Overridepublic void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {resolvers.add(new DefaultHandlerExceptionResolver());}// 6. 配置消息转换器@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {converters.add(new MappingJackson2HttpMessageConverter());}
}

Java配置方式的优势

  • 更加灵活,可以通过代码动态配置
  • 更加类型安全,避免XML配置中的字符串错误
  • 更容易进行单元测试
  • 更符合现代Java开发习惯

6. 常见问题与解决方案

6.1 请求未匹配到处理器的调试方法

问题表现:当请求路径没有对应的处理器时,Spring MVC会抛出`No mapping found for HTTP request`异常,导致404错误 [ty-reference](17) 。排查步骤:
检查日志级别:将Spring日志级别设置为DEBUG,查看`HandlerExecutionChain`是否找到处理器 
 # application.propertieslogging.level.org.springframework.web=DEBUGlogging.level.org.springframework.web.servlet=DEBUG
  1. 检查处理器映射

    • 确认是否使用了正确的HandlerMapping(如RequestMappingHandlerMapping)
    • 确认是否扫描了包含处理器(Controller)的包
  2. 检查处理器注解

    • 确认Controller类是否使用了@Controller注解
    • 确认处理方法是否使用了@RequestMapping等注解
    • 确认注解路径是否与请求路径匹配
  3. 检查拦截器配置:确认拦截器是否阻止了请求的处理

6.2 视图解析失败的排查思路

问题表现:处理器返回了ModelAndView,但Spring MVC无法解析视图,导致500错误。

排查步骤

  1. 检查视图解析器配置:确认是否配置了视图解析器(如InternalResourceViewResolver)

  2. 检查视图名称格式:确认处理器返回的视图名称是否符合视图解析器的解析规则

  3. 检查视图文件位置:确认视图文件是否存在于指定位置(如/WEB-INF/jsp/)

  4. 检查视图文件权限:确认视图文件是否有读取权限

  5. 检查视图渲染异常:查看日志中是否有视图渲染相关的异常信息

解决方案示例

// 配置InternalResourceViewResolver
@Bean
public ViewResolver internalResourceViewResolver() {InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();viewResolver.setPrefix("/WEB-INF/jsp/");  viewResolver.setSuffix(".jsp");  return viewResolver;
}

6.3 多个DispatcherServlet的配置冲突

问题表现:当配置多个DispatcherServlet时,可能会出现URL映射冲突、上下文覆盖等问题。

配置冲突原因

  1. URL映射重叠:多个DispatcherServlet的url-pattern重叠,导致请求被多个Servlet处理 
  2. 命名空间冲突:多个DispatcherServlet的namespace参数相同,导致上下文覆盖 
  3. Bean名称冲突:多个DispatcherServlet的上下文中存在同名Bean,导致Bean覆盖 

解决方案

  1. 区分URL映射:为每个DispatcherServlet设置不同的url-pattern,避免重叠

    <!-- 第一个DispatcherServlet -->
    <servlet-mapping><servlet-name>apiServlet</servlet-name><url-pattern>/api/*</url-pattern>
    </servlet-mapping><!-- 第二个DispatcherServlet -->
    <servlet-mapping><servlet-name>webServlet</servlet-name><url-pattern>/web/*</url-pattern>
    </servlet-mapping>
  2. 设置不同命名空间:为每个DispatcherServlet设置不同的namespace参数,避免上下文冲突

    <!-- 第一个DispatcherServlet -->
    <init-param><param-name>namespace</param-name><param-value>apiContext</param-value>
    </init-param><!-- 第二个DispatcherServlet -->
    <init-param><param-name>namespace</param-name><param-value>webContext</param-value>
    </init-param>
  3. 设置不同初始化顺序:通过load-on-startup参数设置不同的初始化顺序,避免上下文加载冲

    <!-- 第一个DispatcherServlet -->
    <load-on-startup>1</load-on-startup><!-- 第二个DispatcherServlet -->
    <load-on-startup>2</load-on-startup>
  4. 分离配置文件:为每个DispatcherServlet使用不同的配置文件,避免配置冲突

    <!-- 第一个DispatcherServlet -->
    <init-param><param-name>contextConfigLocation</param-name><param-value>classpath:api-servlet.xml</param-value>
    </init-param><!-- 第二个DispatcherServlet -->
    <init-param><param-name>contextConfigLocation</param-name><param-value>classpath:web-servlet.xml</param-value>
    </init-param>

多DispatcherServlet应用场景

  • 前后端分离:一个处理API请求,一个处理Web页面
  • 模块化应用:不同模块使用不同的DispatcherServlet
  • 多视图技术:不同视图技术使用不同的DispatcherServlet

6.4 其他常见问题

6.4.1 404错误排查

问题表现:请求返回404错误,表示请求路径没有对应的处理器。

排查思路

  1. 检查请求路径:确认请求路径是否与处理器映射路径匹配 
  2. 检查HTTP方法:确认处理器是否支持当前HTTP方法 
  3. 检查参数匹配:确认请求参数是否符合处理器参数要求 
  4. 检查静态资源:确认静态资源是否被正确配置
  5. 检查拦截器:确认拦截器是否阻止了请求的处理

解决方案示例

// 确保处理器路径正确
@RestController
@RequestMapping("/api") [ty-reference](12) 
public class示范Controller {// 处理GET请求@GetMapping("/hello") [ty-reference](12) public String hello() {return "Hello World";}// 处理POST请求@PostMapping("/greet") [ty-reference](12) public String greet(@RequestParam String name) { [ty-reference](12) return "Hello " + name;}
}
6.4.2 500错误排查

问题表现:请求返回500错误,表示处理器执行过程中发生了异常。

排查思路

  1. 检查日志:查看Spring日志中是否有异常信息 
  2. 检查处理器方法:确认处理器方法是否有语法错误或逻辑错误 
  3. 检查依赖注入:确认处理器依赖的Bean是否正确注入 
  4. 检查异常处理:确认是否配置了异常处理器(如HandlerExceptionResolver)
  5. 检查视图解析:确认视图解析器是否正确配置

解决方案示例

// 配置全局异常处理器
@ControllerAdvice
public class GlobalExceptionHandler {// 处理所有异常@ExceptionHandler(Exception.class)public ModelAndView handleException(Exception ex) {ModelAndView mv = new ModelAndView("error");mv.addObject("exception", ex);return mv;}// 处理特定异常@ExceptionHandler(NullPointerException.class)public ResponseEntity<String> handleNullPointerException(NullPointerException ex) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Internal server error: " + ex.getMessage());}
}
http://www.dtcms.com/a/315759.html

相关文章:

  • 【开源工具】基于Python的PDF清晰度增强工具全解析(附完整源码)
  • LeetCode算法日记 - Day 2: 快乐数、盛水最多容器
  • 力扣经典算法篇-43-全排列(经典回溯问题)
  • vite面试题及详细答案120题(01-30)
  • 普通树状数组
  • 《Node.js与 Elasticsearch的全文搜索架构解析》
  • Leetcode 13 java
  • 2025-08-05Gitee + PicGo + Typora搭建免费图床
  • MongoDB学习专题(二)核心操作
  • MongoDB 从3.4.0升级到4.0.0完整指南实战-优雅草蜻蜓I即时通讯水银版成功升级-卓伊凡|bigniu
  • 时序数据库flux aggregateWindow命令详解
  • Baumer相机如何通过YoloV8深度学习模型实现道路场所路人口罩的检测识别(C#代码UI界面版)
  • 概率论之条件概率
  • ubuntu自动重启BUG排查指南
  • C++ - 仿 RabbitMQ 实现消息队列--服务端核心模块实现(六)
  • Go 单元测试:如何只运行某个测试函数(精确控制)
  • C++ 网络编程入门:TCP 协议下的简易计算器项目
  • 【STM32】HAL库中的实现(四):RTC (实时时钟)
  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段(14):文法:ていく+きた+单词
  • MQTT学习
  • Starrocks 关于 trace 命令的说明
  • C# --- 本地缓存失效形成缓存击穿触发限流
  • 【面向对象】面向对象七大原则
  • 【乐企板式文件生成工程】关于乐企板式文件(PDF/OFD/XML)生成工程介绍
  • [2401MT-B] 面积比较
  • 翻译的本质:人工翻译vs机器翻译的核心差异与互补性
  • Starrocks中的 Query Profile以及explain analyze及trace命令中的区别
  • MySQL 中 VARCHAR 和 TEXT 的区别
  • 智慧酒店:科技赋能下的未来住宿新体验
  • Spring-rabbit使用实战六