[Spring源码]FrameworkServlet

2021-03-23  本文已影响0人  檀香灰

一.FrameworkServlet 主要介绍

Spring MVC 的核心是DispatcherServlet,其父类是FramworkServlet.

1.1 继承关系

1.png
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
 HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
 if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
  processRequest(request, response);
 }
 else {
  super.service(request, response);
 }
}

说明:

1.2 FrameworkServlet

HttpServlet 中并未对 doGet/doPost 等进行实质性处理,所以FrameworkServlet 中重写了各种请求对应的方法,如:doDelete、doGet、doOptions、doPost、doPut、doTrace 等,其实就是除了 doHead 之外的其他方法都重写了。

1.3 FrameworkServlet 核心方法 processRequest

方法如下:

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
 long startTime = System.currentTimeMillis();
 Throwable failureCause = null;
 LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
 LocaleContext localeContext = buildLocaleContext(request);
 RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
 ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
 WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
 asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
 initContextHolders(request, localeContext, requestAttributes);
 try {
  doService(request, response);
 }
 catch (ServletException | IOException ex) {
  failureCause = ex;
  throw ex;
 }
 catch (Throwable ex) {
  failureCause = ex;
  throw new NestedServletException("Request processing failed", ex);
 }
 finally {
  resetContextHolders(request, previousLocaleContext, previousAttributes);
  if (requestAttributes != null) {
   requestAttributes.requestCompleted();
  }
  logResult(request, response, failureCause, asyncManager);
  publishRequestHandledEvent(request, response, startTime, failureCause);
 }
}

processRequest 其实主要做了两件事,第一件事就是对 LocaleContext 和 RequestAttributes 的处理,第二件事就是发布事件。方法分为三部分:
1.doService 之前主要是一些准备工作,准备工作主要干了两件事:

第一件事就是从 LocaleContextHolder 和 RequestContextHolder 中分别获取它们原来保存的 LocaleContext 和 RequestAttributes 对象存起来,然后分别调用 buildLocaleContext 和 buildRequestAttributes 方法获取到当前请求的 LocaleContext 和 RequestAttributes 对象,再通过 initContextHolders 方法将当前请求的 LocaleContext 和 RequestAttributes 对象分别设置到 LocaleContextHolder 和 RequestContextHolder 对象中;

第二件事则是获取到异步管理器并设置拦截器。

2.接下来就是 doService 方法,这是一个抽象方法,具体的实现在 DispatcherServlet 中
3.最后就是 finally 中,这个里边干了两件事

第一件事就是将 LocaleContextHolder 和 RequestContextHolder 中对应的对象恢复成原来的样子(参考第一步);

第二件事就是通过 publishRequestHandledEvent 方法发布一个 ServletRequestHandledEvent 类型的消息。

1.3 processRequest 的事件发布

finally 代码块中会调用 publishRequestHandledEvent 方法发送一个 ServletRequestHandledEvent 类型的事件。

private void publishRequestHandledEvent(HttpServletRequest request, HttpServletResponse response,
  long startTime, @Nullable Throwable failureCause) {
 if (this.publishEvents && this.webApplicationContext != null) {
  // 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, response.getStatus()));
 }
}

二.LocalContext 和 RequestAttributes

2.1 LocalContext

LocaleContext 里面存放着Locale ,即本地化信息.
国际化的时候,如果需要用到Locale 对象,第一反应是从HttpServletRequest 中获取,类似:

Locale locale = req.getLocale();
但是,HttpServletRequest 只存放于Controller 中,如果想要在Service 层获取,就得cong Controller 中传参数过来,比较麻烦。

Spring MVC 提供了 LocaleContextHolder, 这个工具就是用来保存当前请求的LocaleContext, 是基于ThreadLocal 来保存变量,进而确保不同线程之间互不干扰。有了LocaleContextHolder 之后,就可以在任何地方获取Locale 了:

Locale locale = LocaleContextHolder.getLocale();

2.2 RequestAttributes

RequestAttributes 是一个接口,这个接口可以用来 get/set/remove 某一个属性。
RequestAttributes 有诸多实现类,默认使用的是 ServletRequestAttributes,通过 ServletRequestAttributes,我们可以 getRequest、getResponse 以及 getSession。

和 LocaleContext 类似,RequestAttributes 被保存在 RequestContextHolder
在 SpringMVC 中,如果我们需要在 Controller 之外的其他地方使用 request、response 以及 session,其实不用每次都从 Controller 中传递 request、response 以及 session 等对象,我们完全可以直接通过 RequestContextHolder 来获取:

ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = servletRequestAttributes.getRequest();
HttpServletResponse response = servletRequestAttributes.getResponse();
上一篇 下一篇

猜你喜欢

热点阅读