默认情况下DispatcherServlet会注册3个HandlerMapping,分别是BeanNameUrlHandlerMapping、RequestMappingHandlerMapping及RouterFunctionMapping
HandlerMapping的作用是存储请求路径与处理方法的映射,收到请求后就能通过HandlerMapping找到对应的处理方法
本节我们主要分析RequestMappingHandlerMapping的作用及其原理
1.RequestMappingHandlerMapping的作用
RequestMappingHandlerMapping处理通过Controller注解的类中RequestMapping注解标注的方法,这也是我们平时使用最多的场景,例如:
@Controller
public class Controller01 {
@GetMapping("/test01")
public void test(HttpServletResponse response) throws IOException {
response.getWriter().print("hello test01");
}
}
配置类及测试代码参考前文SpringMVC源码分析(一)--基本组件
浏览器输入http://127.0.0.1:8080/test01,页面即可响应hello test01
2.RequestMappingHandlerMapping原理
在DispatcherServlet初始化中,会初始化每个HandlerMapping实现类
RequestMappingHandlerMapping是HandlerMapping的实现类,同时它也实现了InitializingBean接口,因此创建时会调用afterPropertiesSet进行初始化
public void afterPropertiesSet() {
this.config = new RequestMappingInfo.BuilderConfiguration();
this.config.setUrlPathHelper(getUrlPathHelper());
this.config.setPathMatcher(getPathMatcher());
this.config.setSuffixPatternMatch(useSuffixPatternMatch());
this.config.setTrailingSlashMatch(useTrailingSlashMatch());
this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch());
this.config.setContentNegotiationManager(getContentNegotiationManager());
// 调用AbstractHandlerMethodMapping的初始化方法
super.afterPropertiesSet();
}
父类初始化代码见AbstractHandlerMethodMapping#afterPropertiesSet,会筛选出控制器类,并检测其中的处理方法
public void afterPropertiesSet() {
initHandlerMethods();
}
protected void initHandlerMethods() {
// 1.获取候选的beanName
for (String beanName : getCandidateBeanNames()) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
// 2.处理候选的bean
processCandidateBean(beanName);
}
}
// 3.初始化后处理,可通过子类扩展,这里仅打印日志
handlerMethodsInitialized(getHandlerMethods());
}
protected String[] getCandidateBeanNames() {
// 从容器中获取所有BeanName
// this.detectHandlerMethodsInAncestorContexts为true表示需要从所有父容器和当前容器中查找
// this.detectHandlerMethodsInAncestorContexts为false表示只从当前容器中查找
return (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
obtainApplicationContext().getBeanNamesForType(Object.class));
}
protected void processCandidateBean(String beanName) {
Class<?> beanType = null;
try {
beanType = obtainApplicationContext().getType(beanName);
}
catch (Throwable ex) {
if (logger.isTraceEnabled()) {
logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
}
}
// 判断是不是请求控制器
if (beanType != null && isHandler(beanType)) {
// 检测控制器类中的处理方法
detectHandlerMethods(beanName);
}
}
protected boolean isHandler(Class<?> beanType) {
// bean的类上如果有Controller注解、Controller的派生注解(例如RestController等)、
// RequestMapping注解、RequestMapping的派生注解(例如GetMapping等)
// 那么就是控制器
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
protected void detectHandlerMethods(Object handler) {
// 获取控制器类,如果是字符串,说明是类名,则根据类名从容器中获取控制器类对象
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
// 如果是Cglib的代理类,则获取父类
Class<?> userType = ClassUtils.getUserClass(handlerType);
// 核心方法:查找处理方法
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
});
if (logger.isTraceEnabled()) {
logger.trace(formatMappings(userType, methods));
}
methods.forEach((method, mapping) -> {
// 查找userType类中是否存在method方法
// 如果不存在则去userType的父接口中寻找是否存在,存在即返回,否则抛出异常
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
// 核心方法:注册方法信息
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
具体看一下是如何查找处理方法的,源码见MethodIntrospector#selectMethods
public static <T> Map<Method, T> selectMethods(Class<?> targetType, final MetadataLookup<T> metadataLookup) {
final Map<Method, T> methodMap = new LinkedHashMap<>();
Set<Class<?>> handlerTypes = new LinkedHashSet<>();
Class<?> specificHandlerType = null;
// 如果不是jdk动态代理的代理类
if (!Proxy.isProxyClass(targetType)) {
// 如果是cglib动态代理的代理类,则返回父类
specificHandlerType = ClassUtils.getUserClass(targetType);
// 添加specificHandlerType到handlerTypes中
handlerTypes.add(specificHandlerType);
}
// 添加所有接口到handlerTypes中
handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));
for (Class<?> currentHandlerType : handlerTypes) {
final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);
ReflectionUtils.doWithMethods(currentHandlerType, method -> {
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
// 判断这个方法是否是请求处理方法,如果不是返回空,这里调用的是getMappingForMethod(method, userType)
T result = metadataLookup.inspect(specificMethod);
if (result != null) {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
// 添加到methodMap中
methodMap.put(specificMethod, result);
}
}
}, ReflectionUtils.USER_DECLARED_METHODS);
}
return methodMap;
}
metadataLookup.inspect调用的是RequestMappingHandlerMapping#getMappingForMethod
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
// 判断是否是请求处理方法,如果是则返回RequestMappingInfo,其中封装了方法上的RequestMapping注解信息
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
// 封装类上的RequestMapping注解信息
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
// 合并类和方法上的RequestMapping注解信息
info = typeInfo.combine(info);
}
/**
* 如果该控制器类有路径前缀的配置,场景是创建RequestMappingHandlerMapping对象时可以设置控制器的前缀路径
* 例如:
* @Bean
* public HandlerMapping requestHandlerMapping() {
* RequestMappingHandlerMapping requestMappingHandlerMapping = new RequestMappingHandlerMapping();
* Map<String, Predicate<Class<?>>> map = new HashMap<>();
* map.put("/bbb", clazz -> clazz.getName().contains("Controller01"));
* requestMappingHandlerMapping.setPathPrefixes(map);
* return requestMappingHandlerMapping;
* }
* 这个时候就会将/bbb添加到此路径前缀中
*/
String prefix = getPathPrefix(handlerType);
if (prefix != null) {
// 合并路径前缀到info中
info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
}
}
return info;
}
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
// 判断逻辑是在方法上查找是否有RequestMapping注解或其派生注解
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
RequestCondition<?> condition = (element instanceof Class ?
getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
// 封装方法上的RequestMapping注解中的参数信息
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}
最后注册方法委托给内部的成员变量mappingRegistry去完成
private final MappingRegistry mappingRegistry = new MappingRegistry();
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
实际调用的是MappingRegistry#register进行方法注册
public void register(T mapping, Object handler, Method method) {
if (KotlinDetector.isKotlinType(method.getDeclaringClass())) {
Class<?>[] parameterTypes = method.getParameterTypes();
if ((parameterTypes.length > 0) && "kotlin.coroutines.Continuation".equals(parameterTypes[parameterTypes.length - 1].getName())) {
throw new IllegalStateException("Unsupported suspending handler method detected: " + method);
}
}
this.readWriteLock.writeLock().lock();
try {
// 将执行方法封装成HandlerMethod对象
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
// 校验mapping是否已存在,存在会抛出异常,保证mapping唯一
validateMethodMapping(handlerMethod, mapping);
// 注册到mappingLookup集合中
this.mappingLookup.put(mapping, handlerMethod);
// 提取出url
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
// 注册到urlLookup集合中
this.urlLookup.add(url, mapping);
}
String name = null;
if (getNamingStrategy() != null) {
// 如果namingStrategy不为空,获取到name,注册到nameLookup集合中
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
// 注册跨域配置
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}
// 注册到registry集合中
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}
至此,请求映射注册完成,总结下流程:
- DispatcherServlet初始化时会初始化容器中所有的HandlerMapping
- RequestMappingHandlerMapping在初始化时会遍历容器中所有的bean,筛选出符合条件的控制器方法,即类上有Controller或其派生注解且方法上有RequestMapping注解或其派生注解
- 通过MappingRegistry将这些符合条件的方法注册到集合中
当DispatcherServlet收到请求时,会调用getHandler()获取对应的处理方法,源码见DispatcherServlet#doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
// 省略其他代码...
// 获取方法执行器
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 省略其他代码...
}
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
// 遍历容器中的HandlerMapping
for (HandlerMapping mapping : this.handlerMappings) {
// 从HandlerMapping中获取方法执行器
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
mapping.getHandler(request)是模板方法,源码见AbstractHandlerMapping#getHandler
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 子类实现,获取HandlerMethod,关键方法
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// 如果是字符串,则从容器中获取对应的bean
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 封装为HandlerExecutionChain
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
}
else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
logger.debug("Mapped to " + executionChain.getHandler());
}
if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
config = (config != null ? config.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
RequestMappingInfoHandlerMapping#getHandlerInternal获取HandlerMethod实现是:
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
try {
// 调用AbstractHandlerMapping的getHandlerInternal
return super.getHandlerInternal(request);
}
finally {
ProducesRequestCondition.clearMediaTypesAttribute(request);
}
}
调用父类的getHandlerInternal,源码见AbstractHandlerMapping#getHandlerInternal
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 解析出请求路径
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
this.mappingRegistry.acquireReadLock();
try {
// 根据请求信息查找HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
// 从urlLookup中查找有没有注册这个路径
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
// 将匹配的处理器方法添加到matches中
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// 如果通过urlLookup没有找到,则遍历所有mappingLookup,看有没有匹配的
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
// 如果找到了匹配的处理器方法
if (!matches.isEmpty()) {
Match bestMatch = matches.get(0);
// 校验
if (matches.size() > 1) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
bestMatch = matches.get(0);
if (logger.isTraceEnabled()) {
logger.trace(matches.size() + " matching mappings: " + matches);
}
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();
String uri = request.getRequestURI();
throw new IllegalStateException(
"Ambiguous handler methods mapped for '" + uri + "': {" + 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);
}
}
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
for (T mapping : mappings) {
// 匹配RequestMappingInfo和request,如果匹配上则返回RequestMappingInfo,没有匹配上返回null
T match = getMatchingMapping(mapping, request);
if (match != null) {
matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
}
}
}
获取到HandlerMethod之后,会被封装成HandlerExecutionChain对象
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// 创建HandlerExecutionChain对象
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
// 添加HandlerInterceptor
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
最后将HandlerExecutionChain对象交给HandlerAdapter去执行,这部分将在HandlerAdapter篇章中详述