圖解SpringMVC執(zhí)行流程:
SpringMVC執(zhí)行流程:
1.用戶發(fā)送請(qǐng)求至前端控制器DispatcherServlet
2.DispatcherServlet收到請(qǐng)求調(diào)用處理器映射器HandlerMapping伤锚。
3.處理器映射器根據(jù)請(qǐng)求url找到具體的處理器尊勿,生成處理器執(zhí)行鏈HandlerExecutionChain(包括處理器對(duì)象和處理器攔截器)一并返回給DispatcherServlet唐瀑。
4.DispatcherServlet根據(jù)處理器Handler獲取處理器適配器HandlerAdapter執(zhí)行HandlerAdapter處理一系列的操作徒恋,如:參數(shù)封裝辕近,數(shù)據(jù)格式轉(zhuǎn)換,數(shù)據(jù)驗(yàn)證等操作
5.執(zhí)行處理器Handler(Controller迹冤,也叫頁面控制器)讽营。
6.Handler執(zhí)行完成返回ModelAndView
7.HandlerAdapter將Handler執(zhí)行結(jié)果ModelAndView返回到DispatcherServlet
8.DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器
9.ViewReslover解析后返回具體View
10.DispatcherServlet對(duì)View進(jìn)行渲染視圖(即將模型數(shù)據(jù)model填充至視圖中)。
11.DispatcherServlet響應(yīng)用戶泡徙。
當(dāng)然也有以下幾種表示但是都是與第一種說法一樣.
我們針對(duì)第一張圖進(jìn)行分析
組件說明:
1.DispatcherServlet:前端控制器橱鹏。用戶請(qǐng)求到達(dá)前端控制器,它就相當(dāng)于mvc模式中的c堪藐,dispatcherServlet是整個(gè)流程控制的中心莉兰,由它調(diào)用其它組件處理用戶的請(qǐng)求,dispatcherServlet的存在降低了組件之間的耦合性,系統(tǒng)擴(kuò)展性提高礁竞。由框架實(shí)現(xiàn)
2.HandlerMapping:處理器映射器糖荒。HandlerMapping負(fù)責(zé)根據(jù)用戶請(qǐng)求的url找到Handler即處理器,springmvc提供了不同的映射器實(shí)現(xiàn)不同的映射方式模捂,根據(jù)一定的規(guī)則去查找,例如:xml配置方式捶朵,實(shí)現(xiàn)接口方式蜘矢,注解方式等。由框架實(shí)現(xiàn)
3.Handler:處理器综看。Handler 是繼DispatcherServlet前端控制器的后端控制器品腹,在DispatcherServlet的控制下Handler對(duì)具體的用戶請(qǐng)求進(jìn)行處理。由于Handler涉及到具體的用戶業(yè)務(wù)請(qǐng)求红碑,所以一般情況需要程序員根據(jù)業(yè)務(wù)需求開發(fā)Handler舞吭。
4.HandlAdapter:處理器適配器。通過HandlerAdapter對(duì)處理器進(jìn)行執(zhí)行析珊,這是適配器模式的應(yīng)用羡鸥,通過擴(kuò)展適配器可以對(duì)更多類型的處理器進(jìn)行執(zhí)行。由框架實(shí)現(xiàn)忠寻。
5.ModelAndView是springmvc的封裝對(duì)象兄春,將model和view封裝在一起。
6.ViewResolver:視圖解析器锡溯。ViewResolver負(fù)責(zé)將處理結(jié)果生成View視圖,ViewResolver首先根據(jù)邏輯視圖名解析成物理視圖名即具體的頁面地址哑姚,再生成View視圖對(duì)象祭饭,最后對(duì)View進(jìn)行渲染將處理結(jié)果通過頁面展示給用戶。
7View:是springmvc的封裝對(duì)象叙量,是一個(gè)接口, springmvc框架提供了很多的View視圖類型倡蝙,包括:jspview,pdfview,jstlView绞佩、freemarkerView寺鸥、pdfView等。一般情況下需要通過頁面標(biāo)簽或頁面模版技術(shù)將模型數(shù)據(jù)通過頁面展示給用戶品山,需要由程序員根據(jù)業(yè)務(wù)需求開發(fā)具體的頁面胆建。
執(zhí)行流程對(duì)應(yīng)的代碼
1.請(qǐng)求到達(dá)前端控制器的第一站,先做些準(zhǔn)備工作
/**
* Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
* for the actual dispatching.
*/
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String requestUri = urlPathHelper.getRequestUri(request);
logger.debug("DispatcherServlet with name '" + getServletName() + "' processing " + request.getMethod() +
" request for [" + requestUri + "]");
}
//保護(hù)現(xiàn)場(chǎng)
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
logger.debug("Taking snapshot of request attributes before include");
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));
}
}
}
//將框架相關(guān)信息存儲(chǔ)至request肘交,方便后面的處理器和視圖用到
// Make framework objects available to handlers and view objects.
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
//請(qǐng)求分發(fā)
try {
doDispatch(request, response);
}
finally {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
2.開始處理請(qǐng)求
//通過url查找HandlerMap中最相近的key(url)笆载,然后由key獲取HandlerMapping對(duì)象
//通過處理器映射器獲取處理器;
//通過查詢處理器適配器獲得
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
int interceptorIndex = -1;
try {
ModelAndView mv;
boolean errorView = false;
try {
processedRequest = checkMultipart(request);
// Determine handler for the current request
//步驟3.1~3.4用于獲取包含處理器Handler和攔截器AdapterIntercepters的處理器執(zhí)行鏈HandlerExecutionChain
mappedHandler = getHandler(processedRequest, false);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
//步驟4.1~4.2,根據(jù)HandlerExecutionChain中的處理器Handler獲取處理器適配器
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 (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;
}
}
// Apply preHandle methods of registered interceptors.
HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
if (interceptors != null) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
return;
}
interceptorIndex = i;
}
}
// Actually invoke the handler.
//5.1~5.3通過處理器適配器HandlerApapter來調(diào)用處理器完成對(duì)請(qǐng)求的處理
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// Do we need view name translation?
if (mv != null && !mv.hasView()) {
mv.setViewName(getDefaultViewName(request));
}
// Apply postHandle methods of registered interceptors.
if (interceptors != null) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
}
}
}
catch (ModelAndViewDefiningException ex) {
logger.debug("ModelAndViewDefiningException encountered", ex);
mv = ex.getModelAndView();
}
catch (Exception ex) {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(processedRequest, response, handler, ex);
errorView = (mv != null);
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, processedRequest, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
}
// Trigger after-completion for successful outcome.
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
}
catch (Exception ex) {
// Trigger after-completion for thrown exception.
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
throw ex;
}
catch (Error err) {
ServletException ex = new NestedServletException("Handler processing failed", err);
// Trigger after-completion for thrown exception.
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
throw ex;
}
finally {
// Clean up any resources used by a multipart request.
if (processedRequest != request) {
cleanupMultipart(processedRequest);
}
}
}
3.1 getHandler(HttpServletRequest request)涯呻,經(jīng)由HandlerMapping對(duì)象獲取HandlerExecutionChain(處理器和攔截器)
/**
* Return the HandlerExecutionChain for this request.
* <p>Tries all handler mappings in order.
* @param request current HTTP request
* @return the HandlerExecutionChain, or <code>null</code> if no handler could be found
*/
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() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
3.2.1 getHandler(HttpServletRequest request)凉驻,經(jīng)由request獲取處理器,獲取處理器Handler后复罐,再獲取攔截器涝登,最后組成HandlerExecutionChain
/**
* Look up a handler for the given request, falling back to the default
* handler if no specific one is found.
* @param request current HTTP request
* @return the corresponding handler instance, or the default handler
* @see #getHandlerInternal
*/
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
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);
}
3.2.2 根據(jù)查找到的處理器Handler和request獲取包含Handler和AdaptedInterceptors的HandlerExecutionChain
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain =
(handler instanceof HandlerExecutionChain) ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler);
chain.addInterceptors(getAdaptedInterceptors());
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
for (MappedInterceptor mappedInterceptor : mappedInterceptors) {
if (mappedInterceptor.matches(lookupPath, pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
return chain;
}
/**
* Return the adapted interceptors as HandlerInterceptor array.
* @return the array of HandlerInterceptors, or <code>null</code> if none
*/
protected final HandlerInterceptor[] getAdaptedInterceptors() {
int count = adaptedInterceptors.size();
return (count > 0) ? adaptedInterceptors.toArray(new HandlerInterceptor[count]) : null;
}
3.3.getHandlerInternal(HttpServletRequest request)獲取Handler
/**
* Look up a handler for the URL path of the given request.
* @param request current HTTP request
* @return the handler instance, or <code>null</code> if none found
*/
@Override
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
Object handler = lookupHandler(lookupPath, request);
if (handler == null) {
// We need to care for the default handler directly, since we need to
// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
Object rawHandler = null;
if ("/".equals(lookupPath)) {
rawHandler = getRootHandler();
}
if (rawHandler == null) {
rawHandler = getDefaultHandler();
}
if (rawHandler != null) {
// Bean name or resolved handler?
if (rawHandler instanceof String) {
String handlerName = (String) rawHandler;
rawHandler = getApplicationContext().getBean(handlerName);
}
validateHandler(rawHandler, request);
handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
}
}
if (handler != null && logger.isDebugEnabled()) {
logger.debug("Mapping [" + lookupPath + "] to " + handler);
}
else if (handler == null && logger.isTraceEnabled()) {
logger.trace("No handler mapping found for [" + lookupPath + "]");
}
return handler;
}
3.4 lookupHandler(lookupPath, request)根據(jù)給定url path和request獲取Handler
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
// Direct match?
Object handler = this.handlerMap.get(urlPath);
if (handler != null) {
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
return buildPathExposingHandler(handler, urlPath, urlPath, null);
}
// Pattern match?
List<String> matchingPatterns = new ArrayList<String>();
for (String registeredPattern : this.handlerMap.keySet()) {
if (getPathMatcher().match(registeredPattern, urlPath)) {
matchingPatterns.add(registeredPattern);
}
}
String bestPatternMatch = null;
Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
if (!matchingPatterns.isEmpty()) {
Collections.sort(matchingPatterns, patternComparator);
if (logger.isDebugEnabled()) {
logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
}
bestPatternMatch = matchingPatterns.get(0);
}
if (bestPatternMatch != null) {
handler = this.handlerMap.get(bestPatternMatch);
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath);
// There might be multiple 'best patterns', let's make sure we have the correct URI template variables
// for all of them
Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();
for (String matchingPattern : matchingPatterns) {
if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {
uriTemplateVariables
.putAll(getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath));
}
}
if (logger.isDebugEnabled()) {
logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);
}
return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);
}
// No handler found...
return null;
}
4.1 HandlerAdapter getHandlerAdapter(Object handler),根據(jù)Handler獲取HandlerAdapter
/**
* Return the HandlerAdapter for this handler object.
* @param handler the handler object to find an adapter for
* @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
*/
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
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 +
"]: Does your handler implement a supported interface like Controller?");
}
4.2 supports(Object handler)
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
5.1 使用處理器完成對(duì)請(qǐng)求的處理
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
((Servlet) handler).service(request, response);
return null;
}
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException
{
HttpServletRequest request;
HttpServletResponse response;
if (!(req instanceof HttpServletRequest &&
res instanceof HttpServletResponse)) {
throw new ServletException("non-HTTP request or response");
}
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
service(request, response);
}
5.2 service(HttpServletRequest req, HttpServletResponse resp)
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < lastModified) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
//
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
5.3 doGet(HttpServletRequest req, HttpServletResponse resp)
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_get_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}