springmvc源码分析

简介: springmvc源码分析


image.png

1.springmvc流程分析

各种书上通用写的springmvc流程是这样的:

  1. 用户发送请求至前端控制器DispatcherServlet。
  2. DispatcherServlet收到请求调用HandlerMapping处理器映射器。
  3. 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。(也就是HandlerExecutionChain)
  4. DispatcherServlet调用HandlerAdapter处理器适配器。
  5. HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
  6. Controller执行完成返回ModelAndView。
  7. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
  8. DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
  9. ViewReslover解析后返回具体View.
  10. DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
  11. DispatcherServlet响应用户。

image.png

2.源码分析

1.发送服务,调用servlet

servlet通过doGet和doPost执行方法 ,这两个方法在DispatcherServlet的父类FrameworkServlet中,其中调用到了doService。

1. protected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
2. this.processRequest(request, response);
3.     }
1. protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
2. long startTime = System.currentTimeMillis();
3. Throwable failureCause = null;
4. LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
5. LocaleContext localeContext = this.buildLocaleContext(request);
6. RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
7. ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
8. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
9.         asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor());
10. this.initContextHolders(request, localeContext, requestAttributes);
11. 
12. try {
13. this.doService(request, response);
14.         } catch (IOException | ServletException var16) {
15.             failureCause = var16;
16. throw var16;
17.         } catch (Throwable var17) {
18.             failureCause = var17;
19. throw new NestedServletException("Request processing failed", var17);
20.         } finally {
21. this.resetContextHolders(request, previousLocaleContext, previousAttributes);
22. if (requestAttributes != null) {
23.                 requestAttributes.requestCompleted();
24.             }
25. 
26. this.logResult(request, response, (Throwable)failureCause, asyncManager);
27. this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
28.         }
29. 
30.     }
1. protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
2. 
3. this.logRequest(request);
4.         Map<String, Object> attributesSnapshot = null;
5. if (WebUtils.isIncludeRequest(request)) {
6.             attributesSnapshot = new HashMap();
7.             Enumeration attrNames = request.getAttributeNames();
8. 
9.             label95:
10. while(true) {
11.                 String attrName;
12. do {
13. if (!attrNames.hasMoreElements()) {
14. break label95;
15.                     }
16. 
17.                     attrName = (String)attrNames.nextElement();
18.                 } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));
19. 
20.                 attributesSnapshot.put(attrName, request.getAttribute(attrName));
21.             }
22.         }
23. //设置属性
24. //ApplicationContext、localeResolver、themeResolver等对象添加到request中
25.         request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
26.         request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
27.         request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
28.         request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
29. if (this.flashMapManager != null) {
30.             FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
31. if (inputFlashMap != null) {
32.                 request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
33.             }
34. 
35.             request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
36.             request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
37.         }
38. 
39. try {
40. //具体的方法
41. this.doDispatch(request, response);
42.         } finally {
43. if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
44. this.restoreAttributesAfterInclude(request, attributesSnapshot);
45.             }
46. 
47.         }
48. 
49.     }

2.doDispatch

大部分操作都是在这个类中。

1. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
2. HttpServletRequest processedRequest = request;
3. HandlerExecutionChain mappedHandler = null;
4. boolean multipartRequestParsed = false;
5. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
6. 
7. try {
8. try {
9. ModelAndView mv = null;
10. Object dispatchException = null;
11. 
12. try {
13. // 1. 检查是否是上传文件
14.                     processedRequest = this.checkMultipart(request);
15.                     multipartRequestParsed = processedRequest != request;
16. 
17. //获取到controller在factory中的所有bean的信息
18.                     mappedHandler = this.getHandler(processedRequest);
19. 
20. if (mappedHandler == null) {
21. this.noHandlerFound(processedRequest, response);
22. return;
23.                     }
24. 
25. //获取到处理器 也就是controller类 
26. HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
27. 
28. String method = request.getMethod();
29. boolean isGet = "GET".equals(method);
30. if (isGet || "HEAD".equals(method)) {
31. // 如果是get 根据上次修改的时间戳来判断资源是否已被修改,如果资源未被修改,则直接返回,浏览器将使用缓存
32. long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
33. if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
34. return;
35.                         }
36.                     }
37. 
38. if (!mappedHandler.applyPreHandle(processedRequest, response)) {
39. return;
40.                     }
41. 
42.                     mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
43. if (asyncManager.isConcurrentHandlingStarted()) {
44. return;
45.                     }
46. 
47. this.applyDefaultViewName(processedRequest, mv);
48. //后置处理器
49.                     mappedHandler.applyPostHandle(processedRequest, response, mv);
50.                 } catch (Exception var20) {
51.                     dispatchException = var20;
52.                 } catch (Throwable var21) {
53.                     dispatchException = new NestedServletException("Handler dispatch failed", var21);
54.                 }
55. 
56. this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
57.             } catch (Exception var22) {
58. this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
59.             } catch (Throwable var23) {
60. this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
61.             }
62. 
63.         } finally {
64. if (asyncManager.isConcurrentHandlingStarted()) {
65. if (mappedHandler != null) {
66.                     mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
67.                 }
68.             } else if (multipartRequestParsed) {
69. this.cleanupMultipart(processedRequest);
70.             }
71. 
72.         }
73.     }

1.getHandler方法

获取处理器映射器

1. @Nullable
2. protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
3. 
4. //mapping中放着所有的mapping信息
5. if (this.handlerMappings != null) {
6. Iterator var2 = this.handlerMappings.iterator();
7. 
8. while(var2.hasNext()) {
9. HandlerMapping mapping = (HandlerMapping)var2.next();
10. 
11. //关键方法 获取bean信息的集合
12. HandlerExecutionChain handler = mapping.getHandler(request);
13. 
14. if (handler != null) {
15. return handler;
16.                 }
17.             }
18.         }
19. 
20. return null;
21.     }

自定义的mapping都在RequestMappingHandlerMapping 。

image.png

然后进入 Object handler = this.getHandlerInternal(request);。

1. public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
2. //主要方法
3.         Object handler = this.getHandlerInternal(request);
4. if (handler == null) {
5.             handler = this.getDefaultHandler();
6.         }
7. // 如果还是没有则返回 这时候 DispatcherServlet会返回 404
8. if (handler == null) {
9. return null;
10.         } else {
11. // 如果返回的处理器是字符串 则认为它是一个beanName
12. if (handler instanceof String) {
13.                 String handlerName = (String)handler;
14. // 通过beanName从IOC容器中获取相应的处理器
15.                 handler = this.obtainApplicationContext().getBean(handlerName);
16.             }
17. // 下面是将处理器 和 拦截器封装成处理器执行链
18.             HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
19. if (this.logger.isTraceEnabled()) {
20. this.logger.trace("Mapped to " + handler);
21.             } else if (this.logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
22. this.logger.debug("Mapped to " + executionChain.getHandler());
23.             }
24. 
25. if (CorsUtils.isCorsRequest(request)) {
26.                 CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
27.                 CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request);
28.                 CorsConfiguration config = globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig;
29.                 executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
30.             }
31. // 返回处理器执行链
32. return executionChain;
33.         }
34.     }

之后再进入getHandlerInternal。

1. protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
2. //请求的路径
3.         String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
4. this.mappingRegistry.acquireReadLock();
5. 
6.         HandlerMethod var4;
7. try {
8. //主要方法
9.             HandlerMethod handlerMethod = this.lookupHandlerMethod(lookupPath, request);
10.             var4 = handlerMethod != null ? handlerMethod.createWithResolvedBean() : null;
11.         } finally {
12. this.mappingRegistry.releaseReadLock();
13.         }
14. 
15. return var4;
16.     }

之后再HandlerMethod handlerMethod = this.lookupHandlerMethod(lookupPath, request); 在类中 通过request中的mapping在this.mappingRegistry中获取这个bean的所有信息。

1. @Nullable
2. protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
3.         List<AbstractHandlerMethodMapping<T>.Match> matches = new ArrayList();
4.         List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
5. if (directPathMatches != null) {
6. this.addMatchingMappings(directPathMatches, matches, request);
7.         }
8. 
9. if (matches.isEmpty()) {
10. this.addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
11.         }
12. 
13. if (!matches.isEmpty()) {
14.             Comparator<AbstractHandlerMethodMapping<T>.Match> comparator = new AbstractHandlerMethodMapping.MatchComparator(this.getMappingComparator(request));
15.             matches.sort(comparator);
16.             AbstractHandlerMethodMapping<T>.Match bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
17. if (matches.size() > 1) {
18. if (this.logger.isTraceEnabled()) {
19. this.logger.trace(matches.size() + " matching mappings: " + matches);
20.                 }
21. 
22. if (CorsUtils.isPreFlightRequest(request)) {
23. return PREFLIGHT_AMBIGUOUS_MATCH;
24.                 }
25. 
26.                 AbstractHandlerMethodMapping<T>.Match secondBestMatch = (AbstractHandlerMethodMapping.Match)matches.get(1);
27. if (comparator.compare(bestMatch, secondBestMatch) == 0) {
28.                     Method m1 = bestMatch.handlerMethod.getMethod();
29.                     Method m2 = secondBestMatch.handlerMethod.getMethod();
30.                     String uri = request.getRequestURI();
31. throw new IllegalStateException("Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
32.                 }
33.             }
34. 
35.             request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
36. this.handleMatch(bestMatch.mapping, lookupPath, request);
37. //多个请求会返回最佳请求
38. return bestMatch.handlerMethod;
39.         } else {
40. return this.handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
41.         }
42.     }

然后在进行了其他操作 加入过滤器 最终返回了handler -getHandler方法结束。

image.png

2.getHandlerAdapter

获取处理器适配器。

1. protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
2. if (this.handlerAdapters != null) {
3. Iterator var2 = this.handlerAdapters.iterator();
4. 
5. while(var2.hasNext()) {               
6. HandlerAdapter adapter = (HandlerAdapter)var2.next();
7. //和处理器映射器比对
8. if (adapter.supports(handler)) {
9. return adapter;
10.                 }
11.             }
12.         }
13. 
14. throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
15.     }

3.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

调用controller方法,通过反射,调用到controller中,返回ModelAndView。

1. @Nullable
2. protected Object doInvoke(Object... args) throws Exception {
3.         ReflectionUtils.makeAccessible(this.getBridgedMethod());
4. 
5. try {
6. return this.getBridgedMethod().invoke(this.getBean(), args);
7.         } catch (IllegalArgumentException var4) {
8. this.assertTargetBean(this.getBridgedMethod(), this.getBean(), args);
9.             String text = var4.getMessage() != null ? var4.getMessage() : "Illegal argument";
10. throw new IllegalStateException(this.formatInvokeError(text, args), var4);
11.         } catch (InvocationTargetException var5) {
12.             Throwable targetException = var5.getTargetException();
13. if (targetException instanceof RuntimeException) {
14. throw (RuntimeException)targetException;
15.             } else if (targetException instanceof Error) {
16. throw (Error)targetException;
17.             } else if (targetException instanceof Exception) {
18. throw (Exception)targetException;
19.             } else {
20. throw new IllegalStateException(this.formatInvokeError("Invocation failure", args), targetException);
21.             }
22.         }
23.     }

3.总结

        1.首先调用进入servlet会调用doGet和doPost方法

        2.然后调用中DispatcherServlet的doService

        3.调用doService中的doDispatch

        4.调用doDispatch中的getHandler使用handleMapping处理器映射器 去获取HandlerExecutionChain

                     1.通过mapping去this.mappingRegistry获取到需求bean在factory中的信息

                     2.将得到的hander和过滤器放在返回对象HandlerExecutionChain

         5.获取Adapter

         6.使用Adapter 通过反射调用controller

         7.返回ModelAndView


相关文章
|
28天前
|
设计模式 前端开发 Java
步步深入SpringMvc DispatcherServlet源码掌握springmvc全流程原理
通过对 `DispatcherServlet`源码的深入剖析,我们了解了SpringMVC请求处理的全流程。`DispatcherServlet`作为前端控制器,负责请求的接收和分发,处理器映射和适配负责将请求分派到具体的处理器方法,视图解析器负责生成和渲染视图。理解这些核心组件及其交互原理,有助于开发者更好地使用和扩展SpringMVC框架。
41 4
|
2月前
|
前端开发 Java 开发者
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
167 2
|
3月前
|
JSON 前端开发 Java
SSM:SpringMVC
本文介绍了SpringMVC的依赖配置、请求参数处理、注解开发、JSON处理、拦截器、文件上传下载以及相关注意事项。首先,需要在`pom.xml`中添加必要的依赖,包括Servlet、JSTL、Spring Web MVC等。接着,在`web.xml`中配置DispatcherServlet,并设置Spring MVC的相关配置,如组件扫描、默认Servlet处理器等。然后,通过`@RequestMapping`等注解处理请求参数,使用`@ResponseBody`返回JSON数据。此外,还介绍了如何创建和配置拦截器、文件上传下载的功能,并强调了JSP文件的放置位置,避免404错误。
|
4月前
|
缓存 前端开发 Java
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
Soring Boot的起步依赖、启动流程、自动装配、常用的注解、Spring MVC的执行流程、对MVC的理解、RestFull风格、为什么service层要写接口、MyBatis的缓存机制、$和#有什么区别、resultType和resultMap区别、cookie和session的区别是什么?session的工作原理
|
3月前
|
前端开发 Java 应用服务中间件
【Spring】Spring MVC的项目准备和连接建立
【Spring】Spring MVC的项目准备和连接建立
68 2
|
3月前
|
XML 前端开发 Java
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
本文阐述了Spring、Spring Boot和Spring MVC的关系与区别,指出Spring是一个轻量级、一站式、模块化的应用程序开发框架,Spring MVC是Spring的一个子框架,专注于Web应用和网络接口开发,而Spring Boot则是对Spring的封装,用于简化Spring应用的开发。
251 0
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
|
4月前
|
XML 缓存 前端开发
springMVC02,restful风格,请求转发和重定向
文章介绍了RESTful风格的基本概念和特点,并展示了如何使用SpringMVC实现RESTful风格的请求处理。同时,文章还讨论了SpringMVC中的请求转发和重定向的实现方式,并通过具体代码示例进行了说明。
springMVC02,restful风格,请求转发和重定向
|
5月前
|
Java 数据库连接 Spring
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】
文章是关于Spring、SpringMVC、Mybatis三个后端框架的超详细入门教程,包括基础知识讲解、代码案例及SSM框架整合的实战应用,旨在帮助读者全面理解并掌握这些框架的使用。
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】
|
5月前
|
XML JSON 数据库
SpringMVC入门到实战------七、RESTful的详细介绍和使用 具体代码案例分析(一)
这篇文章详细介绍了RESTful的概念、实现方式,以及如何在SpringMVC中使用HiddenHttpMethodFilter来处理PUT和DELETE请求,并通过具体代码案例分析了RESTful的使用。
SpringMVC入门到实战------七、RESTful的详细介绍和使用 具体代码案例分析(一)
|
5月前
|
前端开发 应用服务中间件 数据库
SpringMVC入门到实战------八、RESTful案例。SpringMVC+thymeleaf+BootStrap+RestFul实现员工信息的增删改查
这篇文章通过一个具体的项目案例,详细讲解了如何使用SpringMVC、Thymeleaf、Bootstrap以及RESTful风格接口来实现员工信息的增删改查功能。文章提供了项目结构、配置文件、控制器、数据访问对象、实体类和前端页面的完整源码,并展示了实现效果的截图。项目的目的是锻炼使用RESTful风格的接口开发,虽然数据是假数据并未连接数据库,但提供了一个很好的实践机会。文章最后强调了这一章节主要是为了练习RESTful,其他方面暂不考虑。
SpringMVC入门到实战------八、RESTful案例。SpringMVC+thymeleaf+BootStrap+RestFul实现员工信息的增删改查