HTTP请求处理流程-SpringMvc
1、在SpringMVC的http请求处理过程中,包括了前端控制器(DispatcherServlet)、处理映射器(HandlerMapping)、处理适配器(HandlerAdapter)、处理器((Handler)Controller)、视图解析器(ViewReslover)、视图(View)这六⼤主要对象。他们负责对http请求做处理,具体流程如下图。
第⼀步:前端控制器dispatcher接受请求
Client---url--->Dispatcher
第⼆步:前端控制器去发起handler映射查请求
Dispatcher---HttpServletRequest---> HandlerMapping
第三步:处理器映射器查hanlder并返回HandlerExetuionChain
Dispatcher <---HandlerExeutionChain---HandlerMapping
第四步:前端控制器发起请求处理器适配器请求执⾏
Dispatcher---Handler---> HandlerAdapter
第五步:处理器适配器去调⽤handler执⾏
HandlerAdapter---HttpServletRequest> Handler(Controller)
第六步:处理器处理后返回ModelAndView给HandlerAdapter
HandlerAdapter <---ModelAndView---Handler(Controller)
第七步:处理器适配器将ModelAndView返回给前端控制器
Dispatcher <---ModelAndView---HandlerAdapter
第⼋步:前端控制器请求视图解析器解析ModelAndView
Dispatcher---ModelAndView---> ViewReslover
第九步:视图解析器解析视图后返回视图View给前端控制器
Dispatcher <---View---ViewReslover
第⼗步:前端控制器请求视图要求渲染视图
Dispatcher--->View--->render
第⼗⼀步:前端控制器返回响应
Response <---Dispatcher
源码探秘
第⼀步接受请求:
我们可以来看看DispatcherServlet的继承结构
其实DispatcherServlet能处理请求是因为HttpServlet类的service⽅法,⽽HttpServlet⼜来⾃Servlet接⼝定义的规范。
可以看到抽象类HttpServlet实现了接⼝Servlet的service⽅法,根据请求类型不同执⾏了不同的⽅法(doGet,doPost)
当请进来后,由HttpServlet的⼦类FrameworkServlet重写的service⽅法执⾏请求,可以看到437⾏⼦类调⽤了⽗类的service⽅法,然后在⽗类执⾏doGet之类的⽅法时,由于⼦类FrameworkServlet重写了⽗类⽅法,交由⼦类执⾏,所以进到了我的doGet断点⾥⾯,它调⽤了处理请求⽅法。
接下来我们看看ProcessRequest⽅法的源码
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
LocaleContext previousLocaleContext = LocaleContext();
LocaleContext localeContext = this.buildLocaleContext(request);
RequestAttributes previousAttributes = RequestAttributes();
ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = AsyncManager(request);
isterCallableInterceptor(Name(), new FrameworkServlet.
RequestBindingInterceptor(null));
this.initContextHolders(request, localeContext, requestAttributes);
try {
this.doService(request, response);
} catch (IOException | ServletException var16) {
failureCause = var16;
throw var16;
} catch (Throwable var17) {
failureCause = var17;
throw new NestedServletException("Request processing failed", var17);
} finally {
if (requestAttributes != null) {
}
this.logResult(request, response, (Throwable)failureCause, asyncManager);
this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
}
}
前⾯⼀系列初始化⼯作我们先不管,看看重要的部分,try⾥⾯的doService⽅法
跟踪进去看了⼀下,由于它是抽象⽅法,所以会由⼦类实现和执⾏,也就是我们的DispatchServlet类了
⽼规矩,先贴上源码,它是DispatchServlet的doService⽅法----------------------------------------------------------
---------------------------------------------------- protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
this.logRequest(request);
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap();
Enumeration attrNames = AttributeNames();
label95:
while(true) {
String attrName;
do {
if (!attrNames.hasMoreElements()) {
break label95;
}
attrName = (Element();
} while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));
attributesSnapshot.put(attrName, Attribute(attrName));
}
}
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, WebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, ThemeSource());
if (this.flashMapManager != null) {
FlashMap inputFlashMap = ieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
}
try {
this.doDispatch(request, response);
} finally {
if (!AsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
}
}
}
所以第⼀步也就完成了,第⼀步的任务就是⾛进这⾥来。
第⼆步:前端控制器去发起handler映射查请求
Dispatcher---HttpServletRequest---> HandlerMapping
上⾯的源码中主要⼯作就是给request实例设置⼀系列参数,要注意的就是doDispatch⽅法,这⾥⾯就是mvc的核⼼了,前⾯第⼀张交互图⾥⾯的流程都是在这⾥实现的。
可以看到,通过HttpRequestServlet作为参数请求handlerMapping
第三步:处理器映射器查hanlder并返回HandlerExetuionChain
Dispatcher <---HandlerExeutionChain---HandlerMapping
可以看到上图中返回了mappedHandler变量,就是HandlerExtuceChain类型
可以看到,已经到并返回了我们的HomeController处理器(Hanlder)
第四步:前端控制器发起请求处理器适配器请求执⾏
Dispatcher---Handler---> HandlerAdapter
从508⾏可以看到,适配器传⼊handler对象和reaquest等信息,执⾏handler()⽅法
第五步:处理器适配器去调⽤handler执⾏
HandlerAdapter---HttpServletRequest> Handler(Controller)
从这⾥可以看到,调⽤的handlerInternal是个抽象⽅法,会调⽤⼦类的实现⽅法,⼦类由RequestMappingHandlerAdapter实现,这个类也是我们经常在xml⾥⾯配置的类
mvc实例通过invokeHandlerMethod⽅法执⾏进到controller⾥⾯
⽅法执⾏后返回我们的index
第六步:处理器处理后返回ModelAndView给HandlerAdapter
HandlerAdapter <---ModelAndView---Handler(Controller)
通过调⽤invokeHandlerMethod⽅法返回ModelAndView
第七步:处理器适配器将ModelAndView返回给前端控制器
Dispatcher <---ModelAndView---HandlerAdapter
第⼋步:前端控制器请求视图解析器解析ModelAndView
Dispatcher---ModelAndView---> ViewReslover
第九步:视图解析器解析视图后返回视图View给前端控制器
Dispatcher <---View---ViewReslover
可以看到,返回的视图,url指向index.jsp页⾯
第⼗步:前端控制器请求视图要求渲染视图
Dispatcher--->View--->render
如果View对象不为空,将会调⽤render⽅法渲染
如果返回的是json对象,属于接⼝的,是不会⾛这⾥的
此时会对应的视图解析器去渲染
⾥⾯其实也没⼲啥,就做了个跳转,到jsp页⾯去绑定数据
第⼗⼀步:前端控制器返回响应
Response <---Dispatcher
到这⾥也就基本上完了。
处理请求完成后做了个重置⼯作,然后发布⼀个事件,你可以选择监听这个事件,做相应处理。再看看response⾥⾯
这个就是我们页⾯上的内容了。