spring 19 RequestMappingHandlerMapping 与 RequestMappingHandlerAdapter
RequestMappingHandlerMapping 与 RequestMappingHandlerAdapter 俩是一对,分别用来
- 处理 @RequestMapping 映射
- 调用控制器方法、并处理方法参数与方法返回值
DispatcherServlet 初始化
点击查看代码
public static void main(String[] args) throws Exception {
AnnotationConfigServletWebServerApplicationContext context
= new AnnotationConfigServletWebServerApplicationContext(S19WebConfig.class);
//作用:解析 @RequestMapping 以及派生注解 @GetMapping 等,生成路径与控制器方法之间的映射关系,在初始化就生成
RequestMappingHandlerMapping handlerMapping = context.getBean(RequestMappingHandlerMapping.class);
//获取映射的结果
Map<RequestMappingInfo, HandlerMethod> handlerMethods = handlerMapping.getHandlerMethods();
handlerMethods.forEach((k,v)-> System.out.println(k + "=" + v));
//请求来了,获取控制器方法,返回处理器执行链对象 MockHttpServletRequest spring 用于测试用模拟的请求对象
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/a");
request.setParameter("s","5");
HandlerExecutionChain chain = handlerMapping.getHandler(request);
System.out.println("chain = " + chain);
//自定义映射处理适配器 调用控制器方法
MyRequestMappingHandlerAdapter adapter = context.getBean(MyRequestMappingHandlerAdapter.class);
MockHttpServletResponse response = new MockHttpServletResponse();
assert chain != null;
adapter.invokeHandlerMethod(request, response, (HandlerMethod) chain.getHandler());
System.out.println("===========参数解析器");
adapter.getArgumentResolvers().forEach(System.out::println);
System.out.println("============返回值处理器");
adapter.getReturnValueHandlers().forEach(System.out::println);
}
@Configuration
@PropertySource(factory = YamlPropertySourceFactory.class,value = "classpath:application.yml")
@ComponentScan
@EnableConfigurationProperties({WebMvcProperties.class, ServerProperties.class})
public class S19WebConfig {
//创建内嵌 web 容器
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory(ServerProperties serverProperties) {
return new TomcatServletWebServerFactory(serverProperties.getPort());
}
//创建 DispatcherServlet
@Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
//创建 DispatcherServletRegister 对象,将 DispatcherServlet 注册到 web 容器中
@Bean
public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet,WebMvcProperties properties) {
DispatcherServletRegistrationBean dispatcherServletRegistrationBean = new DispatcherServletRegistrationBean(dispatcherServlet, properties.getServlet().getPath());
dispatcherServletRegistrationBean.setLoadOnStartup(properties.getServlet().getLoadOnStartup());
return dispatcherServletRegistrationBean;
}
//创建 requestMapping 路径映射
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping (){
return new RequestMappingHandlerMapping();
}
}
@Controller
public class S19Controller {
@GetMapping("/c")
public void s191() {
System.out.println("c...");
}
@RequestMapping("/b")
public int s192() {
System.out.println("b..");
return 0;
}
@PostMapping("/a")
public void s193(@RequestParam int s) {
System.out.println("a." + s);
}
}
收获💡
- DispatcherServlet 是在第一次被访问时执行初始化, 也可以通过配置修改为 Tomcat 启动后就初始化
- 在初始化时会从 Spring 容器中找一些 Web 需要的组件, 如 HandlerMapping、HandlerAdapter 等,并逐一调用它们的初始化
- RequestMappingHandlerMapping 初始化时,会收集所有 @RequestMapping 映射信息,封装为 Map,其中
- key 是 RequestMappingInfo 类型,包括请求路径、请求方法等信息
- value 是 HandlerMethod 类型,包括控制器方法对象、控制器对象
- 有了这个 Map,就可以在请求到达时,快速完成映射,找到 HandlerMethod 并与匹配的拦截器一起返回给 DispatcherServlet
- RequestMappingHandlerAdapter 初始化时,会准备 HandlerMethod 调用时需要的各个组件,如:
- HandlerMethodArgumentResolver 解析控制器方法参数
- HandlerMethodReturnValueHandler 处理控制器方法返回值
自定义参数与返回值处理器
点击查看代码
//自定义令牌参数解析器
public class TokenArgumentResolver implements HandlerMethodArgumentResolver{
@Override
//是否支持某参数,支持才能进行解析
public boolean supportsParameter(MethodParameter parameter) {
Token token = parameter.getParameterAnnotation(Token.class);
System.out.println("token======================" + token);
return token != null;
}
@Override
//解析参数
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
return webRequest.getHeader("token");
}
}
//自定义返回值处理器
public class YmlReturnValueHandler implements HandlerMethodReturnValueHandler {
@Override
public boolean supportsReturnType(MethodParameter returnType) {
Yml yml = returnType.getMethodAnnotation(Yml.class);
return yml != null;
}
@Override // 返回值
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
// 1. 转换返回结果为 yaml 字符串
String str = new Yaml().dump(returnValue);
// 2. 将 yaml 字符串写入响应
HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
response.setContentType("text/plain;charset=utf-8");
response.getWriter().print(str);
// 3. 设置请求已经处理完毕
mavContainer.setRequestHandled(true);
}
}
收获💡
- 体会参数解析器的作用
- 体会返回值处理器的作用