源码分析
# 源码分析
# @SpringBootApplication
@SpringBootConfiguration:底层实际上是一个@Configuration
@ComponentScan:包扫描
@EnableAutoConfiguration:根据每个包下面的metaInfo自动导入自动配置类=>个别配置类注解了条件生效条件,满足IOC中存在某个Bean才生效=>给容器中装配组件。
使用@condition注解实现给bean对象修改id
用户若要使用自己的配置,则直接@Bean重新配置一个方法替换底层组件=>然后查看这个组件的配置类xxxProperties(EnableConfigurationProperties可以看到),根据配置类的prefix+类属性名修改
# @RestController
SpringMVC 默认实现了HiddenHttpMethodFilter来支持RestFul风格,SpringBoot使用时首先需要在yaml中开启filter功能(默认不开启),然后在前端form表单input添加一个隐藏变量name="_method",然后填写真正的请求方式value="delete"
spring: mvc: hiddenmethod: filter: enabled: true ------------------ <form method="post"> <input type="hidden" name="_method" value="delete">1
2
3
4
5
6
7
8表单发送请求(只有表单请求才会转换)流程:被过滤器拦截—>检查是否是post方式—>获取_method值,然后重新包装一个RequestWrapper对象(实现了HttpServletRequest接口),传入_method重写了getMethod方法,包装模式—>过滤器放行这个新的HttpServletRequest(wrapper)。
请求映射原理
handleMapping(RequestMapping,WelcomeMapping...),遍历每个handleMapping看哪个能处理(根据里面的一个配置中心,里面保存我们写过的映射规则)。
DispatcherServlet.doDistpatch:初始化各种参数—>从handleMappings中getHandler找能处理的映射—>然后找对应的处理方法,先根据request方法的url路径找,再根据method找,最终找到一个对应的处理方法(handler)。
# 请求参数处理
找到handle后,找到对应的handleAdapter适配器——>执行目标方法(使用参数解析器确定要执行的目标方法每一个参数是什么—>反射doinvoke调用处理方法)
- 参数解析器:遍历所有参数解析器,找到支持解析该参数的参数解析器(实际上就是看是不是标了对应的注解),把对应参数和解析器丢到缓存中,然后开始解析。
- 参数解析过程:根据参数名,调用servlet一些原生的方法,比如request.getAttribute
- 具体参数类型分析:
- model:model的addAttribute最终相当于底层request.setAttribute往请求域中放数据。
- VIew:视图名
# 视图解析
render(mv)页面渲染:
首先根据View的名字,遍历所有view解析器,看哪一个解析器能根据当前返回值得到View对象
forward开头,则底层调用response.getRequestDispatcher转发
redirect开头,render底层就是重定向,new RedirectView()
普通字符串开头,则返回new ThymeleafView()
然后调用这个视图对象View自己定义的render进行页面渲染(底层原生servlet方法)。
# 拦截器
根据当前请求找到handlerExecutionChain处理器执行链,其中这个处理器请求链对象包含①handler对象,里面指明了由哪个方法处理当前请求②InterceptorList拦截器链包含所有拦截器
mappedHandler = getHandler(processedRequest);1
根据handler获取目标方法的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());1在通过handler适配器调用执行handler方法(controller方法)之前,会执行拦截器调用applyPreHandle方法,如果返回false,则直接跳出doDIspatcher方法,后面的handler不执行。
- applyPreHandle:先遍历所有拦截器,顺序执行prehandler,返回true放行,则继续执行下一个拦截器的prehandler方法;如果prehandler返回false,则直接触发执行triggerAfterCompletion的方法,执行完后返回false。
- afterCompletion:从当前没有放行的拦截器开始,倒序(i--)执行所有已经执行prehandler拦截器的afterComletion方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) return;1
2所有拦截器的prehandler方法都正常放行,ha.handler处理器方法执行完之后,调用applyPostHandle**倒序执行所有拦截器postHandler**方法(遍历拦截器列表i--),若有某个拦截器不放行,则处理规则同上。
mappedHandler.applyPostHandle(processedRequest, response, mv);1执行render渲染完页面后,触发执行triggerAfterCompletion。
整个流程如下:
