一、 Spring-MVC的对象初始化,即 bean放入context的beanFactory中。

1. 对象的初始化工作主要在org.springframework.web.servlet.FrameworkServlet类中的initServletBean方法中完成,initServletBean方法最终会调用到

org.springframework.context.support.AbstractApplicationContext类的refresh方法,refresh方法是主要的bean的初始化方法。refresh方法又调用类里面的obtainFreshBeanFactory方法。

2.  org.springframework.beans.factory.support.DefaultListableBeanFactory为默认的BeanFactory,

DefaultListableBeanFactory 类中的registerBeanDefinition方法为保存对象列表信息的主要方法,beanFactory中的对象存放到成员变量Map<String, BeanDefinition> beanDefinitionMap中。

  1. private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
  2.  
  3. //---------------------------------------------------------------------
  4. // Implementation of BeanDefinitionRegistry interface
  5. //---------------------------------------------------------------------
  6.  
  7. public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
  8. throws BeanDefinitionStoreException {
  9.  
  10. Assert.hasText(beanName, "Bean name must not be empty");
  11. Assert.notNull(beanDefinition, "BeanDefinition must not be null");
  12.  
  13. if (beanDefinition instanceof AbstractBeanDefinition) {
  14. try {
  15. ((AbstractBeanDefinition) beanDefinition).validate();
  16. }
  17. catch (BeanDefinitionValidationException ex) {
  18. throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
  19. "Validation of bean definition failed", ex);
  20. }
  21. }
  22.  
  23. synchronized (this.beanDefinitionMap) {
  24. Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
  25. if (oldBeanDefinition != null) {
  26. if (!this.allowBeanDefinitionOverriding) {
  27. throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
  28. "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
  29. "': There is already [" + oldBeanDefinition + "] bound.");
  30. }
  31. else {
  32. if (this.logger.isInfoEnabled()) {
  33. this.logger.info("Overriding bean definition for bean '" + beanName +
  34. "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
  35. }
  36. }
  37. }
  38. else {
  39. this.beanDefinitionNames.add(beanName);
  40. this.frozenBeanDefinitionNames = null;
  41. }
  42. this.beanDefinitionMap.put(beanName, beanDefinition);
  43. }
  44.  
  45. resetBeanDefinition(beanName);
  46. }

二、   Spring-MVC中Controller中的method与 RequestMappingURL的初始化

1.  Controller中的method与 RequestMappingURL的映射关系绑定初始化工作主要在spring-webmvc.jar中完成。这个jar 文件包含Spring MVC 框架相关的所有类,

包括框架的Servlets,Web MVC框架,控制器和视图支持。

2.   SpringMVC在容器初始化时,绑定请求URL映射到相应的Controller中的方法的工作主要在org.springframework.web.servlet.handler.AbstractHandlerMethodMapping类中的initHandlerMethods方法完成,

AbstractHandlerMethodMapping实现了Spring的org.springframework.beans.factory.InitializingBean接口,在InitializingBean的afterPropertiesSet即调用了initHandlerMethods。

MappingURL与Controller对应方法的映射关系在servlet容器初始化时保存到 AbstractHandlerMethodMapping中的成员变量urlMap中。

AbstractHandlerMethodMapping类的initHandlerMethods为protected修饰 ,可被子类重写。

三、  请求URL到达映射处理的Controller的Method前的逻辑。

执行业务方法的逻辑主要在org.springframework.web.servlet.DispatcherServlet类的doDispatch方法中。

