1. 总控台登场:DispatcherServlet的运作原理
如果把Spring MVC比作剧场表演,DispatcherServlet就是那个掌控全场的总导演。它驻守在Web容器入口,所有HTTP请求都要通过它的调度才能找到对应演员(Controller)。
在典型的Spring MVC项目中,web.xml配置着这个核心调度员:
<!-- 配置Spring MVC请求总控 -->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-mvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 映射所有以.do结尾的请求 -->
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
启动时依次执行:
- 读取初始化参数定位配置文件
- 创建WebApplicationContext(父子容器隔离业务层)
- 加载HandlerMapping、ViewResolver等基础设施
- 注册默认策略实现(当用户未配置时启用)
2. 八步走完请求流程:深度剖析处理链路
当用户请求/user/list.do
时:
// 模拟核心流程的伪代码
public void doDispatch(HttpServletRequest request, HttpServletResponse response) {
// Step1:通过HandlerMapping路由匹配
HandlerExecutionChain mappedHandler = getHandler(request);
// Step2:适配到具体处理方法(支持多种Handler)
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Step3:执行拦截器preHandle()
if (!mappedHandler.applyPreHandle(request, response)) return;
// Step4:实际调用Controller方法
ModelAndView mv = ha.handle(request, response, mappedHandler.getHandler());
// Step5:应用默认视图名(如果方法返回字符串)
applyDefaultViewName(request, mv);
// Step6:执行拦截器postHandle()
mappedHandler.applyPostHandle(request, response, mv);
// Step7:视图解析和渲染
processDispatchResult(request, response, mv, dispatchException);
// Step8:完成后的收尾处理
mappedHandler.triggerAfterCompletion(request, response, null);
}
真实项目中的用户列表控制器示例:
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
// 用户列表查询
@GetMapping("/list.do")
public String listUsers(Model model,
@RequestParam(defaultValue = "1") int pageNo) {
// 查询数据库获取分页数据
Page<User> userPage = userService.getUsersByPage(pageNo, 10);
// 将数据存入模型
model.addAttribute("userList", userPage.getContent());
model.addAttribute("totalPages", userPage.getTotalPages());
// 返回视图逻辑名
return "user/list";
}
// 用户注册表单处理
@PostMapping("/register.do")
public ModelAndView registerUser(@Valid UserForm form, BindingResult result) {
ModelAndView mav = new ModelAndView();
if (result.hasErrors()) {
mav.setViewName("user/register");
mav.addObject("errors", result.getAllErrors());
return mav;
}
userService.createUser(form);
mav.setViewName("redirect:/user/success.do");
return mav;
}
}
3. 黄金搭档:核心组件深度协同
3.1 路由管家 HandlerMapping
提供四种实现策略:
- BeanNameUrlHandlerMapping(基于Bean名称)
- RequestMappingHandlerMapping(注解驱动)
- RouterFunctionMapping(函数式编程)
- SimpleUrlHandlerMapping(XML配置)
配置示例:
<!-- 显式配置处理器映射策略 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="order" value="0"/>
</bean>
3.2 视图魔术师 ViewResolver
常见视图解析方案:
# 内部资源视图解析器
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
# 启用多个视图解析器链
<bean class="org.springframework.web.servlet.view.XmlViewResolver"/>
<bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver"/>
4. 应用场景全景扫描
4.1 典型适用场景
- RESTful API开发(配合@RestController)
- 传统表单驱动Web应用
- 前后端分离项目中的路由控制
- 微服务网关的请求转发
4.2 黄金搭档技术选型
| 技术组合 | 适用场景 |
|------------------|--------------------------|
| Thymeleaf模板引擎 | 传统JSP替代方案 |
| Jackson JSON库 | RESTful API数据序列化 |
| Hibernate Validator | 数据校验 |
| Spring Security | 安全认证控制 |
5. 优劣辩证看:技术选型指南
优势亮点:
- 模块解耦:各组件职责单一明确
- 扩展灵活:支持自定义处理器和视图
- 生态强大:与Spring全家桶无缝集成
- 注解驱动:简化配置提升开发效率
潜在挑战:
- 学习曲线:需理解MVC设计模式
- 配置复杂:多个配置文件的协调
- 性能损耗:相较于直接Servlet开发略有损耗
6. 避坑指南:经验总结
- 路由陷阱:
<!-- 错误的URL映射模式 -->
<url-pattern>/</url-pattern> <!-- 可能导致静态资源被拦截 -->
<!-- 推荐配置方案 -->
<url-pattern>/api/*</url-pattern>
<url-pattern>*.do</url-pattern>
- 并发安全:
// 错误示范:在Controller中定义实例变量
@Controller
public class UnsafeController {
private int counter = 0; // 存在线程安全问题
@GetMapping("/count")
@ResponseBody
public String count() {
return "Current count: " + (++counter);
}
}
- 调试技巧: 启用详细日志配置:
logging.level.org.springframework.web.servlet=DEBUG
logging.level.org.springframework.web=TRACE
7. 未来演进方向
随着Spring Boot的普及,配置方式趋向自动化:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/views/", ".jsp");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoggingInterceptor());
}
}