摘要:封裝了方法,關(guān)鍵就是前一部分是將當(dāng)前請求的對象和屬性,分別設(shè)置到和這兩個抽象類中的對象中,也就是分別將這兩個東西和請求線程做了綁定。方法本質(zhì)是執(zhí)行方法是一個抽象類,方法調(diào)用,是一個接口,在實現(xiàn)類中實現(xiàn)。
DispatcherServlet來看spring mvc請求處理過程 架構(gòu)
官方架構(gòu)圖
可以看到請求處理過程,而DispatcherServlet正是擔(dān)當(dāng)front controller的角色。
通過源碼可以看到,DispatcherServlet繼承自FrameworkServlet,F(xiàn)rameworkServlet繼承HttpServletBean,HttpServletBean繼承HttpServlet。
而Servlet生命周期的三個階段就是【init-service-destroy】
所以對DispatcherServlet而言,類似最初進行servlet編程。繼承HttpServlet,重寫doGet、doPost,在方法中跳轉(zhuǎn)到j(luò)sp頁面,利用注解或者在xml文件中注冊Servlet。
在HttpServletBean中,覆寫了HttpServlet類的init()方法。
前面是將web.xml中在DispatcherServlet這個Servlet下面的
值得一提的是其中有一句
initServletBean();
但是在HttpServletBean中是一個空方法,留給子類來實現(xiàn),這就是模版方法,在父類中定義執(zhí)行流程,把可變的部分留給子類實現(xiàn)。體現(xiàn)了開閉原則。
initServletBean在FrameworkServlet中關(guān)鍵的一句
this.webApplicationContext = initWebApplicationContext();
所以FrameworkServlet存在的意義也用來抽離出建立 WebApplicationContext 上下文這個過程的。建立一個和Servlet關(guān)聯(lián)的Spring容器上下文,并將其注冊到ServletContext中。
因為DispatcherServlet重寫了onRefresh,建立上下文后,通過onRefresh(ApplicationContext context)方法的回調(diào),進入到DispatcherServlet類
onRefresh方法中initStrategies()封裝了初始化策略
以detectAllHandlerMappings為例,detectAllHandlerMappings默認(rèn)為true,把上下文中所有HandlerMapping類型的Bean都注冊在handlerMappings這個List變量中。
總結(jié):HttpServletBean完成的是
以Get請求為例,經(jīng)過HttpServlet基類中service()方法的委派,請求會被轉(zhuǎn)發(fā)到doGet()方法中。doGet()方法,在DispatcherServlet的父類FrameworkServlet類中被重寫。
封裝了processRequest方法,關(guān)鍵就是doService(request, response);
前一部分是將當(dāng)前請求的Locale對象和屬性,分別設(shè)置到LocaleContextHolder和RequestContextHolder這兩個抽象類中的ThreadLocal對象中,也就是分別將這兩個東西和請求線程做了綁定。在doService()處理結(jié)束后,再恢復(fù)回請求前的LocaleContextHolder和RequestContextHolder,也即解除線程綁定。每次請求處理結(jié)束后,容器上下文都發(fā)布了一個ServletRequestHandledEvent事件,你可以注冊監(jiān)聽器來監(jiān)聽該事件。
只是做了一些線程安全的隔離。
doService又是一個抽象方法。子類實現(xiàn)。實現(xiàn)在DispatcherServlet中
doDispatch(request, response);
幾個requet.setAttribute()方法的調(diào)用,將前面在初始化流程中實例化的對象設(shè)置到http請求的屬性中,供下一步處理使用,其中有容器的上下文對象、本地化解析器等SpringMVC特有的編程元素。
doDispatch中
mappedHandler = getHandler(processedRequest);獲得處理請求的handler,返回HandlerExecutionChain
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());獲得處理請求的handler adapter
mappedHandler.applyPreHandle(processedRequest, response執(zhí)行interceptor的prehandle方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());實際調(diào)用handler,返回ModelAndView
applyDefaultViewName(processedRequest, mv);設(shè)置view的名字
mappedHandler.applyPostHandle(processedRequest, response, mv);執(zhí)行intercepter的postHandle方法,
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);發(fā)送結(jié)果
HandlerMapping、HandlerAdapter、View這些接口的設(shè)計。
HandlerAdapter:是一個接口。support方法根據(jù)類型來判斷該adapter是否支持handler實例,handle方法用給定的handler處理請求;
public interface HandlerAdapter { boolean supports(Object handler); ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; long getLastModified(HttpServletRequest request, Object handler); }
HandlerMapping接口中:
getHandler獲取請求的handler和所有interceptors,返回HandlerExecutionChain的對象
public interface HandlerMapping { String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping"; String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern"; String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping"; //... HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
View接口:
主要是render方法
void render(Map
HandlerExecutionChain:主要包含 interceptors的list,和一個handle,這里handler是由Object對象來引用的,沒有綁定任何接口,這里說明了任何對象都可以作為最后的處理對象來生成視圖
ModelAndView是處理的結(jié)果,主要包含Object引用的view,和ModelMap引用的model。view可以是view名(String)或者是一個view的實例。ModelMap繼承LinkedHashMap,也就是一個map,放了屬性名和屬性值。
HandlerInterceptor這個接口,定義了攔截器的實現(xiàn)
preHandle,postHandle,afterCompletion就像剛剛在doDispatch中一樣,環(huán)繞著hanlder實現(xiàn),分別在handler執(zhí)行前,執(zhí)行后和渲染后執(zhí)行。
public interface HandlerInterceptor { boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception; void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception; void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception; }深入處理流程
mappedHandler = getHandler(processedRequest);
可以看出getHandler方法就是遍歷初始化時已經(jīng)獲取的handlerMappings,如果找到一個HandlerMapping,getHandler方法返回的不為null,那么說明找到了這個mappedHandler,并返回。
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; }
getHandler的實現(xiàn)在AbstractHandlerMapping類中,根據(jù)request找到Handler和Interceptor,組合成HandlerExecutionChain類型并返回
@Override 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); } HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); if (CorsUtils.isCorsRequest(request)) { CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request); CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig); executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain; }
getHandlerInternal是個接口
AbstractHandlerMethodMapping,AbstractUrlHandlerMapping都實現(xiàn)了它。其中AbstractHandlerMethodMapping更常用,注解@RequestMapping的方式就屬于它,它將被注解的Method作為handler。
protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;
lookupHandlerMethod方法來查找url和對應(yīng)的方法
@Override protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); this.mappingRegistry.acquireReadLock(); try { HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); } finally { this.mappingRegistry.releaseReadLock(); } }
從mappingRegistry中獲取匹配路徑的mapping,并排序獲取最匹配的handlerMethod
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { Listmatches = new ArrayList (); List directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath); if (directPathMatches != null) { addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) { // No choice but to go through all mappings... addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request); } if (!matches.isEmpty()) { Comparator comparator = new MatchComparator(getMappingComparator(request)); Collections.sort(matches, comparator); Match bestMatch = matches.get(0); if (matches.size() > 1) { if (CorsUtils.isPreFlightRequest(request)) { return PREFLIGHT_AMBIGUOUS_MATCH; } Match secondBestMatch = matches.get(1); if (comparator.compare(bestMatch, secondBestMatch) == 0) { Method m1 = bestMatch.handlerMethod.getMethod(); Method m2 = secondBestMatch.handlerMethod.getMethod(); throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path "" + request.getRequestURL() + "": {" + m1 + ", " + m2 + "}"); } } handleMatch(bestMatch.mapping, lookupPath, request); return bestMatch.handlerMethod; } else { return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request); } }
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
同樣也是遍歷handlerAdapters中所有的adapter,如果和handler的類型匹配,就返回handlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { for (HandlerAdapter ha : this.handlerAdapters) { 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"); }
mappedHandler.applyPreHandle(processedRequest, response依次執(zhí)行interceptor的prehandle方法,如果又一個攔截器返回false就停止
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = 0; i < interceptors.length; i++) { HandlerInterceptor interceptor = interceptors[i]; if (!interceptor.preHandle(request, response, this.handler)) { triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } } return true; }
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
這個方法在handlerAdapter的接口中,有幾個實現(xiàn),AbstractHandlerMethodAdapter,AnnotationMethodHandlerAdapter,,,
SimpleServletHandlerAdapter:handle方法就是調(diào)用Servlet的service((Servlet) handler).service(request, response); 。
SimpleControllerHandlerAdapter:handle方法本質(zhì)是執(zhí)行Controller.handleRequest方法return ((Controller) handler).handleRequest(request, response);
HttpRequestHandlerAdapter: ((HttpRequestHandler) handler).handleRequest(request, response);
AbstractHandlerMethodAdapter:是一個抽象類,handle方法調(diào)用handleInternal,handleInternal是一個接口,在實現(xiàn)類RequestMappingHandlerAdapter中實現(xiàn)。關(guān)鍵的地方在于調(diào)用invokeHandlerMethod
@Override protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelAndView mav; checkRequest(request); //... mav = invokeHandlerMethod(request, response, handlerMethod); //.. prepareResponse(response); //.. return mav; }
invokeHandlerMethod就是在執(zhí)行傳入的handler方法
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ......... //執(zhí)行Controller中的RequestMapping注釋的方法 invocableMethod.invokeAndHandle(webRequest, mavContainer); //返回ModelAndView視圖 return getModelAndView(mavContainer, modelFactory, webRequest); }
applyDefaultViewName(processedRequest, mv);
很簡單,就是設(shè)置一下view
private void applyDefaultViewName(HttpServletRequest request, ModelAndView mv) throws Exception { if (mv != null && !mv.hasView()) { mv.setViewName(getDefaultViewName(request)); } }
同上applyPreHandle,執(zhí)行攔截器list中的postHandle方法
關(guān)鍵就是調(diào)用render方法,然后執(zhí)行攔截器列表中的AfterCompletion方法
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, 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 (mappedHandler != null) { mappedHandler.triggerAfterCompletion(request, response, null); } }
render方法中,關(guān)鍵的一步view.render(mv.getModelInternal(), request, response);
這個接口在AbstractView這個抽象類中定義了模版方法
@Override public void render(Mapmodel, HttpServletRequest request, HttpServletResponse response) throws Exception { Map mergedModel = createMergedOutputModel(model, request, response); prepareResponse(request, response); renderMergedOutputModel(mergedModel, getRequestToExpose(request), response); }
createMergedOutputModel,關(guān)鍵是這些putAll方法,把靜態(tài)的attribute和動態(tài)值方都放進mergedModel中然后返回,可以看到先put staticAttributes后put model,所以說明動態(tài)的值優(yōu)先級更高可能覆蓋靜態(tài)attribute的值
protected MapcreateMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) { ... Map mergedModel = new LinkedHashMap (size); mergedModel.putAll(this.staticAttributes); if (pathVars != null) { mergedModel.putAll(pathVars); } if (model != null) { mergedModel.putAll(model); } // Expose RequestContext? if (this.requestContextAttribute != null) { mergedModel.put(this.requestContextAttribute, createRequestContext(request, response, mergedModel)); } return mergedModel; }
prepareResponse就是設(shè)置response頭
protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) { if (generatesDownloadContent()) { response.setHeader("Pragma", "private"); response.setHeader("Cache-Control", "private, must-revalidate"); } }
renderMergedOutputModel又是一個接口
protected abstract void renderMergedOutputModel(Map
有很多實現(xiàn),對于jsp,在InternalResourceView類中實現(xiàn)
@Override protected void renderMergedOutputModel( Mapmodel, HttpServletRequest request, HttpServletResponse response) throws Exception { // Expose the model object as request attributes. exposeModelAsRequestAttributes(model, request); // Expose helpers as request attributes, if any. exposeHelpers(request); // Determine the path for the request dispatcher. String dispatcherPath = prepareForRendering(request, response); // Obtain a RequestDispatcher for the target resource (typically a JSP). RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath); // If already included or response already committed, perform include, else forward. if (useInclude(request, response)) { response.setContentType(getContentType()); rd.include(request, response); } else { // Note: The forwarded resource is supposed to determine the content type itself. rd.forward(request, response); } }
exposeModelAsRequestAttributes方法就是把model中的值都填到request中
protected void exposeModelAsRequestAttributes(Mapmodel, HttpServletRequest request) throws Exception { for (Map.Entry entry : model.entrySet()) { String modelName = entry.getKey(); Object modelValue = entry.getValue(); if (modelValue != null) { request.setAttribute(modelName, modelValue); } else { request.removeAttribute(modelName); } } }
如果response已經(jīng)提交了,included,否則就執(zhí)行forward
到這里,請求處理結(jié)束。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/66702.html
摘要:是提供的類,為了在容器中建立容器而服務(wù)的。主要處理的請求分發(fā),對進行管理。接收到請求由進行匹配,匹配成功后交由進行業(yè)務(wù)邏輯的處理,業(yè)務(wù)邏輯處理完成后交由進行數(shù)據(jù)的解析同時找到對應(yīng)的,最終由將的結(jié)果到瀏覽器進行解析。 spring給我們帶來了什么? spring IoC、AOP、Transaction這些都是很重要的特性,但是這篇這些都不是主角,主要來談?wù)剆pringMVC是如何對請求參...
摘要:問題來了,我們到底還在用嗎答案是,不全用。后者是初始化的配置,主要是的配置。啟動類測試啟動項目后,在瀏覽器里面輸入。通過查詢已裝載的,并且支持該而獲取的。按照前面對的描述,對于而言,這個必定是。的核心在的方法中。 之前已經(jīng)分析過了Spring的IOC(《零基礎(chǔ)帶你看Spring源碼——IOC控制反轉(zhuǎn)》)與AOP(《從源碼入手,一文帶你讀懂Spring AOP面向切面編程》)的源碼,本次...
摘要:依賴于對請求的支持。使用解析兼容的沒有構(gòu)造器參數(shù),也沒有要設(shè)置的參數(shù),這樣,在應(yīng)用上下文中,將其聲明為就會非常簡單。默認(rèn)是沒有限制的整個請求的容量。 Spring MVC 高級的技術(shù) 本章內(nèi)容: Spring MVC配置的替代方案 處理文件上傳 在控制器中處理異常 使用flash屬性 稍等還沒結(jié)束 說明 如果你有幸能看到。后面的章節(jié)暫時不更新了,改變學(xué)習(xí)方式了。重要理解思想,這本書...
摘要:可以發(fā)現(xiàn),這兩個類都是可以被實例化的,且構(gòu)造器不需要參數(shù)。這段代碼的后半部分其實沒有什么新意,但下半部分的第一行非常關(guān)鍵接受一個作為構(gòu)造器參數(shù)這實際上解決了我們在第四章測試失敗后反思的可能的疑惑我們配置的容器實際上并沒有和融合起來。 如何向一個WebApp引入Spring與Spring MVC 1 在Servlet 3.0環(huán)境中,容器(加載運行webapp的軟件,如Tomcat)會在類...
摘要:核心類類的繼承關(guān)系前端控制器是規(guī)范中的核心類,實現(xiàn)接口,繼承此類用于處理用戶請求。主要配置中初始化參數(shù)。 Spring MVC 核心類 類的繼承關(guān)系Spring MVC前端控制器DispatcherServlet-->FrameworkServlet-->HttpServletBean-->HttpServletshowImg(https://segmentfault.com/img/...
閱讀 3494·2023-04-25 21:43
閱讀 3106·2019-08-29 17:04
閱讀 807·2019-08-29 16:32
閱讀 1546·2019-08-29 15:16
閱讀 2158·2019-08-29 14:09
閱讀 2747·2019-08-29 13:07
閱讀 1633·2019-08-26 13:32
閱讀 1326·2019-08-26 12:00