使用@RequestMapping,@Controller,@ResponseBody
@RestController public class HelloController { @RequestMapping("hello") public String hello (){ return "Hello Spring MVC"; } }
<?xml version="1.0" encoding="UTF-8"?> <beans> <mvc:annotation-driven/> <beans>
WebMvcAutoConfiguration
@Configuration @EnableWebMvc public class WebMvcConfig{ }
添加此标签后,Spring使用自定义的Bean定义解析器AnnotationDrivenBeanDefinitionParser加载了几个比较几个重要的Bean定义,主要是一些围绕HandlerMethod进行处理的基础组件对象
RequestHandlerMapping
根据请求映射找出对应的HandlerMethod进行处理
RequestMappingHandlerAdapter
执行HandlerMethodChain进入到目标方法
public class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { @Override public BeanDefinition parse(Element element, ParserContext parserContext) { Object source = parserContext.extractSource(element); CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source); parserContext.pushContainingComponent(compDefinition); RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, parserContext); // 注册RequestMappingHandlerMapping,用于处理@RequestMaping注解的方法请求映射为HandlerMethod RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class); handlerMappingDef.setSource(source); handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); handlerMappingDef.getPropertyValues().add("order", 0); handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager); String methodMappingName = parserContext.getReaderContext().registerWithGeneratedName(handlerMappingDef); if (element.hasAttribute("enable-matrix-variables")) { Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute("enable-matrix-variables")); handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables); } else if (element.hasAttribute("enableMatrixVariables")) { Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute("enableMatrixVariables")); handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables); } configurePathMatchingProperties(handlerMappingDef, element, parserContext); RuntimeBeanReference conversionService = getConversionService(element, source, parserContext); RuntimeBeanReference validator = getValidator(element, source, parserContext); RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element); 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); ManagedList<?> messageConverters = getMessageConverters(element, source, parserContext); ManagedList<?> argumentResolvers = getArgumentResolvers(element, parserContext); ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, parserContext); String asyncTimeout = getAsyncTimeout(element); RuntimeBeanReference asyncExecutor = getAsyncExecutor(element); ManagedList<?> callableInterceptors = getCallableInterceptors(element, source, parserContext); ManagedList<?> deferredResultInterceptors = getDeferredResultInterceptors(element, source, parserContext); // 注册RequestMappingHandlerAdapter,用于适配处理HandlerMethod 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); 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); } else if (element.hasAttribute("ignoreDefaultModelOnRedirect")) { // "ignoreDefaultModelOnRedirect" spelling is deprecated Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignoreDefaultModelOnRedirect")); 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); String handlerAdapterName = parserContext.getReaderContext().registerWithGeneratedName(handlerAdapterDef); String uriCompContribName = MvcUriComponentsBuilder.MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME; RootBeanDefinition uriCompContribDef = new RootBeanDefinition(CompositeUriComponentsContributorFactoryBean.class); uriCompContribDef.setSource(source); uriCompContribDef.getPropertyValues().addPropertyValue("handlerAdapter", handlerAdapterDef); uriCompContribDef.getPropertyValues().addPropertyValue("conversionService", conversionService); parserContext.getReaderContext().getRegistry().registerBeanDefinition(uriCompContribName, uriCompContribDef); RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class); csInterceptorDef.setSource(source); csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService); RootBeanDefinition mappedCsInterceptorDef = new RootBeanDefinition(MappedInterceptor.class); mappedCsInterceptorDef.setSource(source); mappedCsInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null); mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef); String mappedInterceptorName = parserContext.getReaderContext().registerWithGeneratedName(mappedCsInterceptorDef); RootBeanDefinition exceptionHandlerExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class); exceptionHandlerExceptionResolver.setSource(source); exceptionHandlerExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); exceptionHandlerExceptionResolver.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager); exceptionHandlerExceptionResolver.getPropertyValues().add("messageConverters", messageConverters); exceptionHandlerExceptionResolver.getPropertyValues().add("order", 0); addResponseBodyAdvice(exceptionHandlerExceptionResolver); String methodExceptionResolverName = parserContext.getReaderContext().registerWithGeneratedName(exceptionHandlerExceptionResolver); RootBeanDefinition responseStatusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class); responseStatusExceptionResolver.setSource(source); responseStatusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); responseStatusExceptionResolver.getPropertyValues().add("order", 1); String responseStatusExceptionResolverName = parserContext.getReaderContext().registerWithGeneratedName(responseStatusExceptionResolver); // 注册默认的异常处理解析器 RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class); defaultExceptionResolver.setSource(source); defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); defaultExceptionResolver.getPropertyValues().add("order", 2); String defaultExceptionResolverName = parserContext.getReaderContext().registerWithGeneratedName(defaultExceptionResolver); parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, methodMappingName)); parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, handlerAdapterName)); parserContext.registerComponent(new BeanComponentDefinition(uriCompContribDef, uriCompContribName)); parserContext.registerComponent(new BeanComponentDefinition(exceptionHandlerExceptionResolver, methodExceptionResolverName)); parserContext.registerComponent(new BeanComponentDefinition(responseStatusExceptionResolver, responseStatusExceptionResolverName)); parserContext.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExceptionResolverName)); parserContext.registerComponent(new BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName)); // Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off" MvcNamespaceUtils.registerDefaultComponents(parserContext, source); parserContext.popAndRegisterContainingComponent(); return null; } }
public class MvcNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser()); ...... } }
作用:简单来说NamespaceHandler的作用就是处理自定义标签的,例如<mvc:annotation-driven>,每一个自定义标签都必须隶属于一个namespace下
NamespaceHandler被定义META-INF/spring.handles文件,MvcNamespaceHandler也不例外。
http/://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler
// 解析自定义标签 public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { // 根据标签拿到其namespaceUri String namespaceUri = getNamespaceURI(ele); NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } // 使用Parser来解析标签,上面我们说过的AnnotationDrivenBeanDefinitionParser就是其一 return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }
public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers"; private final String handlerMappingsLocation; // 解析获得能处理该namespace下标签的命名空间处理器 public NamespaceHandler resolve(String namespaceUri) { Map<String, Object> handlerMappings = getHandlerMappings(); // 根据给定的namespaceUri找到对应的NamespaceHandler Object handlerOrClassName = handlerMappings.get(namespaceUri); if (handlerOrClassName == null) { return null; } else if (handlerOrClassName instanceof NamespaceHandler) { return (NamespaceHandler) handlerOrClassName; } else { String className = (String) handlerOrClassName; try { Class<?> handlerClass = ClassUtils.forName(className, this.classLoader); if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) { throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface"); } NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass); namespaceHandler.init(); handlerMappings.put(namespaceUri, namespaceHandler); return namespaceHandler; } catch (ClassNotFoundException ex) { throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "] not found", ex); } catch (LinkageError err) { throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]: problem with handler class file or dependent class", err); } } } private Map<String, Object> getHandlerMappings() { if (this.handlerMappings == null) { synchronized (this) { if (this.handlerMappings == null) { try { // 加载所有的spring.handlers文件内容为Properties对象 Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader); if (logger.isDebugEnabled()) { logger.debug("Loaded NamespaceHandler mappings: " + mappings); } Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size()); CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings); this.handlerMappings = handlerMappings; } catch (IOException ex) { throw new IllegalStateException( "Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex); } } } } return this.handlerMappings; }
at org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver.resolve(DefaultNamespaceHandlerResolver.java:114) at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1419) at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1414) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:189) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:143) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:110) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:508) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:391) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:335) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:303) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:180) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:216) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:187) at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:125) at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:94) at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:129) at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:537) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:452) // 通过打印堆栈信息,我们知道处理自定义标签的步骤发生在spring容器的启动过程中,即refresh->obtainFreshBeanFactory->loadBeanDefinitions // refresh()是构建IOC容器的最核心代码,obtainFreshBeanFactory()加载xml中定义bean,转换为抽象世界中的BeanDefinition
<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.w3school.com.cn" xmlns="http://www.w3school.com.cn" elementFormDefault="qualified"> ... ... </xs:schema>
(1)xmlns:xs="http://www.w3.org/2001/XMLSchema":表明schema中用到的元素和数据类型出自此命名空间,同时规定来自此命名空间的元素和数据都要使用前序xs.
(2)targetNamespace="http://www.w3school.com.cn":显示 schema 中用到的元素和数据类型来自此命名空间.
(3)elementFormDefault="qualified":指出任何xml实例文档所使用的且在此schema中声明过的元素必须被命名空间限定.
使用@EnableWebMvc的作用大体上是与<annotation-driven>标签的作用一致。具体可以看WebMvcConfigurationSupport源码
映射存储在
// RequestMapping->HandlerMethod private final Map<T, HandlerMethod> handlerMethods = new LinkedHashMap<T, HandlerMethod>();
初始化映射的方法AbstractHandlerMethodMapping.initHandlerMethods()
@Override public void afterPropertiesSet() { initHandlerMethods(); }
protected void initHandlerMethods() { if (logger.isDebugEnabled()) { logger.debug("Looking for request mappings in application context: " + getApplicationContext()); } // 获得IOC容器中的所有对象 String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : getApplicationContext().getBeanNamesForType(Object.class)); for (String beanName : beanNames) { // 提取标注有@Controller或@RequestMapping的对象 if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX) && isHandler(getApplicationContext().getType(beanName))){ // 提取所有标注有@RequestMapping的方法,并注册到handlerMethods 中 detectHandlerMethods(beanName); } } handlerMethodsInitialized(getHandlerMethods()); } protected boolean isHandler(Class<?> beanType) { return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) || (AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null)); } protected void detectHandlerMethods(final Object handler) { Class<?> handlerType = (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass()); // Avoid repeated calls to getMappingForMethod which would rebuild RequestMappingInfo instances final Map<Method, T> mappings = new IdentityHashMap<Method, T>(); final Class<?> userType = ClassUtils.getUserClass(handlerType); // 遍历对象筛选标注有@RequestMaping注解的方法 Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() { @Override public boolean matches(Method method) { // 将@RequestMapping注解标注的信息抽象为@RequestMappingInfo对象 T mapping = getMappingForMethod(method, userType); if (mapping != null) { mappings.put(method, mapping); return true; } else { return false; } } }); // 注册请求映射 for (Method method : methods) { registerHandlerMethod(handler, method, mappings.get(method)); } }
上面三步只是简化总结出了请求映射原理,更深一步的请求处理原理还请阅读DispatcherServlet.doDispatch()方法源码。