概述
Spring MVC框架提供了一个HandlerMapping实现类BeanNameUrlHandlerMapping,该实现类会被DispatcherServlet用于映射请求到实现了接口Controller的控制器。本文使用例子讲解BeanNameUrlHandlerMapping的应用。
应用实例讲解
首先需要说明的是,本文例子基于如下项目 :
Springboot 2.1.2.RELEASESpring MVC 5.1.3.RELEASE- 缺省
Servlet容器:Tomcat embeded 9.0.14 - 缺省端口 :
8080
- 缺省
- 服务端模板引擎 :
freemarker Spring MVC配置基于Configuration+@EnableWebMVC+WebMvcConfigurer实现类- 注意 : 没有采用
Springboot缺省的自动配置WebMvcAutoConfiguration
- 注意 : 没有采用
1. 实现自定义Controller
package tut.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
/**
* 此 Controller 配合 ControllerBeanConfig 演示
* BeanNameUrlHandlerMapping + SimpleControllerHandlerAdapter 如何工作
*
*/
public class WelcomeController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
ModelAndView mav = new ModelAndView("welcome");
mav.addObject("now", LocalDateTime.now().toString());
String name = request.getParameter("name");
mav.addObject("name", name == null ? "你是?" : name);
return mav;
}
}
该类WelcomeController实现了接口Controller,该接口约定了一个方法ModelAndView handleRequest(HttpServletRequest, HttpServletResponse)用于处理客户请求。这里的实现只是简单地准备一些参数now,name,然后渲染视图welcome。因为视图的实现不是本文的重点,所以这里不再给出。
2. 将自定义Controller定义为容器bean
package tut.config;
import tut.controller.WelcomeController;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 本配置文件用于演示定义用于 Controller 的 bean, 这些 bean 实现了接口 Controller,
* 会被 Spring MVC HandlerMapping BeanNameUrlHandlerMapping 组件发现和进行映射登记,
* 最终会在访问 URL /welcome 时匹配到 SimpleControllerHandlerAdapter
*/
@Configuration
public class ControllerBeanConfig {
/**
* 这里定义一个 web controller bean, 注意 :
* 1. 该 bean 实现了接口 Controller,
* 2. 该 bean 没有使用注解 @Controller,
* (如果使用了注解@Controller,就会被RequestMappingHandlerMapping接管,而不是由BeanNameUrlHandlerMapping处理)
* 3. 映射到匹配 welcome* 的url
* @return
*/
@Bean(name = "/welcome*")
public WelcomeController beanWelcomeController() {
return new WelcomeController();
}
}
该配置类只有一个目的,定义一个类型为WelcomeController的bean组件,并且bean名称为/welcome*,注意,该bean名称使用一个url pattern的格式,因为只有使用这种格式,该bean才会被BeanNameUrlHandlerMapping看到。
3.运行效果
有了以上的WelcomeController和ControllerBeanConfig配置类之后,运行应用,然后访问http://localhost:8080/welcome,或者http://localhost:8080/welcome.html之类任何匹配/welcome*的地址,可以看到如下界面 :

该结果基于两个参数和一个服务端freemarker试图渲染得到。
4.请求处理分析
通过调试方式代码跟踪,我们发现 :
- 容器启动时,
@EnableWebMVC对应的配置机制会注册一个BeanNameUrlHandlerMappingbean到容器; DispatcherServlet启动时,会获取上面注册的BeanNameUrlHandlerMappingbean,该组件在被获取时也被实例化和被设置ApplicationContext属性。该组件被设置属性ApplicationContext时,它会过滤容器中所有/开头的bean名称/别名,这些bean名称/别名其实是url pattern,如果检测到这样的bean名称/别名,则将每个这样的bean名称/别名和对应的bean名称增加为一个映射项。使用Map<String, Object> handlerMap(定义在AbstractUrlHandlerMapping中)保存映射关系<url pattern,handler对象>对。
具体到本文中的例子,该BeanNameUrlHandlerMappingbean就是将 </welcome*,WelcomeControllerbean>映射关系管理起来。- 用户请求
http://localhost:8080/welcome*时,也就是http://localhost:8080/welcome或者http://localhost:8080/welcome.do所有这类匹配/welcome*的地址时,DispatcherServlet就会根据请求的url从所注册的各个HandlerMapping组件中试图找到所对应的请求处理器(request handler)。最终,DispatcherServelt会从BeanNameUrlHandlerMapping组件找到匹配的WelcomeControllerbean。 DispatcherServelt找到匹配的WelcomeControllerbean之后,然后会从所登记的HandlerAdpater中查找支持WelcomeController组件的适配器,最终,它找到了SimpleControllerHandlerAdapter。DispatcherServelt找到SimpleControllerHandlerAdapter之后,使用该请求处理器适配器针对用户请求调用WelcomeControllerbean的接口Controller方法handleRequest。
正如上面WelcomeController#handleRequest的实现逻辑所示,它会准备一些参数数据,指定一个视图模板welcome,将二者以ModelAndView的形式返回给DispatcherServelt。DispatcherServelt进一步渲染给定的ModelAndView,返回给浏览器端如上运行效果小节所示的效果。
本文详细解析SpringMVC中BeanNameUrlHandlerMapping的工作原理,通过自定义Controller和配置类,演示如何实现URL到Controller的映射,及DispatcherServlet如何调用相应的处理器。
398

被折叠的 条评论
为什么被折叠?



