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);
    }
}

收获💡

  1. DispatcherServlet 是在第一次被访问时执行初始化, 也可以通过配置修改为 Tomcat 启动后就初始化
  2. 在初始化时会从 Spring 容器中找一些 Web 需要的组件, 如 HandlerMapping、HandlerAdapter 等,并逐一调用它们的初始化
  3. RequestMappingHandlerMapping 初始化时,会收集所有 @RequestMapping 映射信息,封装为 Map,其中
    • key 是 RequestMappingInfo 类型,包括请求路径、请求方法等信息
    • value 是 HandlerMethod 类型,包括控制器方法对象、控制器对象
    • 有了这个 Map,就可以在请求到达时,快速完成映射,找到 HandlerMethod 并与匹配的拦截器一起返回给 DispatcherServlet
  4. 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);
    }
}

收获💡

  1. 体会参数解析器的作用
  2. 体会返回值处理器的作用
posted @ 2022-06-27 16:37  xy7112  阅读(64)  评论(0)    收藏  举报