Spring MVC 框架为展现层提供的基于MVC设计理念的优秀的web框架,是目前最主流的MVC框架之一。
关于他的运行流程之前没有在意,这次作为博客的第一篇文章仔细的看一看:
这里我以基于注解的HelloWorld级程序为例进行分析
一:首先就是Spring MVC在web.xml中的配置信息,也就是DispatcherServlet,在相应配置的情况下,对请求进行拦截,然后把这个请求信息交给DIspatcherServlet处理。(servlet-mapping中的url-pattern),关于DIspatcherServlet其他的方法不进行介绍,这个不是本篇文章的重点,主要是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;
// ①:关键点一:获取handler
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// ②:关键点二:通过HandlerAdapter对Handler进行封装
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 获取Http请求方式
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
//return -1
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
String requestUri = urlPathHelper.getRequestUri(request);
logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
// ③:重点三:以统一的适配器接口、通过反射调用目标方法,返回ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
applyDefaultViewName(request, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
//④:重点四:渲染视图
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
}
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
①:第一个重点:通过遍历已注册的HandlerMapping查找对应的handle。
handlerMappings中有几个比较常见:
1)BeanNameUrlHandlerMapping:通过对比Url和bean的name找到对应的对象
2)SimpleUrlHandlerMapping:与上面一样,功能更多
3)DefaultAnnotationHandlerMapping:主要关于注解的方式,已过时
4)RequestMappingHandlerMapping:取代上面的。
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
//getHandler(request)方法在下方
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
//这时候就是已经找到对应的handler类了
return handler;
}
}
return null;
}
--------------------------------------------------------------------------------
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//通过urlPath以及handlerMap来获取对应handler,这是一个抽象的方法,由具体的HandlerMapper来实现
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
return getHandlerExecutionChain(handler, request);
}
②:第二个重点:通过HandlerAdapter对Handler进行封装。
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
//遍历所有的handlerAdapters,判断是否支持这个handler
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
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");
}
----------------------------------------------------------------------------------------
//以第一个HandlerAdapter 为例HttpRequestHandlerAdapter:
public class HttpRequestHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
//就是判断这个handler是否是当前迭代类型的。如果是则直接返回这个Adapter类
return (handler instanceof HttpRequestHandler);
}
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
((HttpRequestHandler) handler).handleRequest(request, response);
return null;
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
③:第三个重点:以统一的适配器接口调用目标方法、返回ModelAndView
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//目标handler
Class> clazz = ClassUtils.getUserClass(handler);
Boolean annotatedWithSessionAttributes = this.sessionAnnotatedClassesCache.get(clazz);
if (annotatedWithSessionAttributes == null) {
annotatedWithSessionAttributes = (AnnotationUtils.findAnnotation(clazz, SessionAttributes.class) != null);
this.sessionAnnotatedClassesCache.put(clazz, annotatedWithSessionAttributes);
}
if (annotatedWithSessionAttributes) {
// Always prevent caching in case of session attribute management.
checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
// Prepare cached set of session attributes names.
}
else {
// Uses configured default cacheSeconds setting.
checkAndPrepare(request, response, true);
}
// 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) {
return invokeHandlerMethod(request, response, handler);
}
}
}
//--
return invokeHandlerMethod(request, response, handler);
}
----------------------------------------------------------------------------------------
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
//☆
Method handlerMethod = methodResolver.resolveHandlerMethod(request);
ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
ServletWebRequest webRequest = new ServletWebRequest(request, response);
ExtendedModelMap implicitModel = new BindingAwareModelMap();
Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
ModelAndView mav =
methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
return mav;
}
-----------------------------------------------------------------------------------
public Method resolveHandlerMethod(HttpServletRequest request) throws ServletException {
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
Comparator<String> pathComparator = pathMatcher.getPatternComparator(lookupPath);
Map<RequestSpecificMappingInfo, Method> targetHandlerMethods = new LinkedHashMap<RequestSpecificMappingInfo, Method>();
Set<String> allowedMethods = new LinkedHashSet<String>(7);
String resolvedMethodName = null;
//遍历当前handler中所有的方法
for (Method handlerMethod : getHandlerMethods()) {
RequestSpecificMappingInfo mappingInfo = new RequestSpecificMappingInfo(this.mappings.get(handlerMethod));
boolean match = false;
............................................
④:第四个重点:渲染视图:这个东西还是比较复杂的,我这里只需知道两点
1)DispatcherServlet借助ViewResoler完成逻辑视图名到真实视图对象的解析
2)得到真实视图对象 View 后, DispatcherServlet使用这个 View 对ModelAndView中的模型数据进行视图渲染。