SpringMvc源码

九大组件

  1. MultipartResolver
    1. 主要用来处理文件上传.如果定义过当前类型的bean对象,那么直接获取,如果没有的话,可以为null
  2. LocaleResolver
    1. 主要用来处理国际化配置,基于URL参数的配置(AcceptHeaderLocaleResolver),基于session的配置(SessionLocaleResolver),基于cookie的配置(CookieLocaleResolver)
  3. ThemeResolver
    1. 主要用来设置主题Theme
  4. HandlerMapping
    1. 映射器,用来将对应的request跟controller进行对应
  5. HandlerAdapter
    1. 处理适配器,主要包含Http请求处理器适配器,简单控制器处理器适配器,注解方法处理器适配器
  6. HandlerExceptionResolver
    1. 基于HandlerExceptionResolver接口的异常处理
  7. RequestToViewNameTranslator
    1. 当controller处理器方法没有返回一个View对象或逻辑视图名称,并且在该方法中没有直接往response的输出流里面写数据的时候,spring将会采用约定好的方式提供一个逻辑视图名称
  8. ViewResolver
    1. 将ModelAndView选择合适的视图进行渲染的处理器
  9. FlashMapManager
    1. 提供请求存储属性,可供其他请求使用

一.源码初识(一)

  1. servlet 生命周期 init service destory DispatchServlet
  2. 配置web.xml给tomcat使用
  3. SpringMvc的扩展
    1. 配置文件,加载mvc需要使用的bean,分别指定spring和mvc的配置文件路径
    2. 先启动spring的容器,再启动springmvc的容器
    3. 所有的应用程序打成war包,放在tomcat中,tomcat需要读取web.xml配置文件
    4. web.xml中配置spring容器需要的配置文件和springmvc需要的配置文件
    5. springmvc就是servlet,servlet配置好启动需要的配置文件路径
  4. 两个容器的意义: 隔离 , 继承
  5. ContextLoaderListener # initWebApplicationContext
  6. initWebApplicationContext(event.getServletContext())
  7. ServletContext ==>里边有params,有spring配置文件的路径
  8. ContextLoaderListener 里边有一个context
  9. createWebApplicationContext
  10. 从ContextLoader.properties文件中获取到contextClassName ==>XmlWebApplicationContext 名称 Root WebApplicationContext 里边有一个beanFactory
  11. configureAndRefreshWebApplicationContext 创建并且准备spring容器
  12. wac.setConfigLocation(configLocationParam); 设置配置文件的路径
  13. wac.refresh();
  14. postProcessBeanFactory(beanFactory)
  15. beanFactory.addBeanPostProcessor(new ServletContextAwareProcesso)
  16. finishRefresh()
  17. publishEvent(new ContextRefreshedEvent(this))
  18. DispatcherServlet(创建好之后)==> FrameworkServlet ==> HttpServletBean # init() servlet的初始化方法
  19. new ServletConfigPropertyValues(getServletConfig()…) 里边有springmvc配置文件的路径
  20. bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment())); 注册自定义的编辑器
protected void initBeanWrapper(BeanWrapper bw) {
    // 使用该工厂的ConversionService来作为bw的ConversionService,用于转换属性值,以替换JavaBeans PropertyEditor
    bw.setConversionService(getConversionService());
    // 将工厂中所有PropertyEditor注册到bw中
    registerCustomEditors(bw);
}
  1. initServletBean()
  2. this.webApplicationContext = initWebApplicationContext();
  3. WebApplicationContext rootContext 父级context,spring的容器
  4. createWebApplicationContext(rootContext) 创建springmvc容器
  5. wac.setParent(parent); 设置父级容器 spring容器
  6. wac.setConfigLocation(getContextConfigLocation()) 配置springmvc配置文件路径
  7. configureAndRefreshWebApplicationContext(wac)

