当前位置: 首页 > 后端技术 > Java

MVCSpring核心原理九大组件解析(一)

时间:2023-04-01 21:06:06 Java

本文节选自《Spring 5核心原理》1什么是SpringMVCSpringMVC是Spring提供的基于MVC设计模式的轻量级Web开发框架,本质上等同于小服务程序。SpringMVC角色分工明确,分工细化。由于SpringMVC本身就是Spring框架的一部分,可以说是与Spring框架无缝集成。在性能方面,它具有先天优势。它是当今业界最主流的Web开发框架和最流行的开发技巧。首先从Spring提供的一个DispatcherServlet入手,重写Serlvet的init()方法、service()方法和destroy()方法。SpringMVC的九个组件在DispatcherServlet的init()方法中初始化,在service()方法中初始化。实施。接下来我们先来看一下SpringMVC的九个组件的初始化。2SpringMVC九大组件名称解释SpringMVC的九大组件都是在DispatcherServlet的init()方法中初始化的。下面详细介绍一下SpringMVC的九大组件的名称和作用。序号组件名称说明1MultipartResolver用于处理多个文件上传请求。2LocaleResolver用于解析请求中的Locale,是i18n的基础。3ThemeResolver用于解析样式、图片的集合及其形成的显示效果。4HandlerMapping保存Url与逻辑处理的映射关系,5HandlerAdapter动态参数适配器,让固定的Servlet处理方法调用Handler进行处理6HandlerExceptionResolver用于处理Handler产生的异常情况。7RequestToViewNameTranslator从请求中获取ViewName8ViewResolvers主要作用是将String类型视图名和Locale解析成View类型视图9FlashMapManager用于重定向时传递参数。具体如下:2.1MultipartResolverMultipartResolver是大家比较熟悉的处理上传请求的组件,它是通过将普通请求封装成MultipartHttpServletRequest来实现的。MultipartHttpServletRequest可以直接通过getFile()方法获取文件。如果上传多个文件,也可以调用getFileMap()方法获取类似Map的结构。MultipartResolver的作用是对普通请求进行封装,使其具有文件上传的功能。2.2LocaleResolverResolver组件的resolveViewName()方法需要两个参数,一个是视图名称,一个是Locale。Locale参数从何而来?这就是LocaleResolver组件的作用。LocaleResolver用于从请求中解析Locale。比如在中国,Locale当然是zh-CN,用来表示一个地区。该组件也是i18n的基础。2.3ThemeResolver顾名思义,ThemeResolver组件就是用来解析主题的。主题是样式、图像及其形成的显示效果的集合。SpringMVC中的一套主题对应一个属性文件,里面存放了与当前主题相关的所有资源,比如图片、CSS样式等。创建一个主题很简单,只要准备好资源,然后创建一个新的“主题”name.properties”并在里面设置资源,放到classpath下,就可以在页面中使用了。SpringMVC中与主题相关的类有ThemeResolver、ThemeSource和Theme。ThemeResolver负责从请求中解析出主题名称,ThemeSource根据主题名称找到具体的主题。它的抽象是Theme,可以通过Theme获取主题和具体的资源。2.4HandlerMappingHandlerMapping用于查找Handler,即处理器。具体的表现形式可以是一个类,也可以是一个方法。比如每一个用@RequestMapping标记的方法都可以看成是一个Handler。Handler负责实际的请求处理。请求到达后,HandlerMapping的作用就是找到请求对应的处理器Handler和Interceptor。2.5HandlerAdapter从名字上看,HandlerAdapter是一个适配器。因为SpringMVC中的Handler可以是任何形式,只要能处理请求即可。但是当请求交给Servlet时,由于Servlet的方法结构是doService(HttpServletRequestreq,HttpServletResponseresp)的形式,所以需要让固定的Servlet处理方法调用Handler进行处理。这一步是HandlerAdapter必须做的。2.6HandlerExceptionResolver从组件的名字看,HandlerExceptionResolver是一个用来处理Handler产生的异常的组件。具体来说,这个组件的作用就是根据异常设置ModelAndView,然后交给渲染方法进行渲染。呈现方法会将ModelAndView呈现到页面中。但是需要注意的是,HandlerExceptionResolver只是用来解决请求处理阶段产生的异常,渲染阶段的异常不受其控制。这也是SpringMVC组件设计的一大原则——分工明确,互不干扰。2.7RequestToViewNameTranslatorRequestToViewNameTranslator组件的作用是从请求中获取ViewName。因为ViewResolver是根据ViewName找到View的,但是经过一些Handlers处理后,View和ViewName都没有设置,所以这个组件就是用来从请求中找到ViewName的。2.8ViewResolverViewResolver就是视图解析器,相信大家对这个组件应该不陌生。通常在SpringMVC的配置文件中,会添加一个实现类,用于视图解析。该组件的主要功能是将String类型的视图名称和Locale解析成View类型的视图,只有一个resolveViewName()方法。从方法的定义可以看出,Controller层返回的String类型的视图名viewName,最终会在这里解析成View。View是用来渲染页面的,也就是说,它将程序返回的参数和数据填充到模板中,生成一个HTML文件。ViewResolver在这个过程中主要做了两件大事:ViewResolver会找到用于渲染的模板(第一件大事)和使用的技术(第二件大事,其实就是寻找view的类型,比如JSP)并填写参数。默认情况下,SpringMVC会自动为我们配置一个InternalResourceViewResolver,它是针对JSP类型视图的。2.9FlashMapManager说到FlashMapManager组件,首先要说的就是FlashMap。FlashMap用于重定向时的参数传递。比如在处理用户订单时,为了避免重复提交,可以在处理完post请求后重定向到一个get请求。此获取请求可用于显示订单详细信息等信息。这样虽然可以避免用户重新提交订单的问题,但是订单的信息应该显示在这个页面上,数据从哪里获取呢?因为重定向没有传递参数的功能,如果不想把参数写到URL中(其实不推荐这样做,只是URL有长度限制,直接暴露参数不安全),然后你可以通过FlashMap传递它们。只需要在重定向前将要传递的数据写入请求的属性OUTPUT_FLASH_MAP_ATTRIBUTE(可通过ServletRequestAttributes.getRequest()方法获取),这样Spring会在重定向后自动设置到Handler中的Model中,并显示数据可以直接从订单信息页面的模型中获取。FlashMapManager用于管理FlashMap。3SpringMVC关键组件的执行过程SpringMVC的九大组件的执行都是在DispatcherServlet的service()方法中完成的。在这里,我将重点介绍几个关键组件HandlerMapping、HandlerAdapter、ViewResolver在service()方法中的执行过程。具体调用分为以下几个步骤:1.HandlerMapping返回调用HandlerAdapter2,HandlerAdapter会返回ModelAndView3。ModelAndView根据用户传入的参数得到ViewResolvers4,ViewResolvers会将用户传入的参数封装成一个View,交给引擎进行渲染。给大家分享一个SpringMVC关键组件的执行流程图,帮助大家更好的理解:注:上图中有两个类大家最熟悉:ModelAndView和View类不属于九大类SpringMVC列表的组件。4SpringMVC优化建议我们分析了SpringMVC的工作原理和源码,在这个过程中有几个优化点。1.如果Controller可以保持单例模式,尽量使用单例模式,减少创建和回收对象的开销。也就是说,如果Controller的类变量和实例变量可以用方法参数声明,尽量用方法参数声明,而不是类变量和实例变量,这样可以避免线程安全问题。2、请求处理方法中的形参必须使用@RequestParam注解,防止SpringMVC使用asm框架读取.class文件获取方法参数名。即使SpringMVC缓存了读取的方法参数名,如果不能读取.class文件就更好了。3、缓存URL在阅读源码的过程中,我们发现SpringMVC并没有缓存URL处理的方法,即每次需要根据请求URL去匹配Controller中方法的URL,如果URL和method的关系被缓存,会不会带来性能的提升?不幸的是,负责解析URL和方法之间关系的ServletHandlerMethodResolver是一个私有的内部类,继承这个类不能直接增强代码,代码之后必须重新编译。当然,如果缓存了URL,就要考虑缓存的线程安全问题。关注微信公众号『汤姆炸弹架构』,回复“Spring”获取完整源码。本文为《汤姆炸弹建筑》原创,转载请注明出处。科技在于分享,我分享我的快乐!如果大家有什么建议,也可以留言或者私信。您的支持是我坚持创作的动力。关注微信公众号『汤姆炸弹建筑』,获取更多技术干货!原创不易,坚持很酷,看到这里了,小伙伴们记得点赞、收藏、观看、加关注哦!如果觉得内容太干,可以分享转发给身边的朋友一起滋润哦!