最近和同事討論一個spring mvc的問題,問到HandlerMapping與HandlerAdapter有什麼關系?雖然使用spring mvc時間也不短,但是瞬間能起來的只有兩個關鍵詞:
@RequestMapping(value = "/bss/{priceId}", method = RequestMethod.GET)
public ValueResult<ProductPrice> getProductPrice(HttpServletRequest request,
@Min(value = 1,message = "priceId不合法")
@PathVariable final long priceId) {
//省略
}
上面兩個關鍵詞盡管與問題有所關聯,但很明顯不是主要的,核心還是這兩個接口都是做什麼的,兩者之間有什麼互動。於是我們可以從一個請求開始調試下spring mvc的調用過程,以此來分析它們的作用以及關系。
XmlWebApplicationContext context = new XmlWebApplicationContext();
context.setConfigLocations(new String[]{"classpath*:applicationContext.xml","classpath*:spring/mvc-dispatcher-servlet.xml"});
ServletContextHandler spingMvcHandler = new ServletContextHandler();
spingMvcHandler.setContextPath(appConfig.getContext());
spingMvcHandler.addEventListener(new ContextLoaderListener(context));
spingMvcHandler.addServlet(new ServletHolder(new DispatcherServlet(context)), "/*");
這裡引用《張開濤》同學的圖來說明上面兩個配置的作用以及關系:

這篇它不是重點至此主止。
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
/**
* Initialize the strategy objects that this servlet uses.
* <p>May be overridden in subclasses in order to initialize further strategy objects.
*/
protected void initStrategies(ApplicationContext context) {
//其它初始化
initHandlerMappings(context);
initHandlerAdapters(context);
//其它初始化
}
initHandlerMappings,主要是調用BeanFactoryUtils.beansOfTypeIncludingAncestors,其中一種非常重要的HandlerMapping是RequestMappingHandlerMapping,我們通過在Controller方面上加@RequestMapping注釋來配合使用,系統會將我們配置的RequestMapping信息注冊到其中,詳細數據參數此圖:mappingRegistry中包含了所有的請求路由信息。

代碼如下:
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
//不加載全部的先省略
//加載默認的邏輯先省略
}
DispatcherServlet核心方法:doDispatch,三個重要步驟:

doDispath獲取頁面處理器,然後根據頁面處理器獲取對應的HanlerAdapter,最後由HanlerAdaper來調用頁面處理器的方法。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//初始化省略
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//其它邏輯省略
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//其它邏輯省略
}
catch (Exception ex) {
dispatchException = ex;
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
//異常邏輯省略
}
具體的調用邏輯比較復雜,只選取與HandlerMapping與HandlerAdaper的部分,時序圖圖如下:

http://jinnianshilongnian.iteye.com/blog/1602617