目录
[1. 命令模式核心角色与 Spring MVC 组件的精准映射](#1. 命令模式核心角色与 Spring MVC 组件的精准映射)
[2. 核心执行流程(命令模式视角)](#2. 核心执行流程(命令模式视角))
[二、Spring MVC 命令模式的源码级实现拆解](#二、Spring MVC 命令模式的源码级实现拆解)
[步骤 1:抽象命令的定义(Spring 内置)](#步骤 1:抽象命令的定义(Spring 内置))
[步骤 2:具体命令的实现(开发者编写)](#步骤 2:具体命令的实现(开发者编写))
[步骤 3:调用者的实现(DispatcherServlet 核心逻辑)](#步骤 3:调用者的实现(DispatcherServlet 核心逻辑))
[步骤 4:命令参数解析(参数注入)](#步骤 4:命令参数解析(参数注入))
[步骤 5:命令执行结果处理](#步骤 5:命令执行结果处理)
[三、Spring MVC 命令模式的扩展实现(实战场景)](#三、Spring MVC 命令模式的扩展实现(实战场景))
[场景 1:命令的异步执行(异步命令)](#场景 1:命令的异步执行(异步命令))
[场景 2:命令的拦截增强(责任链 + 命令模式)](#场景 2:命令的拦截增强(责任链 + 命令模式))
[场景 3:命令的异常处理(统一结果)](#场景 3:命令的异常处理(统一结果))
[场景 4:RESTful 命令(标准化命令)](#场景 4:RESTful 命令(标准化命令))
[四、Spring MVC 命令模式的核心价值与设计优势](#四、Spring MVC 命令模式的核心价值与设计优势)
[1. 彻底解耦](#1. 彻底解耦)
[2. 高度可扩展](#2. 高度可扩展)
[3. 标准化与规范化](#3. 标准化与规范化)
[4. 支持高级特性](#4. 支持高级特性)
Spring MVC 是命令模式在 Web 框架中的经典落地实现,其核心是将 "HTTP 请求处理" 封装为独立的 "命令对象",由前端控制器(调用者)统一触发执行,业务层(接收者)完成实际逻辑。
1. 命令模式核心角色与 Spring MVC 组件的精准映射
| 命令模式角色 | Spring MVC 对应组件 | 核心职责 |
|---|---|---|
| 抽象命令(Command) | Handler 体系(Controller 接口、HandlerMethod) |
定义请求处理的统一接口(如 handleRequest、invoke),是所有请求处理命令的抽象规范 |
| 具体命令(ConcreteCommand) | 自定义 @Controller 类 + 接口方法(如 UserController#getUser) |
实现抽象命令逻辑,封装具体的请求处理行为(参数解析、业务调用、响应返回) |
| 调用者(Invoker) | DispatcherServlet(前端控制器) |
持有具体命令对象,触发命令执行(无需关心命令的具体处理逻辑) |
| 接收者(Receiver) | Service/DAO 层(如 UserService、UserMapper) |
真正执行业务逻辑(查询数据、操作数据库),是命令的最终执行者 |
| 命令参数(Param) | HandlerMethodArgumentResolver 解析的参数(@RequestParam/@RequestBody) |
命令执行所需的参数,由 Spring MVC 自动解析并注入命令对象 |
2. 核心执行流程(命令模式视角)
plaintext
客户端发送 HTTP 请求 →
1. Tomcat 转发请求至 DispatcherServlet(调用者)→
2. DispatcherServlet 通过 HandlerMapping 匹配到具体 Controller 方法(具体命令)→
3. DispatcherServlet 委托 HandlerAdapter 执行命令(调用 Controller 方法)→
4. Controller(命令)调用 Service/DAO(接收者)完成业务逻辑 →
5. HandlerAdapter 将命令执行结果返回给 DispatcherServlet →
6. DispatcherServlet 渲染视图/返回 JSON 响应
二、Spring MVC 命令模式的源码级实现拆解
步骤 1:抽象命令的定义(Spring 内置)
Spring MVC 定义了多层抽象命令接口,最核心的是 Controller 和 HandlerMethod:
java
运行
// 基础抽象命令:Controller 接口(Spring 内置)
public interface Controller {
/**
* 命令执行方法:处理 HTTP 请求并返回视图模型
*/
ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
// 注解式控制器的抽象命令:HandlerMethod(封装 @Controller 方法)
public class HandlerMethod {
private final Object bean; // 具体命令对象(Controller 实例)
private final Method method; // 具体命令方法(如 getUser)
private final MethodParameter[] parameters; // 命令参数
// 执行命令(核心方法)
public Object invoke(Object... args) throws Exception {
return method.invoke(bean, args);
}
}
步骤 2:具体命令的实现(开发者编写)
开发者自定义的 @Controller 是命令模式的 "具体命令",每个接口方法对应一个独立的命令逻辑:
java
运行
/**
* 具体命令类:用户模块请求处理命令
*/
@RestController
@RequestMapping("/user")
public class UserController { // 命令对象
// 接收者:业务逻辑层
@Autowired
private UserService userService;
/**
* 具体命令方法:查询用户(GET /user/{id})
*/
@GetMapping("/{id}")
public Result<User> getUser(
@PathVariable Long id, // 命令参数1
@RequestHeader String token // 命令参数2
) {
// 命令执行逻辑:调用接收者完成业务
User user = userService.getUserById(id);
return Result.success(user);
}
/**
* 具体命令方法:创建用户(POST /user)
*/
@PostMapping
public Result<Long> createUser(@RequestBody UserCreateDTO dto) {
Long userId = userService.createUser(dto);
return Result.success(userId);
}
}
// 接收者:业务逻辑实现
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
// 接收者核心方法:真正执行查询逻辑
public User getUserById(Long id) {
return userMapper.selectById(id);
}
// 接收者核心方法:真正执行创建逻辑
public Long createUser(UserCreateDTO dto) {
User user = new User();
user.setUsername(dto.getUsername());
user.setDeptId(dto.getDeptId());
userMapper.insert(user);
return user.getId();
}
}
步骤 3:调用者的实现(DispatcherServlet 核心逻辑)
DispatcherServlet 是命令模式的 "调用者",核心逻辑在 doDispatch 方法(简化版源码):
java
运行
public class DispatcherServlet extends FrameworkServlet {
// HandlerMapping:匹配命令对象(Controller)
@Nullable
private List<HandlerMapping> handlerMappings;
// HandlerAdapter:适配并执行命令
@Nullable
private List<HandlerAdapter> handlerAdapters;
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
try {
ModelAndView mv = null;
Exception dispatchException = null;
// 1. 匹配具体命令:通过 HandlerMapping 找到 Controller(命令对象)
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 2. 获取命令执行器:HandlerAdapter(适配不同类型的命令)
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 3. 执行命令前置拦截(责任链扩展)
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 4. 触发命令执行:调用 Controller 方法(核心步骤)
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 5. 执行命令后置处理
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception ex) {
dispatchException = ex;
}
// 6. 处理命令执行结果(渲染视图/返回响应)
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
// 匹配命令对象
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
}
步骤 4:命令参数解析(参数注入)
Spring MVC 通过 HandlerMethodArgumentResolver 解析命令参数,保证命令执行所需的参数正确注入:
java
运行
// 自定义参数解析器(扩展命令参数类型)
@Component
public class UserIdArgumentResolver implements HandlerMethodArgumentResolver {
/**
* 判断是否支持该参数类型
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(Long.class)
&& parameter.hasParameterAnnotation(CurrentUserId.class);
}
/**
* 解析参数(从 Token 中获取当前用户ID,注入命令方法)
*/
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
String token = webRequest.getHeader("token");
// 模拟从 Token 解析用户ID
return JwtUtil.getUserIdFromToken(token);
}
}
// 自定义注解:标记当前用户ID参数
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CurrentUserId {
}
// 命令方法使用自定义参数
@GetMapping("/current")
public Result<User> getCurrentUser(@CurrentUserId Long userId) {
User user = userService.getUserById(userId);
return Result.success(user);
}
步骤 5:命令执行结果处理
HandlerAdapter 执行命令后,DispatcherServlet 通过 ViewResolver 处理结果,返回响应:
java
运行
// 命令执行结果处理(简化版)
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
// 异常处理(命令执行失败)
if (exception != null) {
mv = processHandlerException(request, response, mappedHandler, exception);
}
// 渲染视图(命令执行成功)
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
}
三、Spring MVC 命令模式的扩展实现(实战场景)
场景 1:命令的异步执行(异步命令)
Spring MVC 支持 @Async 实现命令的异步执行,调用者触发后无需等待结果:
java
运行
/**
* 异步命令:异步查询用户数据
*/
@RestController
@RequestMapping("/async/user")
public class AsyncUserController {
@Autowired
private UserService userService;
/**
* 异步命令方法
*/
@GetMapping("/{id}")
@Async // 标记为异步命令
public CompletableFuture<Result<User>> asyncGetUser(@PathVariable Long id) {
// 异步执行命令逻辑
return CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000); // 模拟耗时操作
User user = userService.getUserById(id);
return Result.success(user);
} catch (InterruptedException e) {
return Result.fail("查询失败");
}
});
}
}
// 配置异步执行器(启用 @Async)
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(20);
executor.setThreadNamePrefix("async-command-");
executor.initialize();
return executor;
}
}
场景 2:命令的拦截增强(责任链 + 命令模式)
通过 HandlerInterceptor 实现命令执行前后的拦截,扩展命令功能:
java
运行
/**
* 命令拦截器:记录命令执行日志
*/
@Component
public class CommandLogInterceptor implements HandlerInterceptor {
/**
* 命令执行前:记录请求信息
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
String commandName = handlerMethod.getBeanType().getSimpleName() + "#" + handlerMethod.getMethod().getName();
System.out.println("[命令拦截] 开始执行命令:" + commandName);
request.setAttribute("startTime", System.currentTimeMillis());
}
return true;
}
/**
* 命令执行后:记录执行耗时
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
String commandName = handlerMethod.getBeanType().getSimpleName() + "#" + handlerMethod.getMethod().getName();
long startTime = (long) request.getAttribute("startTime");
long cost = System.currentTimeMillis() - startTime;
System.out.println("[命令拦截] 命令执行完成:" + commandName + ",耗时:" + cost + "ms");
}
}
}
// 注册拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private CommandLogInterceptor commandLogInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(commandLogInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login", "/error");
}
}
场景 3:命令的异常处理(统一结果)
通过 @RestControllerAdvice 统一处理命令执行中的异常,保证响应格式一致:
java
运行
/**
* 命令异常处理器:统一处理命令执行失败
*/
@RestControllerAdvice
public class CommandExceptionHandler {
/**
* 处理业务异常
*/
@ExceptionHandler(BusinessException.class)
public Result<?> handleBusinessException(BusinessException e) {
return Result.fail(e.getCode(), e.getMessage());
}
/**
* 处理参数异常
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<?> handleParamException(MethodArgumentNotValidException e) {
String message = e.getBindingResult().getFieldError().getDefaultMessage();
return Result.fail(400, "参数错误:" + message);
}
/**
* 处理通用异常
*/
@ExceptionHandler(Exception.class)
public Result<?> handleException(Exception e) {
e.printStackTrace();
return Result.fail(500, "服务器内部错误");
}
}
// 业务异常类
public class BusinessException extends RuntimeException {
private int code;
public BusinessException(int code, String message) {
super(message);
this.code = code;
}
// getter/setter
}
// 统一响应结果
@Data
public class Result<T> {
private int code;
private String message;
private T data;
// 静态方法:成功/失败响应
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMessage("成功");
result.setData(data);
return result;
}
public static <T> Result<T> fail(int code, String message) {
Result<T> result = new Result<>();
result.setCode(code);
result.setMessage(message);
return result;
}
}
场景 4:RESTful 命令(标准化命令)
RESTful 接口是命令模式的标准化实现,每个 HTTP 方法对应一个命令类型:
java
运行
/**
* RESTful 命令:用户 CRUD
*/
@RestController
@RequestMapping("/api/users")
public class UserRestController {
@Autowired
private UserService userService;
// GET 命令:查询单个用户
@GetMapping("/{id}")
public Result<User> get(@PathVariable Long id) {
return Result.success(userService.getUserById(id));
}
// GET 命令:查询用户列表
@GetMapping
public Result<Page<User>> list(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize
) {
Page<User> page = userService.listPage(new Page<>(pageNum, pageSize));
return Result.success(page);
}
// POST 命令:创建用户
@PostMapping
public Result<Long> create(@RequestBody @Valid UserCreateDTO dto) {
return Result.success(userService.createUser(dto));
}
// PUT 命令:更新用户
@PutMapping("/{id}")
public Result<Boolean> update(@PathVariable Long id, @RequestBody UserUpdateDTO dto) {
return Result.success(userService.updateUser(id, dto));
}
// DELETE 命令:删除用户
@DeleteMapping("/{id}")
public Result<Boolean> delete(@PathVariable Long id) {
return Result.success(userService.deleteUser(id));
}
}
四、Spring MVC 命令模式的核心价值与设计优势
1. 彻底解耦
- 调用者与命令解耦 :
DispatcherServlet无需知道UserController的存在,只需通过HandlerMapping匹配命令; - 命令与接收者解耦 :
UserController只需调用UserService的方法,无需关心UserService的具体实现; - 命令与参数解耦 :参数解析由
HandlerMethodArgumentResolver统一处理,命令方法只需声明参数类型。
2. 高度可扩展
- 新增命令 :只需新增
Controller类 / 方法,无需修改DispatcherServlet核心逻辑; - 扩展参数类型 :只需实现
HandlerMethodArgumentResolver,支持自定义参数注解; - 扩展命令执行逻辑 :通过
HandlerInterceptor拦截命令执行,添加日志、权限、限流等功能。
3. 标准化与规范化
- 所有请求都遵循 "调用者 → 命令 → 接收者" 的统一流程,便于维护和排查问题;
- RESTful 命令标准化了 HTTP 方法与业务操作的映射,降低团队协作成本。
4. 支持高级特性
- 异步命令 :通过
@Async实现非阻塞执行,提升系统吞吐量; - 命令重试:结合 Spring Retry 实现命令执行失败后的重试;
- 命令限流:结合 Sentinel/Gateway 实现命令级别的限流控制。
五、总结
Spring MVC 是命令模式在 Web 框架中的极致落地,核心要点可总结为:
- 核心映射 :
DispatcherServlet是调用者,@Controller方法是具体命令,Service是接收者; - 核心流程:调用者匹配命令 → 解析命令参数 → 执行命令 → 处理命令结果 → 返回响应;
- 扩展能力:通过拦截器、参数解析器、异常处理器扩展命令的执行逻辑;
- 设计优势:解耦请求触发与业务执行,支持标准化、异步化、可扩展的请求处理。
理解 Spring MVC 中的命令模式,不仅能帮助你更深入地掌握框架原理,还能指导你设计高内聚、低耦合的业务代码(如将复杂业务操作封装为 "命令对象",实现可复用、可追踪的业务逻辑)。