
SpringBoot底层还是通过SpringMVC来解析请求的,SpringMvc中最核心的东西就是DispatcherServlet,Springboot启动过程中会先启动tomcat,然后创建DispatcherServlet,去调用里面的init方法
,会创建一个Spring容器,并且添加一个ContextRefreshListener监听器,该监听器会监听ContextRefreshedEvent事件(Spring容器启动完成后就会发布这个事件),也就是说Spring容器启动完成后,就会执行ContextRefreshListener中的onApplicationEvent()方法,从而最终会执行DispatcherServlet中的initStrategies()。
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
//HandlerMapping和适配器
initHandlerMappings(context);
/适配器就相当于一个接口有多个继承类,在继承类里面重写自己的逻辑,方便做扩展,比如自己去重定义HandlerMapping
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
其中最为核心的就是HandlerMapping和HandlerAdapter。
Handler(Handler表示请求处理器,在SpringMVC中有四种Handler):
1.实现了Controller接口的Bean对象
2.实现了HttpRequestHandler接口的Bean对象
3.添加了@RequestMapping注解的方法
4.一个HandlerFunction对象
最常见的也是第三种,在Controller层上面去添加RequestMapping方法,添加路径,定位到业务方法中
HandlerMapping(HandlerMapping负责去寻找Handler,并且保存路径和Handler之间的映射关系)
1.RequestMappingHandlerMapping:负责@RequestMapping的方法(只找一种,剩下几种不常用,就不写了)
RequestMappingHandlerMapping寻找HandlerMapping的流程
1.找出Spring容器中所有beanType
2.判断beanType是不是有@Controller注解,或者是不是有@RequestMapping注解
3.判断成功则继续找beanType中加了@RequestMapping的Method
4.并解析@RequestMapping中的内容,比如method、path,封装为一个RequestMappingInfo对象
5.最后把RequestMappingInfo对象做为key,Method对象封装为HandlerMethod对象后作为value,存入registry中
6.registry就是一个Map
RequestMappingHandlerMapping的 父类AbstractHandlerMapping
AbstractHandlerMapping会负责调用子类的getHandlerInternal(HttpServletRequest request)方法从而找到请求对应的Handler,然后AbstractHandlerMapping负责将Handler和应用中所配置的HandlerInterceptor整合成为一个HandlerExecutionChain对象。
选择哪个HandlerMapping?
当DispatcherServlet接受到请求的时候,会遍历所有的HandlerMapping,找到第一个(前面都说了有多个HandlerMapping,只是这边只写了一个,BeanNameUrlHandlerMapping这个的优先级是最高的)然后去寻找对应的Handler
HandlerAdapter(适配器模式)
1.添加了@RequestMapping注解的方法,具体为一个HandlerMethod,执行的就是当前加了注解的方法
2.因为有多种HandlerMapping,如果没有这种适配器模式的话,你就得写很多的if elseif elseif(什么什么Handler)来实现他的逻辑方法,所以搞了这个东西,相当于一个接口有多种实现类,在自己的实现类里面写自己的逻辑
public boolean supports(Object handler) {
return (handler instanceof HttpRequestHandler);
}
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
public boolean supports(Object handler) {
return handler instanceof HandlerFunction;
}
谁支持就适配谁,然后调用对应的handle方法
SpringMvc的解析逻辑
1.RequestParamMethodArgumentResolver:负责处理@RequestParam
2.RequestHeaderMethodArgumentResolver:负责处理@RequestHeader
3.SessionAttributeMethodArgumentResolver:负责处理@SessionAttribute
4.RequestAttributeMethodArgumentResolver:负责处理@RequestAttribute
5.RequestResponseBodyMethodProcessor:负责处理@RequestBody
6.。。。。还有很多这样的注解
而在判断某个参数该由哪个HandlerMethodArgumentResolver处理时,也是很粗暴
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
//就是遍历所有的HandlerMethodArgumentResolver,哪个能支持处理当前这个参数就由哪个处理。
if (resolver.supportsParameter(parameter)) {
result = resolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
@RequestMapping方法返回值解析
而方法返回值,也会分为不同的情况。比如有没有加@ResponseBody注解,如果方法返回一个String:
1.加了@ResponseBody注解:表示直接将这个String返回给浏览器
2.没有加@ResponseBody注解:表示应该根据这个String找到对应的页面,把页面返回给浏览器
在SpringMVC中,会利用HandlerMethodReturnValueHandler来处理返回值:
1.RequestResponseBodyMethodProcessor:处理加了@ResponseBody注解的情况
2.ViewNameMethodReturnValueHandler:处理没有加@ResponseBody注解并且返回值类型为String的情况
3.ModelMethodProcessor:处理返回值是Model类型的情况
4.还有很多其他的...
RequestResponseBodyMethodProcessor 相当于会把方法返回的对象直接响应给浏览器 ,如果返回的是一个字符串,那么好说,直接把字符串响应给浏览器,那如果返回的是一个Map呢?是一个User对象呢?该怎么把这些复杂对象响应给浏览器呢?
处理这块,SpringMVC会利用HttpMessageConverter来处理,比如默认情况下,SpringMVC会有4个HttpMessageConverter:
1.ByteArrayHttpMessageConverter:处理返回值为字节数组的情况,把字节数组返回给浏览器
2.StringHttpMessageConverter:处理返回值为字符串的情况,把字符串按指定的编码序列号后返回给浏览器
3.SourceHttpMessageConverter:处理返回值为XML对象的情况,比如把DOMSource对象返回给浏览器
4.AllEncompassingFormHttpMessageConverter:处理返回值为MultiValueMap对象的情况