二.源码初识(二)

  1. ServletContext: servlet的上下文对象,包含整个web.xml中的配置
  2. ServletConfig 被某个Servlet持有,对应的servelt中配置的属性
  3. wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener())); 添加了一个监听器 ContextRefreshListener
  4. finishRefresh(); ==>publishEvent(new ContextRefreshedEvent(this)); 发布事件
  5. SourceFilteringListener ==> ContextRefreshListener
    1. FrameworkServlet.this.onApplicationEvent(event)
    2. initStrategies(context) 创建九大内置对象,收到监听后
  6. getDefaultStrategies(context, strategyInterface)
    1. 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
  1. initMultipartResolver(context); 用来处理文件上传 可以为空值
  2. initLocaleResolver(context); 国际化配置,有默认值
  3. initThemeResolver(context); 设置主题Theme
  4. initHandlerMappings(context) 映射器,用来将对应的request跟controller进行对应
  5. initHandlerAdapters(context); 处理适配器,主要包含Http请求处理器适配器,简单控制器处理器适配器,注解方法处理器适配器
  6. initHandlerExceptionResolvers(context) 基于HandlerExceptionResolver接口的异常处理
  7. initRequestToViewNameTranslator(context) 当controller处理器方法没有返回一个View对象或逻辑视图名称
  8. initViewResolvers(context) 将ModelAndView选择合适的视图进行渲染的处理器
  9. initFlashMapManager(context) 提供请求存储属性,可供其他请求使用
  10. DispatcherServlet # FrameworkServlet # void service(HttpServletRequest request, HttpServletResponse response) mvc 请求的入口

三.springMvc请求执行流程

  1. service(HttpServletRequest request, HttpServletResponse response)
  2. HttpMethod.resolve(request.getMethod()) 获取请求方法
  3. processRequest(request, response) 处理请求
  4. super.service(request, response); HttpServlet 中的service方法调用doGet方法
  5. LocaleContext localeContext = buildLocaleContext(request); 获取当前请求的LocalContext
    1. AcceptHeaderLocaleResolver
  6. buildRequestAttributes
    1. new ServletRequestAttributes(request, response)
  7. initContextHolders(request, localeContext, requestAttributes) 赋值到ThreadLocal中
  8. doService(request, response) 真正的执行方法
  9. request.setAttribute(…)
    1. getWebApplicationContext,this.localeResolver
    2. this.themeResolver,getThemeSource() 主题替换,静态资源指定路径,一键替换,类似于i18n
  10. request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE,Collections.unmodifiableMap(inputFlashMap)); 设置flashMap ,flashMap用来redirect传递参数
  11. doDispatch(request, response)
  12. processedRequest = checkMultipart(request) 检查是否是上传请求
  13. mappedHandler = getHandler(processedRequest) 获取处理器
  14. getHandlerAdapter(mappedHandler.getHandler()) 获取适配器 将处理器转换为适配器,可以用同一的方法进行下边流程的处理
  15. lastModified : 浏览器第一次返回数据时会将文件的lastModified带回,第二次获取文件时,发生那个Head请求,服务器会去到文件的最后一次修改时间和该次请求传进来的最后一次修改时间作对比,如果不一样,返回文件,如果一样返回304表示未过期,用之前的文件
  16. mappedHandler.applyPreHandle 执行拦截器的前置处理
  17. ha.handle(processedRequest, response, mappedHandler.getHandler()) 执行具体的逻辑处理,返回的是ModelAndView
  18. applyDefaultViewName(processedRequest, mv) 处理默认的视图
  19. mappedHandler.applyPostHandle 执行拦截器的后置处理
  20. processDispatchResult(processedRequest, …) 处理返回结果和进行页面的渲染
  21. triggerAfterCompletion 发生异常后,执行interceptor的afterCompletion,执行拦截器的异常处理拦截 HandlerInterceptor
  22. 两个阶段 请求处理和页面渲染,分别捕获异常

