概述
RequestMappingHandlerMapping这个Handler我们用的特别多,因为配置url跟类毕竟比较繁琐。所以常使用@RequestMapping作为请求路径的注解的处理器。
RequestMappingHandlerMapping的结构示意图
与BeanNameUrlHandlerMapping和SimpleUrlHandlerMapping类似,都是AbstractHandlerMapping,从RequestMappingHandlerMapping的结构图,先看AbstractHandlerMethodMapping的结构,由一个内部类MappingRegistry,此类定义了一系列的Map,由registry,mappingLookup,urlLookup,nameLookup,corsLookup,先解释这些Map的作用。
urlLookup:保存了url与方法执行条件的映射,url为key,方法条件为value
nameLookup:保存了类名的所有大写字母加“#”加方法的名词
mappingLookup:保存的是方法的执行条件和方法
registry:以方法执行条件为key ,保留了url,方法,方法执行条件,以及类名的所有大写字母加“#”加方法的名词
corsLookup:跨境
AbstractHandlerMethodMapping实现了InitializingBean接口,即会执行初始化方法afterPropertiesSet,然后initHandlerMethods方法,initHandlerMethods跟AbstractUrlHandlerMapping的初始化方法一样,把ioc容器中所有的bean的名称获取,然后对名称进行筛选,符合条件则执行detectHandlerMethods方法进行注册,handlerMethodsInitialized为模板方法,由子类实现。
public void afterPropertiesSet() {
initHandlerMethods();
}
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
//获取bean的名词
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
obtainApplicationContext().getBeanNamesForType(Object.class));
//筛选bean
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
try {
beanType = obtainApplicationContext().getType(beanName);
}
catch (Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}
protected void detectHandlerMethods(final Object handler) {
//获取handler的类
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
final Class<?> userType = ClassUtils.getUserClass(handlerType);
//将methods与该方法的使用条件进行映射,比如是只处理get请求,请求头需要什么等等条件
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.isDebugEnabled()) {
logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
}
//遍历
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
//对方法进行注册
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
public void register(T mapping, Object handler, Method method) {
//加锁
this.readWriteLock.writeLock().lock();
try {
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);
if (logger.isInfoEnabled()) {
logger.info("Mapped "" + mapping + "" onto " + handlerMethod);
}
//将请求条件 --> 方法进行映射放入mappingLookup的Map中
this.mappingLookup.put(mapping, handlerMethod);
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
//urlLookup是MultiValueMap这类型的Map,这个类型的map是key--> List,即一对多的关系
this.urlLookup.add(url, mapping);
}
//将类名+#+方法名 与方法进行映射,放入nameLookup
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
//跨境cors
this.corsLookup.put(handlerMethod, corsConfig);
}
//请求条件,请求条件--》与请求路径,方法映射,类名+#+方法名 以及处理的url作为一个对象放入registry这个Map中
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
}
finally {
//释放锁
this.readWriteLock.writeLock().unlock();
}
}
RequestMappingHandlerMapping实现getMappingForMethod,主要是创建方法的条件以及是否是@RequestMapping注解。
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
//创建方法的信息映射,比如请求头,请求内容
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
info = typeInfo.combine(info);
}
}
return info;
}
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
//找到@RequestMapping注解修饰的RequestMapping
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
//判断注解是类上的还是方法上的
RequestCondition<?> condition = (element instanceof Class ?
getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}
RequestMappingInfoHandlerMapping不参与请求注册,它只是后续匹配http请求以及父类中的Map的请求条件的Map进行校验。
最后
以上就是笑点低保温杯为你收集整理的Springmvc入门(十四)HandlerMapper源码分析--RequestMappingHandlerMapping的Hander的注册的全部内容,希望文章能够帮你解决Springmvc入门(十四)HandlerMapper源码分析--RequestMappingHandlerMapping的Hander的注册所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复