SpringMVC源码分析:一个request请求的完整流程和各组件介绍

简介: SpringMVC源码分析:一个request请求的完整流程和各组件介绍

本节主要目标是探查一个request请求的完整流程,以及流程中各种web组件的简单介绍,组件的细节,将在后续组件专题文章中详细介绍。

DispatcherServlet初始化完毕后,我们发现它注册2个HandlerMapping,3个HandlerAdapter,主要是为了兼容旧的过时的Controllor编写模式,在本例中,实际生效的是RequestMappingHandlerMapping和RequestMappingHandlerAdapter。

我们来看看这几个对象是什么时候注册进去的。

AnnotationDrivenBeanDefinitionParser#parse()方法中,有一段:

// Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
MvcNamespaceUtils.registerDefaultComponents(parserContext, source);
public static void registerDefaultComponents(ParserContext parserContext, Object source) {
  registerBeanNameUrlHandlerMapping(parserContext, source);
  registerHttpRequestHandlerAdapter(parserContext, source);
  registerSimpleControllerHandlerAdapter(parserContext, source);
  registerHandlerMappingIntrospector(parserContext, source);
}

BeanNameUrlHandlerMapping用于处理如下形式的Controllor(已过时):

public class SomeControllor implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        return null;
    }
}
<bean id="/some" class="com.spring.controllor.SomeControllor" />

RequestMappingHandlerMapping是本例真正使用的处理@RequestMapping形式的Controllor。同理,本例使用RequestMappingHandlerAdapter,其余读者可自行查看。

RequestMappingHandlerAdapter的初始化:

RequestMappingHandlerAdapter同样实现了InitializingBean接口,实例化对象时,会调用afterPropertiesSet()方法。

@Override
public void afterPropertiesSet() {
  // 初始化@ControllerAdvice标注的类
  initControllerAdviceCache();
    // 参数解析器
  if (this.argumentResolvers == null) {
    List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
    this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
  }
    // @InitBinder标注的方法参数处理器
  if (this.initBinderArgumentResolvers == null) {
    List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
    this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
  }
    // 返回值处理器
  if (this.returnValueHandlers == null) {
    List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
    this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
  }
}

从源码中我们看到了四个重要信息:@ControllerAdvice、@InitBinder、argumentResolvers、returnValueHandlers。

其中argumentResolvers和returnValueHandlers会用到HttpMessageConverter消息转换器,用以处理@ResponseBody和@RequestBody所标注的方法或参数。

private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
  List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
  // Annotation-based argument resolution
  resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
  resolvers.add(new RequestParamMapMethodArgumentResolver());
  resolvers.add(new PathVariableMethodArgumentResolver());
  resolvers.add(new PathVariableMapMethodArgumentResolver());
  resolvers.add(new MatrixVariableMethodArgumentResolver());
  resolvers.add(new MatrixVariableMapMethodArgumentResolver());
  resolvers.add(new ServletModelAttributeMethodProcessor(false));
    // 使用消息转换器
  resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
    // 使用消息转换器
  resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
  resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
  resolvers.add(new RequestHeaderMapMethodArgumentResolver());
  resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
  resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
  resolvers.add(new SessionAttributeMethodArgumentResolver());
  resolvers.add(new RequestAttributeMethodArgumentResolver());
  // Type-based argument resolution
  resolvers.add(new ServletRequestMethodArgumentResolver());
  resolvers.add(new ServletResponseMethodArgumentResolver());
    // 使用消息转换器
  resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
  resolvers.add(new RedirectAttributesMethodArgumentResolver());
  resolvers.add(new ModelMethodProcessor());
  resolvers.add(new MapMethodProcessor());
  resolvers.add(new ErrorsMethodArgumentResolver());
  resolvers.add(new SessionStatusMethodArgumentResolver());
  resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
  // Custom arguments
  if (getCustomArgumentResolvers() != null) {
    resolvers.addAll(getCustomArgumentResolvers());
  }
  // Catch-all
  resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
  resolvers.add(new ServletModelAttributeMethodProcessor(true));
  return resolvers;
}

方法getMessageConverters()获取的,就是默认的HttpMessageConverter消息转换器。

RequestMappingHandlerAdapter的构造函数,会默认加入4个消息转换器,但是,遗憾的是,它会被Spring自动注入的消息转换器给覆盖掉。

public RequestMappingHandlerAdapter() {
  StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
  stringHttpMessageConverter.setWriteAcceptCharset(false);  // see SPR-7316
  this.messageConverters = new ArrayList<HttpMessageConverter<?>>(4);
  this.messageConverters.add(new ByteArrayHttpMessageConverter());
  this.messageConverters.add(stringHttpMessageConverter);
  this.messageConverters.add(new SourceHttpMessageConverter<Source>());
  this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
}

覆盖逻辑:AnnotationDrivenBeanDefinitionParser#getMessageConverters()方法返回的消息转换器,会覆盖构造函数加入的默认转换器:

private ManagedList<?> getMessageConverters(Element element, Object source, ParserContext parserContext) {
  Element convertersElement = DomUtils.getChildElementByTagName(element, "message-converters");
  ManagedList<? super Object> messageConverters = new ManagedList<Object>();
  if (convertersElement != null) {
    messageConverters.setSource(source);
    for (Element beanElement : DomUtils.getChildElementsByTagName(convertersElement, "bean", "ref")) {
      Object object = parserContext.getDelegate().parsePropertySubElement(beanElement, null);
      messageConverters.add(object);
    }
  }
  if (convertersElement == null || Boolean.valueOf(convertersElement.getAttribute("register-defaults"))) {
    messageConverters.setSource(source);
    messageConverters.add(createConverterDefinition(ByteArrayHttpMessageConverter.class, source));
    RootBeanDefinition stringConverterDef = createConverterDefinition(StringHttpMessageConverter.class, source);
    stringConverterDef.getPropertyValues().add("writeAcceptCharset", false);
    messageConverters.add(stringConverterDef);
    messageConverters.add(createConverterDefinition(ResourceHttpMessageConverter.class, source));
    messageConverters.add(createConverterDefinition(SourceHttpMessageConverter.class, source));
    messageConverters.add(createConverterDefinition(AllEncompassingFormHttpMessageConverter.class, source));
    if (romePresent) {
      messageConverters.add(createConverterDefinition(AtomFeedHttpMessageConverter.class, source));
      messageConverters.add(createConverterDefinition(RssChannelHttpMessageConverter.class, source));
    }
    if (jackson2XmlPresent) {
      Class<?> type = MappingJackson2XmlHttpMessageConverter.class;
      RootBeanDefinition jacksonConverterDef = createConverterDefinition(type, source);
      GenericBeanDefinition jacksonFactoryDef = createObjectMapperFactoryDefinition(source);
      jacksonFactoryDef.getPropertyValues().add("createXmlMapper", true);
      jacksonConverterDef.getConstructorArgumentValues().addIndexedArgumentValue(0, jacksonFactoryDef);
      messageConverters.add(jacksonConverterDef);
    }
    else if (jaxb2Present) {
      messageConverters.add(createConverterDefinition(Jaxb2RootElementHttpMessageConverter.class, source));
    }
    if (jackson2Present) {
      Class<?> type = MappingJackson2HttpMessageConverter.class;
      RootBeanDefinition jacksonConverterDef = createConverterDefinition(type, source);
      GenericBeanDefinition jacksonFactoryDef = createObjectMapperFactoryDefinition(source);
      jacksonConverterDef.getConstructorArgumentValues().addIndexedArgumentValue(0, jacksonFactoryDef);
      messageConverters.add(jacksonConverterDef);
    }
    else if (gsonPresent) {
      messageConverters.add(createConverterDefinition(GsonHttpMessageConverter.class, source));
    }
  }
  return messageConverters;
}

