发表于 2022-9-16 14:48

申请会员ID:chenxiaoqian

1、申 请 I D:chenxiaoqian
2、个人邮箱:963068179@qq.com
3、原创技术文章:
DispatcherServlet类源码分析

DispatcherServlet类结构图http://www.51gjie.com/Images/image1/dqu0y54y.25t.jpg DispatcherServlet源码分析1. 加载配置文件/*** This implementation calls {@link #initStrategies}.*/@Overrideprotected void onRefresh(ApplicationContext context) {        initStrategies(context);}/*** 初始化定位解析器、主题解析器、处理器映射器、处理器适配器、异常解析器、视图解析器等等 */protected void initStrategies(ApplicationContext context) {        initMultipartResolver(context);        initLocaleResolver(context);        initThemeResolver(context);        initHandlerMappings(context);        initHandlerAdapters(context);        initHandlerExceptionResolvers(context);        initRequestToViewNameTranslator(context);        initViewResolvers(context);        initFlashMapManager(context);} initStrategies()方法我们可以看出DispatcherServlet实例化时会初始化web层相关的bean,如HandlerMapping,HandlerAdapter等,并且如果我们没有进行配置,DispatcherServlet会提供默认的配置。以上的Servlet的体系结构以及DispatcherServlet的实例化过程我们可以看出主要完成以下几个事情:
(1)通过配置Servlet实现SpringMVC核心控制器DispatcherServlet的初始化;
(2)通过ServletContext共享Spring根上下文,使得每一个Servlet实例获取根上下文中的bean,用于实例化SpringMVC web层的相关bean。(3)初始化DispatcherServlet作为核心控制器,接收处理请求需要的相关资源,如HandlerMapping,HandlerAdapter等。(4)通过Servlet体系结构中的继承关系以及抽象方法,可以根据具体的需求对各个层级的Servlet抽象方法进行重写以满足不同的功能需要,父类中只定义流程和方法引用,具体实现由子Servlet完成,实现定义与实现的分离,便于扩展。2. processRequest()方法@Overrideprotected final void doGet(HttpServletRequest request, HttpServletResponse response)          throws ServletException, IOException {      processRequest(request, response);}protected final void processRequest(HttpServletRequest request, HttpServletResponse response)          throws ServletException, IOException {      long startTime = System.currentTimeMillis();      Throwable failureCause = null;      // Expose current LocaleResolver and request as LocaleContext.      LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();      LocaleContextHolder.setLocaleContext(buildLocaleContext(request), this.threadContextInheritable);      // Expose current RequestAttributes to current thread.      RequestAttributes previousRequestAttributes = RequestContextHolder.getRequestAttributes();      ServletRequestAttributes requestAttributes = null;      if (previousRequestAttributes == null || previousRequestAttributes.getClass().equals(ServletRequestAttributes.class)) {          requestAttributes = new ServletRequestAttributes(request);          RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);      }      if (logger.isTraceEnabled()) {          logger.trace("Bound request context to thread: " + request);      }      try {          doService(request, response);      }      catch (ServletException ex) {          failureCause = ex;          throw ex;      }      catch (IOException ex) {          failureCause = ex;          throw ex;      }      catch (Throwable ex) {          failureCause = ex;          throw new NestedServletException("Request processing failed", ex);      }      finally {          // Clear request attributes and reset thread-bound context.          LocaleContextHolder.setLocaleContext(previousLocaleContext, this.threadContextInheritable);          if (requestAttributes != null) {            RequestContextHolder.setRequestAttributes(previousRequestAttributes, this.threadContextInheritable);            requestAttributes.requestCompleted();          }          if (logger.isTraceEnabled()) {            logger.trace("Cleared thread-bound request context: " + request);          }            if (logger.isDebugEnabled()) {            if (failureCause != null) {                  this.logger.debug("Could not complete request", failureCause);            }            else {                  this.logger.debug("Successfully completed request");            }          }          if (this.publishEvents) {            // Whether or not we succeeded, publish an event.            long processingTime = System.currentTimeMillis() - startTime;            this.webApplicationContext.publishEvent(                      new ServletRequestHandledEvent(this,                              request.getRequestURI(), request.getRemoteAddr(),                              request.getMethod(), getServletConfig().getServletName(),                              WebUtils.getSessionId(request), getUsernameForRequest(request),                              processingTime, failureCause));          }      }}DispatcherServlet也是通过自己的service()方法来接收和转发Http请求到具体的doGet()或doPost()这些方法的。以一次典型的GET请求为例,经过HttpServlet基类中service()方法的委派,请求会被转发到doGet()方法中。doGet()方法,在DispatcherServlet的父类FrameworkServlet类中被覆写。
processRequest()方法理解的要点是以doService()方法为区隔,前一部分是将当前请求的Locale对象和属性,分别设置到LocaleContextHolder和RequestContextHolder这两个抽象类中的ThreadLocal对象中,也就是分别将这两个东西和请求线程做了绑定。在doService()处理结束后,再恢复回请求前的LocaleContextHolder和RequestContextHolder,也即解除线程绑定。每次请求处理结束后,容器上下文都发布了一个ServletRequestHandledEvent事件,你可以注册监听器来监听该事件。
可以看到,processRequest()方法只是做了一些线程安全的隔离,真正的请求处理,发生在doService()方法中。3. doService()方法@Overrideprotected 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 + "]");        }        // 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));                        }                }        }        // 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); //这边最终也是调用了doDispatch方法,该方法主要用来处理SPring框架的具体业务分发逻辑。        }        finally {                // Restore the original attribute snapshot, in case of an include.                if (attributesSnapshot != null) {                        restoreAttributesAfterInclude(request, attributesSnapshot);                }        }}doService()方法中requet.setAttribute()方法的调用,将前面在初始化流程中实例化的对象设置到http请求的属性中,供下一步处理使用,其中有容器的上下文对象、本地化解析器等SpringMVC特有的编程元素。不同于Struts2中的ValueStack,SpringMVC的数据并没有从HttpServletRequest对象中抽离出来再存进另外一个编程元素,这也跟SpringMVC的设计思想有关。因为从一开始,SpringMVC的设计者就认为,不应该将请求处理过程和Web容器完全隔离。所以,真正发生请求转发的方法doDispatch()中,它的参数是HttpServletRequest和HttpServletResponse对象。4. doDispatch()方法//Spring框架最终的分发都是通过该方法的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.                        mappedHandler = getHandler(processedRequest, false);                        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()) {                                        String requestUri = urlPathHelper.getRequestUri(request);                                        logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);                                }                                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {                                        return;                                }                        }                        // 这里是处理前置拦截器                        HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();                        if (interceptors != null) {                                for (int i = 0; i < interceptors.length; i++) { HandlerInterceptor interceptor = interceptors; if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) { triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null); return; } interceptorIndex = i; } } //处理最终的Action逻辑 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // Do we need view name translation? if (mv != null && !mv.hasView()) { mv.setViewName(getDefaultViewName(request)); } //处理后置拦截器 if (interceptors != null) { for (int i = interceptors.length - 1; i >= 0; i--) {                                        HandlerInterceptor interceptor = interceptors;                                        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);                }        }}doDispatch()是整个请求转发流程中最核心的方法,DispatcherServlet所接收的Http请求,经过层层转发,最终都是汇总到这个方法中来进行最后的请求分发和处理。它通过高度抽象的接口,描述出了一个MVC(Model-View-Controller)设计模式的实现方案。Model、View、Controller三种层次的编程元素,在SpringMVC中都有大量的实现类,各种处理细节也是千差万别。但是,它们最后都是由,也都能由doDispatch()方法来统一描述,这就是接口和抽象的威力,万变不离其宗。

Hmily 发表于 2022-9-19 11:24

抱歉,未能达到申请要求,申请不通过,可以关注论坛官方微信(吾爱破解论坛),等待开放注册通知。
页: [1]
查看完整版本: 申请会员ID:chenxiaoqian