前言
在分析问题前,先看下Tomcat的架构图,有助于后面看代码:
这里可以看出一个Tomcat就是一个Server,一个Server下会有多个Service,Service只负责封装多个Connector和一个Container(Service本身不是容器,可以看做只是用来包装Connector和Container的壳,不负责具体功能),而Container(也叫engine)下又有多个Host,每个Host下对应多个Context,Context下才是我们的Servlet,Tomcat为了使整个架构灵活,所以抽象出这么多层,每层之间都可以根据不同的维度产生一对多个配置。
源码分析
DispatcherServlet用来处理请求的主要流程图如下:
结合流程图看下代码:
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.
// 1、遍历已经配置的HandlerMapping列表,调用HandlerMapping的getHandler方法,获取当前Request对象所对应的处理链HandlerExecutionChain,HandlerExecutionChain对象封装了处理这个Request的所有Interceptor及这个处理这个Request的HandlerMethod对象
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 2、根据1步中的HandlerMethod获取对应的HandleAdapter
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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 3、开始逐个调用第28步中获取的调用链中的interceptor的PreHandle方法,如果需要拦截,则流程被拦截,直接返回
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
// 4、调用第29步中的HandlerAdapter的handle方法处理请求,这里会去请求Controller里的接口,Controller里的方法已经被包装成HandleMethod对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 逐个调用拦截器的postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 处理modelAndView对象,解析视图,比如html、jsp对象等
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", 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);
}
}
}
}
根据流程图 这里出现了几个重要的类HandlerMapping、HandlerExecutionChain、HandlerMethod、HandlerAdapter、HandlerMethodReturnValueHandler,解释下这几个类:
HandlerMapping:该类提供了通过request匹配到对应HandlerExecutionChain的能力,可以理解为一个映射类
HandlerExecutionChain:封装了用来处理请求的调用链,包括所有的拦截器以及用来处理请求的Handler,这里就是封装了Controller方法信息的HandlerMethod
HandlerMethod:封装了用来处理请求的类及方法的元数据信息,包括类、方法以及是spring管理的哪个bean(这里可以理解成是spring管理的那个controller对象)
HandlerAdapter:Handler的适配器,在调用Controller方法场景下,这里的Handler就是HandlerMethod,这个接口的方法有三个:
public interface HandlerAdapter {
// 判断当前HandlerAdapter是否支持handler,比如Controller场景下的,这个handler就是HandlerMethod对象
boolean supports(Object handler);
// 处理请求
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
long getLastModified(HttpServletRequest request, Object handler);
}
HandlerMethodReturnValueHandler:处理返回结果,Controller场景下就是处理 Controller里接口返回结果的
比如我有个Controller,代码如下:
@RestController
@RequestMapping("/api")
public class HelloController {
@RequestMapping("/hello")
public String hello() {
return "hello2";
}
}
我们看下在我请求这个接口,这几个重要步骤是怎么处理的:
第一步、getHandler()
debug图:
这个Controller里的接口已经被解析并保存在这个mapping中,debug截图如下:
在构建这个调用链时,会包含我们的拦截器:
第二步、getHandlerAdapter(handler)
debug图:
第三步、执行调用链中interceptor的PreHandle方法
第四步、adapter的handleInternal方法
这个截图可以看到我们的Controller方法已经被封装成HandlerMethod对象,包含bean、method等信息
第五步、HandlerMethodReturnValueHandler处理返回结果
这里可以看到有很多HandlerMethodReturnValueHandler
,通过HandlerMethodReturnValueHandler.supportsReturnType()
来匹配,我们这里返回的是RequestResponseBodyMethodProcessor对象,通过代码可以看出如果方法被@ResponseBody注解注释,那么就使用这个类来处理返回值。
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}
// 处理返回值
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
// 设置requestHandled为true,表示请求已经处理完毕,后续不需要再做处理,比如解析view视图等逻辑
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// Try even with null return value. ResponseBodyAdvice could get involved.
// 调用ResponseBodyAdvice来处理返回值,并将最终结果写到response的输出流中
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
第六步、解析modelAndView对象
由于这里没有返回视图对象,所以没有做处理,如果你接口里需要返回一个html或者jsp,那么就是这个地方来解析你的View对象
最后贴一张tomcat处理请求的完整流程图: