客户端发起一个http请求,到springboot响应结果。
首先我们对结果做一个合理的猜测,然后debug简单验证下
猜测
1、web容器接到请求,分给线程去处理
2、根据HttpRequest匹配调用的指定方法M
3、反射执行M得到执行结果R
4、HttpReponse write flush 完成请求
debug思路(非常个人)
搭建springboot工程
编写一个controller类,创建一个get请求的方法,直接返回hello qfu, good luck!的字符串
在自己编写方法内部打个debug,浏览器执行,进入debug,查看debugger堆栈
根据堆栈找寻请求的起始点,然后一直debug到接口返回结果就可以了
验证
1、浏览器上调用url, ThreadPoolExecutor.runWorker(Worker w) 这边的逻辑为将接受的任务worker分配给任务线程执行(验证通过)
2、是如何根据url定位到具体的方法的呢,DispatcherServlet.doDispatch(HttpServletRequest request, HttpServletResponse response) 看这个类名方法名就大概可以猜到跟调度相关,我们debug看下实现,该方法中调用getHandler(HttpServletRequest request),这个方法便是关键
RequestMappingHandlerMaping也是很熟悉的,用脚趾头想也是跟我们天天写的某些注解有关联的(@RequestMaping,@GetMaping....)
让我们看下里边有啥:
BINGO!!
这下我们可以得出结论了,在启动springboot工程的时候,根据我们标注的注解将url跟方法的对应关系注册到map集合里,在收到请求时,拿到HttpRequest中的url去map集合中再把对应的方法信息取出来 (验证通过)
3、感觉第三步已经不需要验证了,都拿到反射所需要的一切了,但我们还是跟着DEBUG看一下吧 ServletInvocableHandlerMethod.invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) 中获取ServletInvocableHandlerMethod的实例 invocableMethod,
invocableMethod.invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs);
然后 invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs)
上边执行时,断点到我们自己的方法内部了
(验证完成)
4、响应数据到客户端我们平常估计也经常用到,无非就是write flush ,但是在哪呢,不急,debug到最后一定会有的
AbstractHttpMessageConverter.write(final T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
在前边一步会有一个选择HttpMessageConverter的过程,我们此处不纠结了
看到这里,感觉离我们想要看到的代码不远了,
(验证完成)
总结
整个过程比预想时间长一点,午休泡汤了
总之,只是一次简单的验证,不写下来的话验证过程不会花多少时间,只是要带着问题,同时要有自己的理解,实际过程其实要复杂的多,各种拦截器什么时候注册,什么时候发挥作用,jaskson的各种转换器什么时候注册,什么时候发挥作用,我们如何可以自定义或者直接在原先的基础上进行改造以符合我们的需求。