DispatcherServlet 为 SpringMVC 处理 servlet 的入口.
在 doService 方法中调用 doDispatcher 方法,也就是说业务逻辑主要是在 doDispatcher 中实现.
HandlerMapping 抽象了请求 URL 到请求处理器之间的映射. 当一个请求过来时,DispatcherServlet 会轮询 HandlerMapping 那个请求处理器能处理.
实际上处理请求的是 RequestMappingHandlerMapping 这个类.
HandlerExecutionChain 的字面意思就能够表达清了. 它的概念是 handler 执行的链式结构.
当执行 HandlerExecutionChain handler = hm.getHandler(request); 这段代码后,将调转到 AbstractHandlerMethodMapping.getHandlerInternal 方法.
lookupHandlerMethod 方法返回的是 HandlerMethod 对象. 这个的概念,我理解是类似于反射的机制,用于执行方法.
PS: SpringMVC 的 DispatcherServlet 的设计理念和 OFBiz 关于 Web MVC 的设计很相似,只不过的是 OFBiz 这块的设计是通过 XML 文件实现的,而 Spring MVC 是通过注解实现的. 后续有计划将 OFBiz 有关 XML 的解析替换成注解的方式,来简化工作量.
关于为啥要构造 HandlerExecutionChain 这个对象,是可以在执行实际方法之前,执行某些 HandlerInterceptor.
getHandler 方法会做两步:
1.获取实际的执行方法.
2.构造 HandlerExecutionChain.
经过上面的步骤,我们可以获得 HandlerExecutionChain 对象. 然后进一步的获取 HandlerAdapter 对象.
HandlerAdapter 是啥概念了?HandlerAdapter 是对上面 handler 对象的包装. 或者说 HandlerAdapter 是一个桥梁,承接处理和 ModelView.
然后预执行. 预执行的作用是:比如说我有拦截器,当不满足条件的时候可以跳过. 就不会执行实际的代码.
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
实际执行.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
承接代码执行和 ModelView.
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
实际执行(调用方法)
invocableMethod.invokeAndHandle(webRequest, mavContainer);
返回结果.
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
返回视图.
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) {
return null;
}
ModelMap model = mavContainer.getModel();
// ModelAndView: reference to view with name '/login.html'; model is {} 为调试信息.
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
if (request != null) {
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
}
return mav;
}
处理视图.
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
渲染——感觉 Spring 关于 MVC 的处理逻辑和 OFBiz 非常像,后续在做进一步的验证.
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
View view;
String viewName = mv.getViewName();
if (viewName != null) {
// We need to resolve the view name.
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException(“Could not resolve view with name '” + mv.getViewName() +
“’ in servlet with name '” + getServletName() + “’”);
}
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
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;
}
}
protected final void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
if (this.exposeSpringMacroHelpers) {
if (model.containsKey(SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE)) {
throw new ServletException(
"Cannot expose bind macro helper '" + SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE +
"' because of an existing model object of the same name");
}
// Expose RequestContext instance for Spring macros.
model.put(SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE,
new RequestContext(request, response, getServletContext(), model));
}
applyContentType(response);
renderMergedTemplateModel(model, request, response);
}
补充一点:
Controller 注解和 RequestMapping 注解在哪里被解析的?