SpringMVC4-组件(一)-HandlerMapping

《看透springMvc源代码分析与实践》学习笔记
SpringMVC 版本 4.1.5.RELEASE

HandlerMapping

HandlerMapping的作用是:通过getHandler来获取请求的Handler和Interceptors。
它在 DispatcherServlet.initHandlerMappings(context)中被初始化,在DispatcherServlet.properties中配置:
在这里插入图片描述
默认使用: BeanNameUrlHandlerMappingDefaultAnnotationHandlerMapping

HandlerMapping类图

在这里插入图片描述
HandlerMapping所有的实现类都继承了一个共有的抽象类AbstractHandlerMapping,它所有的子类中分类如下几支:

  • EmptyHandlerMapping: 空处理,直接返回为空
  • AbstractHandlerMethodMapping: 通过method处理
  • AbstractUrlHandlerMapping: 通过url处理

AbstractHandlerMapping

AbstractHandlerMappingHandlerMapping的抽象实现,所有的HandlerMapping的实现类都继承自AbstractHandlerMapping。AbstractHandlerMapping采用模板模式设计了HandlerMapping实现的整体架构,子类只需要通过模板方法提供一些初始值或具体的算法即可
HandlerMapping的作用是根据request找到Handler和Interceptors。

  • 获取Handler的过程通过模板方法getHandlerInternal交给了子类。
  • AbstractHandlerMapping保存了所用配置的Inteceptor,在获取Handler后自己根据从request提取的lookupPath将相应的Intercptors装配上去,当然子类也可以通过getHandlerInternal设置自己的Intercptor.

创建AbstractHandlerMapping

AbstractHandlerMapping继承了WebApplicationObjectSupport,初始化时会自动调用模板方法initApplicationContext,AbstractHandlerMapping的创建就是在initApplicationContext()方法里实现的。

//org.springframework.web.servlet.handler.AbstractHandlerMapping
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
		implements HandlerMapping, Ordered {
		
		/**
		 * 用于配置SpringMVC的拦截器,有两种方式配置:
		 * - 注册HandlerMapping时通过属性设置。
		 * - 通过子类的extendInterceptors模板方法设置。
		 *
		 * interceptors并不会直接使用,而是通过initInterceptors()分配到mappedInterceptors 或者 adaptedInterceptors中进行使用。
		**/
		private final List<Object> interceptors = new ArrayList<Object>();
	
	//全局拦截器:无需匹配url
    	private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<HandlerInterceptor>();

	//path拦截器: 通过匹配url拦截
    	private final List<MappedInterceptor> mappedInterceptors = new ArrayList<MappedInterceptor>();
    	
		@Override
    	protected void initApplicationContext() throws BeansException {
    	    //模板方法,供子类实现: 用于给子类提供一个添加(修改)interceptors的入口,现有SpringMVC 没有实现。
    		extendInterceptors(this.interceptors);

		//初始化mappedInterceptors
    		detectMappedInterceptors(this.mappedInterceptors);
			
		//初始化Interceptor:  分配interceptors 
    		initInterceptors();
    	}
    	
    	//将SpringMVC容器以及父容器中所有的MappedInterceptor类型的Bean添加到mappedInterceptors
    	protected void detectMappedInterceptors(List<MappedInterceptor> mappedInterceptors) {
            mappedInterceptors.addAll(
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(
                            getApplicationContext(),MappedInterceptor.class, true, false).values());
        }	
       
       //将interceptors中各对象类型添加至 mappedInterceptors 或者 adaptedInterceptors
        protected void initInterceptors() {
            if (!this.interceptors.isEmpty()) {
                for (int i = 0; i < this.interceptors.size(); i++) {
                    Object interceptor = this.interceptors.get(i);
                    if (interceptor == null) {
                        throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
                    }
                    if (interceptor instanceof MappedInterceptor) {
                        mappedInterceptors.add((MappedInterceptor) interceptor);
                    }    else {
                        adaptedInterceptors.add(adaptInterceptor(interceptor));
                    }
                }
            }
        }

}

AbstractHandlerMapping之用

HandlerMapping是通过getHandler来获取请求的Handler和Interceptors,下面看下它在AbstractHandlerMapping中的实现。

