日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

spring mvc DispatcherServlet详解之一---处理请求深入解析

發布時間:2025/4/5 c/c++ 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spring mvc DispatcherServlet详解之一---处理请求深入解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

要深入理解spring mvc的工作流程,就需要先了解spring mvc的架構:

從上圖可以看到 前端控制器DispatcherServlet在其中起著主導作用,理解了DispatcherServlet 就完全可以說弄清楚了spring mvc。

為了加深對spring mvc的整個工作流程的理解,本文從分析DispatcherServlet的工作過程來一窺spring mvc的整個面貌。

1. 初始化

protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context); //文件上傳解析,如果請求類型是multipart將通過MultipartResolver進行文件上傳解析;
initLocaleResolver(context); //本地化解析
initThemeResolver(context);   //主題解析
initHandlerMappings(context); //通過HandlerMapping,將請求映射到處理器
initHandlerAdapters(context); //通過HandlerAdapter支持多種類型的處理器
initHandlerExceptionResolvers(context); //如果執行過程中遇到異常將交給HandlerExceptionResolver來解析
initRequestToViewNameTranslator(context); //直接解析請求到視圖名
initViewResolvers(context); //通過ViewResolver解析邏輯視圖名到具體視圖實現
initFlashMapManager(context); //flash映射管理器
}

