Spring源码学习:SpringMVC(3)mvcannotation-driven标签解析【RequestMappingHandlerMapping生成】
目录
- 前言
- mvc:annotation-driven标签概述
- mvc:annotation-driven标签解析【RequestMappingHandlerMapping生成】
- AnnotationDrivenBeanDefinitionParser#parse (解析入口)
- RequestMappingHandlerMapping的实例化
- 类图
- afterPropertiesSet
- AbstractHandlerMethodMapping#afterPropertiesSet
- processCandidateBean
- isHandler
- detectHandlerMethods
- MethodIntrospector#selectMethods
- ReflectionUtils#doWithMethods
- getMappingForMethod
- createRequestMappingInfo
- registerHandlerMethod
- 总结
前言
上一篇我们已经完成了springmvc中子容器的初始化,子容器里面一般是一些和web相关的组件,其中的配置文件中就有mvc:annotation-driven
这个标签,这里主要对这个标签来进行剖析,看下它里面干了一些什么,其实也是为了后面我们能通过请求url找到对应处理器方法完成的一个铺垫
mvc:annotation-driven标签概述
mvc:annotation-driven标签默认会开启SpringMVC的注解驱动模式,默认注册一个RequestMappingHandlerMapping、一个RequestMappingHandlerAdapter、一个ExceptionHandlerExceptionResolver。以支持对使用了 @RequestMapping 、 @ExceptionHandler 及其他注解的控制器方法的请求处理。
mvc:annotation-driven标签解析【RequestMappingHandlerMapping生成】
首先这是一个XML标签,所以我们需要到Spring中refresh()
核心方法中的obtainFreshBeanFactory()
中里面的parseBeanDefinitions(root,delegate)
方法那里打断点,找到解析 mvc:annotation-driven
这个标签的逻辑
注意:node一定得是 mvc:annotation-driven这个标签
public BeanDefinition parseCustomElement(Element ele) {
return parseCustomElement(ele, null);
}
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
//解析节点的命名空间
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
//解析命名空间,得到一个命名空间处理器
//重点
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
//开始解析
//主线 重点
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));\
}
public BeanDefinition parse(Element element, ParserContext parserContext) {
//通过定义的标签属性(如:component-scan)获取对应的BeanDefinitionParser解析对象
BeanDefinitionParser parser = findParserForElement(element, parserContext);
//执行解析 AnnotationDrivenBeanDefinitionParser.parse
return (parser != null ? parser.parse(element, parserContext) : null);
}
关于定位自定义标签解析的过程,以后的IOC中会说明的,这里直接打开AnnotationDrivenBeanDefinitionParser
类并定位到其parse方法
AnnotationDrivenBeanDefinitionParser#parse (解析入口)
/**
* 解析 mvc:annotation-driven 标签
*/
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
XmlReaderContext readerContext = parserContext.getReaderContext();
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
parserContext.pushContainingComponent(compDefinition);
/**
* 获取协商内容视图配置
*/
RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, parserContext);
/**
* 创建RequestMappingHandlerMapping的RootBeanDefinition
* 从这里也可以看出,开启mvc:annotation-driven标签后,
* 将会默认注册RequestMappingHandlerMapping作为默认的HandlerMapping
*/
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
handlerMappingDef.setSource(source);
handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
handlerMappingDef.getPropertyValues().add("order", 0);
handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
// 是否开启矩阵变量
if (element.hasAttribute("enable-matrix-variables")) {
Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute("enable-matrix-variables"));
handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
}
// 解析path-matching路径匹配标签
configurePathMatchingProperties(handlerMappingDef, element, parserContext);
readerContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME , handlerMappingDef);
// 解析cors跨域标签
RuntimeBeanReference corsRef = MvcNamespaceUtils.registerCorsConfigurations(null, parserContext, source);
handlerMappingDef.getPropertyValues().add("corsConfigurations", corsRef);
// 解析conversion-service数据转换、格式化标签
RuntimeBeanReference conversionService = getConversionService(element, source, parserContext);
// 解析validator标签
RuntimeBeanReference validator = getValidator(element, source, parserContext);
// 解析message-codes-resolver标签
RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element);
/**
* 创建ConfigurableWebBindingInitializer的RootBeanDefinition对象
* 并将上一步解析的conversionService、validator、messageCodesResolver
* 作为属性注入到该对象中
*/
RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
bindingDef.setSource(source);
bindingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
bindingDef.getPropertyValues().add("conversionService", conversionService);
bindingDef.getPropertyValues().add("validator", validator);
bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver);
// 解析message-converters标签
ManagedList<?> messageConverters = getMessageConverters(element, source, parserContext);
// 解析argument-resolvers标签
ManagedList<?> argumentResolvers = getArgumentResolvers(element, parserContext);
// 解析return-value-handlers标签
ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, parserContext);
// 解析async-support标签
String asyncTimeout = getAsyncTimeout(element);
// 解析async-support的task-executor子标签
RuntimeBeanReference asyncExecutor = getAsyncExecutor(element);
// 解析async-support的callable-interceptors子标签
ManagedList<?> callableInterceptors = getCallableInterceptors(element, source, parserContext);
// 解析async-support的deferred-result-interceptors子标签
ManagedList<?> deferredResultInterceptors = getDeferredResultInterceptors(element, source, parserContext);
/**
* 创建RequestMappingHandlerAdapter的RootBeanDefinition
* 从这里也可以看出,开启mvc:annotation-driven标签后,
* 将会默认注册RequestMappingHandlerAdapter作为默认的HandlerAdapter
* 并将上面解析的内容绑定到该HandlerAdapter中
*/
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
handlerAdapterDef.setSource(source);
handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
handlerAdapterDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
addRequestBodyAdvice(handlerAdapterDef);
addResponseBodyAdvice(handlerAdapterDef);
if (element.hasAttribute("ignore-default-model-on-redirect")) {
Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignore-default-model-on-redirect"));
handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel);
}
if (argumentResolvers != null) {
handlerAdapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
}
if (returnValueHandlers != null) {
handlerAdapterDef.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
}
if (asyncTimeout != null) {
handlerAdapterDef.getPropertyValues().add("asyncRequestTimeout", asyncTimeout);
}
if (asyncExecutor != null) {
handlerAdapterDef.getPropertyValues().add("taskExecutor", asyncExecutor);
}
handlerAdapterDef.getPropertyValues().add("callableInterceptors", callableInterceptors);
handlerAdapterDef.getPropertyValues().add("deferredResultInterceptors", deferredResultInterceptors);
readerContext.getRegistry().registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME , handlerAdapterDef);
/**
* 创建CompositeUriComponentsContributorFactoryBean的RootBeanDefinition
* CompositeUriComponentsContributorFactoryBean是一个工厂bean,
* 可以用来获取RequestMappingHandlerAdapter中的HandlerMethodArgumentResolver配置
*/
RootBeanDefinition uriContributorDef = new RootBeanDefinition(CompositeUriComponentsContributorFactoryBean.class);
uriContributorDef.setSource(source);
uriContributorDef.getPropertyValues().addPropertyValue("handlerAdapter", handlerAdapterDef);
uriContributorDef.getPropertyValues().addPropertyValue("conversionService", conversionService);
String uriContributorName = MvcUriComponentsBuilder.MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME;
readerContext.getRegistry().registerBeanDefinition(uriContributorName, uriContributorDef);
/**
* 创建ConversionServiceExposingInterceptor的RootBeanDefinition
* 主要用来解析spring:eval标签
*/
RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
csInterceptorDef.setSource(source);
csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);
RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
mappedInterceptorDef.setSource(source);
mappedInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null);
mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef);
String mappedInterceptorName = readerContext.registerWithGeneratedName(mappedInterceptorDef);
/**
* 创建ExceptionHandlerExceptionResolver的RootBeanDefinition
*/
RootBeanDefinition methodExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);
methodExceptionResolver.setSource(source);
methodExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
methodExceptionResolver.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
methodExceptionResolver.getPropertyValues().add("messageConverters", messageConverters);
methodExceptionResolver.getPropertyValues().add("order", 0);
addResponseBodyAdvice(methodExceptionResolver);
if (argumentResolvers != null) {
methodExceptionResolver.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
}
if (returnValueHandlers != null) {
methodExceptionResolver.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
}
String methodExResolverName = readerContext.registerWithGeneratedName(methodExceptionResolver);
/**
* 创建ResponseStatusExceptionResolver的RootBeanDefinition
*
*/
RootBeanDefinition statusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);
statusExceptionResolver.setSource(source);
statusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
statusExceptionResolver.getPropertyValues().add("order", 1);
String statusExResolverName = readerContext.registerWithGeneratedName(statusExceptionResolver);
/**
* 创建DefaultHandlerExceptionResolver的RootBeanDefinition
* 该类是HandlerExceptionResolver的默认实现,可以解析http异常并将相应的http状态码返回
* 例如:404
*/
RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);
defaultExceptionResolver.setSource(source);
defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
defaultExceptionResolver.getPropertyValues().add("order", 2);
String defaultExResolverName = readerContext.registerWithGeneratedName(defaultExceptionResolver);
/**
* 将上面创建的RootBeanDefinition以组件形式纳入SpringIOC容器
*/
parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME));
parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME));
parserContext.registerComponent(new BeanComponentDefinition(uriContributorDef, uriContributorName));
parserContext.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, mappedInterceptorName));
parserContext.registerComponent(new BeanComponentDefinition(methodExceptionResolver, methodExResolverName));
parserContext.registerComponent(new BeanComponentDefinition(statusExceptionResolver, statusExResolverName));
parserContext.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExResolverName));
// Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
// 注册默认组件
MvcNamespaceUtils.registerDefaultComponents(parserContext, source);
parserContext.popAndRegisterContainingComponent();
return null;
}
那么接下来我们需要总结一下,如果mvc:annotation-driven没有配置任何子标签的话,Spring会如何处理呢?
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
RootBeanDefinition uriContributorDef = new RootBeanDefinition(CompositeUriComponentsContributorFactoryBean.class);
RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
RootBeanDefinition methodExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);
RootBeanDefinition statusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);
RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);
可以看到即使不做任何子标签的配置,SpringMVC默认也会创建上述9个内部bean的实例。
RequestMappingHandlerMapping的实例化
类图
上图信息比较多,我们查找关键信息。可以看到这个类间接实现了HandlerMapping
接口,是HandlerMapping
类型的实例。
除此之外还实现了ApplicationContextAware
和IntitalzingBean
这两个接口。在这里简要介绍一下这两个接口:
如果一个类实现了ApplicationContextAware接口,Spring容器在初始化该类时候会自动回调该类的setApplicationContext()方法。这个接口主要用来让实现类得到Spring 容器上下文信息。
如果一个bean实现了IntitalzingBean接口,Spring 容器初始化bean时会回调afterPropertiesSet()方法。这个接口的主要作用是让bean在初始化时可以实现一些自定义的操作。
RequestMappingHandlerMapping
实现了InitializingBean
接口,当设置完属性后肯定会回调afterPropertiesSet
方法,再看afterPropertiesSet
方法逻辑。
afterPropertiesSet
public void afterPropertiesSet() {
// 创建 BuilderConfiguration
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());
super.afterPropertiesSet();
}
上面调用了父类AbstractHandlerMethodMapping
的afterPropertiesSet()方法,沿调用栈继续查看。
AbstractHandlerMethodMapping#afterPropertiesSet
public void afterPropertiesSet() {
initHandlerMethods();
}
protected void initHandlerMethods() {
// 获取所有的 BeanNames
for (String beanName : getCandidateBeanNames()) {
// 判断不是已 scopedTarget 开头
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
//对含有注解的bean进行处理,获取handler函数信息。
processCandidateBean(beanName);
}
}
//简单的日志记录
handlerMethodsInitialized(getHandlerMethods());
}
processCandidateBean是核心方法,该方法内部完成了bean的筛选和对某个Controller内部所有handlerMethod的探测。
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.
// 一个无法解析的bean类型,可能来自一个lazy bean-让我们忽略它。
// 日志打印...
if (logger.isTraceEnabled()) {
logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
}
}
// 不是null 并且 类型是存在 @Controller 或者 @RequestMapping 注解
if (beanType != null && isHandler(beanType)) {
//如果当前bean是一个handler,那么需要探测出该handler内部所有handlerMethod实现
detectHandlerMethods(beanName);
}
}
如果当前bean是一个handler的话则进入detectHandlerMethods(beanName);
isHandler
@Override
protected boolean isHandler(Class<?> beanType) {
// 存在 Controller注解 或者存在 RequestMapping 注解 ..
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
上面逻辑很简单,就是判断该bean是否有@Controller
或@RequestMapping
注解,然后返回判断结果。
如果含有这两个注解之一就进入detectHandlerMethods()
方法进行处理。
detectHandlerMethods
protected void detectHandlerMethods(Object handler) {
// 如果传递是 String 则 获取其类型 ,如果是是class 则直接返回
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
//对类型再次进行处理,主要是针对cglib
Class<?> userType = ClassUtils.getUserClass(handlerType);
//遍历方法,对注解中的信息进行处理,得到RequestMappingInfo对象,得到methods数组
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
// 里面主要是 获取 方法 和类上的 @RequestMapping 将其合并.
// 如果没有的话则会返回 null,而由于是 lambda 这里主要是制订过滤规则
// 如果返回了 null 则 selectMethods 不会将其放入到Map中。
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[Method,{path}]
methods.forEach((method, mapping) -> {
//对方法的可访问性进行校验,如private,static,SpringProxy, //获取最终请求路径
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
// 注册,注册到全局的MappingRegistry实例里
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
上面方法中用了几个回调,可能看起来比较复杂,我们先看MethodIntrospector.selectMethods
,该方法最终会经过筛选完成一个method-》RequestMappingInfo(@RequestMapping注解信息)的映射
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;
//把自身类添加到handlerTypes中
if (!Proxy.isProxyClass(targetType)) {
specificHandlerType = ClassUtils.getUserClass(targetType);
handlerTypes.add(specificHandlerType);
}
//获取该bean所有的接口,并添加到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);
// //回调inspect()方法,这里就会调用到外面的getMappingForMethod函数来生成RequestMappingInfo
T result = metadataLookup.inspect(specificMethod);
if (result != null) {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
methodMap.put(specificMethod, result);
}
}
}, ReflectionUtils.USER_DECLARED_METHODS);
}
return methodMap;
}
MethodIntrospector.selectMethods
的作用可以简单看成是遍历了handler类内部的所有方法,包括其父类和实现接口里面的所有方法,然后交给注册进来的回调接口进行处理,回调接口的返回值作为生成的映射信息,如果返回值不为空,就和当前method组成一条记录,放入map中; 遍历完所有方法后,返回该map集合。
selectMethods完成方法筛选的关键就在于目标方法经过回调接口处理过后,返回值是否为空,如果为空,说明当前方法需要被过滤掉
我们看到又调用了ReflectionUtils.doWithMethods()
ReflectionUtils#doWithMethods
public static void doWithMethods(Class<?> clazz, MethodCallback mc, @Nullable MethodFilter mf) {
// Keep backing up the inheritance hierarchy.
Method[] methods = getDeclaredMethods(clazz, false);
for (Method method : methods) {
if (mf != null && !mf.matches(method)) {
continue;
}
try {
//这里调用的doWith方法就会回到调用方法那里的lambda方法里面
mc.doWith(method);
}
catch (IllegalAccessException ex) {
throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
}
}
if (clazz.getSuperclass() != null && (mf != USER_DECLARED_METHODS || clazz.getSuperclass() != Object.class)) {
doWithMethods(clazz.getSuperclass(), mc, mf);
}
else if (clazz.isInterface()) {
for (Class<?> superIfc : clazz.getInterfaces()) {
doWithMethods(superIfc, mc, mf);
}
}
}
doWith
中执行metadataLookup.inspect
方法,也就是会去执行getMappingForMethod。该方法会根据method来构建RequestMappingInfo,该对象记录了匹配这个method的所有需要满足的条件。
可以简单将上面理解为遍历当前handler类及其实现接口,并获取其中所有的方法,最后进入getMappingForMethod
方法中
getMappingForMethod
@Override
@Nullable
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);
}
String prefix = getPathPrefix(handlerType);
if (prefix != null) {
info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
}
}
return info;
}
进入createRequestMappingInfo(method)
,内部会判断是否存在RequestMapping注解,如果存在才创建,可以看到先根据方法创建一个,之后再根据类创建一个,最后会合并一下,因为需要匹配的上请求url是需要类上的path+方法上的path一起来完成
createRequestMappingInfo
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
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);
}
protected RequestMappingInfo createRequestMappingInfo(
RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {
RequestMappingInfo.Builder builder = RequestMappingInfo
.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
.methods(requestMapping.method())
.params(requestMapping.params())
.headers(requestMapping.headers())
.consumes(requestMapping.consumes())
.produces(requestMapping.produces())
.mappingName(requestMapping.name());
if (customCondition != null) {
builder.customCondition(customCondition);
}
return builder.options(this.config).build();
}
上面把RequestMapping
注解中的信息都放到一个RequestMappingInfo
实例中后返回。之后返回的话最终会到selectMethods
方法里面,判断metadataLookup.inspect
的返回值是否为null,不为null则将方法和RequestMappingInfo
的信息维护到map中,下面就是注册RequestMappingInfo
了
registerHandlerMethod
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
public void register(T mapping, Object handler, Method method) {
// Assert that the handler method is not a suspending one.
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 = createHandlerMethod(handler, method);
//判断映射的唯一性
validateMethodMapping(handlerMethod, mapping);
//将mapping信息和控制器方法对应
this.mappingLookup.put(mapping, handlerMethod);
//将path与处理器映射(一个方法可能可以处理多个url)
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
this.urlLookup.add(url, mapping);
}
//控制器名的大写英文缩写#方法名
String name = null;
if (getNamingStrategy() != null) {
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();
}
}
可以看到将Mehtod和Handler给封装了一层,变成了HandlerMethod,然后最终维护了3个map(不包括跨域)
- this.mappingLookup : 保存requestMappingInfo和控制器方法的映射
- this.urlLookup :保存url和多个控制器方法的映射(主要是因为restFul风格)
- this.registry : 保存requestMappingInfo和registration的映射
class MappingRegistry {
//保存RequestMappingInfo和MappingRegistration的映射关系
private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
//保存RequestMappingInfo和HandlerMethod的映射关系
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
//保存请求路径和RequestMappingInfo的映射关系
private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
//保存handlerMethodName和handlerMethod的映射关系
private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();
//保存handlerMethod和跨域配置的映射关系
private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();
//读写锁
private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
...
总结
- mvc:annotation-driven标签在子容器初始化的过程中会完成扫描,会注入一些bean,其中就包括RequestMappingHandlerMapping
- RequestMappingHandlerMapping实现了InitializingBean接口,所有会在其他bean执行生命周期的时候调用其afterPropertiesSet方法
- 然后判断当前bean是否为一个controller,主要针对类上是否存在@Controller 或者 @RequestMapping注解
- 之后会通过遍历当前类以及其实现的接口类型,获取其中的方法,判断方法是否存在@RequestMapping注解,如果存在则创建RequestMappingInfo实例,该实例中存放了@RequestMappingInfo注解信息(需要注意,创建@RequestMappingInfo会进行两次,一次是根据方法的,一次是根据类,之后会合并为一个,主要为了path的完整),最后会将RequestMappingInfo和相对应的method保存到map中
- 通过上一步的map来完成注册,将信息保存到其父类AbstractHandlerMethodMapping类内部MappingRegistry中的三个map中
以上:内容部分参考:《Spring源码深度解析》
如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎各位大佬指正