zoukankan      html  css  js  c++  java
  • springMVC源码解读笔记

    1: DispatcherServlet 的初始化流程(调用的init方法)
    a) 初始化spring高级容器,WebApplicationContext(容器初始化12个步骤)
    Servlet类的init方法----GenericServlet类的init()---HttpServletBean类的init()--initServletBean()这个方法是FrameworkServlet类实现的---initWebApplicationContext()初始化wbc容器方法--
    a.1) this.configureAndRefreshWebApplicationContext(cwac); 配置并刷新容器方法---wac.refresh();----AbstractAoolicationContext类的 refresh()方法, 该方法中有12个步骤,具体看 https://blog.csdn.net/u011151359/article/details/98496427
    经过这12个步骤之后, 容器创建完成
    a.2) this.onRefresh(wac);---DispatcherServlet类的onRefresh()--this.initStrategies(context);这里是模板方法模式,有一些策略集合方法供子类实现
    b) 初始化DispatcherServlet类需要的一些策略集合(比如: 初始化多部件解析器,初始化国际化解析器,初始化主题解析器,初始化处理器映射器,初始化处理器适配器,初始化异常解析器,初始化视图解析器..), 这里只关注 处理器映射器,处理器适配器. 初始化处理器映射器代码中, 先从所有祖宗容器中获取所有的HandlerMapping, 如果获取不到,当前容器中根据"handlerMapping" 来获取HandlerMapping, 并返回完成初始化, 如果这二步都没有获取到处理器映射器(HandlerMapping), 此时有一个兜底代码: 获取默认的处理器映射器(即: 从默认的配置文件:DispatcherServlet.properties 中读取处理器映射器), 同理, 初始化处理器适配器的代码中,先从所有祖宗容器中获取所有handlerAdapter, 没有, 从当前容器中根据"handlerAdapter"获取处理器适配器, 有就返回,如果没有,也是一个兜底的代码, 从默认的DispatcherServlet.properties 中获取处理器适配器

    这里有个面试题: springmvc 如果没有在springmvc.xml中配置处理器映射器和处理器适配器,是否可以正常处理请求??
    这里需要知道springmvc处理请求的11个步骤,并且没有处理器映射器, 处理器适配器,是不行的, 还要知道springmvc有一个兜底策略,从默认的配置文件中加载默认的处理器适配器, 处理器映射器

    2: DispatcherServlet的处理请求的流程(调用的 service方法)
    a) 从Servlet类的service方法,---到doGet/doPost方法--到FrameworkServlet类的processRequest()方法--到doService()方法-- 到DispatcherServlet的doService方法--doDispatch()方法
    b) DispatcherServlet类的核心方法就是doDispatch()

    上面说到DispatcherServlet初始化时候, 会有一个兜底的策略, 从默认配置文件 DispatcherServlet.properties,加载处理器映射器(RequestMappingHandlerMapping),处理器适配器(RequestMappingHandlerAdapter), 接下来看看这二个处理器的初始化方法...

    RequestMappingHandlerMapping的初始化方法: 1: 看xml文件中的是否有标签 2: 看该对象是否有实现InitializingBean接口,有的话,afterPropertiesSet() 这个方法就是对象的初始化方法.
    而RequestMappingHandlerMapping 是实现了InitializingBean接口, afterPropertiesSet()---initHandlerMethods();---processCandidateBean(beanName);---detectHandlerMethods(beanName);---getMappingForMethod(method, userType);这个方法是将Controller类上的 RequestMapping注解和方法上的注解拼接起来,url. registerHandlerMethod(handler, invocableMethod, mapping);这二个方法是组装了二个map
    在该方法中,组装了二个map: mappingLookup(key:RequestMappingInfo , value:handlerMethod) urlLookup(key:url, value:RequestMappingInfo 这里是一个url对应多个映射关系, 这里是基于rest风格的请求, 一个url因为 请求的method(get,post..)不同,从而访问不同的Controller方法)
    如图所示:


    处理器映射器的目的是能够根据 url找到对应的Controller方法, 这就需要以上二个map来实现精准匹配,, 这里的映射关系映射好了后,接下来就是处理

    RequestMappingHandlerMapping的处理流程: 在DispatcherServlet类中doDispatch()方法中, 有mappedHandler = this.getHandler(processedRequest);----mapping.getHandler(request);这个方法返回的是一个处理器执行器调用链HandlerExecutionChain(里面包含一个Handler 和多个interceptors)----之后根据这个Handler找到对应的处理器适配器HandlerAdapter,---ha.handle() 这个方法返回了ModelAndView---this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException); 这个方法是处理DispatcherServlet的结果
    RequestMappingHandlerAdapter, 可以看到这个类也实现了InitializingBean接口, 所以初始化,直接看 afterPropertiesSet()实现即可 ,

    用户向服务器发送请求,请求会到DispatcherServlet,DispatcherServlet 对请求URL进行解析,得到请求资源标识符(URI),然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括一个Handler处理器对象、多个HandlerInterceptor拦截器对象),最后以HandlerExecutionChain对象的形式返回。
      DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:

    HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
    数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
    数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
    数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
      Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;根据返回的ModelAndView,选择一个适合的ViewResolver返回给DispatcherServlet;ViewResolver 结合Model和View,来渲染视图,最后将渲染结果返回给客户端。

    ==========================================================================
    SpringMVC容器的初始化过程: 首先我们从web.xml中开始, 在web.xml中配置contextLoaderListener, 他的作用是启动web容器时候,自动装配ApplicationContext的配置信息, 因为ContextLoaderListener实现了ServletContextListener接口,所以容器启动的时候,会自动执行ContextInitialized()方法, 这样就能够在客户群请求之前想 ServletContext中添加任意对象,

    contextLoaderListener初始化核心逻辑就是,执行ServletContextListener的 contextInitialized()方法 ----contextInitialized(),该方法中判断context是否为null, 为null就创建context容器 ---createWebApplicationContext()---this.determineContextClass(sc)中,先根据传进来的容器servletContext(这里的servletContext, tomcat启动时候回创建ServletContext上下文环境对象,之后读取web.xml,首先读取这二个标签, 也就是说优先从web.xml中获取配置的"contextClass"对应的全限定类名),获取全限定类名使用反射,创建容器, 如果创建为null, 这里也有一个兜底的代码,从默认的defaultStrategies中获取全限定类名,之后反射创建容器对象. defaultStrategies这个就是默认的配置文件映射成的对象, 在静态代码块中有读取配置文件ContextLoader.properties而来, 也就是不管你赔不配置,最终都会有默认的容器生成

    创建了容器之后,有一个配置刷新Web容器的方法--this.configureAndRefreshWebApplicationContext(cwac, servletContext); --这个方法中先是配置容器属性, 之后又个刷新方法--wac.refresh()
    关于refresh()的解析
    https://blog.csdn.net/u011151359/article/details/98496427
    经过这12个步骤之后, 容器创建完成

    refresh()中obtainFreshBeanFactory()方法解析: 这个方法是refresh()的核心之一: 该方法中做了二件事: 1, refreshBeanFactory():将xml转换为BeanDefinition,存入BeanFactory中, 创建beanFactory、指定序列化Id、定制beanFactory、加载bean定义
    2, getBeanFactory():返回beanFactory实例

    总结:
    1: DispatcherServlet 前端控制器,作用:接受请求,然后分发请求给对应的处理组件
    2: HandlerMapping , 处理器映射器, 作用是将请求,和Controller方法 建立映射关系, 并返回 处理执行调用链对象(一个Handler, 多个HandlerInterceptor)
    3: HandlerAdapter , 根据这个Handler获取对应的 处理这个请求的Controller, Controller处理完请求后,返回ModelAndView
    4: ViewResolver ,视图解析器, 解析ModelAndView,返回对应的视图给前端

    SpringMVC, 先从DispatcherServlet的初始化流程(init), 之后是DispatcherService的处理请求流程(service)

    先从DispatcherServlet的初始化流程(init):
    DispatcherServlet这个类,
    FrameworkServlet, 这个类作用有2个: 1,创建WebApplicationContext容器, 2, 初始化一些策略集合(比如,文件解析器, 初始化多部件解析器,初始化国际化解析器,初始化主题解析器,初始化处理器映射器,初始化处理器适配器,初始化异常解析器,初始化视图解析器..) 初始化策略集合的实现 是在DispatcherServlet中完成的
    AbstractApplicationContext: 这个类作用是 配置和刷新容器(12个步骤)

    DispatcherService的处理请求流程(service方法):
    HttpServlet类: 作用是 处理请求(里面有 doGet() , doPost() )
    FrameworkServlet类: 处理请求, doService()
    DispatcherServlet类; doDispatch() 找到请求对应的Controller,分发给他处理请求,返回ModelAndView

  • 相关阅读:
    background image position问题
    yii 验证器和验证码
    laravel 模板 blade
    tbody添加垂直滚动条
    转:jquery选择器总结
    jquery ajax传递数组给php
    jquery serialize()、serializearray()已经$.param方法
    php stdClass Object 问题
    Codeforces Round #274 (Div. 2) E. Riding in a Lift(DP)
    HTTP协议具体解释
  • 原文地址:https://www.cnblogs.com/lvcai/p/13357907.html
Copyright © 2011-2022 走看看