//org.springframework.web.servlet.handler.AbstractHandlerMapping
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	//模板方法,由子类实现
    Object handler = getHandlerInternal(request);
    if (handler == null) {
        handler = getDefaultHandler();
    }
    if (handler == null) {
        return null;
    }
    // Bean name or resolved handler?
    if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = getApplicationContext().getBean(handlerName);
    }
    return getHandlerExecutionChain(handler, request);
}

getHandler方法的实现分为两部分:找Handler和getHandlerExecutionChain添加拦截器。
找Handle的过程

  • 通过getHandlerInternal()模板方法获取,此方法由子类实现。
  • 如果没有获取到则使用默认的Handler,可以在配置HandlerMapping时通过defaultHandler属性配置。
  • 如果找到的Handler是String类型,则从SpringMVC容器里找到一它为名的Bean.

getHandlerExecutionChain

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    HandlerExecutionChain chain = 
        (handler instanceof HandlerExecutionChain) ?
            (HandlerExecutionChain) handler : new HandlerExecutionChain(handler);
        
    //添加全局inteceptors        
    chain.addInterceptors(getAdaptedInterceptors());
    
    String lookupPath = urlPathHelper.getLookupPathForRequest(request);
    for (MappedInterceptor mappedInterceptor : mappedInterceptors) {
         //根据url 匹配寻找 MappedInterceptor
        if (mappedInterceptor.matches(lookupPath, pathMatcher)) {
            chain.addInterceptor(mappedInterceptor.getInterceptor());
        }
    }
    return chain;
}

getHandlerExecutionChain方法比较简单: 首先是使用handler创建HandlerExecutionChain,然后跟去将adaptedInterceptors和与request匹配的mappedInterceptors添加进去即可。


AbstractUrlHandlerMapping 系列

AbstractUrlHandlerMapping从名称就可以看出它是通过url来进行匹配的。 它工作的大致原理: 将url与对应的Handler保存在一个Map中,在它的getHandlerInternal方法中,使用url从Map中获取Handler.

  • AbstractUrlHandlerMapping实现了根据url从Map获取Handler的逻辑,
    Map的初始化工作则交给了子孙类中实现
  • AbstractUrlHandlerMapping还定义了"/"请求处理器 rootHandler

Handler方法的入口是getHandlerInternal,通过这个方法,查看下Map是如何初始化的。

//org.springframework.web.servlet.handler.AbstractUrlHandlerMapping
public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
    private Object rootHandler;
	private final Map<String, Object> handlerMap = new LinkedHashMap<String, Object>();
    
   	@Override
   	protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
   	    //获取request的请求url
   		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
   		
   		//注1. 从Map中查找匹配的Handler
   		Object handler = lookupHandler(lookupPath, request);
   		if (handler == null) {
   			Object rawHandler = null;
   			if ("/".equals(lookupPath)) {
   				rawHandler = getRootHandler();
   			}
   			if (rawHandler == null) {
   				rawHandler = getDefaultHandler();
   			}
   			if (rawHandler != null) {
   				// 如果handler是String,则到容器找到对应的bean.
   				if (rawHandler instanceof String) {
   					String handlerName = (String) rawHandler;
   					rawHandler = getApplicationContext().getBean(handlerName);
   				}
   				
   				//校验handler与request是否匹配,模板方法由子类实现。(已知的子类中都没有实现)
   				validateHandler(rawHandler, request);
   				
   				//注2. 
   				handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
   			}
   		}
   	       
   	     //log 略.....
   		return handler;
   	}
}

lookupHandler
lookupHandler方法用于使用lookupPath从Map中找到匹配的Handler,不过很多时候并不能直接从Map中get到,因为很多Handler都用了Pattern模式,如“/user/*”,这就造成了

  • 无法直接从Map中get到对应的Handler
  • 同一个url可能会匹配到多个Handler

lookupHandler方法如下:

//org.springframework.web.servlet.handler.AbstractUrlHandlerMapping
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
		// 从map中获取,判断是否直接全字匹配。
		Object handler = this.handlerMap.get(urlPath);
		if (handler != null) {
			// 如果为String,则从容器中获取bean
			if (handler instanceof String) {
				String handlerName = (String) handler;
				handler = getApplicationContext().getBean(handlerName);
			}
			validateHandler(handler, request);
			return buildPathExposingHandler(handler, urlPath, urlPath, null);
		}
		// Pattern 匹配
		List<String> matchingPatterns = new ArrayList<String>();
		for (String registeredPattern : this.handlerMap.keySet()) {
			if (getPathMatcher().match(registeredPattern, urlPath)) {
			    //记录匹配到的 patterns
				matchingPatterns.add(registeredPattern);
			}
		}
		String bestPatternMatch = null;
		
		//自定义Comparator ,按照规则对匹配到的patterns进行匹配:: Comparatorg根据 *,以及{ 个数来判断优先级.
		Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
		if (!matchingPatterns.isEmpty()) {
			Collections.sort(matchingPatterns, patternComparator);
			
			//获取bestPatternMatch
			bestPatternMatch = matchingPatterns.get(0);
		}
		if (bestPatternMatch != null) {
			handler = this.handlerMap.get(bestPatternMatch);
			// 如果为String,则从容器中获取bean
			if (handler instanceof String) {
				String handlerName = (String) handler;
				handler = getApplicationContext().getBean(handlerName);
			}
			validateHandler(handler, request);
			
			/**
			 * 获取pattern通配符即* 匹配的部分
			 * matcher.extractPathWithinPattern("/*/*", "/user/add");  //结果: user/add
			 * matcher.extractPathWithinPattern("/user/*", "/user/add");  //结果: add
			 * matcher.extractPathWithinPattern("/*/add", "/user/add");  //结果: user
			 */
			String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath);
			

			//matchingPatterns中可能有多个 同 bestPatternMatch 优先级相同的 patterns, 将所有同级别的pattern记录
			Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();
			for (String matchingPattern : matchingPatterns) {
			    //通过compare ==0 ,说明matchingPattern与bestPatternMatch 优先级相同
				if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {
				    /**
				     * getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath)伪码表示:
				     *  判断urlPath与matchingPattern是否匹配,
				     *  如果匹配:则返回一个LinkedHashMap<String, String>().of(urlPath,matchingPattern);
				     *  否则:返回一个 LinkedHashMap.empty();
				     */
					uriTemplateVariables.putAll(getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath));
				}
			}
			return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);
		}
		// No handler found...
		return null;
	}

buildPathExposingHandler
buildPathExposingHandler方法用于给查找到的handler注册两个内部拦截器PathExposingHandlerInterceptorUriTemplateVariablesHandlerInterceptor,主要的作用是将与当前url实际匹配的pattern、匹配条件和url等参数设置到request的属性里,这样在后续的处理过程中就可以从request属性中获取,无需再查找一遍。

//org.springframework.web.servlet.handler.AbstractUrlHandlerMapping $ PathExposingHandlerInterceptor
	private class PathExposingHandlerInterceptor extends HandlerInterceptorAdapter {

	private final String bestMatchingPattern;

	private final String pathWithinMapping;

	public PathExposingHandlerInterceptor(String bestMatchingPattern, String pathWithinMapping) {
		this.bestMatchingPattern = bestMatchingPattern;
		this.pathWithinMapping = pathWithinMapping;
	}

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
		exposePathWithinMapping(this.bestMatchingPattern, this.pathWithinMapping, request);
		request.setAttribute(HandlerMapping.INTROSPECT_TYPE_LEVEL_MAPPING, supportsTypeLevelMappings());
		return true;
	}

}

Map初始化
Map的初始化工作是由registerHandler方法进行的, 与之前不同的是,该方法是由子类调用的。 该方法代码如下:

//org.springframework.web.servlet.handler.AbstractUrlHandlerMapping
protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException {
    for (String urlPath : urlPaths) {
        registerHandler(urlPath, beanName);
    }
}


protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
		Object resolvedHandler = handler;

		// 如果没有设置lazyInitHandlers ,且handler是string
		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) {
			// 抛出异常,同一url 全路径完整匹配到多个Handler...
				throw new IllegalStateException(
						"Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
						"]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
			}
		}
		else {
			if (urlPath.equals("/")) {
			    //设置rootHandler
				setRootHandler(resolvedHandler);
			}
			else if (urlPath.equals("/*")) {
			 //设置defaultHandler
				setDefaultHandler(resolvedHandler);
			}
			else {
			    //添加url : handler 至 Map
				this.handlerMap.put(urlPath, resolvedHandler);
			}
		}
	}

AbstractUrlHandlerMapping定义了整体架构,子类只需要将Map初始化就可以了。


SimpleUrlHandlerMapping

SimpleUrlHandlerMapping通过重写initApplicationContext方法来注册Handler,它的代码非常简单,如下:

//org.springframework.web.servlet.handler.SimpleUrlHandlerMapping
public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping {
    
    private final Map<String, Object> urlMap = new HashMap<String, Object>();
    
    //提供设置urlMap接口
    public void setMappings(Properties mappings) {
        CollectionUtils.mergePropertiesIntoMap(mappings, this.urlMap);
    }
    	
    public void initApplicationContext() throws BeansException {
        super.initApplicationContext();
        
        //调用registerHandlers
        registerHandlers(this.urlMap);
    }
        
    protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
        if ( !urlMap.isEmpty()) {
            for (Map.Entry<String, Object> entry : urlMap.entrySet()) {
                String url = entry.getKey();
                Object handler = entry.getValue();
                // url以"/"起始..
                if (!url.startsWith("/")) {
                    url = "/" + url;
                }
                // trim
                if (handler instanceof String) {
                    handler = ((String) handler).trim();
                }
                
                //调用父类方法registerHandler
                registerHandler(url, handler);
            }
        }
    }
}

AbstractDetectingUrlHandlerMapping

AbstractDetectingUrlHandlerMapping也是通过重写initApplicationContext方法来注册Handler的,在方法中调用了detectHandlers,它的逻辑也比较简单,代码如下:

//org.springframework.web.servlet.handler.AbstractDetectingUrlHandlerMapping
public abstract class AbstractDetectingUrlHandlerMapping extends AbstractUrlHandlerMapping {
    
    //标识是否从SpringMVC及其父容器查找Handler
    private boolean detectHandlersInAncestorContexts = false;
    
	@Override
	public void initApplicationContext() throws ApplicationContextException {
		super.initApplicationContext();
		detectHandlers();
	}

    protected void detectHandlers() throws BeansException {
        //detectHandlersInAncestorContexts为ture,从springMVC以及其祖先上下文寻找bean,否则仅从SpringMVC容器中寻找
		String[] beanNames = (this.detectHandlersInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
				getApplicationContext().getBeanNamesForType(Object.class));

		//对每个bean 如果能解析出url,就注册到父类的map中。
		for (String beanName : beanNames) {
		    //determineUrlsForHandler 模板方法,由子类实现。
			String[] urls = determineUrlsForHandler(beanName);
			if (!ObjectUtils.isEmpty(urls)) {
				//注册到父类Map中
				registerHandler(urls, beanName);
			}
		}
	}

}

AbstractDetectingUrlHandlerMapping 有三个子类:

  • DefaultAnnotationHandlerMapping
  • BeanNameUrlHandlerMapping
  • AbstractControllerUrlHandlerMapping

DefaultAnnotationHandlerMapping
DefaultAnnotationHandlerMapping通过判断类以及方法是否存在RequestMapping.class注解,来寻找urls:

public class DefaultAnnotationHandlerMapping extends AbstractDetectingUrlHandlerMapping {
    
    protected String[] determineUrlsForHandler(String beanName) {
    		ApplicationContext context = getApplicationContext();
    		Class<?> handlerType = context.getType(beanName);
    		 //寻找 @RequestMapping bean...
    		RequestMapping mapping = context.findAnnotationOnBean(beanName, RequestMapping.class);
    		if (mapping != null) {
    			//type即类级别的注解
    			this.cachedMappings.put(handlerType, mapping);
    			Set<String> urls = new LinkedHashSet<String>();
    			String[] typeLevelPatterns = mapping.value();
    			if (typeLevelPatterns.length > 0) {
    				//方法级别的注解
    				String[] methodLevelPatterns = determineUrlsForHandlerMethods(handlerType, true);
    				for (String typeLevelPattern : typeLevelPatterns) {
    					if (!typeLevelPattern.startsWith("/")) {
    						typeLevelPattern = "/" + typeLevelPattern;
    					}
    					//存在为空的Method-Mapping
    					boolean hasEmptyMethodLevelMappings = false;
    					for (String methodLevelPattern : methodLevelPatterns) {
    						if (methodLevelPattern == null) {
    							hasEmptyMethodLevelMappings = true;
    						}else {
    						    //将 类级别url + 方法级别url 拼接
                                String combinedPattern = getPathMatcher().combine(typeLevelPattern, methodLevelPattern);
                                addUrlsForPath(urls, combinedPattern);
                            }
    					}
    					
    					/**
    					 * 如果@RequestMapping.value == null的 方法 或者 是Controller子类(controller接口定义如下:)
    					 public interface Controller {
                          	ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
                          }
                          
                         * 将 类级别url 添加urls中
    					 */
    					if (hasEmptyMethodLevelMappings || org.springframework.web.servlet.mvc.Controller.class.isAssignableFrom(handlerType)) {
    						addUrlsForPath(urls, typeLevelPattern);
    					}
    				}
    				return StringUtils.toStringArray(urls);
    			}else {
                    //直接寻找 @RequestMapping 方法
                    return determineUrlsForHandlerMethods(handlerType, false);
                }
    			
    		}//存在@Controller注解,但是Controller没有设置@RequestMapping
            else if (AnnotationUtils.findAnnotation(handlerType, Controller.class) != null) {
                //直接寻找Controller内定义的方法
                return determineUrlsForHandlerMethods(handlerType, false);
            } else {
                 return null;
             }
    	}
    	
    protected String[] determineUrlsForHandlerMethods(Class<?> handlerType, final boolean hasTypeLevelMapping) {
            //获取自类的url结果,此处返回为空
    		String[] subclassResult = determineUrlsForHandlerMethods(handlerType);
    		if (subclassResult != null) {
    			return subclassResult;
    		}
    
    		final Set<String> urls = new LinkedHashSet<String>();
    		Set<Class<?>> handlerTypes = new LinkedHashSet<Class<?>>();
    		handlerTypes.add(handlerType);
    		handlerTypes.addAll(Arrays.asList(handlerType.getInterfaces()));
    		
    		//遍历类 +以及该类 所有的接口 中所有方法存在@RequestMapping的方法。
    		for (Class<?> currentHandlerType : handlerTypes) {
    			ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {
    				public void doWith(Method method) {
    					RequestMapping mapping = AnnotationUtils.findAnnotation(method, RequestMapping.class);
    					if (mapping != null) {
    						String[] mappedPatterns = mapping.value();
    						if (mappedPatterns.length > 0) {
    							for (String mappedPattern : mappedPatterns) {
    								if (!hasTypeLevelMapping && !mappedPattern.startsWith("/")) {
    									mappedPattern = "/" + mappedPattern;
    								}
    								addUrlsForPath(urls, mappedPattern);
    							}
    						}
    						else if (hasTypeLevelMapping) {
    							urls.add(null);
    						}
    					}
    				}
    			}, ReflectionUtils.USER_DECLARED_METHODS);
    		}
    		return StringUtils.toStringArray(urls);
    	}
    	
    	
    protected String[] determineUrlsForHandlerMethods(Class<?> handlerType) {
        return null;
    }
}

BeanNameUrlHandlerMapping
BeanNameUrlHandlerMapping只有一个方法determineUrlsForHandler,检查beanName和alias是不是以"/"开头,如果是就将其作为url.

//org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {
	@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);
	}

}

AbstractControllerUrlHandlerMapping
AbstractControllerUrlHandlerMapping是将实现了Controller接口或者添加@Controller注解的bean作为Handler,并且可以通过设置excludedPackagesexcludedClasses排除不必要的packages和classes.determineUrlsForHandler方法的作用是将符合条件的Handler找出来,而具体用什么Url则交给模板方法buildUrlsForHandler由子类去实现:

//org.springframework.web.servlet.mvc.support.AbstractControllerUrlHandlerMapping
public abstract class AbstractControllerUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping  {
    private ControllerTypePredicate predicate = new AnnotationControllerTypePredicate();

    private Set<String> excludedPackages = Collections.singleton("org.springframework.web.servlet.mvc");
	private Set<Class> excludedClasses = Collections.emptySet();
	
	
	@Override
    protected String[] determineUrlsForHandler(String beanName) {
        Class beanClass = getApplicationContext().getType(beanName);
        //判断是否支持beanClass类型
        if (isEligibleForMapping(beanName, beanClass)) {
            //模板方法,由子类实现
            return buildUrlsForHandler(beanName, beanClass);
        }
        else {
            return null;
        }
    }
    
    protected boolean isEligibleForMapping(String beanName, Class beanClass) {
        if (beanClass == null) {
            return false;
        }
        //排除classes
        if (this.excludedClasses.contains(beanClass)) {
            return false;
        }
        
        //排除package..
        String beanClassName = beanClass.getName();
        for (String packageName : this.excludedPackages) {
            if (beanClassName.startsWith(packageName)) {
                return false;
            }
        }
        
        //判断beanClass是否为Controller子类或者 存在@Controller注解
        return isControllerType(beanClass);
    }
}

它有两个子类:ControllerBeanNameHandlerMappingControllerClassNameHandlerMapping

  • ControllerBeanNameHandlerMapping: 将beanName和alias 当成url;
  • ControllerClassNameHandlerMapping: 将ClassName当成url;
public class ControllerClassNameHandlerMapping extends AbstractControllerUrlHandlerMapping {
    //如果beanclass以"Controller" 则剔除此部分.
    private static final String CONTROLLER_SUFFIX = "Controller";
    
    private boolean caseSensitive = false;
    private String pathPrefix;
    private String basePackage;
    
    private StringBuilder buildPathPrefix(Class beanClass) {
        StringBuilder pathMapping = new StringBuilder();
        if (this.pathPrefix != null) {
            pathMapping.append(this.pathPrefix);
            pathMapping.append("/");
        } else {
             pathMapping.append("/");
         }
       
       //如果配置了basepackage,则subPackage转换为path...
        if (this.basePackage != null) {
            String packageName = ClassUtils.getPackageName(beanClass);
            if (packageName.startsWith(this.basePackage)) {
                String subPackage = packageName.substring(this.basePackage.length()).replace('.', '/');
                
                //判断是否大小写敏感
                pathMapping.append(this.caseSensitive ? subPackage : subPackage.toLowerCase());
                pathMapping.append("/");
            }
        }
        return pathMapping;
    }
}

AbstractUrlHandlerMapping 系列就分析完了。
AbstractUrlHandlerMapping 中设计了整体的结构,并完成通过request-url匹配Handler的通用逻辑。
所有的url和Handler对应关系保存在Map中,Map的初始化工作则由:子类通过调用父类registerHandler方法来完成。



AbstractHandlerMethodMapping 系列

AbstractHandlerMethodMapping从结构图上看非常简单,只有三个类:AbstractHandlerMethodMapping,RequestMappingInfoHandlerMapping,RequestMappingHandlerMapping,这三个类依次继承,AbstractHandlerMethodMapping继承AbstractHandlerMapping
AbstractHandlerMethodMapping系列是将Method作为Handler来使用的,这也是我们使用最多的一种Handler,比如使用@RequestMapping注释的方法就是这种Handler.

创建 AbstractHandlerMethodMapping

创建AbstractHandlerMethodMapping 最先需要理解它定义的三个Map的含义:

//org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
    private final Map<T, HandlerMethod> handlerMethods = new LinkedHashMap<T, HandlerMethod>();
    
    private final MultiValueMap<String, T> urlMap = new LinkedMultiValueMap<String, T>();
    
	private final MultiValueMap<String, HandlerMethod> nameMap = new LinkedMultiValueMap<String, HandlerMethod>();
}

map中使用类泛型<T>,它代表用来匹配Handler的条件专用类。

这里的条件不是url了,还可以有很多其他条件,如request类型(GET,POST)、请求的参数、HEADER等,都可以作为匹配条件,默认使用RequestMappingInfo.
它的类图如下:
在这里插入图片描述

接下来我们分析下Map

  • handlerMethods: 保存匹配条件T和HandlerMethod的对应关系。
  • urlMap:保存着url和匹配条件T的对应关系(url可以使用通配符),这个map不是一个普通的map,而是MultiValueMap,这是一种一个key对应多个值的map,这里的value其实是一个List,它的代码申明如下:
public interface MultiValueMap<K, V> extends Map<K, List<V>> {}
  • nameMap: 这个Map是SpringMVC4新增的。它保存着name与HandlerMethod的对应关系。

这里的name是使用HandlerMethodMappingNamingStrategy策略从HandlerMethod中解析出来的。默认使用RequestMappingInfoHandlerMethodMappingNamingStrategy,解析规则是取类名里的大写字母 + #+方法名。如:GoController.index()即解析为GC#index
这个Map在正常的匹配过程中并不使用,主要用在MvcUriComponentsBuilder里面,这里不再介绍。

AbstractHandlerMethodMapping实现了InitializingBean, 所以spring容器会自动调用afterPropertiesSet方法,而它又调用了initHandlerMethods来完成Handler初始化工作。

//org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping {
	@Override
	public void afterPropertiesSet() {
		initHandlerMethods();
	}
    
    protected void initHandlerMethods() {
        String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
                BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
                getApplicationContext().getBeanNamesForType(Object.class));

        for (String beanName : beanNames) {
            //isHandler()模板方法,由子类实现RequestMappingHandlerMapping实现,判断类是否有@Controller注解
            if (isHandler(getApplicationContext().getType(beanName))){
                detectHandlerMethods(beanName);
            }
        }
        
        //模板方法,由子类实现--- 目前为空,没有实现.
        handlerMethodsInitialized(getHandlerMethods());
    }
    
    protected void detectHandlerMethods(final Object handler) {
        Class<?> handlerType = (handler instanceof String) ? 
                getApplicationContext().getType((String) handler) : handler.getClass();

        final Class<?> userType = ClassUtils.getUserClass(handlerType);
                
        //过滤出userType中 所有符合MethodFilter()的方法
        Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
            public boolean matches(Method method) {
                //模板方法,由子类RequestMappingHandlerMapping实现,判断方法是否带有@RequestMapping注解,并构建RequestMappingInfo并返回。
                return getMappingForMethod(method, userType) != null;
            }
        });
        
        for (Method method : methods) {
            T mapping = getMappingForMethod(method, userType);
            
            //将匹配信息分别注册到 handlerMethods 和urlMap中
            registerHandlerMethod(handler, method, mapping);
        }
    }
    
    protected void registerHandlerMethod(Object handler, Method method, T mapping) {
        HandlerMethod handlerMethod;
        if (handler instanceof String) {
            String beanName = (String) handler;
            handlerMethod = new HandlerMethod(beanName, getApplicationContext(), method);
        }else {
            handlerMethod = new HandlerMethod(handler, method);
        }
        
        HandlerMethod oldHandlerMethod = handlerMethods.get(mapping);
        //为了防止针对同一mapping,注册两个不同的HandlerMethod,直接抛出异常
        if (oldHandlerMethod != null && !oldHandlerMethod.equals(handlerMethod)) {
            throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + handlerMethod.getBean()
                    + "' bean method \n" + handlerMethod + "\nto " + mapping + ": There is already '"
                    + oldHandlerMethod.getBean() + "' bean method\n" + oldHandlerMethod + " mapped.");
        }
        
        handlerMethods.put(mapping, handlerMethod);
        
        //getMappingPathPatterns抽象方法,由子类RequestMappingInfoHandlerMapping实现。
        Set<String> patterns = getMappingPathPatterns(mapping);
        for (String pattern : patterns) {
            if (!getPathMatcher().isPattern(pattern)) {
                urlMap.add(pattern, mapping);
            }
        }
    }
}

RequestMappingInfoHandlerMapping

//org.springframework.web.servlet.handler.RequestMappingInfoHandlerMapping;
public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> {
	@Override
	protected Set<String> getMappingPathPatterns(RequestMappingInfo info) {
		return info.getPatternsCondition().getPatterns();
	}
}

RequestMappingHandlerMapping

//org.springframework.web.servlet.handler.RequestMappingHandlerMapping;
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping {
    @Override
    protected boolean isHandler(Class<?> beanType) {
        return AnnotationUtils.findAnnotation(beanType, Controller.class) != null;
    }
    
    @Override
    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        RequestMappingInfo info = null;
        //获取method的@RequestMapping信息
        RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
        if (methodAnnotation != null) {
            RequestCondition<?> methodCondition = getCustomMethodCondition(method);
			
			//构建RequestMappingInfo 
            info = createRequestMappingInfo(methodAnnotation, methodCondition);
			
			//判断method所在类是否有@RequestMapping注解
            RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
            if (typeAnnotation != null) {
                RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType);
			   
			   //将method和type 对应的RequestMappingInfo  结合,构建新的RequestMappingInfo  返回。
                info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info);
            }
        }
        return info;
    }
}



到这里HandlerMapping解析完毕。HandlerMapping的整体结构在AbstractHandlerMapping中设计,具体操作才各子类中实现。
HandlerMapping的作用简单来说就是:

  • 首先初始化时构注册所有的handler以及inteceptors,
  • 然后根据请求request找到Handler,然后构建HandlerExecutionChain
  • 然后根据请求request找到匹配的Inteceptors,然后添加到HandlerExecutionChain中
  • 最后返回HandlerExecutionChain
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值