SpringMVC之分析AnnotationDrivenBeanDefinitionParser(二)

简介: 在上一篇文章中我们简单的分析了一下AnnotationDrivenBeanDefinitionParser,在这一篇的文章中我们继续分析AnnotationDrivenBeanDefinitionParser的内容。

在上一篇文章中我们简单的分析了一下AnnotationDrivenBeanDefinitionParser,在这一篇的文章中我们继续分析AnnotationDrivenBeanDefinitionParser的内容。AnnotationDrivenBeanDefinitionParser这个类最最重要的一个方法就是parse方法。在这篇文章中我们简单的分析一下parse方法的内容。先看parse中的这一段代码:

		RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
		handlerMappingDef.setSource(source);
		handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);//基础建设类的角色
		handlerMappingDef.getPropertyValues().add("order", 0);//order的顺序
		handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);

		if (element.hasAttribute("enable-matrix-variables")) {//是否支持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);
		}
在上面的这一段代码中我们创建了一个RequestMappingHandlerMapping的BeanDefinition其实也相当于是默认配置了RequestMappingHandlerMapping。在这个BeanDefinition中我们设置了bean的role的值,order的顺序。同时还取了enable-matrix-variables这个属性的值。这个属性值是一个boolean类型,这个属性的作用是支持Matrix variables。通常在我们的URL中是会把带分号的数据移除掉的,如果我们配置了这个属性的值为true的话,就可以在URL的后面添加分号分割的数据。如:/test/name;userName=zhangsan这样。请求映射器的处理是需要在请求映射处理方法上添加@MatrixVariable注解,参数解析器为:MatrixVariableMethodArgumentResolver或MatrixVariableMapMethodArgumentResolver。有关Matrix variables更多的内容可以参考《看透springMvc源代码分析与实践》214页。我们下面接着分析:

configurePathMatchingProperties(handlerMappingDef, element, parserContext);
	private void configurePathMatchingProperties(RootBeanDefinition handlerMappingDef, Element element,
			ParserContext parserContext) {
		/*
		*获取path-matching的元素,配置形式大概如下
		*    <mvc:annotation-driven>
		*		<mvc:path-matching>
        *       </mvc:path-matching>
		*	</mvc:annotation-driven>
		* 这个配置是个可选配置,用来配置请求路径匹配模式的
		*/
		Element pathMatchingElement = DomUtils.getChildElementByTagName(element, "path-matching");
		if (pathMatchingElement != null) {
			Object source = parserContext.extractSource(element);
			if (pathMatchingElement.hasAttribute("suffix-pattern")) {
				//如果suffix-pattern这个属性的话,则取这个属性值。这个属性值默认是:true
				//这个属性值的作用是:是否配置.*这种模式
				//例如我们在一个RequestMapping中配置的URL为:/listUserInfo,则/listUserInfo.json这样的请求也会被
				//这个请求映射处理器方法所处理,即/listUserInfo相当于/listUserInfo.*
				Boolean useSuffixPatternMatch = Boolean.valueOf(pathMatchingElement.getAttribute("suffix-pattern"));
				handlerMappingDef.getPropertyValues().add("useSuffixPatternMatch", useSuffixPatternMatch);
			}
			//这个属性值默认为true。 匹配/users的请求也匹配 /users/
			if (pathMatchingElement.hasAttribute("trailing-slash")) {
				Boolean useTrailingSlashMatch = Boolean.valueOf(pathMatchingElement.getAttribute("trailing-slash"));
				handlerMappingDef.getPropertyValues().add("useTrailingSlashMatch", useTrailingSlashMatch);
			}
			//现在 后缀匹配模式  避免 . 这个字符引起的歧义
			//默认为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这个类  寻找请求路径用的
			//默认为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。可以自定义
			//Ant风格的URL。如:/user/*/createUser 匹配:/user/aaa/createUser、 /user/bbb/createUser 
			//  /user/**/createUser 匹配 /user/createUser 、/user/aaa/bbb/createUser
			//  /user/{userId} 匹配 /user/123 、/user/1455
			if (pathMatchingElement.hasAttribute("path-matcher")) {
				pathMatcherRef = new RuntimeBeanReference(pathMatchingElement.getAttribute("path-matcher"));
			}
			pathMatcherRef = MvcNamespaceUtils.registerPathMatcher(pathMatcherRef, parserContext, source);
			handlerMappingDef.getPropertyValues().add("pathMatcher", pathMatcherRef);
		}
	}
	
这一段逻辑主要是解析<mvc:path-matching>标签。我们接着往下看:

