DiapatcherServlet
SpringMVC的前端控制器(dispatcherServlet)本质就是一个Servlet,它接收并处理除了jsp页面之外的所有请求,其主要功能就是匹配并调用请求对应的controller控制器(处理器),并将控制器处理后的 ModelAndView(数据和视图) 进行渲染后响应给客户端
DispatcherServlet
继承于HTTPServlet
。当有请求发来时,首先执行HttpServlet
的doGet/doPost
方法,而FrameworkServlet
子类重写了doGet/doPost
方法,并在其中调用了processRequest
方法,而processRequest
方法中又调用了抽象方法doService
,该抽象方法是被DispatcherServlet
实现,并在其中调用了doDispatch
方法,doDispatch
方法便是前端控制器(DispathcerServlet) 的核心方法,以下是该方法的分析:
doDispatch()
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
//异步管理器
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// ①检查是否为多部件(文件上传)请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
/** ②根据请求地址确定相应的控制器(处理器)映射对象 **/
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
// ③如果没有找到对应的控制器来处理这个请求,则报404
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
/** ④根据控制器映射对象确定对应的适配器,该适配器(反射工具)用于调用控制器方法 **/
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// ⑤获取请求方式
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
/** ⑥使用之前获取的适配器来调用控制器的业务方法,也就是Controller中的@RequestMapping方法,
并在执行完成后返回视图名。无论控制器业务方法中执行什么,
最终适配器调用完后的数据(模型和视图)都封装成ModelAndView
**/
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// ⑦如果调用完后没有返回视图名,则使用默认的视图名(发送请求的视图名)
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
/** ⑧根据封装了数据和视图的ModelAndView处理转发的页面 **/
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
其中第②、④、⑥、⑧步为关键:
②:getHandler()
获取目标控制器
④:getHandlerAdapter()
获取执行目标控制器方法的适配器
⑥:handle()
使用适配器执行目标控制器方法
⑧:processDispatchResult
处理转发结果
getHandler()
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;
}
handlerMappings
是存放根据不同方式注册(xml配置和注解装配) 的处理器映射的集合。其中索引0为xml配置注册的,索引1为注解注册的(索引2暂时未知)。遍历handlerMappings
,找到其中保存有handler的元素(HandlerMapping)并返回。而使用注解的处理器对象就是索引为1的RequestMappingHandlerMapping
处理器映射这个注解处理器映射对象中有一个
mappingRegistry
属性,便是存放使用@RequestMapping
注解配置的处理器的信息。在IOC容器启动创建Controller对象时,扫描每个处理器都能处理什么请求,并将这些处理器都保存在
mappingRegistry
属性中,以后发送的请求中,查找哪个HandlerMapping中有对应处理器即可。
getHandlerAdapter()
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
此方法同上面的getHandler()
一样,是遍历存放有不同注册方式的处理器对应的适配器,找到支持当前处理器对应的适配器其中
RequestMappingHandlerAdapter
是通过注解注册的处理器对应的适配器,当遍历到它时,当前处理器会和它匹配然后返回这个适配器
handle()
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
通过适配器调用其抽象父类(AbstractHandlerMethodAdapter)的
handle
方法,其中又直接调用适配器(RequestMappingHandlerAdapter)的handleInternal()
方法
handleInternal()
{
ModelAndView mav;
checkRequest(request);
// Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
在
handleInternal()
方法中的第22行执行了invokeHandlerMethod(request, response, handlerMethod)
方法,此方法就是实际调用的处理器方法,得到处理后的ModelAndView并返回。
processDispatchResult()
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable 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.isTraceEnabled()) {
logger.trace("No view rendering, null ModelAndView returned.");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
// Exception (if any) is already handled..
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
在第21行调用的
render()
方法,使用ModelAndView对转发的页面进行渲染