DispatcherServlet与HandlerMapping关系
客户端发送请求,web容器接受请求,如果请求与DispatcherServlet的请求映射路径(url-pattern)匹配,web容器将请求交给DispatcherServlet处理。DispatcherServlet在加载的过程中会对HandlerMapping进行初始化,(具体可参照SpringMVC源码中DispatherServlet类的initHandlerMappings(ApplicationContextcontext)方法)。DispatcherServlet初始化完成后会自动扫描applicationContext.xml中的bean,根据名称(也就是bean的id或者类型来查找,如果找到则使用这个bean,找不到则使用DispatcherServlet.properties中的默认组件.
handlerMapping初始化
简单来说就是用来存储所有URL与处理类的map关系,以及在请求过来的时候根据输入URL
匹配到对应的处理类第一步:DefaultAnnotationHandlerMapping继承了AbstractDetectingUrlHandlerMapping,
在AbstractDetectingUrlHandlerMapping中遍历所有的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"); } } } }第二步:看一下这个类:DefaultAnnotationHandlerMapping,其中determineUrlsForHandler(String beanName)和
determineUrlsForHandlerMethods(Class<?> handlerType,
final boolean hasTypeLevelMapping)解析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; } }第三步: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; if (!this.lazyInitHandlers && handler instanceof String) { String handlerName = (String)handler; if (this.getApplicationContext().isSingleton(handlerName)) { resolvedHandler = this.getApplicationContext().getBean(handlerName); } } Object mappedHandler = this.handlerMap.get(urlPath); if (mappedHandler != null) { if (mappedHandler != resolvedHandler) { throw new IllegalStateException("Cannot map "
this.getHandlerDescription(handler) +
" to URL path [" + urlPath + "]: There is already " +
this.getHandlerDescription(mappedHandler) + " mapped."); } } else if (urlPath.equals("/")) { if (this.logger.isInfoEnabled()) { this.logger.info("Root mapping to " + this.getHandlerDescription(handler)); } this.setRootHandler(resolvedHandler); } else if (urlPath.equals("/*")) { if (this.logger.isInfoEnabled()) { this.logger.info("Default mapping to " + this.getHandlerDescription(handler)); } this.setDefaultHandler(resolvedHandler); } else { this.handlerMap.put(urlPath, resolvedHandler); if (this.logger.isInfoEnabled()) { this.logger.info("Mapped URL path [" + urlPath + "] onto " +
this.getHandlerDescription(handler)); } }}