注:SpringFramework的版本是4.3.x。java
們由DispatcherServlet的初始化簡析得知默認的HandlerMapping是BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping,這倆個類的繼承圖以下圖二、圖3所示,web
圖2 BeanNameUrlHandlerMapping的類繼承圖spring
圖3 DefaultAnnotationHandlerMapping的類繼承圖mvc
BeanNameUrlHandlerMapping是spring-webmvc模塊的,DefaultAnnotationHandlerMapping是spring-webmvc-porlet的。咱們主要分析這倆個HandlerMapping。app
BeanNameUrlHandlerMapping的用法以下,ide
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean name="/hello" class="com.mjduan.project.example8_aop.HelloController"/>
HelloController的源碼以下,this
public class HelloController extends AbstractController { @Override protected ModelAndView handleRequestInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { return null; } }
BeanNameUrlHandlerMapping初始化的時序圖,以下圖4所示:url
圖4 BeanNameUrlHandlerMapping的初始化時序圖spa
圖3的說明:因爲ApplicationObjectSupport實現了ApplicationContextAware接口,全部在執行setApplicationContext的時候會初始化AbstractUrlHandlerMapping的屬性handlerMap。.net
圖4的步驟6中,會從applicationContext中取出全部的MappedInterceptor,放到AbstractHandlerMapping的屬性adaptedInterceptors中,這些MappedInterceptor是HandlerInterceptor的子類,在構造HandlerExecutionChain時用到。
咱們再來分析AbstractDetectingUrlHandlerMapping的detectHandlers方法,源碼以下List-1所示,
List-1 AbstractDetectingUrlHandlerMapping的detectHandlers()源碼
protected void detectHandlers() throws BeansException { if (logger.isDebugEnabled()) { logger.debug("Looking for URL mappings in application context: " + getApplicationContext()); } String[] beanNames = (this.detectHandlersInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : getApplicationContext().getBeanNamesForType(Object.class)); // Take any bean name that we can determine URLs for. for (String beanName : beanNames) { String[] urls = determineUrlsForHandler(beanName); if (!ObjectUtils.isEmpty(urls)) { // URL paths found: Let's consider it a handler. registerHandler(urls, beanName); } else { if (logger.isDebugEnabled()) { logger.debug("Rejected bean name '" + beanName + "': no URL paths identified"); } } } }
determineUrlsForHandler方法的實現是在BeanNameUrlHandlerMapping中,源碼以下List-2所示,
List-2 BeanNameUrlHandlerMapping的determineUrlsForHandler方法源碼
public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping { /** * Checks name and aliases of the given bean for URLs, starting with "/". */ @Override protected String[] determineUrlsForHandler(String beanName) { List<String> urls = new ArrayList<String>(); if (beanName.startsWith("/")) { urls.add(beanName); } String[] aliases = getApplicationContext().getAliases(beanName); for (String alias : aliases) { if (alias.startsWith("/")) { urls.add(alias); } } return StringUtils.toStringArray(urls); } }
由List-1的代碼可知,從applicationContext中取出全部的beanName,以後遍歷全部的beanName,若是該beanName以"/"開頭,則將這個beanName視爲url,記錄。
通常狀況下,咱們不會使用BeanNameUrlHandlerMapping的,BeanNameUrlHandlerMapping使用起來感受不是很靈活。
SimpleUrlHandlerMapping的通常使用方式以下,prop中key的值,是spring bean。這種是之前的用法,如今基本都使用註解的方式了,不多用這種了。注:下面這段代碼來源: https://blog.csdn.net/trigl/article/details/50494492
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/upfile.do">upfile</prop> <prop key="/upfiles.do">upfiles</prop> <prop key="/extjs.do">SpringMVC</prop> <prop key="/show.do">show</prop> </props> </property> </bean>
List-3 DefaultAnnotationHandlerMapping的initApplicationContext()源碼
@Override public void initApplicationContext() throws BeansException { super.initApplicationContext(); detectHandlers(); } /** * Register all handlers specified in the Portlet mode map for the corresponding modes. * @throws org.springframework.beans.BeansException if the handler couldn't be registered */ protected void detectHandlers() throws BeansException { ApplicationContext context = getApplicationContext(); String[] beanNames = context.getBeanNamesForType(Object.class); for (String beanName : beanNames) { Class<?> handlerType = context.getType(beanName); RequestMapping mapping = context.findAnnotationOnBean(beanName, RequestMapping.class); if (mapping != null) { // @RequestMapping found at type level String[] modeKeys = mapping.value(); String[] params = mapping.params(); boolean registerHandlerType = true; if (modeKeys.length == 0 || params.length == 0) { registerHandlerType = !detectHandlerMethods(handlerType, beanName, mapping); } if (registerHandlerType) { AbstractParameterMappingPredicate predicate = new TypeLevelMappingPredicate( params, mapping.headers(), mapping.method()); for (String modeKey : modeKeys) { registerHandler(new PortletMode(modeKey), beanName, predicate); } } } else if (AnnotationUtils.findAnnotation(handlerType, Controller.class) != null) { detectHandlerMethods(handlerType, beanName, mapping); } } }
從List-3中的detectHandlers可知,
List-4 DefaultAnnotationHandlerMapping的detectHandlerMethods方法源碼
protected boolean detectHandlerMethods(Class<?> handlerType, final String beanName, final RequestMapping typeMapping) { final Set<Boolean> handlersRegistered = new HashSet<Boolean>(1); Set<Class<?>> handlerTypes = new LinkedHashSet<Class<?>>(); handlerTypes.add(handlerType); handlerTypes.addAll(Arrays.asList(handlerType.getInterfaces())); for (Class<?> currentHandlerType : handlerTypes) { ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() { @Override public void doWith(Method method) { PortletRequestMappingPredicate predicate = null; String[] modeKeys = new String[0]; String[] params = new String[0]; if (typeMapping != null) { params = PortletAnnotationMappingUtils.mergeStringArrays(typeMapping.params(), params); } ActionMapping actionMapping = AnnotationUtils.findAnnotation(method, ActionMapping.class); RenderMapping renderMapping = AnnotationUtils.findAnnotation(method, RenderMapping.class); ResourceMapping resourceMapping = AnnotationUtils.findAnnotation(method, ResourceMapping.class); EventMapping eventMapping = AnnotationUtils.findAnnotation(method, EventMapping.class); RequestMapping requestMapping = AnnotationUtils.findAnnotation(method, RequestMapping.class); if (actionMapping != null) { params = PortletAnnotationMappingUtils.mergeStringArrays(params, actionMapping.params()); predicate = new ActionMappingPredicate(actionMapping.name(), params); } ......
從List-4可知,detectHandlerMethods方法,對類的方法進行遍歷,以後逐個處理每一個方法。
DefaultAnnotationHandlerMapping處理的就是咱們平時所用的基於註解的方式。