SpringMVC工作原理

先上图,看图说话:
 
0
一、SpringMVC的几大核心组件
  前端控制器(DispatcherServlet)、用户控制器(Controller)、处理器映射器(HandlerMapping)、处理器适配器(HandlerAdapter)、视图解析器(ViewResolver)。
  分别解释:
二、前端控制器
  DispatcherServlet 的本质就是一个:和 SpringMVC 程序同时启动的 Servlet。
  SpringMVC 中的控制器有 2 类:
  • 中央控制器,或叫前端控制器:由SpringMVC框架提供,截获所有请求并进行分流;
  • 用户控制器,或叫响应控制器:由开发者编写,用来响应用户的具体请求。如登录请求、注册请求……
0
  DispatcherServlet是 SpringMVC 中最核心的组件,相当于整个程序中的指挥调度中心。其它的组件都是它的附庸,为前端控制器提供相关的服务。
  DispatcherServlet 的基本功能:
1.1 分流请求
  浏览器向 SpringMVC 程序发起的所有请求都会汇总给 DispatcherServlet ,再由它分流到具体的用户控制器。为什么要将所有请求集中后再分流?
  • 安全: 如同去拜访某一个公司,所有的访客都要经过前台工作人员筛选、登记、确认后才会被引导到具体的会客室。Web程序也是如此,要确保有且仅有一个入口能进入程序;
  • 标准: 将所有请求以相同的方式进行分流处理。比如某个公司,如果对每一个访客没有统一的接待标准,一定会产生额外的工作量。同理,一个统一、协调、标准化的项目,可以做到简洁又高效。
1.2 调度中心
  一次请求、响应的完成,需要多个组件通力合作。如何协调各个组件,保证请求、响应过程有条不紊的进行,就需要一个指挥者或者说一个核心灵魂。DispatcherServlet 就是每一次请求、响应过程的组织者、调度者。
 
三、 用户控制器(Controller)
  用户控制器(也称请求处理器、用户处理器)一般由用户自定义编写,负责处理、响应用户具体的请求。如果说前端控制器是程序的大门,那么用户控制器就是具体的洽谈部门。
  第一步:编写控制器,比如:
复制代码
1 public class IndexController extends AbstractController {
2     @Override
3     protected ModelAndView handleRequestInternal (
4            HttpServletRequest req, HttpServletResponse resp)throws Exception {
5         System.out.println("Hello,SpringMVC!");
6         ModelAndView index = new ModelAndView("index");
7         return index;
8     }
9 }
复制代码

 

  第二步:映射控制器
  在原生 Servlet 开发中,需要在 web.xml 中注册、映射 Servlet 后(Servlet3.0后可以使用@WebServlet注解进行映射),浏览器才能请求到它。类似的,基于SpringMVC的 WEB 项目,也可以在类前面添加@Controller 注解,作用就是通知SpringMVC的上下文对象(WebApplicationContext),控制器的创建工作交给你了!
复制代码
 1 //第1步:添加@Controller注解
 2 @Controller
 3 public class UserController{
 4     //第2步:在控制器的方法上添加 @RequestMapping 注解。将用户的请求url映射到此方法上。
 5     @RequestMapping("/hello")
 6     public String welcome() {
 7         System.out.pirntln("hello");
 8         return "hello";
 9     }
10 }
复制代码

 

  第三步:在Spring的配置文件中开启对@controller注解的支持:
1 <!--开启spring的组件扫描-->
2 <context:component-scan base-package="com.spring.controller"/>
3 <!--开启SpringMVC的注解驱动。通过此标签,可以自动注册处理器映射对象    DefaultAnnotationHandlerMapping和处理器适配器对象AnnotationMethodHandlerAdapter,
4 SpringMVC会通过这两个Bean来实现对@Controllert和@RequestMapping的支持-->
5 <mvc:annotation-driven/>

  此时如果运行项目会报错404,因为还没有告诉SpringMVC:当控制器要响应浏览器的请求时,如何找到视图页面,这是视图解析器组件的工作。

 

四、处理器映射器
  可以将HandlerMapping理解为一个 Map<url,handler>,负责根据用户的请求URL查找处理器Handler,SpringMVC提供了不同的处理器来实现不同的映射方式。
  简单来说,处理器映射器的作用就是检查用户的请求路径中是否存在对应的控制器组件。有点类似于商场的导购员,消费者报一个商品名,然后导购员会告诉你商品所在的真正位置。
0
 
  而处理器Handler,一般就是程序中我们编写的Controller,即上文所说的后端控制器或用户控制器。
  使用 SpringMVC 时,如果开发者没有显式的配置处理器映射器,它会启动默认的映射器组件:
  • BeanNameUrlHandlerMapping :按照Bean的名字查找和用户的请求路径相匹配的处理器。
  • RequestMappingHandlerMapping :查找由 @RequestMapping 注解映射的处理器。
  无论使用哪一种,理论上都无需显式的配置。SpringMVC会根据你的请求信息选择对应的映射器。显然, @RequestMapping 映射更直观,所以它使用的更多。
 
 
