九大组件
MultipartResolver
主要用来处理文件上传.如果定义过当前类型的bean对象,那么直接获取,如果没有的话,可以为null LocaleResolver
主要用来处理国际化配置,基于URL参数的配置(AcceptHeaderLocaleResolver),基于session的配置(SessionLocaleResolver),基于cookie的配置(CookieLocaleResolver) ThemeResolver
主要用来设置主题Theme HandlerMapping
映射器,用来将对应的request跟controller进行对应 HandlerAdapter
处理适配器,主要包含Http请求处理器适配器,简单控制器处理器适配器,注解方法处理器适配器 HandlerExceptionResolver
基于HandlerExceptionResolver接口的异常处理 RequestToViewNameTranslator
当controller处理器方法没有返回一个View对象或逻辑视图名称,并且在该方法中没有直接往response的输出流里面写数据的时候,spring将会采用约定好的方式提供一个逻辑视图名称 ViewResolver
将ModelAndView选择合适的视图进行渲染的处理器 FlashMapManager
提供请求存储属性,可供其他请求使用
一.源码初识(一)
servlet 生命周期 init service destory DispatchServlet 配置web.xml给tomcat使用 SpringMvc的扩展
配置文件,加载mvc需要使用的bean,分别指定spring和mvc的配置文件路径 先启动spring的容器,再启动springmvc的容器 所有的应用程序打成war包,放在tomcat中,tomcat需要读取web.xml配置文件 web.xml中配置spring容器需要的配置文件和springmvc需要的配置文件 springmvc就是servlet,servlet配置好启动需要的配置文件路径 两个容器的意义: 隔离 , 继承 ContextLoaderListener # initWebApplicationContext initWebApplicationContext(event.getServletContext()) ServletContext ==>里边有params,有spring配置文件的路径 ContextLoaderListener 里边有一个context createWebApplicationContext 从ContextLoader.properties文件中获取到contextClassName ==>XmlWebApplicationContext 名称 Root WebApplicationContext 里边有一个beanFactory configureAndRefreshWebApplicationContext 创建并且准备spring容器 wac.setConfigLocation(configLocationParam); 设置配置文件的路径 wac.refresh(); postProcessBeanFactory(beanFactory) beanFactory.addBeanPostProcessor(new ServletContextAwareProcesso) finishRefresh() publishEvent(new ContextRefreshedEvent(this)) DispatcherServlet(创建好之后)==> FrameworkServlet ==> HttpServletBean # init() servlet的初始化方法 new ServletConfigPropertyValues(getServletConfig()…) 里边有springmvc配置文件的路径 bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment())); 注册自定义的编辑器
protected void initBeanWrapper ( BeanWrapper bw) {
bw. setConversionService ( getConversionService ( ) ) ;
registerCustomEditors ( bw) ;
}
initServletBean() this.webApplicationContext = initWebApplicationContext(); WebApplicationContext rootContext 父级context,spring的容器 createWebApplicationContext(rootContext) 创建springmvc容器 wac.setParent(parent); 设置父级容器 spring容器 wac.setConfigLocation(getContextConfigLocation()) 配置springmvc配置文件路径 configureAndRefreshWebApplicationContext(wac)
二.源码初识(二)
ServletContext: servlet的上下文对象,包含整个web.xml中的配置 ServletConfig 被某个Servlet持有,对应的servelt中配置的属性 wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener())); 添加了一个监听器 ContextRefreshListener finishRefresh(); ==>publishEvent(new ContextRefreshedEvent(this)); 发布事件 SourceFilteringListener ==> ContextRefreshListener
FrameworkServlet.this.onApplicationEvent(event) initStrategies(context) 创建九大内置对象,收到监听后 getDefaultStrategies(context, strategyInterface)
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
org.springframework.web.servlet.function.support.RouterFunctionMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
org.springframework.web.servlet.function.support.HandlerFunctionAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
initMultipartResolver(context); 用来处理文件上传 可以为空值 initLocaleResolver(context); 国际化配置,有默认值 initThemeResolver(context); 设置主题Theme initHandlerMappings(context) 映射器,用来将对应的request跟controller进行对应 initHandlerAdapters(context); 处理适配器,主要包含Http请求处理器适配器,简单控制器处理器适配器,注解方法处理器适配器 initHandlerExceptionResolvers(context) 基于HandlerExceptionResolver接口的异常处理 initRequestToViewNameTranslator(context) 当controller处理器方法没有返回一个View对象或逻辑视图名称 initViewResolvers(context) 将ModelAndView选择合适的视图进行渲染的处理器 initFlashMapManager(context) 提供请求存储属性,可供其他请求使用 DispatcherServlet # FrameworkServlet # void service(HttpServletRequest request, HttpServletResponse response) mvc 请求的入口
三.springMvc请求执行流程
service(HttpServletRequest request, HttpServletResponse response) HttpMethod.resolve(request.getMethod()) 获取请求方法 processRequest(request, response) 处理请求 super.service(request, response); HttpServlet 中的service方法调用doGet方法 LocaleContext localeContext = buildLocaleContext(request); 获取当前请求的LocalContext
AcceptHeaderLocaleResolver buildRequestAttributes
new ServletRequestAttributes(request, response) initContextHolders(request, localeContext, requestAttributes) 赋值到ThreadLocal中 doService(request, response) 真正的执行方法 request.setAttribute(…)
getWebApplicationContext,this.localeResolver this.themeResolver,getThemeSource() 主题替换,静态资源指定路径,一键替换,类似于i18n request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE,Collections.unmodifiableMap(inputFlashMap)); 设置flashMap ,flashMap用来redirect传递参数 doDispatch(request, response) processedRequest = checkMultipart(request) 检查是否是上传请求 mappedHandler = getHandler(processedRequest) 获取处理器 getHandlerAdapter(mappedHandler.getHandler()) 获取适配器 将处理器转换为适配器,可以用同一的方法进行下边流程的处理 lastModified : 浏览器第一次返回数据时会将文件的lastModified带回,第二次获取文件时,发生那个Head请求,服务器会去到文件的最后一次修改时间和该次请求传进来的最后一次修改时间作对比,如果不一样,返回文件,如果一样返回304表示未过期,用之前的文件 mappedHandler.applyPreHandle 执行拦截器的前置处理 ha.handle(processedRequest, response, mappedHandler.getHandler()) 执行具体的逻辑处理,返回的是ModelAndView applyDefaultViewName(processedRequest, mv) 处理默认的视图 mappedHandler.applyPostHandle 执行拦截器的后置处理 processDispatchResult(processedRequest, …) 处理返回结果和进行页面的渲染 triggerAfterCompletion 发生异常后,执行interceptor的afterCompletion,执行拦截器的异常处理拦截 HandlerInterceptor 两个阶段 请求处理和页面渲染,分别捕获异常
四:MultipartResolverHandlerMapping
MultipartResolver
isMultipart 判断是否是上传请求 resolveMultipart 将request请求包装成MultipartHttpServletRequest cleanupMultipart 处理完成之后清理上传过程中产生的临时资源 checkMultipart(request)
contentType.toLowerCase(Locale.ENGLISH).startsWith(“multipart/”); this.multipartResolver.resolveMultipart(request) parseRequest(request)
List fileItems = fileUpload.parseRequest(request) new MultipartParsingResult(multipartFiles, multipartParameters, multipartParameterContentTypes) 参数1: 上传的文件, 参数2: 普通表单,参数3:参数的contentType 定义Controller的方式
实现 Controller servlet.mvc包下的,必须在配置文件定义bean方法,需要加请求的映射路径 实现 HttpRequestHandler,在配置文件定义bean方法,需要加请求的映射路径 添加@Controller的注解 HandlerMapping
BeanNameUrlHandlerMapping 根据请求路径匹配 另外两个的处理 RequestMappingHandlerMapping 根据请求方法匹配 @Controller的处理 RouterFunctionMapping getHandler(processedRequest) BeanNameUrlHandlerMapping
AbstractHandlerMapping ==>AbstractUrlHandlerMapping String pathWithinApp = getPathWithinApplication(request) 获取请求路径 Object handler = lookupHandler(lookupPath, request) AbstractDetectingUrlHandlerMapping ## initApplicationContext() 完成urlMapping的map初始化 ApplicationContextAware ==>setApplicationContext ==>initApplicationContext(context) ==>initApplicationContext() 调用源头 detectMappedInterceptors(this.adaptedInterceptors) 扫描已注册MappedInterceptor的Bean detectHandlers() 检测处理器
获取容器中所有的Bean对象 determineUrlsForHandler(beanName) beanName解析url,模板方法,判断beanName或者别名是否以 “/” 开头 registerHandler(urls, beanName);
Map<String, Object> handlerMap 路径和处理器的映射 this.handlerMap.put(urlPath, resolvedHandler); RequestMappingInfoHandlerMapping
MappingRegistry
Map<T, MappingRegistration> registry 注册表 Map<T, HandlerMethod> mappingLookup 保存RequestCondition和handlerMethod的对应关系 MultiValueMap<String, T> urlLookup 保存url与RequestCondition的对应关系 Map<String, List> nameLookup Mapping 的名字与 HandlerMethod 的映射 InitializingBean
afterPropertiesSet()==>initHandlerMethods() 初始化MappingRegistry isHandler 判断是否有Controller 和 RequestMapping 注解 detectHandlerMethods(beanName) 扫描处理器的方法 Map<Method, T> methods 扫描的method,key为方法,value为路径 registerHandlerMethod
this.mappingRegistry.register(mapping, handler, method) HandlerMethod handlerMethod 将调用的方法封装为HandlerMethod 上诉map添加对象 HandlerMethod getHandlerInternal(HttpServletRequest request) 从MappingRegistry中根据路径获取到 HandlerMethod
五.HandlerMappingHandlerAdapter
handler==> adapter通过适配器的方式来进行调用 getHandlerExecutionChain
new HandlerExecutionChain(handler) 把handler对象传进去,有handler和拦截器interceptor
for ( HandlerInterceptor interceptor : this . adaptedInterceptors) {
if ( interceptor instanceof MappedInterceptor ) {
MappedInterceptor mappedInterceptor = ( MappedInterceptor ) interceptor;
if ( mappedInterceptor. matches ( lookupPath, this . pathMatcher) ) {
chain. addInterceptor ( mappedInterceptor. getInterceptor ( ) ) ;
}
}
else {
chain. addInterceptor ( interceptor) ;
}
}
AbstractUrlHandlerMapping (springmvc默认的拦截)
PathExposingHandlerInterceptor UriTemplateVariablesHandlerInterceptor noHandlerFound 如果获取不到Handler直接返回404 需要Adapter的原因
实现Controller创建controller,需要实现ModelAndView handleRequest方法,加适配器SimpleControllerHandlerAdapter 实现HttpRequestHandler创建controller,需要实现void handleRequest方法,加适配器HttpRequestHandlerAdapter 加Controller 注解,里边的方法可以自定义,加适配器 RequestMappingHandlerAdapter 每一个方法调用的方法不一样,所以需要一个适配器将不同的方法统一起来,后续调用的时候可以直接调用adapter的方法 HandlerAdapter support handle 方法
HttpRequestHandlerAdapter SimpleControllerHandlerAdapter RequestMappingHandlerAdapter HandlerFunctionAdapter 常用注解
@RequestBody @RequestMapping @RequestParam @PathVariables @Validated @Valid @CookieValue @SessionAttribute @RequestHeader @InitBulider HandlerAdapter ha = getHandlerAdapte 获取对应的adapter mappedHandler.applyPreHandle interceptor执行拦截方法 preHandle
triggerAfterCompletion int i = this.interceptorIndex; i >= 0; i-- 拦截器走过一次,interceptorIndex++,返回的时候–,逆序执行剩下的拦截器 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()) 执行方法
checkRequest(request) 校验请求(HttpMethod 和 Session 的校验) invokeHandlerMethod(request, response, handlerMethod) invokeHandlerMethod getDataBinderFactory(handlerMethod) 获取数据绑定工厂 getModelFactory(handlerMethod, binderFactory) 获取model对象 createInvocableHandlerMethod(handlerMethod) 创建可执行的对象 invocableMethod.setHandlerMethodArgumentResolvers设置参数处理器
RequestMappingHandlerAdapter # afterPropertiesSet invocableMethod.setHandlerMethodReturnValueHandlers 设置返回值处理器
RequestMappingHandlerAdapter # afterPropertiesSet new ModelAndViewContainer() 返回值 mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)) 将flashmap中的数据设置到model中 modelFactory.initModel(webRequest, mavContainer, invocableMethod) 使用modelFactory将sessionAttributes和注释了@ModelAttribute的方法的参数设置到model中 invocableMethod.invokeAndHandle(webRequest, mavContainer) 执行调用
invokeForRequest getMethodParameters() 获取参数值 doInvoke(args) setResponseStatus 设置响应状态 returnValueHandlers.handleReturnValue 处理返回值
六.HandlerAdapter具体执行流程
getDataBinderFactory
MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS) 将当前Controller中所有被@InitBinder注解修饰的方法都获取到
public static final MethodFilter INIT_BINDER_METHODS = method ->
AnnotatedElementUtils . hasAnnotation ( method, InitBinder . class ) ;
1. ReflectionUtils.doWithMethods 处理方法
2. USER_DECLARED_METHODS ==method -> !method.isBridge() && !method.isSynthetic() 当method不是桥接方法 又 不是合成方法时,返回true;否则返回false
1. isSynthetic 方法是用户自定义的还是编译器创建的
3. mc.doWith(method)
4. T result = metadataLookup.inspect(specificMethod) 判断方式是否被InitBinder注解修饰
5. methodMap.put(specificMethod, result) 将binder方法放入到methodMap
Map<ControllerAdviceBean, Set> initBinderAdviceCache 用于缓存@controllerAdvice注释的类里面注释了@InitBinder的方法
afterPropertiesSet # initControllerAdviceCache 初始化initBinderAdviceCache 属性 createInitBinderMethod(bean, method)
binderMethod.setHandlerMethodArgumentResolvers(this.initBinderArgumentResolvers) 设置binder的参数解析器 initBinderMethods.add(createInitBinderMethod(bean, method)) 将method方法添加到initBinderMethods中 RequestMappingHandlerAdapter # afterPropertiesSet
执行内容
初始化注释了@ControllerAdvice的类的相关属性 初始化 argumentResolvers 属性 初始化 initBinderArgumentResolvers 属性 初始化 returnValueHandlers 属性 initControllerAdviceCache 初始化注释了@ControllerAdvice的类的相关属性
ControllerAdviceBean.findAnnotatedBeans 扫描@ControllerAdvice注解的Bean MethodIntrospector.selectMethods 扫描有@ModelAttribute
,无@RequestMapping
注解的方法 扫描有@InitBinder
注解的方法 RequestBodyAdvice和ResponseBodyAdvice getModelFactory(handlerMethod, binderFactory)
流程类似于getDataBinderFactory
七.HandlerAdapter具体执行流程2
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); 创建可执行的方法载体 invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); 设置参数解析器
在RequestMappingHandlerAdapter的afterPropertiesSet方法赋值 invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); 设置返回值处理器
在RequestMappingHandlerAdapter的afterPropertiesSet方法赋值 invocableMethod.setDataBinderFactory(binderFactory); 设置绑定工厂 getDataBinderFactory(handlerMethod) 的返回值 invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer) 设置参数名称发现器 new DefaultParameterNameDiscoverer() 创建ModelAndViewContainer 的对象,来保存Model和View对象
Object view; 视图对象,object类型,可以是实际视图,也可以是string类型的逻辑视图 ModelMap defaultModel; (BindingAwareModelMap) 默认使用的model对象 对ModelAndViewContainer中的属性进行赋值
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); 将flashmap中的数据设置到model中,redirect的时候参数传递 使用flashMap modelFactory.initModel(webRequest, mavContainer, invocableMethod) 初始化模型
getModelFactory(handlerMethod, binderFactory) 方法的返回值,内含@ModelAttribute 注解修饰的方法 this.sessionAttributesHandler.retrieveAttributes 获取SessionAttribute设置的属性值并且设置到modelAndView中 invokeModelAttributeMethods(request, container) 执行@ModelAttribute并将结果设置到ModelAndView中
ModelAttribute ann = modelMethod.getMethodAnnotation(ModelAttribute.class); 获取方法上的注解 container.containsAttribute(ann.name()) 校验是否之前绑定过model doInvoke(args) 调用@ModelAndAttribute修饰的方法 getNameForReturnValue(returnValue, modelMethod.getReturnType()) 获取model对应的key值 container.addAttribute(returnValueName, returnValue); 将model对象设置到ModelAndView中 map(string, map) 结构 invocableMethod.invokeAndHandle(webRequest, mavContainer) 执行方法的调用
invokeForRequest(webRequest, mavContainer, providedArgs) 通过反射调用方法 getMethodArgumentValues(request, mavContainer, providedArgs) 根据反射获取方法的参数
this.resolvers.supportsParameter(parameter) 参数解析器中是否有支持该参数的
resolver.supportsParameter(parameter) 判断resolver是否支持参数 this.argumentResolverCache.put(parameter, resolver 将resolver放到缓存中 this.resolvers.resolveArgument 解析参数
HandlerMethodArgumentResolver result =this.argumentResolverCache.get(parameter) 从缓存中获取resolver resolver.resolveArgument 解析参数
resolveName(resolvedName.toString(), nestedParameter, webRequest) 参数解析名称 request.getParameterValues(name) 从请求中获取参数 WebDataBinder binder = binderFactory.createBinder 获取绑定的binder binder.convertIfNecessary 利用binder进行参数的转换
this.typeConverterDelegate.convertIfNecessary 类型的转换 doInvoke(args) 具体的调用逻辑
八.第八课
setResponseStatus(webRequest) 设置响应的状态码
getResponseStatus() 获取方法上的状态码 创建HandlerMethod 是, HandlerMethod 的构造方法
evaluateResponseStatus(); annotation = AnnotatedElementUtils.findMergedAnnotation(getBeanType(), ResponseStatus.class); 获取方法上的@ResponseStatus 注解 webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status) 进行响应状态码的设置 handleReturnValue 处理返回值
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType) 选择返回值处理器
handler.supportsReturnType(returnType) 处理器是否支持当前返回类型 handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); 处理器处理返回内容
ViewNameMethodReturnValueHandler 字符串对应的处理器
mavContainer.setViewName(viewName); 给container设置viewName getModelAndView(mavContainer, modelFactory, webRequest); 获取视图和解析器
modelFactory.updateModel 更新model(设置sessionAttributes和给model设置BindingResult)
this.sessionAttributesHandler.storeAttributes(request, defaultModel) 将model中的内容设置到session中 @SessionAttribute 表示向request作用域设值的时候也向session中设置一份 updateBindingResult(request, defaultModel); 参数加valided 自己试试 如果处理器绑定参数时注释了@Valid和@Validated注解,那么会讲校验的结果设置到BindingResult类型的参数中 如果mavContainer.isRequestHandled() 被处理过了,会直接返回null
一些返回值处理器会将此值设置为true mavContainer.setRequestHandled(true); new ModelAndView 创建ModelAndView (viewName, model, status)
getModelMap().addAllAttributes(model); 设置attribute RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); 如果是redirect请求,设置flashAttributes applyDefaultViewName(processedRequest, mv) 当view为空时,根据request设置默认的view
getDefaultViewName(request) 将请求路径当做默认的是viewName返回
this.viewNameTranslator.getViewName(request) RequestToViewNameTranslator 获取默认的viewName,请求路径去掉前后’/’ RequestToViewNameTranslator ===> DefaultRequestToViewNameTranslator 九大内置组件 mv.setViewName(defaultViewName) 设置viewName
九.第九课
RequestResponseBodyMethodProcessor # writeWithMessageConverters 将对象进行转换,并写入到响应中 @ResponseBody注解标注的内容不返回试图,直接将内容写入到响应中
valueType = getReturnValueType(body, returnType) 获取返回value的类型 Type targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass()) 获取泛型
使用位置AbstractMessageConverterMethodProcessor ## writeWithMessageConverters MediaType contentType = outputMessage.getHeaders().getContentType() 获取响应的头信息的MediaType getAcceptableMediaTypes(request) 从请求中获取可以接受的MediaType
HeaderContentNegotiationStrategy # resolveMediaTypes request.getHeaderValues(HttpHeaders.ACCEPT) 获取request请求头中的accept属性 getProducibleMediaTypes(request, valueType, targetType) 获取可能返回的MediaType
this.allSupportedMediaTypes 所有的可能返回的MediaType 类型 遍历this.messageConverters 消息转换器
result.addAll(converter.getSupportedMediaTypes()) 将匹配到的消息转换器支持的MediaType添加到结果中 List mediaTypesToUse = new ArrayList<>() 可以使用的MediaType 如果requestedType.isCompatibleWith(producibleType) 如果可接受的MediaType和可能产生的MediaType一致,则添加到mediaTypesToUse中
mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType)) 遍历mediaTypesToUse集合,选择一个最匹配的,拿到selectedMediaType 遍历messageConverters数组
converter.canWrite 调用converter的canWrite方法进行判断是否能够转换 getAdvice() 获取ControllerAdvice 注解修饰并且实现ResponseBodyAdvice的bean getAdvice().beforeBodyWrite() 执行beforeBodyWrite方法 processBody getMatchingAdvice(returnType, ResponseBodyAdvice.class) 获取ResponseBodyAdvice对应的bean advice.supports 是否支持 ((ResponseBodyAdvice) advice).beforeBodyWrite 执行beforeBodyWrite方法 genericConverter.write ===> AbstractJackson2HttpMessageConverter.write addDefaultHeaders(headers, t, contentType) 给响应头中加默认的content-type writeInternal ObjectWriter objectWriter 获取到objectWrite objectWriter.writeValue(generator, value) 将结果进行序列化 WebMvcConfigurationSupport ## setMessageConverters ## HttpMessageConverter是做什么用的 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException) 处理返回结果,包括处理异常、渲染页面、触发Interceptor的afterCompletion
render(mv, request, response) 渲染页面
this.localeResolver.resolveLocale(request) 解析local对象
response.setLocale(locale) 响应设置local resolveViewName(viewName, mv.getModelInternal(), locale, request) 解析viewName
viewResolver.resolveViewName InternalResourceViewResolver 配置文件中配置的试图解析器 createView(viewName, locale)
return applyLifecycleMethods(REDIRECT_URL_PREFIX, view); 处理重定向视图 return applyLifecycleMethods(FORWARD_URL_PREFIX, view); 处理转发视图 super.createView(viewName, locale 创建视图名对应的 View 对象 getViewClass() ==> org.springframework.web.servlet.view.JstlView View的class类型 BeanUtils.instantiateClass(viewClass) 实例化view对象 buildView ==> view.setUrl(getPrefix() + viewName + getSuffix()) view.setContentType(contentType); … view设置各种属性值 view.render(mv.getModelInternal(), request, response) 渲染
renderMergedOutputModel 进行渲染 rd.forward(request, response); 进行转发
十.第十课
processDispatchResult 处理返回结果,包括处理异常 processHandlerException 处理异常 ModelAndView exMv 异常的试图 HandlerExceptionResolver
ExceptionHandlerExceptionResolver 这个处理器会寻找可处理的异常处理方法 ResponseStatusExceptionResolver DefaultHandlerExceptionResolver ExceptionHandlerExceptionResolver
resolver.resolveException 处理异常 doResolveHandlerMethodException
getExceptionHandlerMethod 获取异常处理的方法 method = getMappedMethod(exceptionType) 获取匹配异常类型的方法 this.mappedMethods.keySet() 被@ExceptionHandler注解标注的异常处理方法 matches.sort(new ExceptionDepthComparator(exceptionType)) 将异常从小到大排序 return ServletInvocableHandlerMethod(handlerMethod.getBean(), method) 返回可执行的异常处理方法 exceptionHandlerMethod.invokeAndHandle
invokeForRequest 执行方法 ResponseStatusExceptionResolver
AnnotatedElementUtils.findMergedAnnotation(ex.getClass(), ResponseStatus.class) 判断异常类上是否有@ResponseStatus 注解 return resolveResponseStatus return new ModelAndView(); 返回空的modelAndView DefaultHandlerExceptionResolver
十一.第十一课
servlet的异步处理
开启一个新的线程执行逻辑 采用长连接的方式,将响应给客户端后不会立马关闭请求,而是服务端将结果返回后再关闭连接 AsyncWebRequest 异步请求对象 WebAsyncManager ==> WebAsyncTask 核心处理类 WebAsyncUtils 异步管理工具 FrameworkServlet # processRequest
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); 获取异步管理器 asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor()); 注册拦截器 RequestBindingInterceptor 将localContext和requestAttribute设置到请求中去,请求完毕后清空掉 DispatcherServlet # doDispatch
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.isConcurrentHandlingStarted() 如果需要异步处理直接返回 RequestMappingHandlerAdapter # invokeHandlerMethod 处理controller注解的对应的执行器
WebAsyncUtils.createAsyncWebRequest 创建异步请求对象 asyncWebRequest.setTimeout(this.asyncRequestTimeout); 设置超时时间
AsyncWebRequest asyncWebRequest = WebAsyncUtils . createAsyncWebRequest ( request, response) ;
asyncWebRequest. setTimeout ( this . asyncRequestTimeout) ;
WebAsyncManager asyncManager = WebAsyncUtils . getAsyncManager ( request) ;
asyncManager. setTaskExecutor ( this . taskExecutor) ;
asyncManager. setAsyncWebRequest ( asyncWebRequest) ;
asyncManager. registerCallableInterceptors ( this . callableInterceptors) ;
asyncManager. registerDeferredResultInterceptors ( this . deferredResultInterceptors) ;
if ( asyncManager. hasConcurrentResult ( ) ) {
Object result = asyncManager. getConcurrentResult ( ) ;
mavContainer = ( ModelAndViewContainer ) asyncManager. getConcurrentResultContext ( ) [ 0 ] ;
asyncManager. clearConcurrentResult ( ) ;
LogFormatUtils . traceDebug ( logger, traceOn -> {
String formatted = LogFormatUtils . formatValue ( result, ! traceOn) ;
return "Resume with async result [" + formatted + "]" ;
} ) ;
invocableMethod = invocableMethod. wrapConcurrentResult ( result) ;
}
asyncManager.isConcurrentHandlingStarted() return null 如果异步请求已经开始了返回null AsyncTaskMethodReturnValueHandler 异步任务返回值处理器
WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(webAsyncTask, mavContainer) 启动异步任务 startAsyncProcessing(processingContext) 异步启动