RequestMappingHandlerMapping 的作用收集路径映射和对应的方法;
RequestMappingHandlerAdapter的作用参数解析以及结果返回
DispatcherServlet初始化的时候会执行一下代码一起初始化九大组件
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
/**
* Initialize the strategy objects that this servlet uses.
* May be overridden in subclasses in order to initialize further strategy objects.
*/
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
RequestMappingHandlerMapping初始化出来以后就会
1,先找到有@Controller或者@RestController的类
@org.springframework.stereotype.Controller
public class Controller {
@GetMapping("/test1")
public ModelAndView test1(){
System.out.println("test1");
return null;
}
}
2,找到方法上加了各种@Mapping的方法把他们筛选处理
@GetMapping("/test1")
public ModelAndView test1(){
System.out.println("test1");
return null;
}
@RequestMapping("/test2")
public ModelAndView test2(){
System.out.println("test2");
return null;
}
@PostMapping ("/test3")
public ModelAndView test3(@Token String token){
System.out.println(token);
return null;
}
3,记录每个方法路径和方法的对应方法关系把他们存储在Map表中也就是存储在RequestMappingHandlerMapping
RequestMappingHandlerMapping handlerMapping = context.getBean(RequestMappingHandlerMapping.class);
Map handlerMethods = handlerMapping.getHandlerMethods();
4,RequestMappingHandlerMapping 初始化时,会收集所有 @RequestMapping 映射信息,封装为 Map,其中
-
key 是 RequestMappingInfo 类型,包括请求路径、请求方法等信息
可以看出上面一段代码Map的2个指定类型其中一个是RequestMappingInfo对象
里面包含了具体路径和请求方式等等
-
value 是 HandlerMethod 类型,包括控制器方法对象、控制器对象
可以看出上面一段代码Map的2个指定类型其中一个是HandlerMethod对象
-
有了这个 Map,就可以在请求到达时,快速完成映射,找到 HandlerMethod 并与匹配的拦截器一起返回给 DispatcherServlet
调用请求的时候,也就是用户发送请求的时候
会首先经过DispatcherServlet 的转发把请求转发给RequestMappingHandlerMapping
RequestMappingHandlerMapping拿着映射请求的路径去他的Map表里面找对应的方法
并且把他和拦截器封装成一个执行链
RequestMappingHandlerMappinghandlerMapping=context.getBean(RequestMappingHandlerMapping.class);
HandlerExecutionChain chain = handlerMapping.getHandler(request);
只会会把包装好的执行链交给RequestMappingHandlerAdapter去执行
一下代码模拟浏览器发送请求,可以看出RequestMappingHandlerAdapter执行的方法是invokeHandlerMethod里面传进去的产生是一个HandlerMethod
//request
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test4");
//response
MockHttpServletResponse response = new MockHttpServletResponse();
//方法执行链
HandlerExecutionChain chain = handlerMapping.getHandler(request);
MyRequestMappingHandlerAdapter handlerAdapter = (MyRequestMappingHandlerAdapter) context.getBean(RequestMappingHandlerAdapter.class);
//如果需要视图分辨率,则调用准备ModelAndView的RequestMapping处理程序方法
ModelAndView modelAndView = handlerAdapter.invokeHandlerMethod(request, response, (HandlerMethod) chain.getHandler());
在RequestMappingHandlerAdapter里做参数解析HandlerMethodArgumentResolver和
返回值处理HandlerMethodReturnValueHandler
在这里面我们可以加入自己的逻辑
可以自己定义参数解析器
自定义参数解析器注册以及使用
定义注解类
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Token {
}
定义控制器
public class TokenArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(Token.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
String token = webRequest.getHeader("token");
//解析逻辑
//解析出来以后直接返回
return token;
}
}
注册解析器到RequestMappingHandlerAdapte
@Bean
public MyRequestMappingHandlerAdapter requestMappingHandlerMapping(){
MyRequestMappingHandlerAdapter myRequestMappingHandlerAdapter = new MyRequestMappingHandlerAdapter();
TokenArgumentResolver tokenArgumentResolver=new TokenArgumentResolver();
//为自定义参数类型提供解析器。自定义解析器在内置解析器之后排序。要覆盖对参数解析的内置支持,请改用setArgumentResolvers 。
List list = new ArrayList<>();
list.add(tokenArgumentResolver);
myRequestMappingHandlerAdapter.setCustomArgumentResolvers(list);
return myRequestMappingHandlerAdapter;
}
使用
@PostMapping ("/test3")
public ModelAndView test3(@Token String token){
System.out.println(token);
return null;
}
测试
//作用解析@RequestMapping以及派生注解,生成路径与控制器方法的映射关系,在初始化时就生成
RequestMappingHandlerMapping handlerMapping = context.getBean(RequestMappingHandlerMapping.class);
//request
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/test3");
request.addHeader("token","我是自定义token解析的");
//response
MockHttpServletResponse response = new MockHttpServletResponse();
//方法执行链
HandlerExecutionChain chain = handlerMapping.getHandler(request);
MyRequestMappingHandlerAdapter handlerAdapter = (MyRequestMappingHandlerAdapter) context.getBean(RequestMappingHandlerAdapter.class);
可以自定义返回结果
自定义返回值处理器
注解
@Target(value = ElementType.METHOD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Yml {
}
控制器
public class YmlHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return returnType.hasMethodAnnotation(Yml.class);
}
@Override
//returnValue 返回值
public void handleReturnValue(Object returnValue,
MethodParameter returnType,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) throws Exception {
//转换返回结果给Yml
String str = new Yaml().dump(returnType);
//写入响应体
HttpServletResponse nativeResponse = webRequest.getNativeResponse(HttpServletResponse.class);
nativeResponse.setContentType("text/plain; charset=UTF-8");
nativeResponse.getWriter().print(str);
//设置请求已经处理完毕
mavContainer.setRequestHandled(true);
}
}
注册控制器
@Bean
public MyRequestMappingHandlerAdapter requestMappingHandlerMapping(){
MyRequestMappingHandlerAdapter myRequestMappingHandlerAdapter = new MyRequestMappingHandlerAdapter();
myRequestMappingHandlerAdapter.setCustomArgumentResolvers(list);
//添加自定义参数解析器
YmlHandlerMethodReturnValueHandler ymlHandlerMethodReturnValueHandler=new YmlHandlerMethodReturnValueHandler();
List returnValueHandlers=new ArrayList<>();
returnValueHandlers.add(ymlHandlerMethodReturnValueHandler);
myRequestMappingHandlerAdapter.setCustomReturnValueHandlers(returnValueHandlers);
return myRequestMappingHandlerAdapter;
}
测试
//作用解析@RequestMapping以及派生注解,生成路径与控制器方法的映射关系,在初始化时就生成
RequestMappingHandlerMapping handlerMapping = context.getBean(RequestMappingHandlerMapping.class);
//request
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test4");
//response
MockHttpServletResponse response = new MockHttpServletResponse();
//方法执行链
HandlerExecutionChain chain = handlerMapping.getHandler(request);
MyRequestMappingHandlerAdapter handlerAdapter = (MyRequestMappingHandlerAdapter) context.getBean(RequestMappingHandlerAdapter.class);
//如果需要视图分辨率,则调用准备ModelAndView的RequestMapping处理程序方法
ModelAndView modelAndView = handlerAdapter.invokeHandlerMethod(request, response, (HandlerMethod) chain.getHandler());
//获取相应内容
byte[] contentAsByteArray = response.getContentAsByteArray();
System.out.println(new String(contentAsByteArray, StandardCharsets.UTF_8));
可以看以下拓展篇,RequestMappingHandlerAdapter内部参数是如何解析的
SpringMVC九大组件之一RequestMappingHandlerAdapter内部参数解析器如何解析@RequestParam
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)