核心分发器DispatcherServlet的doDispatch()方法:

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);
      // 返回RequestMappingHandlerMapping生成的chain对象.
      mappedHandler = getHandler(processedRequest);
      if (mappedHandler == null || mappedHandler.getHandler() == null) {
        noHandlerFound(processedRequest, response);
        return;
      }
      // 返回RequestMappingHandlerAdapter对象.
      HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
      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;
        }
      }
              // 调用拦截器的preHandle()方法
      if (!mappedHandler.applyPreHandle(processedRequest, response)) {
        return;
      }
      // 处理请求,返回ModelAndView对象.
      mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
      if (asyncManager.isConcurrentHandlingStarted()) {
        return;
      }
      applyDefaultViewName(processedRequest, mv);
            // 调用拦截器的postHandle()方法
      mappedHandler.applyPostHandle(processedRequest, response, mv);
    }
    catch (Exception ex) {
      dispatchException = ex;
    }
    catch (Throwable err) {
      dispatchException = new NestedServletException("Handler dispatch failed", err);
    }
        // ViewResolver处理结果视图
    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
  }
  catch (Exception ex) {
        // 调用拦截器的afterCompletion()方法
    triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
  }
  catch (Throwable err) {
    triggerAfterCompletion(processedRequest, response, mappedHandler,
        new NestedServletException("Handler processing failed", err));
  }
  finally {
        //...
  }
}

InvocableHandlerMethod#invokeForRequest()方法中,使用argumentResolvers处理入参:

public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
    Object... providedArgs) throws Exception {
    // 使用argumentResolvers处理入参
  Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
    // 调用Controllor的目标方法
  Object returnValue = doInvoke(args);
  return returnValue;
}

ServletInvocableHandlerMethod#invokeAndHandle()方法中,使用returnValueHandlers处理方法返回值:

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
    Object... providedArgs) throws Exception {
  Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
  //...
  try {
    this.returnValueHandlers.handleReturnValue(
        returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
  }
  catch (Exception ex) {
    //...
    }
    throw ex;
  }
}

DispatcherServlet#render()方法中,使用viewResolvers解析View,并使用View渲染视图:

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
  Locale locale = this.localeResolver.resolveLocale(request);
  response.setLocale(locale);
  View view;
  if (mv.isReference()) {
    // 使用viewResolvers解析出View
    view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
    //...
  }
  else {
    //...
  }
  try {
    if (mv.getStatus() != null) {
      response.setStatus(mv.getStatus().value());
    }
        // view渲染视图
    view.render(mv.getModelInternal(), request, response);
  }
  catch (Exception ex) {
    //...
  }
}

至此,一个reqeust请求的完整流程,就结束了,流程中,我们看到了一些非常重要的注解和组件。

注解:@ControllerAdvice、@InitBinder、@ResponseBody和@RequestBody

组件:HandlerMethodArgumentResolver、HandlerMethodReturnValueHandler、HandlerInterceptor、HttpMessageConverter、ViewResolver

后续我们会对这些注解和组件,进行详细的分析。

补充:

本例我们并没有注册任何自定义的拦截器,但是,我们发现依然有一个ConversionServiceExposingInterceptor拦截器。

public class ConversionServiceExposingInterceptor extends HandlerInterceptorAdapter {
  private final ConversionService conversionService;
  public ConversionServiceExposingInterceptor(ConversionService conversionService) {
    Assert.notNull(conversionService, "The ConversionService may not be null");
    this.conversionService = conversionService;
  }
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws ServletException, IOException {
    request.setAttribute(ConversionService.class.getName(), this.conversionService);
    return true;
  }
}

该拦截器给每一个reqeust请求放入一个ConversionService,那该拦截器是什么时候注册和创建的呢?

RequestMappingHandlerMapping实现了ApplicationContextAware接口,其父类会调用AbstractHandlerMapping#initApplicationContext()方法,该方法会自动加入ConversionServiceExposingInterceptor拦截器:

protected void initApplicationContext() throws BeansException {
  //...
  detectMappedInterceptors(this.adaptedInterceptors);
  //...
}
protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
  mappedInterceptors.addAll(
      BeanFactoryUtils.beansOfTypeIncludingAncestors(
          getApplicationContext(), MappedInterceptor.class, true, false).values());
}

这其中,MappedInterceptor类里,持有了ConversionServiceExposingInterceptor拦截器,是默认加入的。

目录
相关文章
|
1月前
|
设计模式 前端开发 Java
Spring MVC——项目创建和建立请求连接
MVC是一种软件架构设计模式,将应用分为模型、视图和控制器三部分。Spring MVC是基于MVC模式的Web框架,通过`@RequestMapping`等注解实现URL路由映射,支持GET和POST请求,并可传递参数。创建Spring MVC项目与Spring Boot类似,使用`@RestController`注解标记控制器类。
34 1
Spring MVC——项目创建和建立请求连接
|
1月前
|
前端开发 Java
学习SpringMVC,建立连接,请求,响应 SpringBoot初学,如何前后端交互(后端版)?最简单的能通过网址访问的后端服务器代码举例
文章介绍了如何使用SpringBoot创建简单的后端服务器来处理HTTP请求,包括建立连接、编写Controller处理请求,并返回响应给前端或网址。
53 0
学习SpringMVC,建立连接,请求,响应 SpringBoot初学,如何前后端交互(后端版)?最简单的能通过网址访问的后端服务器代码举例
|
2月前
|
XML 缓存 前端开发
springMVC02,restful风格,请求转发和重定向
文章介绍了RESTful风格的基本概念和特点,并展示了如何使用SpringMVC实现RESTful风格的请求处理。同时,文章还讨论了SpringMVC中的请求转发和重定向的实现方式,并通过具体代码示例进行了说明。
springMVC02,restful风格,请求转发和重定向
|
3月前
|
前端开发 Java Spring
SpringMVC种通过追踪源码查看是哪种类型的视图渲染器(一般流程方法)
这篇文章通过示例代码展示了如何在Spring MVC中编写和注册拦截器,以及如何在拦截器的不同阶段添加业务逻辑。
SpringMVC种通过追踪源码查看是哪种类型的视图渲染器(一般流程方法)
|
4月前
|
缓存 前端开发 Java
SpringMVC原理(1)-文件上传请求
【7月更文挑战第2天】SpringMVC文件上传请求原理:文件上传请求的执行流程、文件上传的自动配置原理 涉及组件:MultiPartFile、MultipartResolver、MultipartHttpServlet
|
6月前
|
JSON 前端开发 Java
SpringMVC概述、SpringMVC的工作流程、创建SpringMVC的项目
SpringMVC概述、SpringMVC的工作流程、创建SpringMVC的项目
40 2
|
5月前
|
前端开发 Java Spring
Spring MVC 请求处理流程
Spring MVC 请求处理流程
33 0
|
6月前
|
前端开发 Java 定位技术
生活小事件(SpringMVC主要的组件及作用和执行流程)
Spring MVC 的主要组件包括 DispatcherServlet(核心,请求调度)、HandlerMapping(URL 映射到处理器)、HandlerAdapter(统一执行处理器)、Handler(处理业务逻辑,通常为 @Controller 类)、ViewResolver(视图解析)和 View(渲染输出)。通过这些组件的协作,Spring MVC 实现了从接收请求到返回响应的流程,类似于警察处理交通违规的协调过程。
|
6月前
|
前端开发 Java 应用服务中间件
SpringMvc拦截器和手写模拟SpringMvc工作流程源码详解
MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分。 M: Model,模型层,指工程中的JavaBean,作用是处理数据。 JavaBean分为两类: 1.实体类Bean:专门存储业务数据的,如Student User等 2.业务处理Bean:指Service或Dao对象,专门用于处理业务逻辑和数据访问。
|
6月前
|
设计模式 前端开发 开发者
SpringMVC底层负责请求路由的模块是什么
SpringMVC底层负责请求路由的模块是什么
111 0