分析思路:
肯定是3层Servlet如何处理以及每层具体做了什么,最后分析最重要的一个方法doDispatch
回顾一下Servlet的请求处理过程 在HttpServlet中的service方法根据不同的动作分发了不同7种的请求
HttpServletBean
作用主要参加了创建工作,并没有涉及到请求的处理 这一步它没有具体处理请求
FrameworkServlet
在该类中重写了service doXXX(除了doHead外的所有方法)
并且在service方法中增加了PATCH类型的处理 其他请求默认给父类处理
而doGet doPost doDelete doPut都是自己处理 所有自己需要处理的请求都交给了processRequest方法统一处理
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if (RequestMethod.PATCH.name().equalsIgnoreCase(request.getMethod())) {
processRequest(request, response);
}
else {
super.service(request, response);
}
}
我们发现HttpServlet是按不同请求类型路由到不同的方法处理 而这里相反
它采用另外一种方式处理将不同类型的请求处理用不同的Handler处理 这里后面再讲
思考???为何还不在service中覆盖service
下来分析processRequest方法
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
initContextHolders(request, localeContext, requestAttributes);
//这里省略了异常的捕获
try{
doService(request, response);
}
finally {
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
if (logger.isDebugEnabled()) {
if (failureCause != null) {
this.logger.debug("Could not complete request", failureCause);
}
else {
if (asyncManager.isConcurrentHandlingStarted()) {
logger.debug("Leaving response open for concurrent processing");
}
else {
this.logger.debug("Successfully completed request");
}
}
}
publishRequestHandledEvent(request, startTime, failureCause);
}
}
我们总结一下在service中添加了对PATCH的处理,并将所有需要自己处理的请求集中到了processRequest方法进行统一处理
然后就是processRequest交给了doService处理 另外是对使用当前request获取到的LocaleContext和RequestAttributes进行了保存,以及处理完之后的恢复,在最后发布了ServletRequestHandlerEvent事件
我们这事来分析doService
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
//这里将日志省略
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
//当include请求满足对request的Attribute做快照备份
Map attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap();
Enumeration> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
//对request限制一些属性
// Make framework objects available to handlers and view objects.
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(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 {
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.//还原request的快照
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
但是简单的比如它是调用doDispatch
而在调用doDispatch前做了一些事情
首先判断是不是include请求 如果是则对request的Attribute做个快照备份 等doDispatch之后(如果不是异步请求且未完成)进行还原
在做完之后对request设置一些属性
具体设置了什么呢
// Make framework objects available to handlers and view objects.
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
设置了4个属性webApplicationContext ,localeResolver,themeResolver,themeSource在之后介绍的handler和view中需要使用到时候在分析
后3个属性和flashMap相关,主要用于Redirect转发时参数的传递 这里我没看懂
关于flashMap的使用我后面再更新 现在还不太会
整理一下 doService对request设置了一些属性 如果是include请求还要对request当前的属性做快照备份 并在处理结束后恢复 最后把请求给了doDispatch
再来看doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest, false);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(request, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
是不是有点长啊 看着费力气
我们抓住重要的看 看核心语句
mappedHandler = getHandler(processedRequest, false);
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
1.根据request找到Handler
2.根据Handler找到相应的HandlerAdapter
3.用HandlerAdapter处理Handler
4.调用processDispatchResult方法处理上面处理之后的结果(包括找到View并渲染输出给用户)
关于HandlerMapping,Handler,HandlerAdapter区别
后面再细讲啊
通俗一点理解
Handler是用来干活的工具 HandlerMapping是根据干的活找相应的工具 HandlerAdapter是使用工具干活的人
在SpringMVC中的9大组件HandlerAdapter最复杂
除此之外viewResolver是根据 需要查找view的 view是展示数据的
现在就很好理解他们的逻辑了
根据HandlerMapping找到干活的Handler 找到使用Handler的HandlerAdapter 让个HandlerAdapter使用Handler干活 干完活后将结果提交上去(通过view展示给用户)
然后在回到doDispatch分析还是很复杂
doDispatch可以大体分两部分 处理请求渲染页面
先看它定义的变量
此处省略1万字 太难了 ....................分析不了 以后再说
我们可以看到它是在顶层设计好分配给不同的组件去实现的
这篇文章只是提供了处理请求的大概思路具体的后续再更新
欢迎关注我的个人订阅号,我会推送更好的文章给大家