四:MultipartResolverHandlerMapping

  1. MultipartResolver
    1. isMultipart 判断是否是上传请求
    2. resolveMultipart 将request请求包装成MultipartHttpServletRequest
    3. cleanupMultipart 处理完成之后清理上传过程中产生的临时资源
  2. checkMultipart(request)
    1. contentType.toLowerCase(Locale.ENGLISH).startsWith(“multipart/”);
    2. this.multipartResolver.resolveMultipart(request)
    3. parseRequest(request)
      1. List fileItems = fileUpload.parseRequest(request)
      2. new MultipartParsingResult(multipartFiles, multipartParameters, multipartParameterContentTypes) 参数1: 上传的文件, 参数2: 普通表单,参数3:参数的contentType
  3. 定义Controller的方式
    1. 实现 Controller servlet.mvc包下的,必须在配置文件定义bean方法,需要加请求的映射路径
    2. 实现 HttpRequestHandler,在配置文件定义bean方法,需要加请求的映射路径
    3. 添加@Controller的注解
  4. HandlerMapping
    1. BeanNameUrlHandlerMapping 根据请求路径匹配 另外两个的处理
    2. RequestMappingHandlerMapping 根据请求方法匹配 @Controller的处理
    3. RouterFunctionMapping
  5. getHandler(processedRequest)
  6. BeanNameUrlHandlerMapping
    1. AbstractHandlerMapping ==>AbstractUrlHandlerMapping
    2. String pathWithinApp = getPathWithinApplication(request) 获取请求路径
    3. Object handler = lookupHandler(lookupPath, request)
    4. AbstractDetectingUrlHandlerMapping ## initApplicationContext() 完成urlMapping的map初始化
    5. ApplicationContextAware ==>setApplicationContext ==>initApplicationContext(context) ==>initApplicationContext() 调用源头
    6. detectMappedInterceptors(this.adaptedInterceptors) 扫描已注册MappedInterceptor的Bean
    7. detectHandlers() 检测处理器
      1. 获取容器中所有的Bean对象
      2. determineUrlsForHandler(beanName) beanName解析url,模板方法,判断beanName或者别名是否以 “/” 开头
      3. registerHandler(urls, beanName);
        1. Map<String, Object> handlerMap 路径和处理器的映射
        2. this.handlerMap.put(urlPath, resolvedHandler);
  7. RequestMappingInfoHandlerMapping
    1. MappingRegistry
      1. Map<T, MappingRegistration> registry 注册表
      2. Map<T, HandlerMethod> mappingLookup 保存RequestCondition和handlerMethod的对应关系
      3. MultiValueMap<String, T> urlLookup 保存url与RequestCondition的对应关系
      4. Map<String, List> nameLookup Mapping 的名字与 HandlerMethod 的映射
    2. InitializingBean
      1. afterPropertiesSet()==>initHandlerMethods() 初始化MappingRegistry
      2. isHandler 判断是否有Controller 和 RequestMapping 注解
      3. detectHandlerMethods(beanName) 扫描处理器的方法
      4. Map<Method, T> methods 扫描的method,key为方法,value为路径
      5. registerHandlerMethod
        1. this.mappingRegistry.register(mapping, handler, method)
        2. HandlerMethod handlerMethod 将调用的方法封装为HandlerMethod
        3. 上诉map添加对象
    3. HandlerMethod getHandlerInternal(HttpServletRequest request) 从MappingRegistry中根据路径获取到 HandlerMethod

五.HandlerMappingHandlerAdapter

  1. handler==> adapter通过适配器的方式来进行调用
  2. getHandlerExecutionChain
    1. new HandlerExecutionChain(handler) 把handler对象传进去,有handler和拦截器interceptor
