注: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处理的就是咱们平时所用的基于注解的方式。