RuntimeBeanReference conversionService = getConversionService(element, source, parserContext);
	private RuntimeBeanReference getConversionService(Element element, Object source, ParserContext parserContext) {
		RuntimeBeanReference conversionServiceRef;
		//如果配置了conversion-service属性的值,则使用所指定的bean,这个bean必须是ConversionService的子类。
		if (element.hasAttribute("conversion-service")) {
			conversionServiceRef = new RuntimeBeanReference(element.getAttribute("conversion-service"));
		}
		else {
			//如果没有配置如果配置了conversion-service属性的值,则使用默认的ConversionService
			//这里使用的FormattingConversionServiceFactoryBean,但是这个类没有实现ConversionService这个接口,但是这个类
			//实现了FactoryBean这个接口,在它的getObject方法中返回的是在afterPropertiesSet这个方法中创建的DefaultFormattingConversionService
			//所以默认的ConversionService是DefaultFormattingConversionService这个类。
			//在这个类中大概初始化了118个Converters
			RootBeanDefinition conversionDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class);
			conversionDef.setSource(source);
			conversionDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
			String conversionName = parserContext.getReaderContext().registerWithGeneratedName(conversionDef);
			parserContext.registerComponent(new BeanComponentDefinition(conversionDef, conversionName));
			conversionServiceRef = new RuntimeBeanReference(conversionName);
		}
		return conversionServiceRef;
	}
	
在上面的代码中进行了ConversionService的配置,默认配置了DefaultFormattingConversionService这个类型转换服务类。

RuntimeBeanReference validator = getValidator(element, source, parserContext);
	private RuntimeBeanReference getValidator(Element element, Object source, ParserContext parserContext) {
		if (element.hasAttribute("validator")) {
			return new RuntimeBeanReference(element.getAttribute("validator"));
		}
		//如果类路径中有javax.validation.Validator这个类的话,则配置OptionalValidatorFactoryBean
		//作为默认的校验器类 组合JSR-303 Validation规范和Spring Validator
		else if (javaxValidationPresent) {
			RootBeanDefinition validatorDef = new RootBeanDefinition(
					"org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean");
			validatorDef.setSource(source);
			validatorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
			String validatorName = parserContext.getReaderContext().registerWithGeneratedName(validatorDef);
			parserContext.registerComponent(new BeanComponentDefinition(validatorDef, validatorName));
			return new RuntimeBeanReference(validatorName);
		}
		else {
			return null;
		}
	}
在上面的代码中进行数据校验器的配置,默认配置了OptionalValidatorFactoryBean数据校验器。

RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element);
	private RuntimeBeanReference getMessageCodesResolver(Element element) {
		//默认的信息转换器是:DefaultMessageCodesResolver
		//用来转换校验失败信息。
		if (element.hasAttribute("message-codes-resolver")) {
			return new RuntimeBeanReference(element.getAttribute("message-codes-resolver"));
		}
		else {
			return null;
		}
	}
在上面的代码中进行MessageCode是Resolver的配置,默认配置的是DefaultMessageCodesResolver。
		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);
在上面的这段代码中默认配置了ConfigurableWebBindingInitializer这个bean,并设置了三个属性值conversionService、validator、messageCodesResolver。

相关文章
|
前端开发 容器 JavaScript
SpringMVC之分析AnnotationDrivenBeanDefinitionParser(三)
我们在之前的文章中对这篇文章中AnnotationDrivenBeanDefinitionParser的parse方法进行了一些分析,我们在这篇文章中接着分析AnnotationDrivenBeanDefinitionParser的parse方法的内容。
1252 0
|
前端开发 Java Spring
SpringMVC之分析AnnotationDrivenBeanDefinitionParser(一)
首先我们会想一下,我们在进行SpringMVC配置的时候是怎样配置的(不是web.xml)?我们会在SpringMVC的配置文件中添加这样的一些东西: xmlns:mvc="http://www.
1291 0
|
7月前
|
设计模式 前端开发 JavaScript
Spring MVC(一)【什么是Spring MVC】
Spring MVC(一)【什么是Spring MVC】
|
6月前
|
设计模式 前端开发 Java
【Spring MVC】快速学习使用Spring MVC的注解及三层架构
【Spring MVC】快速学习使用Spring MVC的注解及三层架构
102 1
|
6月前
|
前端开发 Java 应用服务中间件
Spring框架第六章(SpringMVC概括及基于JDK21与Tomcat10创建SpringMVC程序)
Spring框架第六章(SpringMVC概括及基于JDK21与Tomcat10创建SpringMVC程序)
|
7月前
|
前端开发 Java 关系型数据库
基于ssm框架旅游网旅游社交平台前后台管理系统(spring+springmvc+mybatis+maven+tomcat+html)
基于ssm框架旅游网旅游社交平台前后台管理系统(spring+springmvc+mybatis+maven+tomcat+html)
|
6月前
|
XML Java 数据格式
SpringMVC的XML配置解析-spring18
SpringMVC的XML配置解析-spring18
|
6月前
|
应用服务中间件
从代码角度戳一下springMVC的运行过程-spring16
从代码角度戳一下springMVC的运行过程-spring16
|
前端开发 Java Go
Spring MVC 和 Spring Boot 的区别
Spring MVC 和 Spring Boot 的区别
233 0
|
7月前
|
移动开发 Java 测试技术
Spring MVC+Spring+Mybatis实现支付宝支付功能(附完整代码)
Spring MVC+Spring+Mybatis实现支付宝支付功能(附完整代码)
188 1