//添加拦截器链
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
        // 需要匹配,若路径匹配,则添加到 chain 中
        if (interceptor instanceof MappedInterceptor) {
            MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
            if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        }
        // 无需匹配,直接添加到 chain 中
        else {
            chain.addInterceptor(interceptor);
        }
    }
  1. AbstractUrlHandlerMapping (springmvc默认的拦截)
    1. PathExposingHandlerInterceptor
    2. UriTemplateVariablesHandlerInterceptor
  2. noHandlerFound 如果获取不到Handler直接返回404
  3. 需要Adapter的原因
    1. 实现Controller创建controller,需要实现ModelAndView handleRequest方法,加适配器SimpleControllerHandlerAdapter
    2. 实现HttpRequestHandler创建controller,需要实现void handleRequest方法,加适配器HttpRequestHandlerAdapter
    3. 加Controller 注解,里边的方法可以自定义,加适配器 RequestMappingHandlerAdapter
    4. 每一个方法调用的方法不一样,所以需要一个适配器将不同的方法统一起来,后续调用的时候可以直接调用adapter的方法
  4. HandlerAdapter support handle 方法
    1. HttpRequestHandlerAdapter
    2. SimpleControllerHandlerAdapter
    3. RequestMappingHandlerAdapter
    4. HandlerFunctionAdapter
  5. 常用注解
    1. @RequestBody @RequestMapping @RequestParam @PathVariables
    2. @Validated @Valid @CookieValue @SessionAttribute
    3. @RequestHeader @InitBulider
  6. HandlerAdapter ha = getHandlerAdapte 获取对应的adapter
  7. mappedHandler.applyPreHandle interceptor执行拦截方法 preHandle
    1. triggerAfterCompletion
    2. int i = this.interceptorIndex; i >= 0; i-- 拦截器走过一次,interceptorIndex++,返回的时候–,逆序执行剩下的拦截器
  8. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()) 执行方法
    1. checkRequest(request) 校验请求(HttpMethod 和 Session 的校验)
    2. invokeHandlerMethod(request, response, handlerMethod)
  9. invokeHandlerMethod
  10. getDataBinderFactory(handlerMethod) 获取数据绑定工厂
  11. getModelFactory(handlerMethod, binderFactory) 获取model对象
  12. createInvocableHandlerMethod(handlerMethod) 创建可执行的对象
  13. invocableMethod.setHandlerMethodArgumentResolvers设置参数处理器
    1. RequestMappingHandlerAdapter # afterPropertiesSet
  14. invocableMethod.setHandlerMethodReturnValueHandlers 设置返回值处理器
    1. RequestMappingHandlerAdapter # afterPropertiesSet
  15. new ModelAndViewContainer() 返回值
  16. mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)) 将flashmap中的数据设置到model中
  17. modelFactory.initModel(webRequest, mavContainer, invocableMethod) 使用modelFactory将sessionAttributes和注释了@ModelAttribute的方法的参数设置到model中
  18. invocableMethod.invokeAndHandle(webRequest, mavContainer) 执行调用
    1. invokeForRequest
    2. getMethodParameters() 获取参数值
    3. doInvoke(args)
    4. setResponseStatus 设置响应状态
    5. returnValueHandlers.handleReturnValue 处理返回值

六.HandlerAdapter具体执行流程

  1. getDataBinderFactory
    1. 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
  1. Map<ControllerAdviceBean, Set> initBinderAdviceCache 用于缓存@controllerAdvice注释的类里面注释了@InitBinder的方法
    1. afterPropertiesSet # initControllerAdviceCache 初始化initBinderAdviceCache 属性
  2. createInitBinderMethod(bean, method)
    1. binderMethod.setHandlerMethodArgumentResolvers(this.initBinderArgumentResolvers) 设置binder的参数解析器
  3. initBinderMethods.add(createInitBinderMethod(bean, method)) 将method方法添加到initBinderMethods中
  4. RequestMappingHandlerAdapter # afterPropertiesSet
    1. 执行内容
      1. 初始化注释了@ControllerAdvice的类的相关属性
      2. 初始化 argumentResolvers 属性
      3. 初始化 initBinderArgumentResolvers 属性
      4. 初始化 returnValueHandlers 属性
    2. initControllerAdviceCache 初始化注释了@ControllerAdvice的类的相关属性
      1. ControllerAdviceBean.findAnnotatedBeans 扫描@ControllerAdvice注解的Bean
      2. MethodIntrospector.selectMethods 扫描有@ModelAttribute,无@RequestMapping注解的方法
      3. 扫描有@InitBinder注解的方法
      4. RequestBodyAdvice和ResponseBodyAdvice
  5. getModelFactory(handlerMethod, binderFactory)
    1. 流程类似于getDataBinderFactory

