SpringMVC运行时序图解析

本文详细解析了SpringMVC的工作流程,包括DispatcherServlet作为前端控制器的角色,HandlerMapping的URL到Controller映射,Controller的请求处理,以及视图解析。文章还探讨了SpringMVC初始化时如何建立URL和Controller的关系,以及请求处理阶段的详细步骤,如参数绑定和方法调用。最后,概述了Spring MVC核心组件的关联关系。
摘要由CSDN通过智能技术生成

《Spring in Action》一书中 ,Spring MVC 的核心组件和大致处理流程如下:在这里插入图片描述
①、DispatcherServlet 是SpringMVC 中的前端控制器(Front Controller),负责接收Request 并将Request 转发给对应的处理组件。
② 、HanlerMapping 是SpringMVC 中完成url 到Controller 映射的组件。DispatcherServlet 接收Request, 然后从HandlerMapping 查找处理Request 的Controller。
③、Controller 处理Request,并返回ModelAndView 对象,Controller 是SpringMVC中负责处理Request 的组件(类似于Struts2 中的Action),ModelAndView 是封装结果视图的组件。
④、⑤、⑥视图解析器解析ModelAndView 对象并返回对应的视图给客户端。容器初始化时会建立所有url 和Controller 中的Method 的对应关系,保存到HandlerMapping 中,用户请求是根据Request 请求的url 快速定位到Controller 中的某个方法。在Spring 中先将url 和Controller 的对应关系,保存到Map<url,Controller>中。Web 容器启动时会通知Spring 初始化容器(加载Bean 的定义信息和初始化所有单例Bean),然后SpringMVC 会遍历容器中的Bean,获取每一个Controller 中的所有方法访问的url,然后将url 和Controller 保存到一个Map中;这样就可以根据Request 快速定位到Controller,因为最终处理Request 的是Controller 中的方法,Map 中只保留了url 和Controller 中的对应关系,所以要根据Request 的url 进一步确认Controller 中的Method,这一步工作的原理就是拼接Controller 的url(Controller 上@RequestMapping 的值) 和方法的url(Method 上@RequestMapping 的值),与request 的url 进行匹配,找到匹配的那个方法;确定处理请求的Method 后,接下来的任务就是参数绑定,把Request 中参数绑定到方法的形式参数上,这一步是整个请求处理过程中最复杂的一个步骤。
先来看一 张图,DispatcherServlet和HttpServlet的继承关系:
在这里插入图片描述
众所周知,SpringMVC的入口是DispatcherServle,而DispatcherServle继承了 FrameworkServlet, FrameworkServlet继承了 HttpServletBean, HttpServletBean继承了 HttpServlet, HttpServletBean的init方法如下:
在这里插入图片描述
在 HttpServletBean的init 方法中调用了子类FrameworkServlet的 initServletBean方法:
org.springframework.web.servlet.FrameworkServlet#onRefresh在这里插入图片描述
在 initServletBean方法中初始化 WebApplicationContext实例, 并调用了onRefresh方法
在这里插入图片描述
而org.springframework.web.servlet.FrameworkServlet的 onRefresh只是一个抽象的定义,它的实现其实是在DispatcherServlet 重写的
onRefresh方法。在 DispatcherServlet 的 onRefresh0方法中又调用了 initstrategies0方法,初始化 SpringMVC的九大组件,到这里SpringMVC初始化完成。
在这里插入图片描述
上面复杂的调用关系,一句话总结就是在 Servlet的 init() 方法中初始化了IOC容器和SpringMVC的九大组件,流程概括如下:
在这里插入图片描述
那么,URL和Controller之间的关系是如何建立的呢? HandlerMapping是个接口。先来看一下HandlerMapping 的实现类,会看到一个AbstractDetectingUrlHandlerMapping,可以看到其实现了ApplicationContextAware,在Spring容器会检测容器中的所有Bean,如果发现某个Bean实现了ApplicationContextAware接口,Spring容器会在创建该Bean之后,自动调用该Bean的setApplicationContextAware()方法。看看他的类图再慢慢去寻找这个触发点。
在这里插入图片描述
会在ApplicationObjectSupport 发现了这个方法,继而调用到了HandlerMapping 的子类AbstractDetectingUrlHandlerMapping 中的initApplicationContext()方法,所以我们直接看子类中的初始化容器方法:

//建立当前ApplicationContext 中的所有Controller 和url 的对应关系
protected void detectHandlers() throws BeansException {
   
        ApplicationContext applicationContext = obtainApplicationContext();
        if (logger.isDebugEnabled()) {
   
            logger.debug("Looking for URL mappings in application context: " + applicationContext);
        }
        // 获取ApplicationContext 容器中所有bean 的Name
        String[] beanNames = (this.detectHandlersInAncestorContexts ?
                BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :
                applicationContext.getBeanNamesForType(Object.class));

        // Take any bean name that we can determine URLs for.
        // 遍历beanNames,并找到这些bean 对应的url
        for (String beanName : beanNames) {
   
            // 找bean 上的所有url(Controller 上的url+方法上的url),该方法由对应的子类实现
            String[] urls = determineUrlsForHandler(beanName);
            if (!ObjectUtils.isEmpty(urls)) {
   
                // URL paths found: Let's consider it a handler.
                // 保存urls 和beanName 的对应关系,put it to Map<urls,beanName>,
                // 该方法在父类AbstractUrlHandlerMapping 中实现
                registerHandler(urls, beanName);
            }
            else {
   
                if (logger.isDebugEnabled()) {
   
                    logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");
                }
            }
        }
}

    /** 获取Controller 中所有方法的url,由子类实现,典型的模板模式**/
protected abstract String[] determineUrlsForHandler(String beanName);

determineUrlsForHandler(String beanName)方法的作用是获取每个Controller 中的url,不同的子类有不同的实现,这是一个典型的模板设计模式。因为开发中我们用的最多的就是用注解来配置Controller 中的url , Be

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值