• springbank 开发日志 SpringMVC是如何找到handler找到对应的方法并执行的


    从DispatcherServlet说起,本文讨论的内容都是DispatcherServlet的doDispatch方法完成

    mappedHandler是一个HandlerExecutionChain,其中封装了一个handler,和一个由interceptor组成的list

    如果这张图够高,往下能看到handler是如何执行的,不过不是handler.execute()这样的形式,而是由这样的:

    // Actually invoke the handler.
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

    从注释就可以看出,是通过反射的方式来调用,我已经看过一遍代码了,实际上里面是通过找到Method的对象,进行的反射调用,重点就在于,这个Method对象是如何找到的

    而找的这个过程,是包含在第一张图中的下述方法调用里的:

    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

    这里使用的handlerAdapters是在private void initHandlerAdapters(ApplicationContext context)方法中得到初始化的,大致思想就是将所有实现了HandlerAdapter接口的类的实例都找出来放到这个list中

    ha 是 AnnotationMethodHandlerAdapter 的实例时:执行上图的逻辑

    getMethodResolver的逻辑,已经执行执行中methodResolverCache的内容如上图,可以看出里面是我们的handler对应的具体的Adapter对象

    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

    所以上面的ha实际上是比如:org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter@52d5661c

    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

    好吧,接着往下看,就是调用了,上面也提到过的,就是上面这段代码

    它里面是上面这样,代码挺多,但我只关心return invokeHandlerMethod(request, response, handler);

    protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
    
            ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
            Method handlerMethod = methodResolver.resolveHandlerMethod(request);
            ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
            ServletWebRequest webRequest = new ServletWebRequest(request, response);
            ExtendedModelMap implicitModel = new BindingAwareModelMap();
    
            Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
            ModelAndView mav =
                    methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
            methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
            return mav;
        }

    上面就是具体的调用。看到这里,整个过程都结束了,已经返回了ModelAndView

    但是但是但是但是,很多个但是。只有认真看了,或者像我一样,尝试学习这样的实现,才会注意到很多细节。比如上面这个方法实际上只传了一个handler进来,它怎么知道invoke哪个Method呢???

    ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
    Method handlerMethod = methodResolver.resolveHandlerMethod(request);

    重点就是上面这个methodResolver了,可以看到里面有一个mappings,存储了被@requestMapping注解的方法,和注解的值这样的一个对应关系

    这是全文的重中之重

    这个方法只有在服务器启动后,第一次接受请求时,才能走到resolver = new ServletHandlerMethodResolver(handlerClass);后面的都是使用methodResolverCache了

    上面的init实现如下

     这里面很关键,但是很不起眼的代码,竟然还被杠掉了,有空看看新的实现是什么,这段代码就是:if (isHandlerMethod(specificMethod)),

    这个方法是属于AnnotationMethodHandlerAdapter类的,这个方法的参数就是Method,比如调试的时候是public java.lang.String com.test.springmvc.HelloWorld.hello()

    上面这段代码执行的时候,

    mapping的内容是:

    @org.springframework.web.bind.annotation.RequestMapping(name=, value=[/helloworld], path=[/helloworld], method=[], params=[], headers=[], consumes=[], produces=[])

    patterns的内容是

    [/helloworld]

    所以this.mappings.put(method, mappingInfo);的结果是

    {public java.lang.String com.test.springmvc.HelloWorld.hello()=[/helloworld]}

    就这样吧,明天来实现一把,当然不想按照它这个流程来,太复杂了,我最好简化一下

  • 相关阅读:
    在其他博客里看到的比较好的map用法,进行储存啦啦~ x
    codevs 2597 团伙x
    codevs 1009 产生数x
    格子游戏x(并查集)
    codevs 5929 亲戚x
    [HDOJ2389]Rain on your Parade(二分图最大匹配,HK算法)
    [HDOJ2819]Swap(二分图最大匹配, 匈牙利算法)
    [HDOJ1281]棋盘游戏(二分图最大匹配,匈牙利算法)
    [HDOJ1083]Courses(二分图最大匹配,匈牙利算法)
    [HDOJ2444]The Accomodation of Students(二分图染色判定,最大匹配,匈牙利算法)
  • 原文地址:https://www.cnblogs.com/heben/p/7158392.html
Copyright © 2020-2023  润新知