RequestMappingHandlerMapping也是存在路径与类的关系,它是存放以下的方式配置Controller的对应关系
@Controller
@RequestMapping("/cong")
public class TestController {
@RequestMapping("/test")
@ResponseBody
public String test(){
return "123";
}
}
首先不多说,先看调用栈
从调用栈来看,基本和 BeanNameUrlHandlerMapping初始化类似,区别在于BeanNameUrlHandlerMapping是通过后置处理器初始化对应关系,而RequestMappingHandlerMapping通过实现InitializingBean来实现,熟悉spring初始化的生命周期的都知道,spring在创建完bean之后都会执行InitializingBean 的afterPropertiesSet()方法
从调用栈来看,会调用这个方法AbstractHandlerMethodMapping的processCandidateBean方法
protected void processCandidateBean(String beanName) {
Class<?> beanType = null;
try {
beanType = obtainApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isTraceEnabled()) {
logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
}
}
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
其中isHandler会判断是否有@Controller注解
最后调用 AbstractHandlerMethodMapping的detectHandlerMethods方法
protected void detectHandlerMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
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) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
从代码看,就是通过反射把各个方法映射到map中,其中在RequestMappingHandlerMapping的mappingLookup熟悉就是存放这个的,至此已经把映射存放好,再等访问的时候就可以通过url来匹配对应的bean和方法,再看一下调试信息