一.servlet及web.xml方式启动springMVC
1.servletContextListener servletContext初始化后,会传递进servletContextListener用于servlet和filter的初始及销毁的通知,并通过init
2.ContextLoaderListener( is a ContextLoader and is a servletContextListener) 通过servletContextListener的初始通知方法获取ServletContext,并 通过ContextLoader 的initWebApplicationContext方法构建WebApplicationContext,如果上下文是ConfigurableWebApplicationContext 则通过 ContextLoader.configureAndRefreshWebApplicationContext方法获取web.xml里面的context-param标签中contextConfigLocation的值(也就是我们配置的spring容器初始化时需要读取的xml的路径)配置进上下文,再通过ApplicationContextInitiallizer对上下文进行初始化处理后,调用上下文的刷新方法,最后将WebApplicationContext设置进ServletContext
3.DispatchServlet 通过DispatchServleAutoConfiguration的Bean标签注入到上下文中, WebMvcProperties对应spring.mvc开头的yaml中的属性配置,HttpProperties对应spring.http开头的yaml中的属性配置通过@EnableConfigurationProperties注入到DispatchServleAutoConfiguration中的属性中,并赋值给DispatchServlet
4.WebMvcAutoConfiguration 是springboot用于整合MVC配置的配置类,WebMvcConfigurationSupport是SpringMVC的配置类配置了RequestMappingHandlerAdapter 及 RequestMappingHandlerMapping。RequestMappingHandlerAdapter 会被设置上MessageConverters。MessageConverters 根据WebMvcConfigurationSupport的静态加载属性判断添加什么类型的MessageConverter, 静态加载属性jackson2Present对应的是MappingJackson2HttpMessageConverter,该属性为true的判断条件是com.fasterxml.jackson.databind.ObjectMapper ,com.fasterxml.jackson.core.JsonGenerator 这两个类当前能被加载,WebMvcProerties读取了配置文件中前缀为spring.mvc的配置,InternalResourceViewResolver这个视图解析器读取了其中的视图前后缀路径的属性值
5.DispatcherServletRegistrationBean 继承 ServletRegistrationBean 封装了DispatchServlet,获取springboot 创建服务器时,ServletWebServerFactory的实例,依赖DispatcherServletRegistrationBean,DispatcherServletRegistrationBean.addRegistration方法中DispatcherServlet被添加进ServletContext
二.springBoot的启动方式
1.在ApplicationContext的refresh方法中调用onRefresh方法,通过getSelfInitializer方法生成ServletContextInitializer(获取容器中所有的ServletContextInitializer的实现Bean,同时执行这些Bean的OnStartUp方法,其中获取ServletRegistrationBean时会实例化DispatcherServlet的实例),之后通过新建的WebServer(一般是TomcatWebServer)的initialize方法中的Tomcat的start方法开启新线程运行所有之前生成的ServletContextInitializer的onStart方法,
三.与客户端回话
1.RequestMappingHandlerMapping(is a InitializingBean )负责解析@RequestMapping及@Controller标注的类的方法及注释的信息,将解析后的@RequestMapping信息封装成 RequestMappingInfo,将handler(Controller类的BeanName或者实例)及对应的Method封装成HandlerMethod 存放在AbstractHandlerMethodMapping.MappingRegistry这个内部类的mappingLookup这个Map中,RequestMappingInfo当key,HandlerMethod当value(在父类AbstractHandlerMethodMapping的afterPropertiesSet方法中实现)。
2.请求进来时,根据其访问的url和RequestMappingHandlerMapping找到相应的HandlerMethod同时实例化HandlerMethod封装的Handler(Controller)实例,并找到对应url的拦截器,并封装成Handler执行链(HandlerExecutionChain),用于执行该次url访问所涉及的拦截器方法和拦截器链策略。(注册拦截器时,如果没有设置任何拦截路径默认是全部拦截,则是直接用自己实现的拦截器对象,如果设置了路径则使用MappedInterceptor对象(装饰者模式,封装了自己实现的拦截器对象)),HandlerInterceptor接口3个方法是default,其中pre默认返回true,WebRequestInterceptor也是一种类型的拦截器接口但是3个方法都是抽象的,多个拦截器时的post和after方法是逆序执行的。
3.根据HandlerMapping找到对应的handler(是个处理器的概念,一般是HandlerMethod类型的handler)根据handler的类型找到对应的HandlerAdapter(如果是HandlerMethod则找到的是RequestMappingHandlerAdapter,HandlerMethodReturnValueHandlerComposite,HandlerMethodArgumentResolverComposite,HttpMessageConverter是他的成员变量,这3个成员变量在WebMvcConfigurationSupport(@Bean的方式配置)中被配置到RequestMappingHandlerAdapter中)
4.执行HandlerExecutionChain的applyPreHandle方法启动拦截器的前置方法链
5.执行HandlerAdapter的handle方法并返回一个ModelAndView的对象(执行方法返回值为void或者有@ResponseBody标签时返回null):主要是执行了Controller中对应的方法
HandlerAdapter.handle(AbstractHandlerMethodAdapter 重写)
—>
RequestMappingHandlerAdapter .handleInternal()
–>
RequestMappingHandlerAdapter .invokeHandlerMethod()
–>
RequestMappingHandlerAdapter .createInvocableHandlerMethod:创建ServletInvocableHandlerMethod来执行2中封装的HandlerMethod的Handler的相关方法
–>
ServletInvocableHandlerMethod.invokeAndHandle():
ServletInvocableHandlerMethod.invokeForRequest():
ServletInvocableHandlerMethod. getMethodArgumentValues
1.获取该Controller的对应方法的参数对象
2.根据该参数信息找到对应的ArgumentResolver(享元模式,第一次根据参数找到后,放入缓存,key是MethodParameter,value是对应的ArgumentResolver,查找的方法是根据该方法上的@requestParam @requestBoby,路径参数,@requestPart等注解或者参数类型等选择对应的ArgumentResolver 如有@requestParam 则选择RequestParamMethodArgumentResolver)
3.用ArgumentResolver解析request中的入参数信息并与方法的参数信息,并返回执行方法所需要的参数值(一种方式是,根据方法的参数名,用request.getParameterValues(参数名)来获取前端传入到该方法参数的值)。
InvocableHandlerMethod. doInvoke(返回的参数) (ServletInvocableHandlerMethod是其实现类)
执行controller的方法并返回相应的结果对象
HandlerMethodReturnValueHandlerComposite.handleReturnValue():
1.根据返回值的类型,执行方法上的标签,执行对象类上的标签等信息,找到合适的HandlerMethodReturnValueHandler(如标记了@ResponseBody及其继承注解的方法和标记了@ResponseBody及其继承注解如@RestController的类,对应的ReturnValueHandler 是 RequestResponseBodyMethodProcessor)
2.执行选中的HandlerMethodReturnValueHandler的handleReturnValue方法:
选择合适的HttpMessageConverter(HandlerMethodReturnValueHandler的HttpMessageConverter成员变量指向HandlerAdapter中的HttpMessageConverters)来转化对应的返回值(如是@ResponseBody同时返回的是对象则会选择MappingJackson2HttpMessageConverter来将对象转换为JSON,如果是@ResponseBody同时返回的是String则会返回StringHttpMessageConverter处理,这两种都会直接将处理后的返回值传递给前端)
6.执行HandlerExecutionChain的applyPostHandle方法启动拦截器的后置方法链
7.根据返回的ModelAndView 对象找到对应的ViewResolver来解析ModelAndView获取View对象,再通过View.render来整合相关的Model值,并在整合完成后转发请求至相应的视图资源路径,将相应的视图资源传递给前台(少数情况下也会不转发,直接返回,如内置的404错误页面)
8.执行HandlerExecutionChain的triggerAfterCompletion启动方法拦截器的完成通知方法
三.主要的接口
3.1 ViewResolver
实现类:
1.InternalResourceView(extends UrlBasedViewResolver) 根据viewName转发请求(转发是一样的请求与响应对象,其中请求对象会被封装一层封装的是原请求对象(RequestFacade实例))到对应的资源url, 会通过RequestFacade.getRequestDispatcher(viewname)获取RequestDispatcher对象进行请求转发,如果prefix+viewName+suffix中不不包含"/“则转发路径为请求路径最后一个/之前的路径(如 abc/a 则取abc/)+prefix+viewname+suffix ,如果包含“/”则转发路径为StandardContext的根路径(path变量的值一般是”/")+prefix+viewname+suffix