Spring MVC(Model-View-Controller)是一个用于构建基于Web应用程序的框架,它是Spring框架的一部分。以下是Spring MVC的设计与实现的基本概述:
Spring MVC采用经典的MVC架构:
- Model(模型): 负责应用程序的数据逻辑,通常对应数据库中的表。
- View(视图): 展示数据的界面部分,通常是HTML或JSP页面。
- Controller(控制器): 处理用户请求,并将模型数据传递给视图。
基本组件
- DispatcherServlet: 核心控制器,负责将请求分发到相应的处理器。
- HandlerMapping: 根据请求URL找到对应的处理器(Controller)。
- Controller: 具体处理请求的类,通常使用
@Controller注解。 - ViewResolver: 解析逻辑视图名并映射到具体的视图实现,如JSP、Thymeleaf等。
Spring MVC执行流程的详细步骤
1. 用户发送请求
用户通过浏览器发送一个HTTP请求到服务器。这通常是通过点击链接、提交表单等操作触发的。
2. DispatcherServlet接收请求
所有的请求首先都会到达DispatcherServlet。它是前端控制器(Front Controller),负责整个请求处理流程的协调。
3. HandlerMapping映射请求
DispatcherServlet通过HandlerMapping确定哪个控制器(Controller)将处理该请求。HandlerMapping根据请求URL找到相应的处理器。
4. 调用处理器方法
找到合适的处理器后,DispatcherServlet调用该处理器,处理请求。处理器通常是一个带有@Controller注解的类,具体的方法使用@RequestMapping注解来匹配请求路径。
5. 处理请求逻辑
控制器方法处理业务逻辑,可能需要与服务层或数据库进行交互,并准备数据模型返回给视图。
6. 返回ModelAndView
控制器方法返回一个ModelAndView对象,它包含了视图名和模型数据。
7. ViewResolver解析视图
DispatcherServlet使用ViewResolver将逻辑视图名解析为实际的视图实现(如JSP页面)。
8. 渲染视图
DispatcherServlet将模型数据传递给视图对象,视图对象进行渲染,将最终生成的HTML返回给客户端。
9. 响应返回给客户端
生成的HTML作为HTTP响应被发送回客户端,用户在浏览器中看到处理后的结果。
流程图
以下是流程的简化图示:
用户请求
↓
DispatcherServlet(前端控制器)
↓
HandlerMapping(确定处理器)
↓
Controller(控制器方法处理请求)
↓
Service/DAO(业务逻辑和数据访问)
↓
ModelAndView(返回模型和视图)
↓
ViewResolver(解析视图)
↓
View(渲染视图)
↓
响应返回给客户端
源码分析
DispatcherServlet源码分析
DispatcherServlet 是 Spring MVC 框架的核心组件,负责将 HTTP 请求分发给适当的处理程序,并协调各个组件以完成请求的处理。以下是对 DispatcherServlet 源码的详细分析和解释。
DispatcherServlet 类的定义与初始化
Spring MVC 中的 DispatcherServlet 继承自 FrameworkServlet,并实现了 HttpServlet 接口中的主要方法,是一个标准的 Servlet。
public class DispatcherServlet extends FrameworkServlet {
//...
}
1. 初始化策略(initStrategies)
在 FrameworkServlet 的 initServletBean() 方法中会调用 DispatcherServlet 的 initStrategies() 方法来初始化各种策略对象。这些策略对象包括多部分解析器、区域解析器、主题解析器、处理器映射、处理器适配器、视图解析器等。
@Override
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context); //初始化文件上传解析器
initLocaleResolver(context); //初始化区域解析器
initThemeResolver(context); //初始化主题解析器
initHandlerMappings(context); //初始化处理器映射,将 URL 映射到具体的处理器(控制器)上。
initHandlerAdapters(context); //初始化处理器适配器,用于将请求传递给合适的处理器执行。
initHandlerExceptionResolvers(context); //初始化异常处理器,用于处理处理器执行过程中抛出的异常。
initRequestToViewNameTranslator(context); //初始化默认视图名称转换器
initViewResolvers(context); //初始化视图解析器
initFlashMapManager(context); //初始化闪存映射管理器
}
每个策略对象的初始化方法都从 Spring 应用上下文中获取相应的 Bean,如果没有配置则使用默认策略。例如:
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
} else {
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
} catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
// Ensure we have at least one HandlerMapping, by registering
// a default HandlerMapping if no other mappings are found.
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerMappings found in servlet '" + getServletName() +
"': using default");
}
}
}
请求处理流程
当 DispatcherServlet 接收到一个 HTTP 请求时,会执行 doDispatch 方法进行请求处理。以下是该方法的简化版本及其关键步骤分析:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 1. 检查是否为文件上传请求,并包装请求对象
processedRequest = checkMultipart(request);
// 2. 获取处理请求的处理器
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 3. 根据处理器类型获取对应的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 4. 实际调用处理器方法处理请求,返回ModelAndView对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 5. 处理请求结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
dispatchException = ex;
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
}
2. 获取处理器(getHandler)
getHandler 方法遍历已注册的 HandlerMapping,根据请求 URL 找到相应的处理器(控制器)。
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
3. 调用处理器适配器(getHandlerAdapter)
getHandlerAdapter 方法返回可以处理该处理器的适配器。Spring MVC 内置了多种处理器适配器,如 SimpleControllerHandlerAdapter、RequestMappingHandlerAdapter 等。
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
4. 处理请求并返回模型和视图(HandlerAdapter.handle)
处理器适配器调用实际的处理器方法,并返回一个 ModelAndView 对象,其中包含了视图名和模型数据。
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// ... 具体实现由不同的HandlerAdapter定义
}
例如,对于 RequestMappingHandlerAdapter,其 handle 方法可能会查找并调用带有 @RequestMapping 注解的方法。
5. 处理结果(processDispatchResult)
processDispatchResult 方法根据处理后的结果来渲染视图或者处理异常。
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
} else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("No view rendering, no ModelAndView: Dispatching Result.");
}
}
}
6. 渲染视图(render)
如果处理器返回了一个 ModelAndView,则 render 方法负责将其渲染为最终的响应。
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
View view;
String viewName = mv.getViewName();
if (viewName != null) {
view = resolveViewName(viewName, mv.getModelInternal(), request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + viewName + "' in servlet with name '" + getServletName() + "'");
}
}
else {
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a View object in servlet with name '" + getServletName() + "'");
}
}
try {
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'", ex);
}
throw ex;
}
}
DispatcherServlet 类的职责总结
通过分析 DispatcherServlet 源码,可以看到它主要承担了以下职责:
- 初始化策略对象:在启动时加载和配置各种策略对象,如处理器映射、处理器适配器、视图解析器等。
- 分发请求:接收 HTTP 请求,将请求分发给相应的处理器。
- 调用处理器:使用适当的处理器适配器调用处理器(控制器)方法来处理请求。
- 处理返回结果:根据控制器返回的
ModelAndView对象渲染视图并返回给客户端。 - 异常处理:在请求处理过程中捕获并处理任何异常。
HandlerMapping源码分析
HandlerMapping 负责将 HTTP 请求映射到相应的处理器(控制器)上。Spring 提供了多种 HandlerMapping 的实现,其中最常用的是 RequestMappingHandlerMapping。下面我们详细分析 HandlerMapping 接口及其常见实现类的源码。
HandlerMapping 接口
HandlerMapping 是一个顶层接口,定义了一个方法:getHandler。
public interface HandlerMapping {
// 用于解析请求并返回处理器执行链
@Nullable
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
该方法接收一个 HttpServletRequest 对象,并返回一个 HandlerExecutionChain,其中包含要处理请求的处理器和相应的拦截器。
AbstractHandlerMapping 抽象类
AbstractHandlerMapping 是 HandlerMapping 的抽象实现类,实现了一些通用功能,如拦截器管理等。
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered {
@Nullable
private Object defaultHandler;
private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<>();
@Nullable
private final PathMatcher pathMatcher;
// 获取处理器并构建处理器执行链
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = this.defaultHandler;
}
if (handler == null) {
return null;
}
// Build the HandlerExecutionChain with interceptors.
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
return executionChain;
}
// 子类必须实现的方法,用于查找具体的处理器
@Nullable
protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;
// 构建处理器执行链,包括全局和特定处理器的拦截器
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
chain.addInterceptors(this.adaptedInterceptors.toArray());
return chain;
}
}
RequestMappingHandlerMapping 类
RequestMappingHandlerMapping 是最常用的 HandlerMapping 实现类,它通过注解(如 @RequestMapping 等)来映射请求到处理器方法上。
1. 初始化请求映射
RequestMappingHandlerMapping 在初始化时会扫描所有带有请求映射注解的控制器方法,并将这些映射关系存储起来,通常是在 afterPropertiesSet() 方法中调用 initHandlerMethods() 完成。
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
initHandlerMethods();
}
protected void initHandlerMethods() {
// 扫描所有控制器类的方法,建立请求路径与方法的映射关系
for (String beanName : getCandidateBeanNames()) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
processCandidateBean(beanName);
}
}
}
2. 查找处理器(getHandlerInternal)
当有请求到来时,RequestMappingHandlerMapping 会根据请求路径找到相应的处理器方法。
@Override
@Nullable
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().resolveAndCacheLookupPath(request);
this.mappingRegistry.acquireReadLock();
try {
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
} finally {
this.mappingRegistry.releaseReadLock();
}
}
// 查找具体的处理器方法
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
// 从缓存中获取匹配的HandlerMethod
List<Match> matches = new ArrayList<>();
this.mappingRegistry.getMappingsByUrl(lookupPath).forEach((mapping) -> addMatchingMappings(mapping, matches, request));
if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
Match bestMatch = matches.get(0);
return bestMatch.getHandlerMethod();
}
return null;
}
在 lookupHandlerMethod 方法中,通过 mappingRegistry.getMappingsByUrl(lookupPath) 获取与请求路径匹配的映射方法,并通过 addMatchingMappings 方法进一步筛选符合条件的 HandlerMethod。
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
this.mappingRegistry.getMappingsByUrl(lookupPath)
.forEach((mapping) -> addMatchingMappings(mapping, matches, request));
if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
Match bestMatch = matches.get(0);
return bestMatch.getHandlerMethod();
}
return null;
}
getMappingsByUrl 方法会返回一个集合,其中包含了所有与给定 lookupPath 匹配的请求映射。
public List<T> getMappingsByUrl(String urlPath) {
List<T> mappings = this.urlLookup.get(urlPath);
return (mappings != null ? mappings : Collections.emptyList());
}
接下来看 addMatchingMappings 方法,它会检查每个映射是否与当前请求匹配,如果匹配则将其添加到候选列表中:
private void addMatchingMappings(T mapping, List<Match> matches, HttpServletRequest request) {
if (getMatchingCondition(mapping, request) != null) {
matches.add(new Match(mapping, getHandlerMethods().get(mapping)));
}
}
@Nullable
protected abstract C getMatchingCondition(T mapping, HttpServletRequest request);
getMatchingCondition 方法在不同的子类中有不同的实现,用于根据具体的匹配条件(如请求方法、参数等)来判断是否匹配当前请求。
3. 建立处理器执行链(getHandlerExecutionChain)
找到处理器方法后,会调用 getHandlerExecutionChain 方法建立处理器执行链,这包括全局和特定处理器的拦截器。
@Override
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = super.getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration config = getCorsConfiguration(handler, request);
if (config != null) {
CorsInterceptor interceptor = new CorsInterceptor(config);
chain.addInterceptor(0, interceptor);
}
}
return chain;
}
HandlerExecutionChain 包含实际的处理器对象和一系列的拦截器:
public class HandlerExecutionChain {
private final Object handler;
private HandlerInterceptor[] interceptors;
// 添加拦截器
public void addInterceptor(HandlerInterceptor interceptor) {
this.interceptors = append(this.interceptors, interceptor);
}
// 添加多个拦截器
public void addInterceptors(HandlerInterceptor... interceptors) {
for (HandlerInterceptor interceptor : interceptors) {
addInterceptor(interceptor);
}
}
}
总结
- HandlerMapping 接口定义了一个核心方法
getHandler(HttpServletRequest request),用于根据请求查找处理器。 - AbstractHandlerMapping 实现了一些通用功能,如管理拦截器、默认处理器等,同时提供模板方法
getHandlerInternal(HttpServletRequest request)留给子类实现。 - RequestMappingHandlerMapping 是最常用的实现类,通过注解扫描初始化请求映射关系,并在请求到来时根据路径查找相应的处理器方法。
- 处理器查找过程 涉及从缓存中获取匹配的
HandlerMethod,并筛选出最合适的处理器方法。 - 处理器执行链 包含实际的处理器对象和一系列的拦截器,在处理请求前后对其进行拦截和处理。