吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1698|回复: 1
收起左侧

[会员申请] 申请会员ID:chenxiaoqian

[复制链接]
吾爱游客  发表于 2022-9-16 14:48
1、申 请 I D:chenxiaoqian
2、个人邮箱:963068179@qq.com
3、原创技术文章:
DispatcherServlet类源码分析

DispatcherServlet类结构图
DispatcherServlet源码分析1. 加载配置文件/**  * This implementation calls {@link #initStrategies}.  */  @Override  protected 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()方法@Override  protected 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()方法@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 + "]");          }          // 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
抱歉,未能达到申请要求,申请不通过,可以关注论坛官方微信(吾爱破解论坛),等待开放注册通知。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-15 01:25

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表