zoukankan      html  css  js  c++  java
  • SpringMVC源码情操陶冶-AnnotationDrivenBeanDefinitionParser注解解析器

    mvc:annotation-driven节点的解析器,是springmvc的核心解析器

    官方注释

    
    Open Declaration   org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser
    
    
    A BeanDefinitionParser that provides the configuration for the <annotation-driven/> MVC namespace element. 
    
    This class registers the following <<HandlerMappings>>:
    •RequestMappingHandlerMapping ordered at 0 for mapping requests to annotated controller methods. 
    •BeanNameUrlHandlerMapping ordered at 2 to map URL paths to controller bean names. 
    
    Note: Additional HandlerMappings may be registered as a result of using the <view-controller> or the <resources> MVC namespace elements. 
    
    
    
    This class registers the following <<HandlerAdapters>>: 
    •RequestMappingHandlerAdapter for processing requests with annotated controller methods. 
    •HttpRequestHandlerAdapter for processing requests with HttpRequestHandlers. 
    •SimpleControllerHandlerAdapter for processing requests with interface-based Controllers. 
    
    
    
    This class registers the following <<HandlerExceptionResolvers>>: 
    •ExceptionHandlerExceptionResolver for handling exceptions through @ExceptionHandler methods. 
    •ResponseStatusExceptionResolver for exceptions annotated with @ResponseStatus. 
    •DefaultHandlerExceptionResolver for resolving known Spring exception types 
    
    
    
    This class registers an org.springframework.util.<<AntPathMatcher>> and a org.springframework.web.util.<<UrlPathHelper>> to be used by: 
    •the RequestMappingHandlerMapping, 
    •the HandlerMapping for ViewControllers 
    •and the HandlerMapping for serving resources 
    Note that those beans can be configured by using the path-matching MVC namespace element. 
    Both the RequestMappingHandlerAdapter and the ExceptionHandlerExceptionResolver are configured with instances of the following by default: 
    •A ContentNegotiationManager 
    •A DefaultFormattingConversionService 
    •A org.springframework.validation.beanvalidation.LocalValidatorFactoryBean if a JSR-303 implementation is available on the classpath 
    •A range of HttpMessageConverters depending on what 3rd party libraries are available on the classpath. 
    
    

    主要注册HandlerMappings-路径匹配器HandlerAdapters-路径匹配适配器HandlerExceptionResolvers-异常解析器AntPathMatcher-路径解析器UrlPathHelper-请求路径获取帮助类等beans,提前为mvc做好基础的准备

    AnnotationDrivenBeanDefinitionParser#parse

    从此方法中,提炼实现的最主要代码片段,代码如下

    
    		parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME));
    		parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME));
    		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);
    

    跟官方注释提及的一样,主要目的是注册与mvc处理有关的相关beans以及默认的mvc组件,下面我们将从以上代码的不同组件生成进行逐个分析

    HandlerMappings组件注册

    对应parse()方法的代码片段如下

    		//生成RequestMappingHandlerMapping组件对象
    		RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
    		handlerMappingDef.setSource(source);
    		handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    		//优先级设置为最高
    		handlerMappingDef.getPropertyValues().add("order", 0);
    //添加contentNegotiationManager属性,处理media type		handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
    		
    		//查看mvc:annotation-driven有无enable-matrix-variables/enableMatrixVariables,表示是否开启多变量映射比如/cars;a=1;b=1
    		//具体使用可查阅相关文档,默认removeSemicolonContent为false
    		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);
    //将RequestMappingHandlerMapping注册为bean对象放置bean工厂中		readerContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME , handlerMappingDef);
    

    RequestMappingHandlerMapping主要是处理@Controller@RequestMapping注解的,另外再看下configurePathMatchingProperties()配置路径解析器方法

    AnnotationDrivenBeanDefinitionParser#configurePathMatchingProperties-路径匹配解析器配置

    代码如下

    	private void configurePathMatchingProperties(RootBeanDefinition handlerMappingDef, Element element,
    			ParserContext parserContext) {
    		//获取mvc:annotation-driven下子节点mvc:path-matching
    		Element pathMatchingElement = DomUtils.getChildElementByTagName(element, "path-matching");
    		
    		if (pathMatchingElement != null) {
    			Object source = parserContext.extractSource(element);
    			//是否采用suffix-pattern,即.*,比如/user也匹配/user.*。默认为true
    			if (pathMatchingElement.hasAttribute("suffix-pattern")) {
    				Boolean useSuffixPatternMatch = Boolean.valueOf(pathMatchingElement.getAttribute("suffix-pattern"));
    				handlerMappingDef.getPropertyValues().add("useSuffixPatternMatch", useSuffixPatternMatch);
    			}
    			//是否采用分隔符,特指/,比如/user也匹配/user/。默认为true
    			if (pathMatchingElement.hasAttribute("trailing-slash")) {
    				Boolean useTrailingSlashMatch = Boolean.valueOf(pathMatchingElement.getAttribute("trailing-slash"));
    				handlerMappingDef.getPropertyValues().add("useTrailingSlashMatch", useTrailingSlashMatch);
    			}
    			//是否采用contentNegotiationManager中的格式,比如*.json/*.xml。默认为false
    			if (pathMatchingElement.hasAttribute("registered-suffixes-only")) {
    				Boolean useRegisteredSuffixPatternMatch = Boolean.valueOf(pathMatchingElement.getAttribute("registered-suffixes-only"));
    				handlerMappingDef.getPropertyValues().add("useRegisteredSuffixPatternMatch", useRegisteredSuffixPatternMatch);
    			}
    			RuntimeBeanReference pathHelperRef = null;
    			//路径解析帮助类,可指定,默认为UrlPathHelper
    			if (pathMatchingElement.hasAttribute("path-helper")) {
    				pathHelperRef = new RuntimeBeanReference(pathMatchingElement.getAttribute("path-helper"));
    			}
    			pathHelperRef = MvcNamespaceUtils.registerUrlPathHelper(pathHelperRef, parserContext, source);
    			handlerMappingDef.getPropertyValues().add("urlPathHelper", pathHelperRef);
    
    			RuntimeBeanReference pathMatcherRef = null;
    			//路径解析器,默认为AntPathMatcher解析器
    			if (pathMatchingElement.hasAttribute("path-matcher")) {
    				pathMatcherRef = new RuntimeBeanReference(pathMatchingElement.getAttribute("path-matcher"));
    			}
    			pathMatcherRef = MvcNamespaceUtils.registerPathMatcher(pathMatcherRef, parserContext, source);
    			handlerMappingDef.getPropertyValues().add("pathMatcher", pathMatcherRef);
    		}
    	}
    

    看代码逻辑,主要是通过mvc:annotation-driven下的mvc:path-matching节点来配置

    1. suffix-pattern-是否启用后缀匹配,默认为true,即对指定的url会再新增.*,比如/user实际匹配/user.*->/user匹配/user.html,/user.jsp
    2. trailing-slash-是否启动尾部斜线匹配,默认为true,即对指定的url会新增/,比如/user也会匹配/user/
    3. registered-suffixes-only-是否启用media type类型的匹配,即对指定的url新增*.json/*.xml等匹配,默认为false
    4. path-helper-路径获取帮助类,默认为UrlPathHelper类
    5. path-matcher-路径匹配解析器,默认为AntPathMather

    HandlerAdapters组件注册

    相应的代码片段如下

    		//获取conversion-service属性,默认为FormattingConversionServiceFactoryBean
    		//处理一些基本类的格式与转换,比如时间、数字等
    		RuntimeBeanReference conversionService = getConversionService(element, source, parserContext);
    		//获取validator,默认为OptionalValidatorFactoryBean,基于java自带的Validator接口,表示校验器,可用于javabean的参数校验等
    		RuntimeBeanReference validator = getValidator(element, source, parserContext);
    		//获取message-codes-resolver属性,默认为null。
    		RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element);
    		//设置ConfigurableWebBindingInitializer类 用于数据绑定
    		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子节点的配置,消息转换器,可用于向前端发送数据再次自定义组装
    		//比如MappingJackson2HttpMessageConverter json转字符串
    		ManagedList<?> messageConverters = getMessageConverters(element, source, parserContext);
    		//argument-resolvers子节点配置,参数解析
    		ManagedList<?> argumentResolvers = getArgumentResolvers(element, parserContext);
    		//return-value-handlers子节点解析
    		ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, parserContext);
    		//async-support子节点解析,获取其中的default-timeout属性,作为异步处理超时时间,默认null
    		String asyncTimeout = getAsyncTimeout(element);
    		//async-support子节点解析,获取其中的task-executor属性。异步任务线程池
    		RuntimeBeanReference asyncExecutor = getAsyncExecutor(element);
    		//async-support子节点解析,获取其中的callable-interceptors节点。异步处理callable类型拦截器
    		ManagedList<?> callableInterceptors = getCallableInterceptors(element, source, parserContext);
    		ManagedList<?> deferredResultInterceptors = getDeferredResultInterceptors(element, source, parserContext);
    
    		//将上述的属性添加到RequestMappingHandlerAdapter中
    		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);
    
    		//ignoreDefaultModelOnRedirect属性配置
    		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);
    		readerContext.getRegistry().registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME , handlerAdapterDef);
    

    配置的主要是RequestMappingHandlerAdapter对象,其中的属性较多,读者可查看>>>SpringMVC源码情操陶冶-RequestMappingHandlerAdapter适配器。其主要支持HandlerMethod类,而这些类都是由RequestMappingHandlerMapping来生成的,而这又是通过AbstractHandlerMethodMapping#initHandlerMethods来实现的,有兴趣的可以自行去查阅

    ExceptionResolver组件注册

    默认采用ExceptionHandlerExceptionResolverResponseStatusExceptionResolverDefaultHandlerExceptionResolver作为异常处理类

    		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 = readerContext.registerWithGeneratedName(exceptionHandlerExceptionResolver);
    
    		RootBeanDefinition responseStatusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);
    		responseStatusExceptionResolver.setSource(source);
    		responseStatusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    		responseStatusExceptionResolver.getPropertyValues().add("order", 1);
    		String responseStatusExceptionResolverName =
    				readerContext.registerWithGeneratedName(responseStatusExceptionResolver);
    
    		RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);
    		defaultExceptionResolver.setSource(source);
    		defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    		defaultExceptionResolver.getPropertyValues().add("order", 2);
    		String defaultExceptionResolverName =
    				readerContext.registerWithGeneratedName(defaultExceptionResolver);
    
    • ExceptionHandlerExceptionResolver-处理@ExceptionHandler方法注解

    • ResponseStatusExceptionResolver-处理@ResponseStatus类型、方法注解

    • DefaultHandlerExceptionResolver-处理普通的spring异常

    更准确的可查看官方注释说明

    小结

    mvc:annotation-driven一句话便囊括了springmvc的基本处理组件注册成bean到springmvc上下文,结合此处再去理解springmvc的逻辑源码就简单了

  • 相关阅读:
    BOOST 信号与槽,获取槽函数返回值,使用占位参数传递信号携带的参数
    单例模式,reorder详解,线程安全,双检查锁
    编程源自生活:抽象 -> 生活中的洗头问题
    前置声明透彻理解,以及和直接头文件包含的区别,注意事项
    三种工厂模式详解
    个人作品1
    Python基本汇总问题
    Json字符串转换成Json对象
    html div可以进行编辑
    父页面访问iframe页面的js
  • 原文地址:https://www.cnblogs.com/question-sky/p/7090875.html
Copyright © 2011-2022 走看看