springmvc源码分析-阿里云开发者社区

开发者社区> 小鲍侃java> 正文

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


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
10089 0
Activiti源码分析
ExecutionEntity内部含有parent,是一个执行树或执行路径,应该是一个流程实例的执行过程,一个实例对应一个ExecutionEntity,通过getActivity得到的是当前正在执行的activity. Activiti之流程部署: 流程文件部署主要涉及到3个表,分别是:ACT_GE_BYTEARRAY、ACT_RE_DEPLOYMENT、ACT_
6004 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,大概有三种登录方式:
2962 0
怎么设置阿里云服务器安全组?阿里云安全组规则详细解说
阿里云服务器安全组设置规则分享,阿里云服务器安全组如何放行端口设置教程
8478 0
openstack 源码分析
  Nova对于底层Hypervisor(如KVM/QEMU等)的调用与管理主要通过LibvirtDriver类,nova/virt/libvirt/driver.py   Libvirt对Hypervisor的连接有两种方式:一种是只读式,用于管理;另一种是认证式,用于操作;   创建实例过程:/nova/api/ec2/cloud.
996 0
使用OpenApi弹性释放和设置云服务器ECS释放
云服务器ECS的一个重要特性就是按需创建资源。您可以在业务高峰期按需弹性的自定义规则进行资源创建,在完成业务计算的时候释放资源。本篇将提供几个Tips帮助您更加容易和自动化的完成云服务器的释放和弹性设置。
12076 0
http 服务源码分析
多读go的源码,可以加深对go语言的理解和认知,今天分享一下http相关的源码部分 在不使用第三方库的情况下,我们可以很容易的的用go实现一个http服务, package main import ( "fmt" "net/http" ) func IndexHandler(w http.
966 0
JDK源码分析系列之四:HashSet深入理解以及源码分析
其实HashSet中的源码还是非常简单的,底层实现都是通过HashMap来进行的,并且通过HashMap的key来进行元素的存储。以前我们都是关注HashMap的源码实现,对于HashSet的源码没有在意,如果不是这次分析崩溃的问题也不会发现HashSet的底层实现逻辑。所以有时候越简单的懂越要知道其内部实现,这样就不会阴沟里翻船了。
10 0
+关注
小鲍侃java
小作坊架构师。
365
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载