DispatcherServlet.doDispatch方法的getHandler(request)方法
/**
* 返回此请求的HandlerExecutionChain。
* <p>按顺序尝试所有处理程序映射。
*
* @param request current HTTP request
* @return the HandlerExecutionChain, or {@code null} if no handler could be found
*/
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
1.hm.getHandler(HttpServletRequest request)方法由AbstractHandlerMapping实现
/**
* 查找给定请求的handler,如果没有找到,回退到默认值
*
* @param request current HTTP request
* @return the corresponding handler instance, or the default handler
* @see #getHandlerInternal
*/
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//获取request的处理程序Handler
Object handler = getHandlerInternal(request);
if (handler == null) {
//返回默认的Handler
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean名称或已解析的处理程序
if (handler instanceof String) {
//如果找到的handler是个bean名称
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
//全局cors配置
CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
每个request请求都会对应到相关的请求处理bean或者处理方法getHandlerInternal(request)方法便是获取请求处理器的,可以参考https://blog.csdn.net/qq_23536449/article/details/99944430,然后对于每个request请求对应的处理器SpringMVC除了让我们可以在执行处理请求执行的前后添加相关的拦截器getHandlerExecutionChain(Object handler, HttpServletRequest request)
/**
* 为给定的处理程序构建{@link HandlerExecutionChain},包括
* 适用的拦截器。
* <p>默认实现使用给定的处理程序,处理程序映射的公共拦截器以及与当前请求URL
* 匹配的任何{@link MappedInterceptor}构建标准{@link HandlerExecutionChain}。
* 拦截器按其注册顺序添加。 子类可以覆盖它以扩展/重新排列拦截器列表。
* <p><b>注意:</ b>传入的处理程序对象可以是原始处理程序或预构建的{@link HandlerExecutionChain}。
* 这种方法应该明确地处理这两种情况,要么建立一个新的{@link HandlerExecutionChain},要么扩展现有的链。
* <p>要简单地在自定义子类中添加拦截器,请考虑调用{@code super.getHandlerExecutionChain(handler,request)}
* 并在返回的链对象上调用{@link HandlerExecutionChain#addInterceptor}。
* @param handler the resolved handler instance (never {@code null})
* @param request current HTTP request
* @return the HandlerExecutionChain (never {@code null})
* @see #getAdaptedInterceptors()
*/
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
//handler可能为HandlerExecutionChain类型
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
//mappedInterceptor类型需要
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
//给定路径匹配成功
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
该方法将handler处理器封装为HandlerExecutionChain对象其中HandlerExecutionChain对象主要属性
public class HandlerExecutionChain {
private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
/**
* 处理器,处理请求
*/
private final Object handler;
/**
* 拦截器
*/
private HandlerInterceptor[] interceptors;
}
handler用于执行请求处理的逻辑,interceptors用于在执行请求逻辑生命周期进行拦截操作。
2.当我们学习过https://blog.csdn.net/qq_23536449/article/details/99944430之后我们知道对于请求的处理要么是Spring帮我们找到一个继承AbstractController的bean处理请求比如通过BeanNameUrlHandlerMapping和SimpleUrlHandlerMapping,要么通过@RequestMapping注解定义对一个请求的处理,这时候请求的处理器是方法级别的,这种模式下Spring通过RequestMappingHandlerMapping帮我们实现对于请求处理方法(统一封装为HandlerMethod)的查找。所以Spring给我们提供了继承AbstractHandlerMapping的两个抽象类AbstractHandlerUrlMapping和AbstractHandlerMethodMapping类用于查找方法级别的请求处理对象和bean级别的请求处理器
3.AbstractHandlerUrlMapping.getHandlerInternal(HttpServletRequest request)
/**
* 查找给定请求的URL路径的处理程序。
* @param request current HTTP request
* @return the handler instance, or {@code null} if none found
*/
@Override
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
Object handler = lookupHandler(lookupPath, request);
if (handler == null) {
// We need to care for the default handler directly, since we need to
// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
Object rawHandler = null;
//根处理器
if ("/".equals(lookupPath)) {
rawHandler = getRootHandler();
}
//默认的处理器
if (rawHandler == null) {
rawHandler = getDefaultHandler();
}
if (rawHandler != null) {
// Bean name or resolved handler?
if (rawHandler instanceof String) {
String handlerName = (String) rawHandler;
rawHandler = getApplicationContext().getBean(handlerName);
}
validateHandler(rawHandler, request);
handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
}
}
if (handler != null && logger.isDebugEnabled()) {
logger.debug("Mapping [" + lookupPath + "] to " + handler);
}
else if (handler == null && logger.isTraceEnabled()) {
logger.trace("No handler mapping found for [" + lookupPath + "]");
}
return handler;
}
/**
* 查找给定URL路径的处理程序实例。
* <p>支持直接匹配,例如 注册的“/ test”匹配“/ test”,
* 和各种Ant风格的模式匹配,例如 注册的“/ t *”匹配“/ test”和“/ team”。 有关详细信息,请参阅AntPathMatcher类。
* <p>寻找最精确的模式,其中最精确的定义为最长的路径模式。
* @param urlPath the URL the bean is mapped to
* @param request current HTTP request (to expose the path within the mapping to)
* @return the associated handler instance, or {@code null} if not found
* @see #exposePathWithinMapping
* @see org.springframework.util.AntPathMatcher
*/
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
// Direct match?
//通过url直接能查找到Handler
Object handler = this.handlerMap.get(urlPath);
if (handler != null) {
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
return buildPathExposingHandler(handler, urlPath, urlPath, null);
}
// Pattern match?
// 使用pathMatcher查找Handler
List<String> matchingPatterns = new ArrayList<String>();
for (String registeredPattern : this.handlerMap.keySet()) {
if (getPathMatcher().match(registeredPattern, urlPath)) {
matchingPatterns.add(registeredPattern);
}
else if (useTrailingSlashMatch()) {
if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
matchingPatterns.add(registeredPattern + "/");
}
}
}
String bestMatch = null;
Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
if (!matchingPatterns.isEmpty()) {
Collections.sort(matchingPatterns, patternComparator);
if (logger.isDebugEnabled()) {
logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
}
bestMatch = matchingPatterns.get(0);
}
if (bestMatch != null) {
handler = this.handlerMap.get(bestMatch);
if (handler == null) {
if (bestMatch.endsWith("/")) {
handler = this.handlerMap.get(bestMatch.substring(0, bestMatch.length() - 1));
}
if (handler == null) {
throw new IllegalStateException(
"Could not find handler for best pattern match [" + bestMatch + "]");
}
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath);
// There might be multiple 'best patterns', let's make sure we have the correct URI template variables
// for all of them
Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();
for (String matchingPattern : matchingPatterns) {
if (patternComparator.compare(bestMatch, matchingPattern) == 0) {
Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
uriTemplateVariables.putAll(decodedVars);
}
}
if (logger.isDebugEnabled()) {
logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);
}
return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables);
}
// No handler found...
return null;
}
方法内容比较多,忽略其他的复杂逻辑该方法,主要是从AbstractUrlHandlerMapping的handlerMap属性中获取request的url对应的处理器的bean谢谢。
对于handlerMap的初始化BeanNameUrlHandlerMapping和SimpleUrlHandlerMapping有所差异
SimpleUrlHandlerMapping通过它的registerHandlers(Map<String,Object> map)方法注册url对应的请求处理bean;
public void setUrlMap(Map<String, ?> urlMap) {
this.urlMap.putAll(urlMap);
}
@Override
public void initApplicationContext() throws BeansException {
super.initApplicationContext();
registerHandlers(this.urlMap);
}
/**
* 注册URL映射中为相应路径指定的所有处理程序。
* @param urlMap Map with URL paths as keys and handler beans or bean names as values
* @throws BeansException if a handler couldn't be registered
* @throws IllegalStateException if there is a conflicting handler registered
*/
protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
if (urlMap.isEmpty()) {
logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
}
else {
for (Map.Entry<String, Object> entry : urlMap.entrySet()) {
String url = entry.getKey();
Object handler = entry.getValue();
// Prepend with slash if not already present.
if (!url.startsWith("/")) {
url = "/" + url;
}
// Remove whitespace from handler bean name.
if (handler instanceof String) {
handler = ((String) handler).trim();
}
registerHandler(url, handler);
}
}
}
如果我们了解SimpleUrlHandlerMapping的用法,上面代码不难理解,读取配置的SimpleUrlHandlerMapping的map属性通过initApplicationContext()方法调用registerHandlers方法将配置的map属性的url对应的处理bean注册到AbstractHandlerMapping中的urlMap中。
BeanNameUrlHandlerMapping通过父类AbstractDetectingUrlHandlerMapping的detectHandlers();方法查找每个bean是否为请求处理对象通过beanName和aliasName是否以"/"开始判断。
/**
* 除了超类的初始化之外,还调用{@link #detectHandlers()}方法
*/
@Override
public void initApplicationContext() throws ApplicationContextException {
super.initApplicationContext();
detectHandlers();
}
/**
* 注册当前ApplicationContext中找到的所有处理程序。
* <p>处理程序的实际URL确定取决于具体情况
* {@link #determineUrlsForHandler(String)}实现。 没有这样的URL可以确定的bean根本不被认为是处理程序。
* @throws org.springframework.beans.BeansException if the handler couldn't be registered
* @see #determineUrlsForHandler(String)
*/
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));
for (String beanName : beanNames) {
//查找给定beanName的所有url
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(beanName);该方法委托给子类BeanNameUrlHandlerMapping实现
/**
* 检查URL的给定bean的名称和别名,以“/”开头。
*/
@Override
protected String[] determineUrlsForHandler(String beanName) {
List<String> urls = new ArrayList<String>();
if (beanName.startsWith("/")) {
urls.add(beanName);
}
//获取bean的别名
String[] aliases = getApplicationContext().getAliases(beanName);
for (String alias : aliases) {
if (alias.startsWith("/")) {
urls.add(alias);
}
}
//获取给定beanName的所有urls
return StringUtils.toStringArray(urls);
}
大致逻辑就是对于每个bean都可能是潜在的处理器,如果beanName或者alias为以"/"开头的,则认为该bean为处理器,并且它处理的请求url为自身的beanName或者alias。
4.AbstractHandlerMethodMapping.getHandlerInternal(HttpServletRequest request)
/**
* 查找给定请求的处理程序方法。
*/
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath);
}
//加上读锁
this.mappingRegistry.acquireReadLock();
try {
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");
}
else {
logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
//释放读锁
this.mappingRegistry.releaseReadLock();
}
}
/**
* 查找当前请求的最佳匹配处理程序方法。如果找到多个匹配项,则选择最佳匹配项。
* @param lookupPath mapping lookup path within the current servlet mapping
* @param request the current request
* @return the best-matching handler method, or {@code null} if no match
* @see #handleMatch(Object, String, HttpServletRequest)
* @see #handleNoMatch(Set, String, HttpServletRequest)
*/
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<Match>();
//获取到了@RequestMapping注解产生的RequestMappingInfo数据
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
//如果不为null
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// No choice but to go through all mappings...
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
//如果不为空
if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
Collections.sort(matches, comparator);
if (logger.isTraceEnabled()) {
logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
lookupPath + "] : " + matches);
}
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
查找的中心主要是围绕着AbstractHandlerMethodMapping对象的MappingRegistry属性查找。
关于MappingRegistry的初始化逻辑主要如下
/**
* Detects handler methods at initialization.
*/
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
/**
* 在ApplicationContext中扫描bean,检测并注册处理程序方法。
* @see #isHandler(Class)
* @see #getMappingForMethod(Method, Class)
* @see #handlerMethodsInitialized(Map)
*/
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
try {
beanType = getApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
//对应class类有@Controller或者@RequestMapping注解
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}
/**
* 在处理程序中查找处理程序方法。
* @param handler the bean name of a handler or a handler instance
*/
protected void detectHandlerMethods(final Object handler) {
//处理器的类型如果是String类型,把该bean创建起来
Class<?> handlerType = (handler instanceof String ?
getApplicationContext().getType((String) handler) : handler.getClass());
final Class<?> userType = ClassUtils.getUserClass(handlerType);
//查找userType每个method方法上的@RequestMapping并映射成为{@link RequestMappingInfo}
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
new MethodIntrospector.MetadataLookup<T>() {
@Override
public T inspect(Method method) {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
}
});
if (logger.isDebugEnabled()) {
logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
}
//遍历每个methods
for (Map.Entry<Method, T> entry : methods.entrySet()) {
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
//方法上用于映射请求处理的的元数据
T mapping = entry.getValue();
registerHandlerMethod(handler, invocableMethod, mapping);
}
}
/**
* 注册处理程序方法及其唯一映射。 在启动时为每个检测到的处理程序方法调用。
* @param handler the bean name of the handler or the handler instance
* @param method the method to register
* @param mapping the mapping conditions associated with the handler method
* @throws IllegalStateException if another method was already registered
* under the same mapping
*/
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
大致逻辑主要为获取所有beanNames,然后过滤真正的请求处理bean(bean包含@Controller或者@RequestMapping)注解的beanName,然后解析这些beanName所有的方法并将那些有@RequestMapping注解的方法连同beanName对应的bean和@RequestMapping注解的元数据封装起来,注册到MappingRegistry。
class MappingRegistry {
/**
* key-RequestMappingInfo value-MappingRegistration
*/
private final Map<T, MappingRegistration<T>> registry = new HashMap<T, MappingRegistration<T>>();
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<T, HandlerMethod>();
private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<String, T>();
private final Map<String, List<HandlerMethod>> nameLookup =
new ConcurrentHashMap<String, List<HandlerMethod>>();
private final Map<HandlerMethod, CorsConfiguration> corsLookup =
new ConcurrentHashMap<HandlerMethod, CorsConfiguration>();
private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
}