以下为doDispatch方法的代码:

  1. /**
  2. * Process the actual dispatching to the handler.
  3. * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
  4. * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
  5. * to find the first that supports the handler class.
  6. * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
  7. * themselves to decide which methods are acceptable.
  8. * @param request current HTTP request
  9. * @param response current HTTP response
  10. * @throws Exception in case of any kind of processing failure
  11. */
  12. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
  13. HttpServletRequest processedRequest = request;
  14. HandlerExecutionChain mappedHandler = null;
  15. int interceptorIndex = -1;
  16.  
  17. try {
  18. ModelAndView mv;
  19. boolean errorView = false;
  20.  
  21. try {
  22. processedRequest = checkMultipart(request);
  23.  
  24. // Determine handler for the current request.
  25. mappedHandler = getHandler(processedRequest, false);
  26. if (mappedHandler == null || mappedHandler.getHandler() == null) {
  27. noHandlerFound(processedRequest, response);
  28. return;
  29. }
  30.  
  31. // Determine handler adapter for the current request.
  32. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
  33.  
  34. // Process last-modified header, if supported by the handler.
  35. String method = request.getMethod();
  36. boolean isGet = "GET".equals(method);
  37. if (isGet || "HEAD".equals(method)) {
  38. long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
  39. if (logger.isDebugEnabled()) {
  40. String requestUri = urlPathHelper.getRequestUri(request);
  41. logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
  42. }
  43. if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
  44. return;
  45. }
  46. }
  47.  
  48. // Apply preHandle methods of registered interceptors.
  49. HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
  50. if (interceptors != null) {
  51. for (int i = 0; i < interceptors.length; i++) {
  52. HandlerInterceptor interceptor = interceptors[i];
  53. if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
  54. triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
  55. return;
  56. }
  57. interceptorIndex = i;
  58. }
  59. }
  60.  
  61. // Actually invoke the handler.
  62. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  63.  
  64. // Do we need view name translation?
  65. if (mv != null && !mv.hasView()) {
  66. mv.setViewName(getDefaultViewName(request));
  67. }
  68.  
  69. // Apply postHandle methods of registered interceptors.
  70. if (interceptors != null) {
  71. for (int i = interceptors.length - 1; i >= 0; i--) {
  72. HandlerInterceptor interceptor = interceptors[i];
  73. interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
  74. }
  75. }
  76. }
  77. catch (ModelAndViewDefiningException ex) {
  78. logger.debug("ModelAndViewDefiningException encountered", ex);
  79. mv = ex.getModelAndView();
  80. }
  81. catch (Exception ex) {
  82. Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
  83. mv = processHandlerException(processedRequest, response, handler, ex);
  84. errorView = (mv != null);
  85. }
  86.  
  87. // Did the handler return a view to render?
  88. if (mv != null && !mv.wasCleared()) {
  89. render(mv, processedRequest, response);
  90. if (errorView) {
  91. WebUtils.clearErrorRequestAttributes(request);
  92. }
  93. }
  94. else {
  95. if (logger.isDebugEnabled()) {
  96. logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
  97. "': assuming HandlerAdapter completed request handling");
  98. }
  99. }
  100.  
  101. // Trigger after-completion for successful outcome.
  102. triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
  103. }
  104.  
  105. catch (Exception ex) {
  106. // Trigger after-completion for thrown exception.
  107. triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
  108. throw ex;
  109. }
  110. catch (Error err) {
  111. ServletException ex = new NestedServletException("Handler processing failed", err);
  112. // Trigger after-completion for thrown exception.
  113. triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
  114. throw ex;
  115. }
  116.  
  117. finally {
  118. // Clean up any resources used by a multipart request.
  119. if (processedRequest != request) {
  120. cleanupMultipart(processedRequest);
  121. }
  122. }
  123. }

主要执行的过程有四个步骤,如下所示:

1. 通过调用org.springframework.web.servlet.handler.AbstractHandlerMethodMapping类的getHandlerInternal方法来获得相应的请求url的映射的controller和method的HandlerMethod,

AbstractHandlerMethodMapping中的成员变量urlMap保存的即为servlet容器启动时初始化的RequestMapping映射的Controller和Method的信息。

getHandlerInternal方法代码如下:

  1. /**
  2. * Look up the best-matching handler method for the current request.
  3. * If multiple matches are found, the best match is selected.
  4. * @param lookupPath mapping lookup path within the current servlet mapping
  5. * @param request the current request
  6. * @return the best-matching handler method, or {@code null} if no match
  7. * @see #handleMatch(Object, String, HttpServletRequest)
  8. * @see #handleNoMatch(Set, String, HttpServletRequest)
  9. */
  10. protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
  11. List<Match> matches = new ArrayList<Match>();
  12.  
  13. List<T> directPathMatches = this.urlMap.get(lookupPath);
  14. if (directPathMatches != null) {
  15. addMatchingMappings(directPathMatches, matches, request);
  16. }
  17.  
  18. if (matches.isEmpty()) {
  19. // No choice but to go through all mappings
  20. addMatchingMappings(this.handlerMethods.keySet(), matches, request);
  21. }
  22.  
  23. if (!matches.isEmpty()) {
  24. Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
  25. Collections.sort(matches, comparator);
  26.  
  27. if (logger.isTraceEnabled()) {
  28. logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
  29. }
  30.  
  31. Match bestMatch = matches.get(0);
  32. if (matches.size() > 1) {
  33. Match secondBestMatch = matches.get(1);
  34. if (comparator.compare(bestMatch, secondBestMatch) == 0) {
  35. Method m1 = bestMatch.handlerMethod.getMethod();
  36. Method m2 = secondBestMatch.handlerMethod.getMethod();
  37. throw new IllegalStateException(
  38. "Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" +
  39. m1 + ", " + m2 + "}");
  40. }
  41. }
  42.  
  43. handleMatch(bestMatch.mapping, lookupPath, request);
  44. return bestMatch.handlerMethod;
  45. }
  46. else {
  47. return handleNoMatch(handlerMethods.keySet(), lookupPath, request);
  48. }
  49. }

