文章环境说明:
spring mvc 版本3.2.4.RELEASE,项目中注解方式注册Controller。
众所周知Spring Mvc 中的DispatcherServlet中会使用HandlerMapping 将请求Url解析成为handler处理器。
关于HandlerMapping 实际只有两个突出的功能注册和查找。由于注册是在spring容器加载时就已将Controller的每一个方法注册成handler,学起来门槛较高。因此此文将先说查找反推出注册。
注:由于Spring Mvc 的版本不同所以相应代码存在出入,以下代码全部出于spring Mvc 3.2.4.RELEASE。
查找:
在DispatcherServlet中doDispatch方法中可以看到根据request使用HandlerMapping获取HandlerExecutionChain对象。代码如下所示:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { //在spring-servlet中是否配有MultipartResolver用于解析特殊 //的request 比如附件上传:CommonsMultipartResolver processedRequest = checkMultipart(request); multipartRequestParsed = processedRequest != request; // Determine handler for the current request. //根据request 在HandlerMapping 查找handler信息 mappedHandler = getHandler(processedRequest, false); ..... }catch (Exception ex) { dispatchException = ex; } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); }catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); }catch (Error err) { triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err); }finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); return; } // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } }
DispatcherServlet中的getHandler代码如下所示:
@Deprecated protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception { return getHandler(request); } protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { //handlerMappings 在容器启动时就已经将handlerMapping进行了赋值 for (HandlerMapping hm : this.handlerMappings) { if (logger.isTraceEnabled()) { logger.trace( "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'"); } HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; }
关于handlerMappings 的赋值代码同样在DispatcherServlet代码中,代码如下所示
protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); //初始化handlerMapping initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); } private void initHandlerMappings(ApplicationContext context) { this.handlerMappings = null; //可在Web.xml进行显示指定,默认是true 是否默认加载所有HandlerMapping下的values if (this.detectAllHandlerMappings) { // Find all HandlerMappings in the ApplicationContext, including ancestor contexts. //获取context中的所有HandlerMappings的子类,并将其下的values 初始化到handlerMappings中 //其中的子类有 //RequestMappingHandlerMapping(所有使用注解定义的Controller) //BeanNameUrlHandlerMapping(配置文件中定义的Interceptor) //SimpleUrlHandlerMapping(配置文件中的mvc:resources显示定义的) 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. OrderComparator.sort(this.handlerMappings); } }else { try { HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default HandlerMapping later. } } // Ensure we have at least one HandlerMapping, by registering // a default HandlerMapping if no other mappings are found. if (this.handlerMappings == null) { this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); if (logger.isDebugEnabled()) { logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default"); } } }至于在DispatcherServlet的getHandler调用的hm.getHandler()方法就比较简单,在RequestMappingHandlerMapping、BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping类中并没有对其父类AbstractHandlerMapping的getHandler方法进行重写。其AbstractHandlerMapping的getHandler方法如下所示(spring MVC升级中对并未对此方法进行修改):
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { //此段代码只会在controller是注解方式定义的时候使用到 Object handler = getHandlerInternal(request); //如果在注解中没有查到相应Handler 取默认defaultHandler if (handler == null) { handler = getDefaultHandler(); } if (handler == null) { return null; } // Bean name or resolved handler? //当handler是String类型时直接从Contest容器中查找 if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } return getHandlerExecutionChain(handler, request); } protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { //将handler转换为HandlerExecutionChain对象 HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain) ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler); //将拦截器放到HandlerExecutionChain 处理器中此处的拦截器继承自HandlerInterceptor chain.addInterceptors(getAdaptedInterceptors()); //将拦截器放到HandlerExecutionChain 处理器中此处的拦截器继承自MappedInterceptor String lookupPath = urlPathHelper.getLookupPathForRequest(request); for (MappedInterceptor mappedInterceptor : mappedInterceptors) { if (mappedInterceptor.matches(lookupPath, pathMatcher)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); } } return chain; }关于getHandlerInternal()方法,只在其子类AbstractHandlerMethodMapping<T>对其进行了实现。由于AbstractHandlerMethodMapping 此类较复杂,将于后续文章对其补充说明!