目录
[一、Spring MVC 中命令模式的核心映射关系](#一、Spring MVC 中命令模式的核心映射关系)
[二、Spring MVC 中命令模式的执行流程](#二、Spring MVC 中命令模式的执行流程)
[1. 抽象命令:Handler 接口体系](#1. 抽象命令:Handler 接口体系)
[2. 具体命令:自定义 Controller(封装请求处理逻辑)](#2. 具体命令:自定义 Controller(封装请求处理逻辑))
[3. 调用者:DispatcherServlet(触发命令执行)](#3. 调用者:DispatcherServlet(触发命令执行))
[4. 接收者:Service/DAO 层(执行核心业务)](#4. 接收者:Service/DAO 层(执行核心业务))
[三、Spring MVC 中命令模式的扩展特性(命令模式的高级用法)](#三、Spring MVC 中命令模式的扩展特性(命令模式的高级用法))
[1. 命令参数化(动态适配不同请求参数)](#1. 命令参数化(动态适配不同请求参数))
[2. 命令的异常处理(统一命令执行结果)](#2. 命令的异常处理(统一命令执行结果))
[3. 命令拦截(责任链 + 命令模式结合)](#3. 命令拦截(责任链 + 命令模式结合))
[4. 命令的异步执行(异步命令)](#4. 命令的异步执行(异步命令))
[四、Spring MVC 中命令模式的典型应用场景](#四、Spring MVC 中命令模式的典型应用场景)
[1. 不同请求类型的命令适配](#1. 不同请求类型的命令适配)
[2. RESTful 接口(REST 命令)](#2. RESTful 接口(REST 命令))
[3. 表单提交(命令对象模式)](#3. 表单提交(命令对象模式))
[五、Spring MVC 命令模式的核心价值](#五、Spring MVC 命令模式的核心价值)
[1. 解耦请求触发与业务执行](#1. 解耦请求触发与业务执行)
[2. 高度可扩展](#2. 高度可扩展)
[3. 统一请求处理流程](#3. 统一请求处理流程)
[六、命令模式 vs Spring MVC 传统理解的区别](#六、命令模式 vs Spring MVC 传统理解的区别)
一、Spring MVC 中命令模式的核心映射关系
Spring MVC 的核心请求处理流程完全贴合命令模式的设计思想,其本质是将 "HTTP 请求处理" 封装为命令对象,由前端控制器(调用者)触发执行,业务逻辑层(接收者)完成实际处理。
先明确命令模式核心角色与 Spring MVC 组件的对应关系:
| 命令模式角色 | Spring MVC 对应组件 | 核心职责 |
|---|---|---|
| 抽象命令(Command) | Handler 接口体系(Controller、HttpRequestHandler、Servlet) |
定义请求处理的统一接口(如 handleRequest、doGet/doPost),是所有 "请求处理命令" 的抽象 |
| 具体命令(ConcreteCommand) | 自定义 @Controller 类(如 UserController)、@RestController 类 |
实现抽象命令接口(隐式实现),封装具体的请求处理逻辑(如 /user/get 接口) |
| 调用者(Invoker) | DispatcherServlet(前端控制器) |
持有具体命令对象(Handler),触发命令执行(调用 HandlerAdapter.handle()),不关心具体处理逻辑 |
| 接收者(Receiver) | Service/DAO 层(如 UserService、UserMapper) |
真正执行业务逻辑(如查询用户、操作数据库),是命令的最终执行者 |
| 命令参数(Command Param) | HandlerMethodArgumentResolver 解析的参数(如 @RequestParam、@RequestBody) |
命令对象执行所需的参数,由 Spring MVC 自动解析并传入具体命令 |
二、Spring MVC 中命令模式的执行流程
Spring MVC 处理 HTTP 请求的过程,就是命令模式 "调用者触发命令、命令调用接收者" 的完整落地,核心流程如下:
plaintext
客户端发送 HTTP 请求 →
1. Tomcat 转发请求到 DispatcherServlet(调用者)→
2. DispatcherServlet 通过 HandlerMapping 匹配到具体的 Controller(具体命令)→
3. DispatcherServlet 委托 HandlerAdapter 执行 Controller 方法(触发命令执行)→
4. Controller 调用 Service/DAO(接收者)完成业务逻辑 →
5. Service/DAO 返回结果给 Controller(命令执行完成)→
6. DispatcherServlet 渲染视图/返回 JSON(命令执行结果响应)
关键环节拆解(结合源码级逻辑)
1. 抽象命令:Handler 接口体系
Spring MVC 定义了多种 "请求处理命令" 的抽象,最核心的是 Controller 接口(简化版):
java
运行
// 抽象命令:处理 HTTP 请求的核心接口
public interface Controller {
// 命令执行方法:处理请求并返回 ModelAndView
ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
此外,@Controller 注解的类本质是 "隐式的具体命令",Spring MVC 通过 RequestMappingHandlerAdapter 适配其方法执行,等价于实现了抽象命令的 execute 方法。
2. 具体命令:自定义 Controller(封装请求处理逻辑)
开发者编写的 @Controller 是命令模式的 "具体命令",每个接口方法对应一个具体的命令逻辑:
java
运行
// 具体命令:用户模块请求处理命令
@Controller
@RequestMapping("/user")
public class UserController { // 具体命令类
// 接收者:业务逻辑层
@Autowired
private UserService userService;
// 具体命令方法:处理 /user/get 请求
@GetMapping("/get")
@ResponseBody
public User getUser(@RequestParam Long id) { // 命令参数
// 命令执行逻辑:调用接收者完成业务
return userService.getUserById(id);
}
}
- 该
UserController是 "具体命令对象",getUser方法是命令的 "执行逻辑"; @RequestParam Long id是命令执行所需的参数;UserService是命令的 "接收者",负责真正的业务处理。
3. 调用者:DispatcherServlet(触发命令执行)
DispatcherServlet 是命令模式的 "调用者",核心逻辑在 doDispatch 方法(简化版):
java
运行
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
try {
ModelAndView mv = null;
// 1. 匹配具体命令:通过 HandlerMapping 找到对应的 Controller(具体命令)
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 2. 获取命令执行器:HandlerAdapter(适配不同类型的命令)
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 3. 触发命令执行:调用 Controller 方法(执行具体命令)
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 4. 处理命令执行结果:渲染视图/返回响应
processDispatchResult(processedRequest, response, mappedHandler, mv, null);
} catch (Exception ex) {
// 异常处理
}
}
getHandler():从HandlerMapping(如RequestMappingHandlerMapping)中匹配到UserController这个具体命令;ha.handle():触发命令执行(调用UserController.getUser()),调用者无需知道getUser的具体逻辑;- 整个过程中,
DispatcherServlet只负责 "触发命令",不关心命令的具体实现。
4. 接收者:Service/DAO 层(执行核心业务)
UserService 是命令的 "接收者",包含真正的业务逻辑,与命令对象解耦:
java
运行
// 接收者:用户业务逻辑处理
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
// 接收者的核心方法:真正执行"查询用户"逻辑
public User getUserById(Long id) {
return userMapper.selectById(id);
}
}
命令对象(UserController)只需调用接收者的方法,无需关心 "如何查询数据库",实现了 "请求触发" 与 "业务执行" 的解耦。
三、Spring MVC 中命令模式的扩展特性(命令模式的高级用法)
Spring MVC 基于命令模式的核心设计,扩展了命令模式的典型能力,贴合实际业务需求:
1. 命令参数化(动态适配不同请求参数)
命令模式支持 "命令参数化",Spring MVC 通过 HandlerMethodArgumentResolver 实现参数的动态解析,让同一个命令(Controller 方法)适配不同参数:
java
运行
// 同一个命令方法,支持不同参数(参数化命令)
@PostMapping("/create")
@ResponseBody
public Long createUser(@RequestBody User user) { // JSON 参数
return userService.createUser(user);
}
@PostMapping("/update")
@ResponseBody
public Boolean updateUser(@RequestParam Long id, @RequestParam String name) { // 普通参数
return userService.updateUserName(id, name);
}
- 不同参数类型(JSON、表单、路径参数)通过不同的
ArgumentResolver解析后传入命令方法; - 命令对象(Controller)无需关心参数来源,只需接收参数并调用接收者,体现命令模式 "参数封装" 的特性。
2. 命令的异常处理(统一命令执行结果)
Spring MVC 通过 HandlerExceptionResolver 统一处理命令执行中的异常,等价于命令模式中 "命令执行失败的统一处理":
java
运行
// 全局异常处理器(统一处理命令执行异常)
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public Result<?> handleBusinessException(BusinessException e) {
return Result.fail(e.getCode(), e.getMessage());
}
}
- 命令执行(Controller 方法)中抛出的异常,由统一的处理器处理,避免每个命令都编写异常逻辑;
- 符合命令模式 "解耦命令执行与异常处理" 的设计思想。
3. 命令拦截(责任链 + 命令模式结合)
Spring MVC 的 HandlerInterceptor 是责任链模式,但与命令模式结合,实现命令执行前后的拦截增强:
java
运行
// 拦截命令执行前后的逻辑
@Component
public class LogInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 命令执行前:记录请求日志
System.out.println("命令执行前:" + request.getRequestURI());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 命令执行后:记录响应日志
System.out.println("命令执行后:" + response.getStatus());
}
}
- 拦截器在命令(Controller 方法)执行前后增强逻辑,不修改命令本身,符合命令模式 "开闭原则";
- 责任链 + 命令模式的结合,让命令执行流程更灵活。
4. 命令的异步执行(异步命令)
Spring MVC 支持 @Async 实现命令的异步执行,等价于命令模式的 "异步命令":
java
运行
// 异步命令:后台执行,不阻塞请求响应
@GetMapping("/async/get")
@ResponseBody
@Async
public CompletableFuture<User> asyncGetUser(@RequestParam Long id) {
return CompletableFuture.supplyAsync(() -> userService.getUserById(id));
}
- 调用者(
DispatcherServlet)触发命令后,无需等待命令执行完成,直接返回响应; - 命令在后台线程中执行,体现命令模式 "解耦调用者与命令执行时机" 的特性。
四、Spring MVC 中命令模式的典型应用场景
1. 不同请求类型的命令适配
Spring MVC 支持多种 "命令类型"(Handler),适配不同的请求处理场景,均基于命令模式:
| 命令类型 | 适用场景 | 示例 |
|---|---|---|
@Controller + @RequestMapping |
普通 MVC 请求(返回视图 / JSON) | UserController 处理 /user/* 请求 |
HttpRequestHandler |
低级别 Servlet 风格请求处理 | 处理静态资源、文件下载 |
Servlet |
原生 Servlet 适配 | 集成老旧 Servlet 程序 |
FunctionController |
函数式请求处理(Spring 6+) | RouterFunctions.route() 定义路由 |
2. RESTful 接口(REST 命令)
RESTful 接口是命令模式的典型落地,每个 HTTP 方法(GET/POST/PUT/DELETE)对应一个具体命令:
java
运行
// RESTful 命令:CRUD 对应不同命令
@RestController
@RequestMapping("/api/user")
public class UserRestController {
@Autowired
private UserService userService;
// GET 命令:查询用户
@GetMapping("/{id}")
public User get(@PathVariable Long id) {
return userService.getUserById(id);
}
// POST 命令:创建用户
@PostMapping
public Long create(@RequestBody User user) {
return userService.createUser(user);
}
// PUT 命令:更新用户
@PutMapping("/{id}")
public Boolean update(@PathVariable Long id, @RequestBody User user) {
return userService.updateUser(id, user);
}
// DELETE 命令:删除用户
@DeleteMapping("/{id}")
public Boolean delete(@PathVariable Long id) {
return userService.deleteUser(id);
}
}
- 每个 REST 接口方法是一个独立的 "具体命令",封装了对应的业务操作;
- 调用者(
DispatcherServlet)根据 HTTP 方法和路径匹配对应的命令,触发执行。
3. 表单提交(命令对象模式)
Spring MVC 支持将表单参数封装为 "命令对象"(Command Object),是命令模式的直接应用:
java
运行
// 命令对象:封装表单参数
@Data
public class UserForm {
private String username;
private String password;
private Integer age;
}
// 具体命令:处理表单提交
@Controller
@RequestMapping("/form")
public class UserFormController {
@Autowired
private UserService userService;
// 命令方法:接收命令对象参数
@PostMapping("/user")
public String submitUserForm(UserForm userForm) {
userService.createUserFromForm(userForm);
return "redirect:/user/list";
}
}
UserForm是 "命令参数对象",封装了表单提交的所有参数;submitUserForm是命令执行方法,接收参数并调用接收者完成业务。
五、Spring MVC 命令模式的核心价值
1. 解耦请求触发与业务执行
DispatcherServlet(调用者)只需触发命令执行,无需知道 "如何查询用户、如何创建订单";Controller(命令对象)只需调用Service(接收者),无需关心 "请求如何转发、参数如何解析";Service(接收者)只需专注业务逻辑,无需关心 "请求从哪里来、响应如何返回"。
2. 高度可扩展
- 新增业务接口(命令),只需新增
Controller类 / 方法,无需修改DispatcherServlet核心逻辑; - 新增参数类型(如自定义注解参数),只需新增
ArgumentResolver,无需修改命令对象; - 新增命令类型(如 WebSocket 处理),只需实现对应的
Handler接口,适配HandlerAdapter即可。
3. 统一请求处理流程
所有请求都通过 "调用者 → 命令对象 → 接收者" 的流程处理,保证了请求处理的一致性:
- 统一的参数解析、异常处理、拦截增强;
- 统一的请求日志、性能监控、安全校验。
六、命令模式 vs Spring MVC 传统理解的区别
很多开发者认为 Spring MVC 是 "MVC 模式",但 MVC 是架构模式,而命令模式是行为模式,二者并不冲突:
- MVC 模式:关注 "模型(Model)、视图(View)、控制器(Controller)" 的分层,解决 "数据、展示、交互" 的分离;
- 命令模式:关注 "请求触发与业务执行" 的解耦,解决 "谁触发、谁执行、怎么执行" 的分离;
- Spring MVC 中,
Controller既是 MVC 模式的 "控制器",也是命令模式的 "具体命令对象",是两种模式的结合落地。
总结
Spring MVC 是命令模式在 Web 框架中的经典落地,核心要点:
- 核心映射 :
DispatcherServlet是调用者,@Controller是具体命令,Service/DAO是接收者; - 核心流程:调用者匹配命令 → 触发命令执行 → 命令调用接收者 → 处理执行结果;
- 核心价值:解耦请求触发与业务执行,支持命令的参数化、异步化、拦截增强;
- 扩展特性:结合责任链(拦截器)、参数解析、异常处理,让命令模式适配 Web 场景的复杂需求。
理解 Spring MVC 中的命令模式,能帮助开发者更清晰地设计可扩展的 Controller 层,也能更好地理解 Spring MVC 的核心源码逻辑(如 DispatcherServlet.doDispatch、HandlerAdapter.handle)。