單個resolver
initMultipartResolver,initLocaleResolver,initThemeResolver,initRequestToViewNameTranslator,initFlashMapManager 這五個初始化方法流程相同,都是使用
context.getBean(String name, Class<FlashMapManager> requiredType)的方式獲取到相應的Resolver。以initMultipartResolver為例,見如下: /*** Initialize the MultipartResolver used by this class.* <p>If no bean is defined with the given name in the BeanFactory for this namespace,* no multipart handling is provided.*/private void initMultipartResolver(ApplicationContext context) {try {this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);if (logger.isDebugEnabled()) {logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");}}catch (NoSuchBeanDefinitionException ex) {// Default is no multipart resolver.this.multipartResolver = null;if (logger.isDebugEnabled()) {logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME +"': no multipart request handling provided");}}}

多個resolver

initHandlerMappings,initHandlerAdapters,initHandlerExceptionResolvers,initViewResolvers 獲取方式相同,使用:
BeanFactoryUtils.beansOfTypeIncludingAncestors(ListableBeanFactory lbf, Class<HandlerMapping> type, boolean includeNonSingletons, boolean allowEagerInit) 的方式獲取到相應的Resolver。以initHandlerMappings為例,見如下: /*** Initialize the HandlerMappings used by this class.* <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,* we default to BeanNameUrlHandlerMapping.*/private void initHandlerMappings(ApplicationContext context) {this.handlerMappings = null;if (this.detectAllHandlerMappings) {// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.Map<String, HandlerMapping> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);if (!matchingBeans.isEmpty()) {this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());// We keep HandlerMappings in sorted order.OrderComparator.sort(this.handlerMappings);}}else {try {HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);this.handlerMappings = Collections.singletonList(hm);}catch (NoSuchBeanDefinitionException ex) {// Ignore, we'll add a default HandlerMapping later. }}// Ensure we have at least one HandlerMapping, by registering// a default HandlerMapping if no other mappings are found.if (this.handlerMappings == null) {this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);if (logger.isDebugEnabled()) {logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");}}}

那么深入看一下BeanFactoryUtils.beansOfTypeIncludingAncestors 究竟做了什么?返回指定類型和子類型的所有bean,若該bean factory 是一個繼承類型的beanFactory,這個方法也會獲取祖宗factory中定義的指定類型的bean。

/*** Return all beans of the given type or subtypes, also picking up beans defined in* ancestor bean factories if the current bean factory is a HierarchicalBeanFactory.* The returned Map will only contain beans of this type.* <p>Does consider objects created by FactoryBeans if the "allowEagerInit" flag is set,* which means that FactoryBeans will get initialized. If the object created by the* FactoryBean doesn't match, the raw FactoryBean itself will be matched against the* type. If "allowEagerInit" is not set, only raw FactoryBeans will be checked* (which doesn't require initialization of each FactoryBean).* <p><b>Note: Beans of the same name will take precedence at the 'lowest' factory level,* i.e. such beans will be returned from the lowest factory that they are being found in,* hiding corresponding beans in ancestor factories.</b> This feature allows for* 'replacing' beans by explicitly choosing the same bean name in a child factory;* the bean in the ancestor factory won't be visible then, not even for by-type lookups.* @param lbf the bean factory* @param type type of bean to match* @param includeNonSingletons whether to include prototype or scoped beans too* or just singletons (also applies to FactoryBeans)* @param allowEagerInit whether to initialize <i>lazy-init singletons</i> and* <i>objects created by FactoryBeans</i> (or by factory methods with a* "factory-bean" reference) for the type check. Note that FactoryBeans need to be* eagerly initialized to determine their type: So be aware that passing in "true"* for this flag will initialize FactoryBeans and "factory-bean" references.* @return the Map of matching bean instances, or an empty Map if none* @throws BeansException if a bean could not be created*/public static <T> Map<String, T> beansOfTypeIncludingAncestors(ListableBeanFactory lbf, Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)throws BeansException {Assert.notNull(lbf, "ListableBeanFactory must not be null");Map<String, T> result = new LinkedHashMap<String, T>(4);result.putAll(lbf.getBeansOfType(type, includeNonSingletons, allowEagerInit));if (lbf instanceof HierarchicalBeanFactory) {HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf;if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {Map<String, T> parentResult = beansOfTypeIncludingAncestors((ListableBeanFactory) hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit);for (Map.Entry<String, T> entry : parentResult.entrySet()) {String beanName = entry.getKey();if (!result.containsKey(beanName) && !hbf.containsLocalBean(beanName)) {result.put(beanName, entry.getValue());}}}}return result;}

?2. 提供服務

? ? ?我們來看看這個servlet是如何提供服務的?

@Overrideprotected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {if (logger.isDebugEnabled()) {String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");}// 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)) {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. 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);try {doDispatch(request, response);}finally {if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {return;}// Restore the original attribute snapshot, in case of an include.if (attributesSnapshot != null) {restoreAttributesAfterInclude(request, attributesSnapshot);}}}

? ?從上面我們可以看到,提供服務只要分4步:

? 1. 保存現場。保存request 熟悉的快照,以便能在必要時恢復。

? 2. 將框架需要的對象放入request中,以便view和handler使用。

? 3. 請求分發服務.

? 4. 恢復現場。

其中最重要的是請求分發服務:

/*** Process the actual dispatching to the handler.* <p>The handler will be obtained by applying the servlet's HandlerMappings in order.* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters* to find the first that supports the handler class.* <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers* themselves to decide which methods are acceptable.* @param request current HTTP request* @param response current HTTP response* @throws Exception in case of any kind of processing failure*/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);if (mappedHandler == null || mappedHandler.getHandler() == 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 (logger.isDebugEnabled()) {logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);}if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {return;}}if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}try {// Actually invoke the handler.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);}}}

分發過程如下:

1. 判斷是否設置了multipart resolver,設置的話轉換為multipart request,沒有的話則繼續下面的步驟。

2. 根據當前request,獲取hangdler。

3. 根據當前request,獲取HandlerAdapter。

4. 如果支持http請求頭,處理?last-modified header請求頭。

5. 應用已注冊interceptor的preHandle方法

6.?HandlerAdapter處理請求。

7. 設置默認視圖。

8.?應用已注冊interceptor的postHandle方法。

9. 處理異常或者視圖渲染。

小結:

? ?DispatherServlet整個過程的細節一章之內很難描述的面面俱到,只能分析部分流程,想了解更具體的實現需要從源代碼中去尋找。

?

轉載于:https://www.cnblogs.com/davidwang456/p/4096530.html

總結

以上是生活随笔為你收集整理的spring mvc DispatcherServlet详解之一---处理请求深入解析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。