本节主要目标是探查一个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拦截器,是默认加入的。