SpringMVC组件(一)--HandlerMapping
《看透springMvc源代码分析与实践》学习笔记
HandlerMapping
HandlerMapping的作用是:通过getHandler来获取请求的Handler和Interceptors。
它在 DispatcherServlet.initHandlerMappings(context)
中被初始化,在DispatcherServlet.properties
中配置:
默认使用: BeanNameUrlHandlerMapping
和DefaultAnnotationHandlerMapping
。
HandlerMapping类图
HandlerMapping所有的实现类都继承了一个共有的抽象类AbstractHandlerMapping
,它所有的子类中分类如下几支:
-
EmptyHandlerMapping
: 空处理,直接返回为空 -
AbstractHandlerMethodMapping
: 通过method处理 -
AbstractUrlHandlerMapping
: 通过url处理
AbstractHandlerMapping
AbstractHandlerMapping
是HandlerMapping
的抽象实现,所有的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;
}
}
lookupHandlerlookupHandler
方法用于使用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;
}
buildPathExposingHandlerbuildPathExposingHandler
方法用于给查找到的handler注册两个内部拦截器PathExposingHandlerInterceptor
和UriTemplateVariablesHandlerInterceptor
,主要的作用是将与当前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,并且可以通过设置excludedPackages
和excludedClasses
排除不必要的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);
}
}
它有两个子类:ControllerBeanNameHandlerMapping
和ControllerClassNameHandlerMapping
-
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 {
private final Map<T, HandlerMethod> handlerMethods = new LinkedHashMap<T, HandlerMethod>();
private final MultiValueMap<String, T> urlMap = new LinkedMultiValueMap<String, T>();
}
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>> {}
AbstractHandlerMethodMapping继承了AbstractHandlerMapping
, 它也是通过重写initApplicationContext
方法来注册Handler的。
//org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping {
@Override
public void initApplicationContext() throws ApplicationContextException {
super.initApplicationContext();
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