使用@RequestMapping,@Controller,@ResponseBodyjava
@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>
WebMvcAutoConfigurationweb
@Configuration @EnableWebMvc public class WebMvcConfig{ }
添加此標籤後,Spring使用自定義的Bean定義解析器AnnotationDrivenBeanDefinitionParser加載了幾個比較幾個重要的Bean定義,主要是一些圍繞HandlerMethod進行處理的基礎組件對象spring
RequestHandlerMappingapi
根據請求映射找出對應的HandlerMethod進行處理
RequestMappingHandlerAdaptermvc
執行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下app
NamespaceHandler被定義META-INF/spring.handles文件,MvcNamespaceHandler也不例外。async
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中聲明過的元素必須被命名空間限定.ide
使用@EnableWebMvc的做用大致上是與<annotation-driven>標籤的做用一致。具體能夠看WebMvcConfigurationSupport源碼ui
映射存儲在this
// 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()方法源碼。