class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
extends AbstractHandlerMethodMapping<RequestMappingInfo>
extends AbstractHandlerMapping implements InitializingBean {
// 执行初始化逻辑
public void afterPropertiesSet() {
// 初始化HandlerMethods,就是Handler和Methods关系
initHandlerMethods();{
// 找出所有的Bean
for (String beanName : getCandidateBeanNames(){
obtainApplicationContext().getBeanNamesForType(Object.class)
})
{
// private static final String SCOPED_TARGET_NAME_PREFIX = "scopedTarget.";
// 是个自定义的Bean
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
// 对这个bean进行操作
processCandidateBean(beanName);{
Class<?> beanType = obtainApplicationContext().getType(beanName);
// 判断是否一个handler处理器
if (beanType != null && isHandler(beanType){
// 存在Controller.class注解,或者添加了RequestMapping注解(前提是个Bean才行)
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
})
{
// 查找实际处理请求的方法,因为处理请求的方式有很多,可能是一个方法,也可能是一个实现了Servlet/Controller接口的类
detectHandlerMethods(beanName);{
// 找对对应的处理类
Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass());
// 找到真实的类型
Class<?> userType = ClassUtils.getUserClass(handlerType);{
// 如果是Cglib代理类,获取实际类型
if (clazz.getName().contains("$$")) { return clazz.getSuperclass(); }
return clazz;
}
// 找到所有添加了RequestMapping的方法,并且使用Method对象作为Map的key,通过RequestMapping注解信息创建的RequestMappingInfo对象为Value
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
// 找到所有的方法对象
return getMappingForMethod(method, userType);{
// 根据RequestMapping封装成RequestMappingInfo对象
RequestMappingInfo info = createRequestMappingInfo(method);{
// 找到有RequestMappingInfo注解,创建RequestMappingInfo对象
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition){
RequestMappingInfo.Builder builder = RequestMappingInfo
.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
.methods(requestMapping.method())...;
} : null);
}
if (info != null) {
// 判断是否存在类注解
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
// 如果存在,则需要和方法路径合并
if (typeInfo != null) {
info = typeInfo.combine(info);
}
// getPathPrefix: 如果配置了通用URL前缀,可以通过webmvcConfigurer来配置
// class A implements WebMvcConfigurer
// public void configurePathMatch(PathMatchConfigurer configurer) {
// 这样,当满足后面这个条件的情况下,url会自动拼接前缀
// configurer.addPathPrefix("/api/v1", aClass -> aClass.isAssignableFrom(TestController.class));
// }
// }
// 注意: 这个前缀是和HandlerMapping绑定的,使用@EnableWebMvc注解,会导入@Import(DelegatingWebMvcConfiguration.class)类
// DelegatingWebMvcConfiguration类会执行所有实现了WebMvcConfigurer接口的类的方法
// DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport,而WebMvcConfigurationSupport会注册多个Bean
// 其中包括3个HandlerMapping和多个RequestMappingHandlerAdapter
// 其中RequestMappingHandlerMapping创建的过程中,就设置了一些属性,例如mapping.setPathPrefixes(pathConfig.getPathPrefixes());
// 就是刚才在configurePathMatch添加的前缀就会赋值给HandlerMapping的前缀,这样请求就添加了统一前缀了
// 具体的@EnableWebMvc原理在后面讲
String prefix = getPathPrefix(handlerType);
if (prefix != null) {
// 拼接路径
info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
}
}
return info;
}
});
// 将所有查找到的方法和url映射到注册到mappingRegistry中
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping);{
// 将映射信息保存
// MappingRegistry mappingRegistry = new MappingRegistry(){
// 实际上,所有的url,method映射都是存在registry这里
// private final Map<T, MappingRegistration<T>> registry = new HashMap<>();{
// // MappingRegistration类的字段
// private final T mapping;
// private final HandlerMethod handlerMethod;
// private final Set<String> directPaths;
// }
// 为什么是多个值的map,因为restful支持相同的url和不同的请求方式,所以,url是同一个,RequestMappingInfo有多个
// private final MultiValueMap<String, T> pathLookup = new LinkedMultiValueMap<>();
// private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();
// private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();
// }
this.mappingRegistry.register(mapping, handler, method);{
// 将handler和method封装成Handler对象
HandlerMethod handlerMethod = createHandlerMethod(handler, method);{
if (handler instanceof String) {
return new HandlerMethod((String) handler,beanFactory, method);
}
return new HandlerMethod(handler, method);
}
// 校验是否要相同url的method
validateMethodMapping(handlerMethod, mapping);
// 获取RequestMapping可以处理的路径,因为RequestMapping的value是可以数组,可以处理多个url
Set<String> directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);
// 保存到pathLookup中,pathLookup是存储了url->requestMappingInfo的映射
// 也就是直接通过url找到对应的RequestMappingInfo,在通过RequestMappingInfo获取MappingRegistration对象,下面this.registry.put(mapping)几行有解释
for (String path : directPaths) {
this.pathLookup.add(path, mapping);
}
// 初始化跨域配置
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
// 将方法,bean,映射,url等信息包装成MappingRegistration对象,然后使用RequestMappingInfo作为Key
// 这样请求来了可以通过pathLookup获取对对应的RequestMappingInfo,在从registry获取MappingRegistration,就可以执行方法了
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directPaths, name, corsConfig != null));
}
}
});
}
}
}
}
}
}
// 查询了所有的方法映射之后做的初始化操作,没有逻辑
handlerMethodsInitialized(getHandlerMethods());
}
}
}