分析版本Spring5.0.9.release,Springboot2.0.3.releasehtml
spring-webmvc的META-INFO/spring.handles文件中,有MvcNamespaceHandler,这是用来解析标签的,来看下MvcNamespaceHandler的init(),以下List-1,咱们暂时只关注AnnotationDrivenBeanDefinitionParser。java
List-1git
@Override public void init() { registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser()); registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser()); registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser()); registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser()); registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser()); registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser()); registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser()); registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser()); registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser()); registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser()); registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser()); registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser()); registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser()); }
AnnotationDrivenBeanDefinitionParser的parse方法里面有不少代码,可是咱们只关注俩个,以下List-2:github
List-2web
@Override @Nullable public BeanDefinition parse(Element element, ParserContext context) { ... RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class); ... // Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off" MvcNamespaceUtils.registerDefaultComponents(context, source); return null; }
RequestMappingHandlerMapping的继承图以下图1所示:spring
图1mvc
图1中,AbstractHandlerMethodMapping实现了接口InitializingBean,实现了afterPropertiesSet(),若是了解SpringIOC,应该知道这个方法意味着什么,Spring在建立Bean的时候会调用这个方法。app
List-3cors
@Override public void afterPropertiesSet() { initHandlerMethods(); }
由List-3知道afterPropertiesSet调用了initHandlerMethods(),以下List-4,首先从ApplicationContext或者全部的beanName,以后循环它们。isHandler方法由子类RequestMappingHandlerMapping实现,判断类上是否有Controller或者RequestMapping注解,因此即便不加上@Controller,只是用@RequestMapping注解也能够。List-4中的handlerMethodsInitialized是空方法,不用管。ide
List-4
protected void initHandlerMethods() { if (logger.isDebugEnabled()) { logger.debug("Looking for request mappings in application context: " + getApplicationContext()); } String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) : obtainApplicationContext().getBeanNamesForType(Object.class)); for (String beanName : beanNames) { if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { 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.isDebugEnabled()) { logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex); } } if (beanType != null && isHandler(beanType)) { detectHandlerMethods(beanName); } } } handlerMethodsInitialized(getHandlerMethods()); }
来看List-4中的方法detectHandlerMethods,传入的是String类型的bean name,以下List-5,首先获取bean name对应的Class,getMappingForMethod在RequestMappingHandlerMapping中实现,如List-6所示,判断方法上是否有RequestMapping注解,若是有,则获取参数、path、header等信息,用builder模式构造出RequestMappingInfo。MethodIntrospector.selectMethods会遍历类上的方法,因此总体上对类的全部方法进行是否有RequestMapping的检查。须要注意的是,相似GetMapping等是组合注解,它们仍是基于RequestMapping,因此方法上有GetMapping/PostMapping等都会会扫描并建立出对应的RequestMappingInfo。
List-5
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.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); }); } }
List-6
@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); } } return info; } @Nullable 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(); }
List-5中的registerHandlerMethod,会将获得的Mapper信息注册到mappingRegistry到,这个mappingRegistry后面在DispatcherServlet中使用到。注意传入到registerHandlerMethod方法的handler是String类型的bean name。
Springboot中,RequestMappingHandlerMapping是经过@Configuration方式注入的,以下List-7
List-7
@Bean public RequestMappingHandlerMapping requestMappingHandlerMapping() { RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping(); ...