欢迎光临散文网 会员登陆 & 注册

Spring MVC之初始化

2022-05-14 17:35 作者:做架构师不做框架师  | 我要投稿


什么是SpringMVC?SpringMVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过把Model,View,Controller分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。

工作流程

大致流程如下:

  1. 用户发起请求一个url到中央控制器

  2. 中央控制器接收到请求后调用处理器映射器以获取相应的处理器(即controller)

  3. 处理器映射器返回处理器的位置给中央控制器

  4. 中央控制器调用处理器适配器获取到指定的处理器(即controller)

  5. 处理器适配器把请求交给指定的处理器执行请求

  6. 处理器执行完业务逻辑后,返回数据和视图给处理器适配器

  7. 处理器适配器把数据和视图返回给中央处理器

  8. 中央处理器请求视图解析器进行视图解析

  9. 视图解析器解析相应的视图并返回给中央控制器

  10. 中央控制器通过view将数据和模型填充到视图中

  11. view渲染完视图后返回给中央控制器

  12. 中央控制器把结果响应给用户

九大组件

  • MultipartResolver:文件处理器,用于处理上传请求,通过将普通的 Request 包装成MultipartHttpServletRequest来实现。MultipartHttpServletRequest 可以通过 getFile() 直接获得文件,如果是多个文件上传,还可以通过调用 getFileMap 得到 Map<FileName, File> 这样的结构。MultipartResolver 的作用就是用来封装普通的 request,使其拥有处理文件上传的功能。

  • LocaleResolver: 当前环境处理器,ViewResolver的 resolveViewName()方法,需要两个参数。那么第 二个参数 Locale 是从哪来的呢,这就是 LocaleResolver 要做的事了。LocaleResolver 用于从 request 中解析出 Locale, 在中国大陆地区,Locale 当然就会是 zh-CN 之类, 用来表示一个区域。这个类也是 i18n 的基础。

  • ThemeResolver:主题处理器,主题,就是样式,图片以及它们所形成的 显示效果的集合。Spring MVC 中一套主题对应一个 properties 文件,里面存放着跟当 前主题相关的所有资源,如图片,css 样式等。创建主题非常简单,只需准备好资源,然 后新建一个 "主题名.properties" 并将资源设置进去,放在 classpath 下,便可以在页面中跟主题有关的类有 ThemeResolver, ThemeSource 和 Theme。ThemeResolver 负责从 request 中解析出主题名, ThemeSource 则根据主 题名找到具体的主题, 其抽象也就是 Theme, 通过 Theme 来获取主题和具体的资源。

  • HandlerMApping:处理器映射器,是用来查找 Handler 的,也就是处理器,具体的表现形式可以是类也可以是方法。比如,标注了@RequestMApping 的每个 method 都可以看成是一个 Handler,由 Handler 来负责实际的请求处理。HandlerMApping 在请求到达之后, 它的作用便是找到请求相应的处理器 Handler 和 Interceptors。

  • HandlerAdapters:处理器适配器,因为 Spring MVC 中 Handler 可以是任意形式的,只要能够处理请求便行, 但是把请求交给 Servlet 的时候,由于 Servlet 的方法结构都是如 doService(HttpServletRequest req, HttpServletResponse resp) 这样的形式,让固定的 Servlet 处理方法调用 Handler 来进行处理,这一步工作便是 HandlerAdapter 要做的事。

  • HandleExceptionResolvers:异常处理器,用来处理 Handler 过程中产生的异常情况的组件。具体来说,此组件的作用是根据异常设置 ModelAndView, 之后再交给 render()方法进行渲染 ,而 render() 便将 ModelAndView 渲染成页面。不过有一点,HandlerExceptionResolver 只是用于解析对请求做处理阶段产生的异常,而渲染阶段的异常则不归他管了,这也是 Spring MVC 组件设计的一大原则分工明确互不干涉。

  • RequestToViewNameTranslator:视图名称翻译器,从 Request 中获取 viewName.。因为 ViewResolver 是根据 ViewName 查找View, 但有的 Handler 处理完成之后,没有设置 View 也没有设置 ViewName, 便要通过这个组件来从 Request 中查找 viewName。

  • ViewResolvers:页面渲染处理器,因为通常在 SpringMVC 的配置文件中, 都会配上一个该接口的实现类来进行视图的解析。这个组件的主要作用,便是将 String 类型的视图名和Locale解析为View类型的视图。这个接口只有一个resolveViewName() 方法。从方法的定义就可以看出,Controller 层返回的 String 类型的视图名 viewName, 最终会在这里被解析成为 View。View 是用来渲染页面的,也就是说,它会将程序返回的参数和数据填入模板中,最终生成 html 文件。ViewResolver 在这个过程中,主要做两件大事,即,ViewResolver 会找到渲染所用的模板(使用什么模板来渲染?)和所用的技术(其实也就是视图的类型,如 JSP )填入参数。默认情况下,Spring MVC 会为我们自动配置一个 InternalResourceViewResolver,这个是针 对 JSP 类型视图的。

  • FlashMapManager:参数传递管理器说到 FlashMapManager,就得先提一下 FlashMap。FlashMap 用于重定向 Redirect 时的参数数据传递,比如,在处理用户订单提交时,为了避免重复提交,可以处理完 post 请求后 redirect 到一个 get 请求,这个 get 请求可以 用来显示订单详情之类的信息。这样做虽然可以规避用户刷新重新提交表单的问题,但是在这个页面上要显示订单的信息,那这些数据从哪里去获取呢,因为 redirect 重定向是没有传递参数这一功能的,如果不想把参数写进 url(其实也不推荐这么做,url 有长度限制不说,把参数都直接暴露,感觉也不安全), 那么就可以通过 flashMap 来传递。只需要在 redirect 之前,将要传递的数据写入 request( 可以通过 ServletRequestAttributes.getRequest() 获 得)的属性 OUTPUT_FLASH_MAP_ATTRIBUTE 中,这样在 redirect 之后的 handler 中 Spring 就会自动将其设置到 Model 中,在显示订单信息的页面上,就可以直接从 Model 中取得数据了。而 FlashMapManager 就是用来管理 FlashMap 的。

