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]}

就這樣吧,明天來實現一把,當然不想按照它這個流程來,太復雜了,我最好簡化一下


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM