SpringMVC源码系列文章
SpringMVC源码剖析(一):web容器启动流程
SpringMVC源码剖析(二):哀求执行流程
前言
前文中我们介绍了SpringMVC容器的启动,包括前端控制器DispatcherServlet对象的创建,过滤器添加到Tomcat容器的过滤器集合中,将全部拦截器、跨域设置、消息转换器等设置统一添加到各自集合中,剖析@RequestMapping注解生成哀求路径和Controller方法的映射map。本章来研究下哀求的执行过程。
说到哀求过程,那么得先说下入口在哪里?入口肯定是统一分发哀求给处置惩罚程序的DispatcherServlet,DispatcherServlet归根结底也是Servlet。Tomcat通过哀求Mapping映射和Servelt对应关系找到Servelt,调用Servelt之前会执行过滤器链,全部过滤器放行才会走到Servelt真正的执行逻辑。
- // 接受User对象并返回
- @PostMapping("/test")
- @ResponseBody
- public User test(@RequestBody User user) {
- user.setName("李四");
- System.out.println(user);
- return user;
- }
复制代码
- HttpServelt#service分水岭doPost方法,只要找到DispatcherServelt重写的doPost方法就是入口了
本文就不讲过滤器的调用了,因为从DispatcherServelt开始,过滤器链已经执行完成,之前文章Tomcat源码剖析(八):一个哀求的执行流程(附Tomcat整体总结)有介绍过。
DispatcherServlet入口
DispatcherServlet的类图如下:
从doPost到doDispatch方法
- doPost方法是由DispatcherServelt的父类FrameworkServlet实现的
- 岂论post还是get哀求都是调用同一个方法processRequest(request, response)
- 对于方法参数request和respons都是Tomcat容器创建的,以前文章Tomcat源码剖析(七):底层怎样获取哀求url、哀求头、json数据?有详细介绍
- 主要方法doService(request, response)
- // FrameworkServlet类方法
- protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- long startTime = System.currentTimeMillis();
- Throwable failureCause = null;
- ...
- try {
- doService(request, response);
- }
- catch (ServletException | IOException ex) {
- failureCause = ex;
- throw ex;
- }
- catch (Throwable ex) {
- failureCause = ex;
- throw new NestedServletException("Request processing failed", ex);
- }
- finally {
- ...
- }
- }
复制代码
- 主要方法doDispatch(request, response)
- // DispatcherServlet类方法
- @Override
- protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
- // ... 设置一堆Attribute属性
- try {
- doDispatch(request, response);
- }
- finally {
- ...
- }
- }
复制代码 核心方法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);
- // 如果是上传请求,这个参数置为true,最后会去清理资源
- multipartRequestParsed = (processedRequest != request);
- // 获取HandlerExcutionChain (内部包括Handler)
- mappedHandler = getHandler(processedRequest);
- if (mappedHandler == null) {
- // 请求url找不到404就会走到这里
- noHandlerFound(processedRequest, response);
- return;
- }
- // 获取适配器
- HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
- // get请求缓存相关,以后有机会单独将
- String method = request.getMethod();
- boolean isGet = HttpMethod.GET.matches(method);
- if (isGet || HttpMethod.HEAD.matches(method)) {
- long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
- if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
- return;
- }
- }
-
- // 调用拦截器的前置方法preHandle
- if (!mappedHandler.applyPreHandle(processedRequest, response)) {
- return;
- }
- // 执行handler方法
- // 需要跳转页面这里才会返回ModelAndView对象,否则@ResponseBody返回对象这里返回null
- 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) {
- //从4.3开始,我们也在处理处理程序方法抛出的错误,
- //使它们可用于@ExceptionHandler方法和其他场景。
- dispatchException = new NestedServletException("Handler dispatch failed", err);
- }
- // 处理结果
- processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
- }
- catch (Exception ex) {
- // 调用拦截器请求处理完成后的回调triggerAfterCompletion
- triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
- }
- catch (Throwable err) {
- // 调用拦截器请求处理完成后的回调triggerAfterCompletion
- triggerAfterCompletion(processedRequest, response, mappedHandler,
- new NestedServletException("Handler processing failed", err));
- }
- finally {
- if (asyncManager.isConcurrentHandlingStarted()) {
- // 异步处理的回调
- if (mappedHandler != null) {
- mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
- }
- }
- else {
- // 如果是上传请求,清理相关资源
- if (multipartRequestParsed) {
- cleanupMultipart(processedRequest);
- }
- }
- }
- }
复制代码 一、获取HandlerExcutionChain(包括Handler)
遍历全部的HandlerMapping,只要getHandler方法能获取到HandlerExecutionChain立即返回。
- // DispatcherServlet类方法
- @Nullable
- protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
- if (this.handlerMappings != null) {
- for (HandlerMapping mapping : this.handlerMappings) {
- HandlerExecutionChain handler = mapping.getHandler(request);
- if (handler != null) {
- return handler;
- }
- }
- }
- return null;
- }
复制代码 如下这三个HandlerMapping是web容器启动时候加载的,上篇文章SpringMVC源码剖析(一):web容器启动流程有详细介绍。三个轮番调用getHandler方法,而HandlerMapping也有次序的,RequestMappingHanderMapping排序为0优先级最高,而它也是处置惩罚@RequestMapping注解的映射关系的映射器。
调用抽象类的方法,那么上面看到的三个HandlerMapping应该都会调用此方法,而这里肯定有一些核心的不同的方法实现在不同的HandlerMapping详细实现类中,典型的模板方法计划模式。
- // AbstractHandlerMapping类方法
- @Override
- @Nullable
- public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
- // 获取Handler
- Object handler = getHandlerInternal(request);
- if (handler == null) {
- handler = getDefaultHandler();
- }
- if (handler == null) {
- return null;
- }
- // handler为bean的名称
- // 这种Controller应该是实现Controler、HttpRequestHandler接口的方式
- // 以前的老实现方式,暂不研究
- if (handler instanceof String) {
- String handlerName = (String) handler;
- handler = obtainApplicationContext().getBean(handlerName);
- }
-
- ...
-
- // 获取执行链(包括Handler和拦截器)
- HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
- // ...打印日志
-
- // 添加跨域设置(本身也是拦截器)到拦截器链中第一个位置
- if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
- CorsConfiguration config = getCorsConfiguration(handler, request);
- if (getCorsConfigurationSource() != null) {
- CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request);
- config = (globalConfig != null ? globalConfig.combine(config) : config);
- }
- if (config != null) {
- config.validateAllowCredentials();
- }
- executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
- }
- return executionChain;
- }
复制代码 1、获取Handler
- 主要内容就是调用父类AbstractHandlerMethodMapping的雷同方法
- // RequestMappingInfoHandlerMapping类方法
- @Override
- @Nullable
- protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
- request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
- try {
- // 核心方法调用父类的getHandlerInternal方法
- return super.getHandlerInternal(request);
- }
- finally {
- ProducesRequestCondition.clearMediaTypesAttribute(request);
- }
- }
复制代码
- 通过request获取查找路径
- 通过查找路径获取HandlerMethod
- // AbstractHandlerMethodMapping类方法
- @Override
- @Nullable
- protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
- // 通过request获取查找路径
- String lookupPath = initLookupPath(request);
- this.mappingRegistry.acquireReadLock();
- try {
- // 通过查找路径获取HandlerMethod
- HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
- return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
- }
- finally {
- this.mappingRegistry.releaseReadLock();
- }
- }
复制代码 1.1、通过request获取查找路径
- 截取哀求uri,如图/springmvc/test,/springmvc为项目路径,/test为我们需要的查找路径
1.2、通过查找路径获取HandlerMethod
这个方法的核心内容就是从之前讲的SpringMVC源码剖析(一):web容器启动流程注册的两个map获取数据。
- // AbstractHandlerMethodMapping类方法
- @Nullable
- protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
- List<Match> matches = new ArrayList<>();
- // 通过查找路径获取RequestMappingInfo
- List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
- if (directPathMatches != null) {
- // 通过RequestMappingInfo获取HandlerMethod
- addMatchingMappings(directPathMatches, matches, request);
- }
- ...
- if (!matches.isEmpty()) {
- Match bestMatch = matches.get(0);
- if (matches.size() > 1) {
- //...匹配多个,抛错异常
- }
- request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
- handleMatch(bestMatch.mapping, lookupPath, request);
- // 获取HandlerMethod并返回
- return bestMatch.getHandlerMethod();
- }
- else {
- return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
- }
- }
复制代码
2、获取执行链(包括Handler、拦截器)
我们自定义的拦截器统一用MappedInterceptor这个拦截器包装了一层,为了统一调用matcher方法,匹配此拦截器哀求是否拦截本次哀求,如果是则会添加到拦截器链中。
- // AbstractHandlerMapping类方法
- protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
- // 创建HandlerExecutionChain对象
- HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
- (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
-
- // 遍历所有的拦截器,这拦截器是web容器启动时候解析加载的的
- for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
- // 我们自定义的拦截器统一用MappedInterceptor这个拦截器包装了一层
- // 为了统一的匹配方法,下面调用maches
- if (interceptor instanceof MappedInterceptor) {
- MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
- // matcher匹配当前请求路径是否符合拦截器的拦截请求
- if (mappedInterceptor.matches(request)) {
- chain.addInterceptor(mappedInterceptor.getInterceptor());
- }
- }
- else {
- chain.addInterceptor(interceptor);
- }
- }
- return chain;
- }
- // 执行器链对象,主要就是两个属性handler:Handler对象,interceptorList:拦截器集合
- public class HandlerExecutionChain {
- private final Object handler;
- private final List<HandlerInterceptor> interceptorList = new ArrayList<>();
- // 构造方法
- public HandlerExecutionChain(Object handler) {
- this(handler, (HandlerInterceptor[]) null);
- }
- ...
- }
复制代码
二、获取适配器
看下HandlerAdapter接口
- public interface HandlerAdapter {
- /**
- * 因为有多个HandlerMapping和HandlerAdapter
- * 对于HandlerAdapter是否支持对应的HandlerMapping,通过此方法判断
- */
- boolean supports(Object handler);
- /**
- * 具体调用Hangder的方法
- */
- @Nullable
- ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
- }
复制代码 因为不同的Hander(@RequestMapping、实现Controller接口、实现HttpRequestHandler接口)对应的HandlerAdapter(适配器)不一样,通过HandlerAdapter的supports方法判断当前HandlerAdapter是否支持此次哀求的Hander。
- // DispatcherServlet类方法
- protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
- if (this.handlerAdapters != null) {
- for (HandlerAdapter adapter : this.handlerAdapters) {
- if (adapter.supports(handler)) {
- return adapter;
- }
- }
- }
- throw new ServletException("No adapter for handler [" + handler +
- "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
- }
复制代码
- 这个是抽象类实现的supports方法,全部HandlerAdapter判断是否支持都会走这里
- 其主要作用就是supportsInternal方法,在不同的HandlerAdapter实现类中重写
- RequestMappingHandlerAdapter重写的supportsInternal返回true,表示其支持
- // AbstractHandlerMethodAdapter类方法
- @Override
- public final boolean supports(Object handler) {
- return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
- }
- // RequestMappingHandlerAdapter类方法
- @Override
- protected boolean supportsInternal(HandlerMethod handlerMethod) {
- return true;
- }
复制代码 由上面HandlerAdapter接口可以猜到,RequestMappingHandlerAdapter适配器就是我们需要的,之后会通过handle方法去执行Hangder方法即调用Controller#Method。
三、执行Handler( |