HandlerMethod类主要包括的信息有 匹配处理的Controller ,处理方法Method,以及方法的传入参数 parameters等信息。HandlerMethod的主要成员变量代码如下:

  1. public class HandlerMethod {
  2.  
  3. /** Logger that is available to subclasses */
  4. protected final Log logger = LogFactory.getLog(HandlerMethod.class);
  5.  
  6. private final Object bean;
  7.  
  8. private final Method method;
  9.  
  10. private final BeanFactory beanFactory;
  11.  
  12. private MethodParameter[] parameters;
  13.  
  14. private final Method bridgedMethod;
  15.  
  16. }

bean为url映射匹配到Controller, method为映射到的处理方法。

2. 执行url匹配的过滤器的preHandle方法。

3. 执行主要的业务过程处理方法,即执行步骤1中找到的Controller对应的Method。

执行主要的业务处理方法的是在org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter类的invokeHandlerMethod方法中调用。

  1. /**
  2. * Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView} if view resolution is required.
  3. */
  4. private ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response,
  5. HandlerMethod handlerMethod) throws Exception {
  6.  
  7. ServletWebRequest webRequest = new ServletWebRequest(request, response);
  8.  
  9. WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
  10. ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
  11. ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);
  12.  
  13. ModelAndViewContainer mavContainer = new ModelAndViewContainer();
  14. mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
  15. modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
  16. mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
  17.  
  18. requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
  19. modelFactory.updateModel(webRequest, mavContainer);
  20.  
  21. if (mavContainer.isRequestHandled()) {
  22. return null;
  23. }
  24. else {
  25. ModelMap model = mavContainer.getModel();
  26. ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
  27. if (!mavContainer.isViewReference()) {
  28. mav.setView((View) mavContainer.getView());
  29. }
  30. if (model instanceof RedirectAttributes) {
  31. Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
  32. RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
  33. }
  34. return mav;
  35. }
  36. }

业务方法调用主要在org.springframework.web.method.support.InvocableHandlerMethod类的invokeForRequest方法中,过程包括组装request的请求参数传入到handleMethod的参数数组args[]中,方法调用等。

方法通过java的反射机制执行,即java.lang.reflect.Method.invoke(Object controller, Object... args);  参数一controller为方法所属的Controller,参数二args为请求参数

  1. /**
  2. * Invoke the method after resolving its argument values in the context of the given request. <p>Argument
  3. * values are commonly resolved through {@link HandlerMethodArgumentResolver}s. The {@code provideArgs}
  4. * parameter however may supply argument values to be used directly, i.e. without argument resolution.
  5. * Examples of provided argument values include a {@link WebDataBinder}, a {@link SessionStatus}, or
  6. * a thrown exception instance. Provided argument values are checked before argument resolvers.
  7. *
  8. * @param request the current request
  9. * @param mavContainer the ModelAndViewContainer for this request
  10. * @param providedArgs "given" arguments matched by type, not resolved
  11. * @return the raw value returned by the invoked method
  12. * @exception Exception raised if no suitable argument resolver can be found, or the method raised an exception
  13. */
  14. public final Object invokeForRequest(NativeWebRequest request,
  15. ModelAndViewContainer mavContainer,
  16. Object... providedArgs) throws Exception {
  17. Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
  18.  
  19. if (logger.isTraceEnabled()) {
  20. StringBuilder builder = new StringBuilder("Invoking [");
  21. builder.append(this.getMethod().getName()).append("] method with arguments ");
  22. builder.append(Arrays.asList(args));
  23. logger.trace(builder.toString());
  24. }
  25.  
  26. Object returnValue = invoke(args);
  27.  
  28. if (logger.isTraceEnabled()) {
  29. logger.trace("Method [" + this.getMethod().getName() + "] returned [" + returnValue + "]");
  30. }
  31.  
  32. return returnValue;
  33. }

4. 执行url匹配的过滤器的postHandle方法。

