最近本人在找工作,作为一个java菜狗,两次面试面试官都问到了我SpringMVC 的执行流程,我三下五除二简单了说了一下。事实上对这个已经很模糊了。 于是本人回来之后打开了IDE看了下org.springframework.web.servlet.DispatcherServlet的源码。
众所周知,客户端发送的Http请求都会走**doService()方法,因此我看了看。主要是调用doDispatch()**方法
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 检查请求类型
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 寻找是否有请求对应的handler,没有返回404
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 根据handler找到对应的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
其实以上代码就是整个MVC请求接口最核心的代码。 如果想深入细节建议先了解责任链模式,不然会一头雾水。 其实流程并不复杂,主要是在阅读的过程中引发了自己的一点思考,也算是对基础的回顾吧。
主要是以下两个问题:
1.springMVC的handler/handlerMapping/handlerAdapter是什么时候存在于服务中的?
2.springMVC为什么是线程不安全的?
针对第一个问题,其实是很基础的一个问题,我们在学习servlet的时候知道有三个核心方法:init()/doService()/destroy().
init()方法会在容器启动的时候执行,并且只会执行一次,看DispatcherServlet的源码可知它的结构是这样的:
然后第二个问题,其实很简单因为在容器启动的时侯通过扫描@RestController注解将他注入到spring容器中,默认是单例的。只要是单例就会涉及线程安全的问题,假若我们在controller中存在一个静态字段,那么如果使用原子容器或者ThreadLocal那么就会涉及线程 安全问题。
其实这本来都是很简单的问题,但是却引发了我对spring的设计的理解加深。spring大量的单例模式的运用其实通过面向对象的思维来理解是很精妙的,并且在客户端与服务端的交互中性能的确会好很多。其实还引发了一切其他的思考,例如容器上下文ApplicationContext等等,暂时先放放。