深入剖析前后端分离场景下SpringMVC工作流程(附SSM配置指南)

193 阅读2分钟

一、前后端分离架构下的SpringMVC流程重塑

1.1 核心组件交互流程(重点!)

sequenceDiagram
    participant Client
    participant DispatcherServlet
    participant HandlerMapping
    participant HandlerAdapter
    participant Controller
    participant MessageConverter

    Client->>DispatcherServlet: HTTP Request
    DispatcherServlet->>HandlerMapping: 获取HandlerExecutionChain
    HandlerMapping-->>DispatcherServlet: 返回Chain(包含拦截器链)
    DispatcherServlet->>Interceptor: preHandle()顺序执行
    Interceptor-->>DispatcherServlet: 是否放行
    alt 全部通过
        DispatcherServlet->>HandlerAdapter: 获取适配器
        HandlerAdapter->>MessageConverter: 反序列化请求体
        HandlerAdapter->>Controller: 执行方法
        Controller-->>HandlerAdapter: 返回结果对象
        HandlerAdapter->>MessageConverter: 序列化响应体
        HandlerAdapter-->>DispatcherServlet: ModelAndView
        DispatcherServlet->>Interceptor: postHandle()逆序执行
    else 拦截
        DispatcherServlet->>Client: 直接返回错误
    end
    DispatcherServlet->>Interceptor: afterCompletion()逆序执行
    DispatcherServlet-->>Client: HTTP Response

二、核心源码解析

2.1 DispatcherServlet入口方法

// 核心请求处理方法
protected void doDispatch(HttpServletRequest req, HttpServletResponse resp) {
    // 1. 获取HandlerExecutionChain
    HandlerExecutionChain mappedHandler = getHandler(processedRequest);
    
    // 2. 获取HandlerAdapter
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

    // 3. 执行拦截器preHandle
    if (!mappedHandler.applyPreHandle(processedRequest, response)) return;

    // 4. 实际执行Controller方法
    ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

    // 5. 触发postHandle
    mappedHandler.applyPostHandle(processedRequest, response, mv);

    // 6. 处理返回结果
    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}

2.2 RequestMappingHandlerMapping

public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping {
    // 通过注解扫描生成映射关系
    protected void detectHandlerMethods(Object handler) {
        Class<?> handlerType = (handler instanceof String ?
                getApplicationContext().getType((String) handler) : handler.getClass());
        
        Map<Method, RequestMappingInfo> methods = MethodIntrospector.selectMethods(handlerType,
                (MethodIntrospector.MetadataLookup<RequestMappingInfo>) method -> getMappingForMethod(method, handlerType));
        
        methods.forEach((method, mapping) -> registerHandlerMethod(handler, method, mapping));
    }
}

2.3 RequestMappingHandlerAdapter

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter {
    // 实际执行Controller方法
    protected ModelAndView handleInternal(HttpServletRequest req, HttpServletResponse res, HandlerMethod handlerMethod) {
        // 参数解析
        Object[] args = getMethodArgumentValues(request, response, handlerMethod);
        
        // 反射调用
        Object returnValue = invokeForRequest(req, res, handlerMethod, args);
        
        // 返回值处理
        return getModelAndView(returnValue, handlerMethod, req, res);
    }
}

三、关键流程拆解

3.1 请求匹配阶段

graph TD
    A[DispatcherServlet] --> B[遍历所有HandlerMapping]
    B --> C{是否找到Handler?}
    C -->|是| D[返回HandlerExecutionChain]
    C -->|否| E[返回404错误]

3.2 参数处理流程

// HandlerMethodArgumentResolver工作流程
public interface HandlerMethodArgumentResolver {
    boolean supportsParameter(MethodParameter parameter);
    Object resolveArgument(...) throws Exception;
}

// 典型实现:@RequestBody处理
public class RequestResponseBodyMethodProcessor implements HandlerMethodArgumentResolver {
    public Object resolveArgument(...) {
        // 使用HttpMessageConverter转换
        return readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
    }
}

四、SSM环境手动配置SpringMVC

4.1 web.xml配置

<!-- 配置DispatcherServlet -->
<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<!-- 映射所有请求 -->
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

4.2 spring-mvc.xml核心配置

<!-- 启用注解驱动 -->
<mvc:annotation-driven>
    <mvc:message-converters>
        <!-- 配置JSON转换器 -->
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
    </mvc:message-converters>
</mvc:annotation-driven>

<!-- 组件扫描 -->
<context:component-scan base-package="com.example.controller"/>

<!-- 静态资源处理 -->
<mvc:resources mapping="/static/**" location="/static/"/>

<!-- 拦截器配置 -->
<mvc:interceptors>
    <bean class="com.example.interceptor.LogInterceptor"/>
</mvc:interceptors>

五、Spring Boot自动配置对比

5.1 配置差异对比表

配置项SSM手动配置Spring Boot自动配置
DispatcherServletweb.xml声明自动注册,默认路径/
消息转换器XML显式定义根据依赖自动配置(如Jackson)
组件扫描XML配置base-package@SpringBootApplication隐含扫描
静态资源<mvc:resources>自动映射/static/**

5.2 启动类模拟实现

// 模拟Spring Boot启动原理
public class SSMApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    
    // 根容器配置(Service、DAO层)
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{RootConfig.class};
    }

    // SpringMVC配置(Controller层)
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{WebMvcConfig.class};
    }

    // Servlet映射
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

六、高频面试题深度解析

6.1 为什么需要HandlerAdapter?

  • 解耦设计:DispatcherServlet无需知道具体Handler类型
  • 扩展性:支持多种处理器(Controller、HttpRequestHandler等)
  • 统一接口:提供统一的handle()方法入口

6.2 如何实现RESTful响应?

// 基于HttpMessageConverter的转换流程
public class MappingJackson2HttpMessageConverter extends AbstractHttpMessageConverter<Object> {
    protected void writeInternal(Object object, HttpOutputMessage outputMessage) {
        // 将对象序列化为JSON
        objectMapper.writeValue(outputMessage.getBody(), object);
    }
}

七、调试技巧与学习建议

7.1 关键断点设置

  1. DispatcherServlet.doDispatch()
  2. RequestMappingHandlerMapping.getHandler()
  3. RequestMappingHandlerAdapter.handleInternal()

7.2 学习路线建议

  1. 从XML配置入手理解组件关系
  2. 通过DEBUG跟踪完整请求流程
  3. 对比Spring Boot自动配置源码(WebMvcAutoConfiguration)