demo

下面这个图是我从网上找的一个入门配置,DispatcherServlet在SpringMVC中是集中访问点,负责分派调度工作。因此我们需要告诉Web容器,我们将使用DispatcherServlet,并将URL映射到DispatcherServlet。在这里我们会通过“init-param”配置项进行初始一些参数,比如:HandlerMApping类、HandlerAdapter、ViewResolver等。接下来我们会讲解MVC是如何初始化的。


注意:本文是以5.2.3版本为讲解。

步骤一:初始化


通过DispatcherServlet类图,看到他继承HttpServlet类,我们上学时学过Servlet类的初始化方法是init()方法,然后我们发现其iinit方法其实在父类HttpServletBean中。大致业务如下:

  • 从初始化参数设置 bean 属性

  • 委派给子类进行初始化

步骤二:初始化WebApplicationContext

HttpServletBean的重写方法,在设置任何bean属性后调用。创建当前servlet的WebApplicationContext。

步骤三:初始化IOC容器

这个方法大致业务如下:

  • 初始化IOC容器(比如)

  • 调用onRefresh:刷新上下文,这个方法是一个模板方法,被子类重写来添加特定于servlet的业务。

步骤四:初始化策略对象

在这个方法里会把九大组件进行初始化,在这里我们着重看下initHandlerMApping方法,在这里会初始化url与controller的关系。

步骤五:初始化HandlerMAppings

如果BeanFactory中没有在namespace指定HandlerMApping,则默认为BeanNameUrlHandlerMApping。

步骤六:初始化容器

BeanNameUrlHandlerMApping类继承AbstractDectingUrlHandlerMApping类,在这个类里有个“initApplicationContext”的方法,业务逻辑如下:

  • initAppliicationContext:初始化父类容器,诸如各种拦截器

  • detectHandlers:注册在当前 ApplicationContext 中找到的所有url和controller的对应关系

步骤七:注册当前ApplicationContext中找到的所有url和controller的对应关系

业务逻辑如下:

  • obtainApplicationContext:获取当前ApplicationContext

  • 获取ApplicationContext容器中所有的beanName

  • determineUrlsForHandler:确定给定处理程序 bean 的 URL,该方法在当前类是一个抽象方法,具体是由BeanNameUrlHandlerMApping类来实现的

  • registerHandler:为指定的 URL 集合注册指定的处理器

步骤八:确定指定处理程序bean的URL

步骤九:循环遍历URL注册到指定的处理器

步骤十:为给定的URL注册指定的处理器

这个方法很简单,就是把给定的URL注册到handlerMap中

时序图

写在最后

好兄弟可以点赞并关注我的公众号“javaAnswer”,全部都是干货。


Spring MVC之初始化的评论 (共 条)

分享到微博请遵守国家法律