1. handlerMapping的作用
简单来说就是用来存储所有URL与处理类的map关系,以及在请求过来的时候根据输入URL匹配到对应的处理类
2. handlerMapping的默认配置:
org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping: 用来解析@RequestMapping
3. handlerMapping初始化
以常用的DefaultAnnotationHandlerMapping为例:
ApplicationObjectSupport.setApplicationContext(ApplicationContext context)
WebApplicationObjectSupport.initApplicationContext(ApplicationContext context)
ApplicationObjectSupport.initApplicationContext(ApplicationContext context)
AbstractDetectingUrlHandlerMapping.initApplicationContext()
AbstractDetectingUrlHandlerMapping.detectHandlers()
BeanNameUrlHandlerMapping.determineUrlsForHandler(String beanName) 或者 DefaultAnnotationHandlerMapping.determineUrlsForHandler(String beanName)
4. AbstractDetectingUrlHandlerMapping.detectHandlers()
遍历所有的DispatcherServlet配置文件中的所有bean,找到相应的URL并进行缓存
protected void detectHandlers() throws BeansException { if (logger.isDebugEnabled()) { logger.debug("Looking for URL mappings in application context: " + getApplicationContext()); } //获取了所有的bean,值得注意的是此处仅取出所有DispatcherServlet相关配置文件涉及的所有类 String[] beanNames = (this.detectHandlersInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : getApplicationContext().getBeanNamesForType(Object.class)); // 遍历 for (String beanName : beanNames) { //拿到Controller 上配置的所有URL String[] urls = determineUrlsForHandler(beanName); if (!ObjectUtils.isEmpty(urls)) { // 将所有的 url与controller对应关系存储下来 registerHandler(urls, beanName); } else { if (logger.isDebugEnabled()) { logger.debug("Rejected bean name '" + beanName + "': no URL paths identified"); } } } } 5.DefaultAnnotationHandlerMapping.determineUrlsForHandler(String beanName)解析bean的@RequestMapping
protected String[] determineUrlsForHandler(String beanName) { ApplicationContext context = getApplicationContext(); Class<?> handlerType = context.getType(beanName); //找到对应bean 类级别标注的所有的 @RequestMapping RequestMapping mapping = context.findAnnotationOnBean(beanName, RequestMapping.class); if (mapping != null) { this.cachedMappings.put(handlerType, mapping); Set<String> urls = new LinkedHashSet<String>(); String[] typeLevelPatterns = mapping.value(); if (typeLevelPatterns.length > 0) { // 找到对应bean 方法级别的所有 @RequestMapping String[] methodLevelPatterns = determineUrlsForHandlerMethods(handlerType, true); for (String typeLevelPattern : typeLevelPatterns) { if (!typeLevelPattern.startsWith("/")) { typeLevelPattern = "/" + typeLevelPattern; } boolean hasEmptyMethodLevelMappings = false; for (String methodLevelPattern : methodLevelPatterns) { if (methodLevelPattern == null) { hasEmptyMethodLevelMappings = true; } else { String combinedPattern = getPathMatcher().combine(typeLevelPattern, methodLevelPattern); //将类级别@RequestMapping和方法级别的@RequestMapping组合放入list addUrlsForPath(urls, combinedPattern); } } if (hasEmptyMethodLevelMappings || org.springframework.web.servlet.mvc.Controller.class.isAssignableFrom(handlerType)) { addUrlsForPath(urls, typeLevelPattern); } } return StringUtils.toStringArray(urls); } else { // actual paths specified by @RequestMapping at method level return determineUrlsForHandlerMethods(handlerType, false); } } else if (AnnotationUtils.findAnnotation(handlerType, Controller.class) != null) { // @RequestMapping to be introspected at method level return determineUrlsForHandlerMethods(handlerType, false); } else { return null; } } 6. AbstractUrlHandlerMapping.registerHandler(String urlPath, Object handler)将url 和 controller放入缓存,后续处理url请求时将会用到
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException { Assert.notNull(urlPath, "URL path must not be null"); Assert.notNull(handler, "Handler object must not be null"); Object resolvedHandler = handler; // Eagerly resolve handler if referencing singleton via name. if (!this.lazyInitHandlers && handler instanceof String) { String handlerName = (String) handler; if (getApplicationContext().isSingleton(handlerName)) { resolvedHandler = getApplicationContext().getBean(handlerName); } } Object mappedHandler = this.handlerMap.get(urlPath); if (mappedHandler != null) { if (mappedHandler != resolvedHandler) { throw new IllegalStateException( "Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath + "]: There is already " + getHandlerDescription(mappedHandler) + " mapped."); } } else { if (urlPath.equals("/")) { if (logger.isInfoEnabled()) { logger.info("Root mapping to " + getHandlerDescription(handler)); } setRootHandler(resolvedHandler); } else if (urlPath.equals("/*")) { if (logger.isInfoEnabled()) { logger.info("Default mapping to " + getHandlerDescription(handler)); } setDefaultHandler(resolvedHandler); } else { this.handlerMap.put(urlPath, resolvedHandler); if (logger.isInfoEnabled()) { logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler)); } } } }