五、处理器适配器
  首先,什么是适配器?其实我们可能天天都在用,比如电源适配器:将源电流电压转换为适合不同电器的电流电压。如下图。
0
  同理,程序中的适配器的本质也是运用适配器设计模式、匹配不兼容的接口规范。比如调用者只能识别接口2类型,但是A提供的是接口1类型。适配器就可以把接口1转换成接口2。这样使用者就能使用A 提供的功能了。如下图。
0
 
  HandlerAdapter的作用是:根据处理器映射器找到的Handler信息,去执行相关的Handler。
  简要描述 3 个适配器的应用场景:
  • SimpleControllerHandlerAdapter: 简单的控制器处理器适配器,支持实现了 Controller 接口的控制器;
  • HttpRequestHandlerAdapter: http请求处理器适配器,编写控制器时要实现 HttpRequestHandler 接口。此类控制器可以很方便的获取请求包中的相关信息。但使用的并不多;
  • RequestMappingHandlerAdapter: 请求映射处理器适配器,适配使用了注解的用户控制器。本课程就是使用了此适配器,此适配器的实现比前两个都复杂。
  因为有适配器的存在,可以让控制器的设计变得非常灵活。
  Tips: 这3类适配器都是 SpringMVC 默认提供的,不用显式配置,除非有定制需求。
 
 
六、视图解析器
  要讲解视图解析器,则需要回归到用户控制器上。比如以下代码:
@RequestMapping("/hello")
public String welcome() {
     System.out.pirntln("hello");
     return "hello";
}
  如果没有视图解析器的解析,上述方法返回的字符串hello就只是一个单纯的字符串。但是有了视图解析器,就会把这个字符串当成一个视图的逻辑名,并映射到真正的视图上。
  所以视图解析器的作用就是解析视图信息。首先将逻辑视图名解析为物理视图名,即具体的视图文件的地址。再生成View视图对象返回给前端控制器。
  • SpringMVC 默认使用InternalResourceViewResolver作为视图解析器,提供对JSP视图的支持。
  • 无论是SpringMVC默认提供的、还是开发者自定义的视图解析器,都必须实现ViewResolver接口。
  那为什么不在用户控制器的方法中直接返回物理视图(即完整的资源路径),而是要绕个弯,使用视图解析器来映射物理位置?答案很简单:
  • 控制器不需要知道视图文件的真正位置,通过视图解析器可以解耦控制器对视图的真实物理位置的依赖;
  • 通过独立的视图解析器组件,可以扩展SpringMVC对各种视图技术的支持(SpringMVC几乎支持市面上所有的视图技术,比如JSP、PDF、JSON、XML、EXCEL、Freemarker、Thymeleaf...);
  • 简化控制器中的响应代码;
  最后,不要忘了配置视图解析器:
<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>  <!--指定视图的前缀-->
        <property name="suffix" value=".jsp"/>  <!--指定视图的后缀-->
</bean>
  SpringMVC虽然提供了视图解析器,但它不可能聪明到知道开发者会把物理视图文件放在哪个位置,所以需要通过配置前后缀来指定物理视图的真正位置,此例中最终得到的物理视图地址为:前缀+视图名+后缀,即:/WEB-INF/jsp/hello.jsp。
  Tips:视图解析器和映射器有相似之处:
  • 映射器是入口时根据请求控制器逻辑名找到物理控制器;
  • 视图解析器是出口时根据视图逻辑名找到物理视图。
 
七、运行过程
  1、用户通过浏览器向服务器发送请求,请求会被SpringMVC的前端控制器DispatcherServlet拦截,拦截到请求后,会调用处理器映射器(HandlerMapping);
  2、处理器映射器根据请求URL找到具体的处理器,生成处理器对象及处理器拦截器(如果有)一并返回给前端控制器;
  3、前端控制器根据返回的信息选择合适的处理器适配器(HandlerAdapter),适配器调用并执行处理器(Handler,一般指用户控制器Controller)。
  4、Controller执行完成后返回一个ModelAndView对象,该对象中包含有视图名或视图名+数据模型。
  5、处理器适配器将ModelAndView对象返回给前端控制器,前端控制器去调用视图解析器,将逻辑视图名解析为真正的视图地址。
  6、视图解析器解析完成后,会向前端控制器返回具体的视图View对象,前端控制器渲染视图View(将模型数据填充到视图中)。
  7、前端控制器向用户响应结果。
 
  以上执行过程中,前端控制器、处理器映射器、处理器适配器、视图解析器的工作都是在SpringMVC框架内部执行的,开发人员只需动手配置前端控制器、完成Controller中的业务逻辑并在视图View中展示即可。
  总之,在SpringMVC中,用户的每一次请求都需要众多组件的紧密团结、通力合作,它们是相亲相爱的一家人。完结,撒花!
posted @   皮蛋&&瘦肉  阅读(893)  评论(3编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示