配置SpringMVC的应用的过程和使用这在这篇博客中Spring MVC应用已经配置好了。那么,前端控制器DispatcherServlet截获请求后做了什么工作呢?DispatcherServlet又是如何分派请求的呢?
代码位置:orglspringframeworklweb/servIetIDispatcherServlet.java
第一步初始化组件
protected void initStrategies(ApplicationContextcontext){
initMultipartResolver(context);//初始化上传文件解析器
initLocaleResolver(context);//初始化本地化解析器
initThemeResolver(context);//初始化主题解析器
initHandlerMappings(context),//初始化处理器映射器,将请求映射到处理器
initHandlerAdapters(context);//初始化处理器适配器
initHandlerExceptionResolvers(context);
//初始化处理器异常解析器,如果执行过程中遇到异常将交给HandlerExceptionResolver来解析
initRequestTOViewNameTranslator(con七ext);//初始化请求到视图名称解析器
initViewResolvers(context);
//初始化视图解析器,通过ViewResolver解析逻辑视图名到具体视图实现
initFlashMapManager(context);//初始化flash映射管理器
}
initStrategies方法将在WebApplicationContext初始化后自动执行,自动扫描上下文的Bean。根据名称或类型匹配的机制查找自定义的组件,如果没有找到则会装配一套Spring的默认组件。在org.springframeworlc.web.servlet路径下有一个DispatcherServlet.properties配置文件,该文件指定了DispatcherServlet所使用的默认组件。
当然开发者希望使用自定义类型的组件,有时候也是必须的,因为上传文件组件是默认不安装的,我们再Spring配置文件中配置自定义的Bean组件即可。Spring MVC如果发现上下文中有用户自定义的组件,就不会使用默认的组件,如:。
文件上传解析器。只允许一个实例
(1)查找名为muliipartResolver、类型为MuliipartResolver的Bean作为该类型组件。
(2)如果用户没有在上下文中显式定义MuliipartResolver类型的组件,则DispatcherServlet将不会加载该类型的组件。
(3)所以我们要用到时要配置这种实例,可以看这篇文章springMVC和springBoot使用MultipartFile上传文件
第二步,服务过程
一般来说Servlet有一个服务方法doService来为Http清求提供服务,DispatcherServlet也是如此,它的doService方法如下:
@Override
prctected void doService (HttpServletRequestrequest,HttpServietResponse
response) throws Exception{
if(logger.isDebugEnabled()){
String resumed=WebAsyncUtils.getAsyncManager(request).hasConcurrentResult()?
resumed“:””;
logger.debug(“DispatcherServiet with name”,+getServletName()+”‘“+resumed+
“processing”+request.getMethod()+“request for [“ +qetRequestUri(request)“+”]“);
}
//快照处理
//Keep a snapshot of the requestattributes in case of an include
//to be able to rest。rethe original attributes after the include
Map<String, Object>attributesSnapshot=null;
if (WebUtils.isIncludeRequest(request)){
attributesSnapshot=new HashMap<String, Object>();
Enumeration attrNames=request.getAttributeNames();
while (attrNames.hasMoreElements()){
String attrName=(String) attrNames .nextElement();
if (this.cleanupAfterinclude
attrName.startsWith(“org.springframework.web.servlet”)){
attributesSnapshot.put(attrName,request.getAttribute (attrName));
}
)
//Make framework objects available to handlers and view objects.
//设置Web IOC容器
request.setAttribute(WEB APPLICATION CONTEXT ATTRIBUTE,getWebApplicationContext());
//设置国际化属性
request.setAttribute(LOCALE RESOLVER ATTRIBUTE,this.localeResolver);
//主题属性
request.setAttribute(THEME RESOLVER ATTRIBUTE,七his.themeResolver);
//主题源属性
….
try{
//处理分发
doDispatch(request,response);
}
finally{
if(!WebAsyncUtils.getAsyncManaqer(request) .isConcurrentHandimgStarted()){
//Restore the original attribute snapshot,in case of an include.
if (attributesSnapshot!=null){
restoreAttributesAfterinclude(request,attributesSnapshot);
}
}
}
}
从这段源码中我们看到了快照的处理,使用快照可以更快响应用户请求,并且设置些属书!最后所有的流程都集中在了doDispatch方法中。在Spring MVC流程中这是一个最为重要的方法,因此我们还需要探索它,如:
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 my=null;
//错误处理
Exception dispatchException=null;
try{
//文件上传处理解析器
processedRequest=checkMultipart(request);
//是否为文件上传请求
multipartRequestParsed=(processedRequest!=request);
//Determine handler for the current request.
//获取匹配的执行链
mappedHandler=getHandler(processedRequest);
//没有处理器错误
if (mappedHandler==null || mappedHandler .getHandler()==null){
noHandlerFound(processedRequest,response)
return;
}
//找到对应的处理适配器(HandlerAdapter)
HandlerAdapter ha =getHandlerAdapter(mappedHandler.getHandler());
//判断是http的get方法还是post方法
String method=request.getMethod();
boolean isGet=“GET”.equals(method);
//GET方法的处理
if(isGet ||“HEAD”.equals(method)){
long hastModified=ha .getLastModified(request,mappedHandler .getHandler());
if(logger .isDebugEnabled()){
logger.debug(“Last-Modifie value for [“+getRequestUri(request)+“]iS:”+lastModified);
if(new ServletWebRequest(request,response).checkNotModified(lastModified)&&isGet){
return;}}
//执行拦截器的事前方法,如果返回false,则流程结束
if(!mappedHandler.applyPreHandle(processedRequest,response)){
return;
}
//执行处理器,返回ModelAndView
mv =ha .handle (processedRequest,response,mappedHandler.getHandler())
if(asyncManager.isConcurrentHandlingStarted()){
return;
}
//如果视图为空,给子设置默认视图的名称
applyDefaultViewName(processedRequest,mv);
//执行处理器拦截器的事后方法
mappedHandler.applyPostHandle(processedRequest,responce,mv);
catch (Exception ex)
//记录异常
dispatchException=eX;
}
catch (Throwable err)
//记录异常
dispatchException=new NestedServletException(“Handler dispatch failed”,err);
}
通过源码可以看出其流程是:
原创来源:滴一盘技术