spring 24 控制器方法执行流程

图1

classDiagram class ServletInvocableHandlerMethod { +invokeAndHandle(ServletWebRequest,ModelAndViewContainer) } HandlerMethod <|-- ServletInvocableHandlerMethod HandlerMethod o-- bean HandlerMethod o-- method ServletInvocableHandlerMethod o-- WebDataBinderFactory ServletInvocableHandlerMethod o-- ParameterNameDiscoverer ServletInvocableHandlerMethod o-- HandlerMethodArgumentResolverComposite ServletInvocableHandlerMethod o-- HandlerMethodReturnValueHandlerComposite

HandlerMethod 需要

  • bean 即是哪个 Controller
  • method 即是 Controller 中的哪个方法

ServletInvocableHandlerMethod 需要

  • WebDataBinderFactory 负责对象绑定、类型转换
  • ParameterNameDiscoverer 负责参数名解析
  • HandlerMethodArgumentResolverComposite 负责解析参数
  • HandlerMethodReturnValueHandlerComposite 负责处理返回值
点击查看代码
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(WebConfig.class);
        //为了获得一些资源添加到容器中
        RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter();
        adapter.setApplicationContext(context);
        adapter.afterPropertiesSet();

        MockHttpServletRequest request = new MockHttpServletRequest();
        request.setParameter("name", "张三");
        /*
            现在可以通过 ServletInvocableHandlerMethod 把这些整合在一起, 并完成控制器方法的调用, 如下
         */
        ServletInvocableHandlerMethod handlerMethod = new ServletInvocableHandlerMethod(
                new Controller1(), Controller1.class.getMethod("foo", User.class));

        ServletRequestDataBinderFactory factory = new ServletRequestDataBinderFactory(null, null);
        //绑定工厂, @InitBinder  负责对象绑定、类型转换
        handlerMethod.setDataBinderFactory(factory);
        //参数名解析
        handlerMethod.setParameterNameDiscoverer(new DefaultParameterNameDiscoverer());
        //参数解析
        handlerMethod.setHandlerMethodArgumentResolvers(getArgumentResolvers(context));

        ModelAndViewContainer container = new ModelAndViewContainer();

        // 获取模型工厂方法
        Method getModelFactory = RequestMappingHandlerAdapter.class.getDeclaredMethod("getModelFactory", HandlerMethod.class, WebDataBinderFactory.class);
        getModelFactory.setAccessible(true);
        ModelFactory modelFactory = (ModelFactory) getModelFactory.invoke(adapter, handlerMethod, factory);

        // 初始化模型数据 查找加了注解 @ModelAttribute 的控制器方法,或者配置类中加了 @ControllerAdvice 的 @ModelAttribute ,利用反射判断。
        modelFactory.initModel(new ServletWebRequest(request), container, handlerMethod);
        //调用控制器方法
        handlerMethod.invokeAndHandle(new ServletWebRequest(request), container);
        //获得存储在 container 中的模型数据
        System.out.println(container.getModel());

        context.close();
@Configuration
public class WebConfig {

    @ControllerAdvice  // @ModelAtribute 加在 @ControllerAdvice 上面,全局设置,所有的控制器方法都要满足。
    static class MyControllerAdvice {
        @ModelAttribute("a") //将方法返回值作为模型数据加入 container 中,没设置名字,默认返回值类型首字母小写。
        public String aa() {
            return "aa";
        }
    }

    @Controller
    static class Controller1 {
        @ModelAttribute("b") //将方法返回值作为模型数据加入 container 中,没设置名字,默认返回值类型首字母小写。
        public String aa() {
            return "bb";
        }

        @ResponseStatus(HttpStatus.OK)  //方法上加了可以跳过返回值解析过程,说明响应已经设置完成,可以返回了。
        public ModelAndView foo(@ModelAttribute("u") User user) {  //将传入的参数作为模型数据加入 container 中,没设置名字,默认参数类型首字母小写。
            System.out.println("foo");
            return null;
        }
    }

图2

图3

posted @ 2022-07-04 16:03  xy7112  阅读(58)  评论(0)    收藏  举报