七.HandlerAdapter具体执行流程2

  1. ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); 创建可执行的方法载体
  2. invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); 设置参数解析器
    1. 在RequestMappingHandlerAdapter的afterPropertiesSet方法赋值
  3. invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); 设置返回值处理器
    1. 在RequestMappingHandlerAdapter的afterPropertiesSet方法赋值
  4. invocableMethod.setDataBinderFactory(binderFactory); 设置绑定工厂 getDataBinderFactory(handlerMethod) 的返回值
  5. invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer) 设置参数名称发现器 new DefaultParameterNameDiscoverer()
  6. 创建ModelAndViewContainer 的对象,来保存Model和View对象
    1. Object view; 视图对象,object类型,可以是实际视图,也可以是string类型的逻辑视图
    2. ModelMap defaultModel; (BindingAwareModelMap) 默认使用的model对象
  7. 对ModelAndViewContainer中的属性进行赋值
    1. mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); 将flashmap中的数据设置到model中,redirect的时候参数传递 使用flashMap
    2. modelFactory.initModel(webRequest, mavContainer, invocableMethod) 初始化模型
      1. getModelFactory(handlerMethod, binderFactory) 方法的返回值,内含@ModelAttribute 注解修饰的方法
      2. this.sessionAttributesHandler.retrieveAttributes 获取SessionAttribute设置的属性值并且设置到modelAndView中
      3. invokeModelAttributeMethods(request, container) 执行@ModelAttribute并将结果设置到ModelAndView中
        1. ModelAttribute ann = modelMethod.getMethodAnnotation(ModelAttribute.class); 获取方法上的注解
        2. container.containsAttribute(ann.name()) 校验是否之前绑定过model
        3. doInvoke(args) 调用@ModelAndAttribute修饰的方法
        4. getNameForReturnValue(returnValue, modelMethod.getReturnType()) 获取model对应的key值
        5. container.addAttribute(returnValueName, returnValue); 将model对象设置到ModelAndView中 map(string, map) 结构
  8. invocableMethod.invokeAndHandle(webRequest, mavContainer) 执行方法的调用
    1. invokeForRequest(webRequest, mavContainer, providedArgs) 通过反射调用方法
    2. getMethodArgumentValues(request, mavContainer, providedArgs) 根据反射获取方法的参数
      1. this.resolvers.supportsParameter(parameter) 参数解析器中是否有支持该参数的
        1. resolver.supportsParameter(parameter) 判断resolver是否支持参数
        2. this.argumentResolverCache.put(parameter, resolver 将resolver放到缓存中
      2. this.resolvers.resolveArgument 解析参数
        1. HandlerMethodArgumentResolver result =this.argumentResolverCache.get(parameter) 从缓存中获取resolver
        2. resolver.resolveArgument 解析参数
          1. resolveName(resolvedName.toString(), nestedParameter, webRequest) 参数解析名称
          2. request.getParameterValues(name) 从请求中获取参数
        3. WebDataBinder binder = binderFactory.createBinder 获取绑定的binder
        4. binder.convertIfNecessary 利用binder进行参数的转换
          1. this.typeConverterDelegate.convertIfNecessary 类型的转换
    3. doInvoke(args) 具体的调用逻辑

八.第八课

  1. setResponseStatus(webRequest) 设置响应的状态码
    1. getResponseStatus() 获取方法上的状态码
    2. 创建HandlerMethod 是, HandlerMethod 的构造方法
      1. evaluateResponseStatus();
      2. annotation = AnnotatedElementUtils.findMergedAnnotation(getBeanType(), ResponseStatus.class); 获取方法上的@ResponseStatus 注解
    3. webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status) 进行响应状态码的设置
  2. handleReturnValue 处理返回值
    1. HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType) 选择返回值处理器
      1. handler.supportsReturnType(returnType) 处理器是否支持当前返回类型
      2. handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); 处理器处理返回内容
        1. ViewNameMethodReturnValueHandler 字符串对应的处理器
          1. mavContainer.setViewName(viewName); 给container设置viewName
  3. getModelAndView(mavContainer, modelFactory, webRequest); 获取视图和解析器
    1. modelFactory.updateModel 更新model(设置sessionAttributes和给model设置BindingResult)
      1. this.sessionAttributesHandler.storeAttributes(request, defaultModel) 将model中的内容设置到session中
      2. @SessionAttribute 表示向request作用域设值的时候也向session中设置一份
      3. image.png
      4. updateBindingResult(request, defaultModel); 参数加valided 自己试试 如果处理器绑定参数时注释了@Valid和@Validated注解,那么会讲校验的结果设置到BindingResult类型的参数中
    2. 如果mavContainer.isRequestHandled() 被处理过了,会直接返回null
      1. 一些返回值处理器会将此值设置为true mavContainer.setRequestHandled(true);
    3. new ModelAndView 创建ModelAndView (viewName, model, status)
      1. getModelMap().addAllAttributes(model); 设置attribute
    4. RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); 如果是redirect请求,设置flashAttributes
  4. applyDefaultViewName(processedRequest, mv) 当view为空时,根据request设置默认的view
    1. getDefaultViewName(request) 将请求路径当做默认的是viewName返回
      1. this.viewNameTranslator.getViewName(request) RequestToViewNameTranslator 获取默认的viewName,请求路径去掉前后’/’
      2. RequestToViewNameTranslator ===> DefaultRequestToViewNameTranslator 九大内置组件
    2. mv.setViewName(defaultViewName) 设置viewName

