请求映射原理
springboot启动过程中,扫描所有@RestController @Controller注解定义类,将含有请求注解如@GetMapping、@PostMapping注解存放到一个map(Map<T, MappingRegistration>)中,通过请求接口地址,获取MappingRegistration,调用具体的接口类执行
springboot是如何加载映射器到容器的?
通过自动配置类WebMvcAutoConfiguration,默认使用RequestMappingHandlerMapping解析接口地址,WebMvcAutoConfiguration在spring.fatories中有定义
@Bean
@Primary
public RequestMappingHandlerMapping requestMappingHandlerMapping(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, @Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService, resourceUrlProvider);
}
然后执行父类方法,构造RequestMappingHandlerMapping 作为默认的映射处理器
@Bean
@SuppressWarnings("deprecation")
public RequestMappingHandlerMapping requestMappingHandlerMapping(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);
mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
mapping.setContentNegotiationManager(contentNegotiationManager);
mapping.setCorsConfigurations(getCorsConfigurations());
PathMatchConfigurer pathConfig = getPathMatchConfigurer();
if (pathConfig.getPatternParser() != null) {
mapping.setPatternParser(pathConfig.getPatternParser());
}
else {
mapping.setUrlPathHelper(pathConfig.getUrlPathHelperOrDefault());
mapping.setPathMatcher(pathConfig.getPathMatcherOrDefault());
Boolean useSuffixPatternMatch = pathConfig.isUseSuffixPatternMatch();
if (useSuffixPatternMatch != null) {
mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
}
Boolean useRegisteredSuffixPatternMatch = pathConfig.isUseRegisteredSuffixPatternMatch();
if (useRegisteredSuffixPatternMatch != null) {
mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
}
}
Boolean useTrailingSlashMatch = pathConfig.isUseTrailingSlashMatch();
if (useTrailingSlashMatch != null) {
mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
}
if (pathConfig.getPathPrefixes() != null) {
mapping.setPathPrefixes(pathConfig.getPathPrefixes());
}
return mapping;
}
方法映射加载时机
首先看RequestMappingHandlerMapping的diagram图
从图中可以看出RequestMappingHandlerMapping继承AbstractHandlerMethodMapping,而且AbstractHandlerMethodMapping实现了InitializingBean。InitializingBean的作用:
InitializingBean是Spring提供的拓展性接口,InitializingBean接口为bean提供了属性初始化后的处理方法,它只有一个afterPropertiesSet方法,凡是继承该接口的类,在bean的属性初始化后都会执行该方法,也就是当属性扫描结束后,都会执行该afterPropertiesSet方法,请求映射也是在这里执行的。
在AbstractHandlerMethodMapping类中是这样定义的
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
protected void initHandlerMethods() {
for (String beanName : getCandidateBeanNames()) {
//不以SCOPED_TARGET_NAME_PREFIX = "scopedTarget."开始的类执行processCandidateBean(beanName);
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
processCandidateBean(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
protected void processCandidateBean(String beanName) {
//obtainApplicationContext()返回ApplicationContext
//等价于ApplicationContext.getBean(class)
//例如返回TestController
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);
}
}
protected void detectHandlerMethods(Object handler) {
//获取正在解析的类 例如 TestController
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 {
//返回接口地址映射方法 实际调用为RequestMappingHandlerMapping的getMappingForMethod方法
//Method作为Key com.test.TestController.test()
//T RequestMappingInfo->接口地址以及请求方式 post/get/delete.
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));
}
else if (mappingsLogger.isDebugEnabled()) {
mappingsLogger.debug(formatMappings(userType, methods));
}
methods.forEach((method, mapping) -> {
//方法名 public void com.test.controller.TestController.test()
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
//注册方法映射
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
最终注册时调用AbstractHandlerMethodMappin的register方法
public void register(T mapping, Object handler, Method method) {
this.readWriteLock.writeLock().lock();
try {
//省略代码
//注册方法映射
//mapping 接口路径 /rest/test |Get
//handlerMethod com.test.controller.TestController#test()
//这里的registry就是前文提到的Map<T, MappingRegistration<T>>
//最终将接口路径保存到内存中
this.registry.put(mapping,
new MappingRegistration<>(mapping, handlerMethod, directPaths, name, corsConfig != null));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}
@Override
@Nullable
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
//方法上的RequestMapping值,这里可以是@GetMapping||@PostMapping...
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
//获取类上的RequestMapping
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
info = typeInfo.combine(info);
}
String prefix = getPathPrefix(handlerType);
if (prefix != null) {
info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
}
}
return info;
}
本文主要记录接口路径扫描到内存中的逻辑,后续持续记录前端调用接口请求,springmvc是如何将请求映射到具体的接口类中