Spring-MVC运行原理的更多相关文章

  1. struts1,struts2,hibernate,spring的运行原理结构图

    一.struts1运行原理 1.初始化:struts框架的总控制器ActionServlet是一个Servlet,它在web.xml中配置成自动启动的Servlet,在启动时总控制器会读取配置文件(s ...

  2. (4.1)Spring MVC执行原理和基于Java的配置过程

    一.Spring MVC执行原理和基于Java配置的配置过程 (一)Spring MVC执行过程,大致为7步. 所有的请求都会经过Spring的一个单例的DispacherServlet. Dispa ...

  3. Spring MVC简单原理

    Spring MVC原理 针对有Java Web基础.Spring基础和Spring MVC使用经验者. 前言 目前基于Java的web后端,Spring生态应该是比较常见了.虽然现在流行前后端分离, ...

  4. spring Mvc 执行原理 及 xml注解配置说明 (六)

    Spring MVC 执行原理 在 Spring Mvc 访问过程里,每个请求都首先经过 许多的过滤器,经 DispatcherServlet 处理; 一个Spring MVC工程里,可以配置多个的 ...

  5. Spring MVC执行原理和基于Java的配置过程

    一.Spring MVC执行原理和基于Java配置的配置过程 (一)Spring MVC执行过程,大致为7步. 所有的请求都会经过Spring的一个单例的DispacherServlet. Dispa ...

  6. Spring MVC工作原理(好用版)

    Spring MVC工作原理 参考: SpringMVC工作原理 - 平凡希 - 博客园https://www.cnblogs.com/xiaoxi/p/6164383.html SpringMVC的 ...

  7. Spring Boot运行原理

    概述 本文主要写了下Spring Boot运行原理,还有一个小例子. Spring4.x提供了基于条件来配置Bean的能力,而Spring Boot的实现也是基于这一原理的. Spring Boot关 ...

  8. Spring MVC工作原理 及注解说明

    SpringMVC框架介绍 1) spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面. Spring 框架提供了构建 Web 应用程序的全功 ...

  9. Spring MVC 底层原理

    参考博客:http://www.cnblogs.com/xiaoxi/p/6164383.html Spring MVC处理的流程: 具体执行步骤如下: 1 首先用户发送请求给前端控制器,前端控制器根 ...

  10. Spring Boot 运行原理

    Spring Boot并没有任何新的技术,全都是基于Spring4提供的技术,用优秀的设计,为Web开发提供了一套新的方式. 在HelloWorld中,我们没有进行任何显示的配置,但是程序还是运行起来 ...

随机推荐

  1. Exce 快捷键 tips

    1. 填充快捷键 ctrl+R  向下填充 CTRL+D 向右填充 2. 筛选快捷键 CTRL+SHIFT+L 3. 移动到当前区域的边缘: Ctrl + shift + 方向箭头 4. 字符连接:& ...

  2. 如何用jquery获取form表单的值

    $(function(){ $('.btn').click(function(){ alert($('#form').serialize()); }) }) 这样就获取到了 #form的值.

  3. Java并发编程随笔

    死锁:两个线程互相等待对方释放锁才可以继续运行. 避免死锁的常见方法: 1.避免一个线程同时获取多个锁 2.避免一个线程在锁内同时占用多个资源,尽量保证一个锁只占用一个资源 3.尝试使用定时锁,使用l ...

  4. ReactiveX 学习笔记(25)使用 RxJS + Vue.js 调用 REST API

    JSON : Placeholder JSON : Placeholder (https://jsonplaceholder.typicode.com/) 是一个用于测试的 REST API 网站. ...

  5. Redis 数据类型归纳

    Redis的数据类型从整体上看,都是Key-Value键值对的模型,数据类型更确切地说,应该是Value的数据类型,比如string,set,list等,都是key值对应的Value的数据集合格式.不 ...

  6. StreamReader和StreamWriter说明

    StreamReader/StreamWriter操作的是字符数据(char),而FileStream操作的是字节数据(byte) FileStream与StreamXXXX类的默认编码都是UTF8, ...

  7. Grafana报警--通知渠道配置

    最近研究了prometheus+grafana的系统监控,使用grafana的报警功能,grafana支持很多种通知渠道,下文记录使用到的几种notification channels,分别是emai ...

  8. Pycharm配置支持vue语法

    1. 2. 3. 4. 5.

  9. C++读取与保持图片

    #include<iostream> using namespace std; void main(void) { //保存输入图像文件名和输出图像文件名 ]; ]; //图像数据长度 i ...

  10. gb2312,gbk,utf8的区别

    GB2312编码大约包含6000多汉字(不包括特殊字符),编码范围为第一位b0-f7,第二位编码范围为a1-fe(第一位为cf时,第二位为a1-d3),计算一下汉字个数为6762个汉字.当然还有其他的 ...