九.第九课

  1. RequestResponseBodyMethodProcessor # writeWithMessageConverters 将对象进行转换,并写入到响应中 @ResponseBody注解标注的内容不返回试图,直接将内容写入到响应中
    1. valueType = getReturnValueType(body, returnType) 获取返回value的类型
    2. Type targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass()) 获取泛型
      1. 使用位置AbstractMessageConverterMethodProcessor ## writeWithMessageConverters
    3. MediaType contentType = outputMessage.getHeaders().getContentType() 获取响应的头信息的MediaType
    4. getAcceptableMediaTypes(request) 从请求中获取可以接受的MediaType
      1. HeaderContentNegotiationStrategy # resolveMediaTypes
      2. request.getHeaderValues(HttpHeaders.ACCEPT) 获取request请求头中的accept属性
    5. getProducibleMediaTypes(request, valueType, targetType) 获取可能返回的MediaType
      1. this.allSupportedMediaTypes 所有的可能返回的MediaType 类型
      2. 遍历this.messageConverters 消息转换器
        1. result.addAll(converter.getSupportedMediaTypes()) 将匹配到的消息转换器支持的MediaType添加到结果中
    6. List mediaTypesToUse = new ArrayList<>() 可以使用的MediaType
    7. 如果requestedType.isCompatibleWith(producibleType) 如果可接受的MediaType和可能产生的MediaType一致,则添加到mediaTypesToUse中
      1. mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType))
    8. 遍历mediaTypesToUse集合,选择一个最匹配的,拿到selectedMediaType
    9. 遍历messageConverters数组
      1. converter.canWrite 调用converter的canWrite方法进行判断是否能够转换
    10. getAdvice() 获取ControllerAdvice 注解修饰并且实现ResponseBodyAdvice的bean
    11. getAdvice().beforeBodyWrite() 执行beforeBodyWrite方法
    12. processBody
    13. getMatchingAdvice(returnType, ResponseBodyAdvice.class) 获取ResponseBodyAdvice对应的bean
    14. advice.supports 是否支持
    15. ((ResponseBodyAdvice) advice).beforeBodyWrite 执行beforeBodyWrite方法
    16. genericConverter.write ===> AbstractJackson2HttpMessageConverter.write
    17. addDefaultHeaders(headers, t, contentType) 给响应头中加默认的content-type
    18. writeInternal
    19. ObjectWriter objectWriter 获取到objectWrite
    20. objectWriter.writeValue(generator, value) 将结果进行序列化
  2. WebMvcConfigurationSupport ## setMessageConverters ## HttpMessageConverter是做什么用的
  3. processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException) 处理返回结果,包括处理异常、渲染页面、触发Interceptor的afterCompletion
    1. render(mv, request, response) 渲染页面
      1. this.localeResolver.resolveLocale(request) 解析local对象
        1. response.setLocale(locale) 响应设置local
      2. resolveViewName(viewName, mv.getModelInternal(), locale, request) 解析viewName
        1. viewResolver.resolveViewName InternalResourceViewResolver 配置文件中配置的试图解析器
        2. createView(viewName, locale)
          1. return applyLifecycleMethods(REDIRECT_URL_PREFIX, view); 处理重定向视图
          2. return applyLifecycleMethods(FORWARD_URL_PREFIX, view); 处理转发视图
          3. super.createView(viewName, locale 创建视图名对应的 View 对象
          4. getViewClass() ==> org.springframework.web.servlet.view.JstlView View的class类型
          5. BeanUtils.instantiateClass(viewClass) 实例化view对象
          6. buildView ==> view.setUrl(getPrefix() + viewName + getSuffix())
          7. view.setContentType(contentType); … view设置各种属性值
      3. view.render(mv.getModelInternal(), request, response) 渲染
        1. renderMergedOutputModel 进行渲染
        2. rd.forward(request, response); 进行转发

十.第十课

  1. processDispatchResult 处理返回结果,包括处理异常
  2. processHandlerException 处理异常
  3. ModelAndView exMv 异常的试图
  4. HandlerExceptionResolver
    1. ExceptionHandlerExceptionResolver 这个处理器会寻找可处理的异常处理方法
    2. ResponseStatusExceptionResolver
    3. DefaultHandlerExceptionResolver
  5. ExceptionHandlerExceptionResolver
    1. resolver.resolveException 处理异常
    2. doResolveHandlerMethodException
      1. getExceptionHandlerMethod 获取异常处理的方法
      2. method = getMappedMethod(exceptionType) 获取匹配异常类型的方法
      3. this.mappedMethods.keySet() 被@ExceptionHandler注解标注的异常处理方法
      4. matches.sort(new ExceptionDepthComparator(exceptionType)) 将异常从小到大排序
    3. return ServletInvocableHandlerMethod(handlerMethod.getBean(), method) 返回可执行的异常处理方法
    4. exceptionHandlerMethod.invokeAndHandle
      1. invokeForRequest 执行方法
  6. ResponseStatusExceptionResolver
    1. AnnotatedElementUtils.findMergedAnnotation(ex.getClass(), ResponseStatus.class) 判断异常类上是否有@ResponseStatus 注解
    2. return resolveResponseStatus
    3. return new ModelAndView(); 返回空的modelAndView
  7. DefaultHandlerExceptionResolver

十一.第十一课

  1. servlet的异步处理
    1. 开启一个新的线程执行逻辑
    2. 采用长连接的方式,将响应给客户端后不会立马关闭请求,而是服务端将结果返回后再关闭连接
  2. AsyncWebRequest 异步请求对象
  3. WebAsyncManager ==> WebAsyncTask 核心处理类
  4. WebAsyncUtils 异步管理工具
  5. FrameworkServlet # processRequest
    1. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); 获取异步管理器
    2. asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor()); 注册拦截器
    3. RequestBindingInterceptor 将localContext和requestAttribute设置到请求中去,请求完毕后清空掉
  6. DispatcherServlet # doDispatch
    1. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    2. asyncManager.isConcurrentHandlingStarted() 如果需要异步处理直接返回
  7. RequestMappingHandlerAdapter # invokeHandlerMethod 处理controller注解的对应的执行器
    1. WebAsyncUtils.createAsyncWebRequest 创建异步请求对象
    2. asyncWebRequest.setTimeout(this.asyncRequestTimeout); 设置超时时间
// 创建AsyncWebRequest异步请求对象
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);

// 创建WebAsyncManager异步请求管理器对象
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
//设置执行器
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
//设置拦截器
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
// 如果当前异步请求已经处理并得到结果,则将返回的结果放到mavContainer对象中,然后将invocable对象进行包装转换,转成需要的执行对象然后开始执行
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 + "]";
    });
    // 转换具体的invocable执行对象
    invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
  1. asyncManager.isConcurrentHandlingStarted() return null 如果异步请求已经开始了返回null
  2. AsyncTaskMethodReturnValueHandler 异步任务返回值处理器
    1. WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(webAsyncTask, mavContainer) 启动异步任务
    2. startAsyncProcessing(processingContext) 异步启动
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值