2019独角兽企业重金招聘Python工程师标准>>>
本节主要目标是探查一个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;
}
}
RequestMappingHandlerMapping是本例真正使用的处理@RequestMapping形式的Controllor。同理,本例使用RequestMappingHandlerAdapter,其余读者可自行查看。
RequestMappingHandlerAdapter的初始化:
RequestMappingHandlerAdapter同样实现了InitializingBean接口,实例化对象时,会调用afterPropertiesSet()方法。
@Override
public void afterPropertiesSet() {
// 初始化@ControllerAdvice标注的类
initControllerAdviceCache();
// 参数解析器
if (this.argumentResolvers == null) {
List resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
// @InitBinder标注的方法参数处理器
if (this.initBinderArgumentResolvers == null) {
List resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
// 返回值处理器
if (this.returnValueHandlers == null) {
List handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
从源码中我们看到了四个重要信息:@ControllerAdvice、@InitBinder、argumentResolvers、returnValueHandlers。
其中argumentResolvers和returnValueHandlers会用到HttpMessageConverter消息转换器,用以处理@ResponseBody和@RequestBody所标注的方法或参数。
private List getDefaultArgumentResolvers() {
List resolvers = new ArrayList();
// 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>(4);
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(stringHttpMessageConverter);
this.messageConverters.add(new SourceHttpMessageConverter
覆盖逻辑:AnnotationDrivenBeanDefinitionParser#getMessageConverters()方法返回的消息转换器,会覆盖构造函数加入的默认转换器:
private ManagedList> getMessageConverters(Element element, Object source, ParserContext parserContext) {
Element convertersElement = DomUtils.getChildElementByTagName(element, "message-converters");
ManagedList super Object> messageConverters = new ManagedList
核心分发器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 mappedInterceptors) {
mappedInterceptors.addAll(
BeanFactoryUtils.beansOfTypeIncludingAncestors(
getApplicationContext(), MappedInterceptor.class, true, false).values());
}
这其中,MappedInterceptor类里,持有了ConversionServiceExposingInterceptor拦截器,是默认加入的。
原文出处:http://my.oschina.net/zudajun