一.RequestMappingHandlerMapping
RequestMappingHandlerMapping是sprringmvc核心的控制映射组件,它主要是用来解析
@RequestMapping和它的一些派生注解,例如@GetMapping,@PostMapping等
它和对应的路径和处理方法联系起来
二.RequestMappingHandlerMapping示例
1.创建Controller
我们创建springboot项目,然后我们先配置好MyController类
@Controller
public class MyController {
@GetMapping("/test1")
public String test1(){
return "test1";
}
@PostMapping("/test2")
public String test2(@RequestParam("p1") String p1){
return "test2";
}
@RequestMapping("/test3")
public String test3(){
return "test3";
}
}
2.配置自定义RequesetMappingHandlerMapping
注意:要说明一点,如果我们自己不配置RequestMappingHandlerMapping,那么spring使用的是默认的处理映射,如果自己配置了,那么就会用我们的,下面我们来自己配置处理映射
在配置类中声明为bean即可:
//自定义RequestMappingHandlerMappening
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping(){
return new RequestMappingHandlerMapping();
}
3.测试
然后我们通过容器获取这个bean,通过getHandlerMethods()获取它的路径方法映射集合
public static void main(String[] args) {
AnnotationConfigServletWebServerApplicationContext context =
new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
RequestMappingHandlerMapping handlerMapping =
context.getBean(RequestMappingHandlerMapping.class);
Map<RequestMappingInfo, HandlerMethod> handlerMethods =
handlerMapping.getHandlerMethods();
handlerMethods.forEach((k,v)->{
System.out.println(k+"="+v);
});
}
我们运行一下:
{POST [/test2]}=com.jjh.config.MyController#test2(String)
{ [/test3]}=com.jjh.config.MyController#test3()
{GET [/test1]}=com.jjh.config.MyController#test1()
我们发现我们在Controller里定义的方法都获取出来了!
4.模拟请求获取调用链
下面我们来模拟一个get请求,观察一下他的调用链:
这里我们为了方便演示,我们使用了Spring为我们提供的MockHttpServletRequest,它可以模拟发送http请求
HandlerExecutionChain chain = handlerMapping
.getHandler(new MockHttpServletRequest("GET", "/test1"));
System.out.println(chain);
我们运行一下:
09:38:04.100 [main] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped to com.jjh.config.MyController#test1()
HandlerExecutionChain with [com.jjh.config.MyController#test1()] and 0 interceptors
我们看到这个调用链,它调用了我们的test1方法,现在没有拦截器,所以拦截器数量为0
三.RequestMappingHandlerAdaptor
该对象是用来调用上面调用链中的controller方法的,下面我们来模拟实现一下:
1.通过继承修改权限为public来突破保护
该类中有个关键方法是invokeHandlerMethod,它就是用来调用chain中的方法,但是他是protectecd的,不能直接使用,我们可以自定义一个类来继承它,然后重新该方法,只需要把该方法改为public就可以了,然后super调用原来的方法就可以了,这是一种解决方法,我们以后可以用这种方法来突破保护
2.自定义MyRequestMappingHandlerAdaptor,继承RequestMappingHandlerAdaptor
public class MyRequestMappingHandlerAdapter extends RequestMappingHandlerAdapter {
@Override
public ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
return super.invokeHandlerMethod(request, response, handlerMethod);
}
}
3.将自定义的这个类注册为bean,以覆盖spring默认的适配器
//自定义RequestMappingHandlerAdapter
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(){
return new MyRequestMappingHandlerAdapter();
}
3.测试
MyRequestMappingHandlerAdapter handlerAdapter = context
.getBean(MyRequestMappingHandlerAdapter.class);
//创建模拟请求 和 响应
HttpServletRequest request = new MockHttpServletRequest("GET", "/test1");
HttpServletResponse response = new MockHttpServletResponse();
//调用该方法
handlerAdapter.invokeHandlerMethod(request,response, (HandlerMethod) chain.getHandler());
运行一下,查看:
10:18:52.436 [main] INFO com.jjh.config.MyController - test1...
我们可以看到成功调用了test1方法!