Spring validation参数校验系列
1、Spring validation参数校验基本使用
2、Spring validation参数校验之自定义校验规则及编程式校验等进阶篇
3、Spring validation参数校验原理解析之Controller控制器参数校验中@RequestBody参数校验实现原理
4、Spring validation参数校验原理解析之Controller控制器参数校验中@ModelAttribute及实体类参数校验实现原理
5、Spring validation参数校验原理解析之基本类型参数及Service层方法参数校验实现原理
6、Spring validation校验的核心类ValidatorImpl、MetaDataProvider和AnnotationMetaDataProvider源码分析
7、Spring validation参数校验高级篇之跨参数校验Cross-Parameter及分组序列校验@GroupSequenceProvider、@GroupSequence
8、【源码】Spring validation参数校验之跨参数校验Cross-Parameter原理分析
9、【源码】Spring validation参数校验之分组序列校验@GroupSequenceProvider、@GroupSequence的实现原理
前言
本篇继续从源码的角度分析一下Spring validation参数校验的分组序列校验@GroupSequenceProvider、@GroupSequence的实现原理。
温馨提醒:
Hibernate validation的设计比较复杂,要一次性全部分析清楚很困难,关联的细节很多。所以《Spring validation参数校验系列》文章通过从整体到细节,在每一篇中,不影响主题内容的情况下,穿插引入一些细节。在分享中,也会暂时忽略一些细节,留在下一篇讲解。建议如果本篇不太理解的,可以看看该系列的上一篇或者下一篇源码讲解文章。
一、解析分组序列
类中添加的约束元数据信息首次解析是在BeanMetaDataManagerImpl的createBeanMetaData()方法中调用。首次解析调用流程详见
【源码】Spring validation参数校验原理解析之Controller控制器参数校验中@RequestBody参数校验实现原理_@requestbody 校验字段-CSDN博客
的ValidatorImpl.validate()部分。入口方法为BeanMetaDataManagerImpl的createBeanMetaData()方法。
private <T> BeanMetaDataImpl<T> createBeanMetaData(Class<T> clazz) {BeanMetaDataBuilder<T> builder = BeanMetaDataBuilder.getInstance(constraintCreationContext, executableHelper, parameterNameProvider,validationOrderGenerator, clazz, methodValidationConfiguration );for ( MetaDataProvider provider : metaDataProviders ) {// getBeanConfigurationForHierarchy()方法遍历beanClass及其父类,调用AnnotaionMetaDataProvider.getBeanConfiguration()方法// 获取对应类添加的约束注解,封装成BeanConfiguration对象for ( BeanConfiguration<? super T> beanConfiguration : getBeanConfigurationForHierarchy( provider, clazz ) ) {// 在BeanMetaDataBuilder中添加BeanConfiguration对象// BeanMetaDataBuilder.add()【获取并遍历约束元素,获取beanConfiguration中的sequenceSource// 和defaultGroupSequence保存到builder中builder.add( beanConfiguration );}}// 将类中添加的约束信息封装成BeanMetaDataImpl对象。return builder.build();}
1.1 AnnotationMetaDataProvider的getBeanConfiguration()方法解析类中的方法、属性、构造器添加的约束注解。
public class AnnotationMetaDataProvider implements MetaDataProvider {/*** 获取bean类中定义的属性、类、参数、方法添加的约束信息、配置来源、分组序列以及动态分组序列程序*/@Override@SuppressWarnings("unchecked")public <T> BeanConfiguration<T> getBeanConfiguration(Class<T> beanClass) {if ( Object.class.equals( beanClass ) ) {return (BeanConfiguration<T>) objectBeanConfiguration;}return retrieveBeanConfiguration( beanClass );}/*** 检索bean类的元数据信息*/private <T> BeanConfiguration<T> retrieveBeanConfiguration(Class<T> beanClass) {// 获取类中定义的属性添加的约束元素信息Set<ConstrainedElement> constrainedElements = getFieldMetaData( beanClass );// 获取类中定义的方法添加的约束元素信息constrainedElements.addAll( getMethodMetaData( beanClass ) );// 获取类的构造方法添加的约束元素信息constrainedElements.addAll( getConstructorMetaData( beanClass ) );// 获取类级添加的约束信息Set<MetaConstraint<?>> classLevelConstraints = getClassLevelConstraints( beanClass );if ( !classLevelConstraints.isEmpty() ) {ConstrainedType classLevelMetaData =new ConstrainedType(ConfigurationSource.ANNOTATION,beanClass,classLevelConstraints);constrainedElements.add( classLevelMetaData );}// 封装成BeanConfiguration对象,来源为Annotationreturn new BeanConfiguration<>(ConfigurationSource.ANNOTATION,beanClass,constrainedElements,// 获取bean中添加的@GroupSequence注解的组序列。getDefaultGroupSequence( beanClass ),// 获取类中定义的动态分组的约定程序getDefaultGroupSequenceProvider( beanClass ));}/*** 获取bean中添加的@GroupSequence注解的组序列。组序列中的组顺序执行,排前面的组对应的注解约束会先判断,如果前面的失败了,不会校验排后面的组* @param beanClass* @return*/private List<Class<?>> getDefaultGroupSequence(Class<?> beanClass) {GroupSequence groupSequenceAnnotation = beanClass.getAnnotation( GroupSequence.class );return groupSequenceAnnotation != null ? Arrays.asList( groupSequenceAnnotation.value() ) : null;}/*** 获取类中定义的动态分组的约定程序* @param beanClass* @param <T>* @return*/private <T> DefaultGroupSequenceProvider<? super T> getDefaultGroupSequenceProvider(Class<T> beanClass) {// 判断对应的bean是否添加了GroupSequenceProvider注解GroupSequenceProvider groupSequenceProviderAnnotation = beanClass.getAnnotation( GroupSequenceProvider.class );// 只有添加了GroupSequenceProvider注解才会返回动态分组的约定程序if ( groupSequenceProviderAnnotation != null ) {// 获取GroupSequenceProvider注解中指定的约定程序类,该类实现了DefaultGroupSequenceProvider接口@SuppressWarnings("unchecked")Class<? extends DefaultGroupSequenceProvider<? super T>> providerClass =(Class<? extends DefaultGroupSequenceProvider<? super T>>) groupSequenceProviderAnnotation.value();// 创建一个自定义的DefaultGroupSequenceProvider实例return newGroupSequenceProviderClassInstance( beanClass, providerClass );}return null;}/*** 创建一个DefaultGroupSequenceProvider实例,getValidationGroups()方法的参数必现是beanClass类型* @param beanClass* @param providerClass* @param <T>* @return*/private <T> DefaultGroupSequenceProvider<? super T> newGroupSequenceProviderClassInstance(Class<T> beanClass,Class<? extends DefaultGroupSequenceProvider<? super T>> providerClass) {Method[] providerMethods = run( GetMethods.action( providerClass ) );for ( Method method : providerMethods ) {Class<?>[] paramTypes = method.getParameterTypes();// 判断DefaultGroupSequenceProvider接口的getValidationGroups()方法的参数是否为beanClass类型if ( "getValidationGroups".equals( method.getName() ) && !method.isBridge()&& paramTypes.length == 1 && paramTypes[0].isAssignableFrom( beanClass ) ) {return run(NewInstance.action( providerClass, "the default group sequence provider" ));}}throw LOG.getWrongDefaultGroupSequenceProviderTypeException( beanClass );}}
在retrieveBeanConfiguration()方法中,会调用getDefaultGroupSequence()和getDefaultGroupSequenceProvider()分别解析@GroupSequence和@GroupSequenceProvider注解的分组序列及自定义的DefaultGroupSequenceProvider对象,并保存到BeanConfiguration中。
1.2 通过BeanMetaDataBuilder.add(beanConfiguration)方法中,获取约束元素,获取beanConfiguration中的sequenceSource和defaultGroupSequence保存到builder中。
1.3 执行builder.build(),new一个BeanMetaDataImpl对象,将类中添加的约束信息封装成BeanMetaDataImpl对象。在BeanMetaDataImpl的构造方法中,对分组系列及动态分组系列程序进行解析处理。
/*** defaultGroupSequence:分组序列组。在AnnotaionMetaDataProvider.getDefaultGroupSequence()方法中获取,* 如果没有设置@GroupSequence,则该值为null* defaultGroupSequenceProvider:动态分组约定程序,自定义的DefaultGroupSequenceProvider对象。* 在defaultGroupSequence:分组序列组。在AnnotaionMetaDataProvider.getDefaultGroupSequenceProvider()中获取,如果没有为null* constraintMetaDataSet:类及父类的所有属性、构造器、方法添加的约束元数据*/public BeanMetaDataImpl(Class<T> beanClass,List<Class<?>> defaultGroupSequence,DefaultGroupSequenceProvider<? super T> defaultGroupSequenceProvider,Set<ConstraintMetaData> constraintMetaDataSet,ValidationOrderGenerator validationOrderGenerator) {// 保存基础信息this.validationOrderGenerator = validationOrderGenerator;this.beanClass = beanClass;this.propertyMetaDataMap = newHashMap();Set<PropertyMetaData> propertyMetaDataSet = newHashSet();Set<ExecutableMetaData> executableMetaDataSet = newHashSet();Set<Signature> tmpUnconstrainedExecutables = newHashSet();boolean hasConstraints = false;Set<MetaConstraint<?>> allMetaConstraints = newHashSet();// 对constraintMetaDataSet进行分类,分成属性、类、方法for ( ConstraintMetaData constraintMetaData : constraintMetaDataSet ) {boolean elementHasConstraints = constraintMetaData.isCascading() || constraintMetaData.isConstrained();hasConstraints |= elementHasConstraints;// 属性添加的约束if ( constraintMetaData.getKind() == ElementKind.PROPERTY ) {propertyMetaDataSet.add( (PropertyMetaData) constraintMetaData );}// 类添加的约束else if ( constraintMetaData.getKind() == ElementKind.BEAN ) {allMetaConstraints.addAll( ( (ClassMetaData) constraintMetaData ).getAllConstraints() );}else {// 方法添加的约束ExecutableMetaData executableMetaData = (ExecutableMetaData) constraintMetaData;if ( elementHasConstraints ) {executableMetaDataSet.add( executableMetaData );}else {tmpUnconstrainedExecutables.addAll( executableMetaData.getSignatures() );}}}// 级联Set<Cascadable> cascadedProperties = newHashSet();for ( PropertyMetaData propertyMetaData : propertyMetaDataSet ) {propertyMetaDataMap.put( propertyMetaData.getName(), propertyMetaData );cascadedProperties.addAll( propertyMetaData.getCascadables() );allMetaConstraints.addAll( propertyMetaData.getAllConstraints() );}this.hasConstraints = hasConstraints;this.cascadedProperties = CollectionHelper.toImmutableSet( cascadedProperties );this.allMetaConstraints = CollectionHelper.toImmutableSet( allMetaConstraints );this.classHierarchyWithoutInterfaces = CollectionHelper.toImmutableList( ClassHierarchyHelper.getHierarchy(beanClass,Filters.excludeInterfaces()) );// 转换并将分组序列信息存放在分组序列上下文中DefaultGroupSequenceContext<? super T> defaultGroupContext = getDefaultGroupSequenceData( beanClass, defaultGroupSequence, defaultGroupSequenceProvider, validationOrderGenerator );this.defaultGroupSequenceProvider = defaultGroupContext.defaultGroupSequenceProvider;this.defaultGroupSequence = CollectionHelper.toImmutableList( defaultGroupContext.defaultGroupSequence );this.validationOrder = defaultGroupContext.validationOrder;this.directMetaConstraints = getDirectConstraints();this.executableMetaDataMap = CollectionHelper.toImmutableMap( bySignature( executableMetaDataSet ) );this.unconstrainedExecutables = CollectionHelper.toImmutableSet( tmpUnconstrainedExecutables );// 如果有通过@GroupSequence添加序列组或定义DefaultGroupSequenceProvider,// 则defaultGroupSequenceRedefined为truethis.defaultGroupSequenceRedefined = this.defaultGroupSequence.size() > 1 || hasDefaultGroupSequenceProvider();// 如果有动态分组序列,执行DefaultGroupSequenceProvider的getValidationGroups()方法获取分组,否则返回null// 由于此处传入getValidationGroups()的值为null,所以在自定义的DefaultGroupSequenceProvider// 类的getValidationGroups()方法要对参数进行判空处理this.resolvedDefaultGroupSequence = getDefaultGroupSequence( null );}/*** 转换并将分组序列信息存放在分组序列上下文中*/private static <T> DefaultGroupSequenceContext<T> getDefaultGroupSequenceData(Class<?> beanClass, List<Class<?>> defaultGroupSequence, DefaultGroupSequenceProvider<? super T> defaultGroupSequenceProvider, ValidationOrderGenerator validationOrderGenerator) {if ( defaultGroupSequence != null && defaultGroupSequenceProvider != null ) {throw LOG.getInvalidDefaultGroupSequenceDefinitionException();}DefaultGroupSequenceContext<T> context = new DefaultGroupSequenceContext<>();// 如果有动态分组序列,则分组序列defaultGroupSequence标记为空,不考虑校验顺序if ( defaultGroupSequenceProvider != null ) {context.defaultGroupSequenceProvider = defaultGroupSequenceProvider;context.defaultGroupSequence = Collections.emptyList();context.validationOrder = null;}// 否则的话,如果有分组系列,解析获取分组系列else if ( defaultGroupSequence != null && !defaultGroupSequence.isEmpty() ) {context.defaultGroupSequence = getValidDefaultGroupSequence( beanClass, defaultGroupSequence );context.validationOrder = validationOrderGenerator.getDefaultValidationOrder( beanClass, context.defaultGroupSequence );}else {// 使用默认分组context.defaultGroupSequence = DEFAULT_GROUP_SEQUENCE;context.validationOrder = ValidationOrder.DEFAULT_SEQUENCE;}return context;}/*** 获取分组序列。必须添加beanClass类作为分组中的元素,且会转换为Default分组*/private static List<Class<?>> getValidDefaultGroupSequence(Class<?> beanClass, List<Class<?>> groupSequence) {List<Class<?>> validDefaultGroupSequence = new ArrayList<>();boolean groupSequenceContainsDefault = false;if ( groupSequence != null ) {for ( Class<?> group : groupSequence ) {// 如果分组序列中存在类名的分组,则添加Default分组,且groupSequenceContainsDefault为trueif ( group.getName().equals( beanClass.getName() ) ) {validDefaultGroupSequence.add( Default.class );groupSequenceContainsDefault = true;}// 如果在分组系列中添加了Default分组,则抛异常else if ( group.getName().equals( Default.class.getName() ) ) {throw LOG.getNoDefaultGroupInGroupSequenceException();}else {// 添加分组validDefaultGroupSequence.add( group );}}}// 如果groupSequenceContainsDefault为false,即在分组序列中没有添加对应类名的分组,则抛异常if ( !groupSequenceContainsDefault ) {throw LOG.getBeanClassMustBePartOfRedefinedDefaultGroupSequenceException( beanClass );}if ( LOG.isTraceEnabled() ) {LOG.tracef("Members of the default group sequence for bean %s are: %s.",beanClass.getName(),validDefaultGroupSequence);}return validDefaultGroupSequence;}/*** 如果有动态分组序列,执行DefaultGroupSequenceProvider的getValidationGroups()方法获取分组,否则返回分组系列*/@Overridepublic List<Class<?>> getDefaultGroupSequence(T beanState) {if ( hasDefaultGroupSequenceProvider() ) {List<Class<?>> providerDefaultGroupSequence = defaultGroupSequenceProvider.getValidationGroups( beanState );return getValidDefaultGroupSequence( beanClass, providerDefaultGroupSequence );}return defaultGroupSequence;}/*** 获取当前beanClass的分组序列。如果定义了DefaultGroupSequenceProvider,则执行getValidationGroups(),获得动态分组序列Sequence集合*/@Overridepublic Iterator<Sequence> getDefaultValidationSequence(T beanState) {// 如果有动态分组序列if ( hasDefaultGroupSequenceProvider() ) {// 执行DefaultGroupSequenceProvider的getValidationGroups(),获取动态分组序列List<Class<?>> providerDefaultGroupSequence = defaultGroupSequenceProvider.getValidationGroups( beanState );return validationOrderGenerator.getDefaultValidationOrder(beanClass,// 获取分组序列。必须添加类名的分组,且会转换为Default分组。此处说明在自定义// 的DefaultGroupSequenceProvider.getValidationGroups()方法中返回的分组序列也必须包含beanClass类作为分组getValidDefaultGroupSequence( beanClass, providerDefaultGroupSequence )).getSequenceIterator();}else {return validationOrder.getSequenceIterator();}}
}
注:通过构造器的最后一行代码调用了getDefaultGroupSequence(null),传入的值为null。如果有动态分组程序,该方法会执行DefaultGroupSequenceProvider.getValidationGroups(),且传入null,所以要在该方法中进行判空处理。另外,结合getValidDefaultGroupSequence()方法的代码,在使用@GroupSequence时,需要添加beanClass的分组作为默认分组,该方法会自动转换为Default分组。
二、分组序列校验
validation校验的时候,会调用ValidatorImol的validate()或validateXXX()方法,不明白的可以看前面的博文。ValidatorImol.validate()代码如下:
@Overridepublic final <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) {Contracts.assertNotNull( object, MESSAGES.validatedObjectMustNotBeNull() );sanityCheckGroups( groups );@SuppressWarnings("unchecked")Class<T> rootBeanClass = (Class<T>) object.getClass();// 从BeanMetaDataManager中获取类对应的BeanMetaData对象,为BeanMetaDataImpl实例BeanMetaData<T> rootBeanMetaData = beanMetaDataManager.getBeanMetaData( rootBeanClass );if ( !rootBeanMetaData.hasConstraints() ) {return Collections.emptySet();}BaseBeanValidationContext<T> validationContext = getValidationContextBuilder().forValidate( rootBeanClass, rootBeanMetaData, object );// 确定组验证顺序ValidationOrder validationOrder = determineGroupValidationOrder( groups );BeanValueContext<?, Object> valueContext = ValueContexts.getLocalExecutionContextForBean(validatorScopedContext.getParameterNameProvider(),object,validationContext.getRootBeanMetaData(),PathImpl.createRootPath());// 验证return validateInContext( validationContext, valueContext, validationOrder );}private ValidationOrder determineGroupValidationOrder(Class<?>[] groups) {Collection<Class<?>> resultGroups;// 没有添加分组的话,默认为Default分组if ( groups.length == 0 ) {resultGroups = DEFAULT_GROUPS;}else {resultGroups = Arrays.asList( groups );}// 获取验证组顺序return validationOrderGenerator.getValidationOrder( resultGroups );}
2.1 在该方法中,先从BeanMetaDataManager中获取类对应的BeanMetaData对象,及上面1.3中讲解的BeanMetaDataImpl对象。
2.2 然后执行determineGroupValidationOrder(Class<?>[] groups),其中的groups为validate()方法中传入的,为@Validated注解中添加的,默认为Default分组。该方法调用validationOrderGenerator.getValidationOrder( resultGroups )获取分组顺序。
public class ValidationOrderGenerator {private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() );private final ConcurrentMap<Class<?>, Sequence> resolvedSequences = new ConcurrentHashMap<Class<?>, Sequence>();/*** 为指定的验证组生成组和序列的顺序,返回验证的执行顺序对象ValidationOrder*/public ValidationOrder getValidationOrder(Collection<Class<?>> groups) {// 必须有分组if ( groups == null || groups.size() == 0 ) {throw LOG.getAtLeastOneGroupHasToBeSpecifiedException();}// 如果只有Default.class分组,返回默认分组顺序if ( groups.size() == 1 && groups.contains( Default.class ) ) {return ValidationOrder.DEFAULT_GROUP;}// 分组必须的接口for ( Class<?> clazz : groups ) {if ( !clazz.isInterface() ) {throw LOG.getGroupHasToBeAnInterfaceException( clazz );}}DefaultValidationOrder validationOrder = new DefaultValidationOrder();// 遍历分组for ( Class<?> clazz : groups ) {if ( Default.class.equals( clazz ) ) { // HV-621validationOrder.insertGroup( Group.DEFAULT_GROUP );}// 如果分组中添加了@GroupSequence注解else if ( isGroupSequence( clazz ) ) {insertSequence( clazz, clazz.getAnnotation( GroupSequence.class ).value(), true, validationOrder );}else {Group group = new Group( clazz );// 将分组添加到validationOrder,在validationOrder对象中,使用List<Group>存放validationOrder.insertGroup( group );// 将继承的组递归添加到组链List<Group>中insertInheritedGroups( clazz, validationOrder );}}return validationOrder;}/*** 获取验证顺序。将defaultGroupSequence中的分组和clazz组成Sequence,添加到ValidationOrder*/public ValidationOrder getDefaultValidationOrder(Class<?> clazz, List<Class<?>> defaultGroupSequence) {// 定义一个DefaultValidationOrder对象DefaultValidationOrder validationOrder = new DefaultValidationOrder();// 以clazz为单位【当前分组类】,记录分组序列中的分组,封装成Sequence对象,保存到validationOrder中insertSequence( clazz, defaultGroupSequence.toArray( new Class<?>[defaultGroupSequence.size()] ), false, validationOrder );return validationOrder;}private boolean isGroupSequence(Class<?> clazz) {return clazz.getAnnotation( GroupSequence.class ) != null;}/*** 将继承的组递归添加到组链中*/private void insertInheritedGroups(Class<?> clazz, DefaultValidationOrder chain) {for ( Class<?> inheritedGroup : clazz.getInterfaces() ) {Group group = new Group( inheritedGroup );chain.insertGroup( group );insertInheritedGroups( inheritedGroup, chain );}}/*** 以sequenceClass为单位,记录分组序列中的分组,封装成Sequence对象,保存到validationOrder中*/private void insertSequence(Class<?> sequenceClass, Class<?>[] sequenceElements, boolean cache, DefaultValidationOrder validationOrder) {// 如果是@GroupSequence注解中的分组序列,cache为true,会进行缓存Sequence sequence = cache ? resolvedSequences.get( sequenceClass ) : null;if ( sequence == null ) {// 解析sequenceClass中的所有分组系列,如果分组系列中的分组还有@GroupSequence,递归调用,全部添加到ArrayList中sequence = resolveSequence( sequenceClass, sequenceElements, new ArrayList<Class<?>>() );// 只有在确定序列是否可扩展后,才能扩展继承的组sequence.expandInheritedGroups();// 缓存if ( cache ) {final Sequence cachedResolvedSequence = resolvedSequences.putIfAbsent( sequenceClass, sequence );if ( cachedResolvedSequence != null ) {sequence = cachedResolvedSequence;}}}// 添加到validationOrder的Map属性中,key为分组类名称,value为分组类中添加的@GroupSequence分组validationOrder.insertSequence( sequence );}/*** 遍历sequenceClass分组中的@GroupSequence分组sequenceElements到List中,封装成Sequence对象。如果分组中还有@GroupSequence,则递归调用*/private Sequence resolveSequence(Class<?> sequenceClass, Class<?>[] sequenceElements, List<Class<?>> processedSequences) {// 如果sequenceClass分组已经处理了,则抛异常if ( processedSequences.contains( sequenceClass ) ) {throw LOG.getCyclicDependencyInGroupsDefinitionException();}else {// 将sequenceClass分组添加到已处理集合中processedSequences.add( sequenceClass );}List<Group> resolvedSequenceGroups = new ArrayList<Group>();// 遍历分组序列中的分组for ( Class<?> clazz : sequenceElements ) {// 继续判断对应的分组添加了@GroupSequence,则递归遍历@GroupSequence中的分组序列if ( isGroupSequence( clazz ) ) {Sequence tmpSequence = resolveSequence( clazz, clazz.getAnnotation( GroupSequence.class ).value(), processedSequences );// 将分组中添加的@GroupSequence序列分组信息添加到resolvedSequenceGroups中addGroups( resolvedSequenceGroups, tmpSequence.getComposingGroups() );}else {List<Group> list = new ArrayList<Group>();list.add( new Group( clazz ) );// 将分组添加到resolvedSequenceGroups中addGroups( resolvedSequenceGroups, list );}}return new Sequence( sequenceClass, resolvedSequenceGroups );}/*** 将groups中的分组信息添加到resolvedGroupSequence中*/private void addGroups(List<Group> resolvedGroupSequence, List<Group> groups) {for ( Group tmpGroup : groups ) {if ( resolvedGroupSequence.contains( tmpGroup ) && resolvedGroupSequence.indexOf( tmpGroup ) < resolvedGroupSequence.size() - 1 ) {throw LOG.getUnableToExpandGroupSequenceException();}resolvedGroupSequence.add( tmpGroup );}}}
如果分组添加了@GroupSequence,则会遍历分组序列,如果分组序列的分组还添加了@GroupSequence,会循环递归遍历。解析所有的分组,封装成Sequence对象。保存到ValidationOrder对象中。
注:在自定义的DefaultGroupSequenceProvider.getValidationGroups()方法中,返回的分组数组必须包含beanClass作为分组
2.3 执行validateInContext()方法
public class ValidatorImpl implements Validator, ExecutableValidator {private <T, U> Set<ConstraintViolation<T>> validateInContext(BaseBeanValidationContext<T> validationContext, BeanValueContext<U, Object> valueContext,ValidationOrder validationOrder) {if ( valueContext.getCurrentBean() == null ) {return Collections.emptySet();}BeanMetaData<U> beanMetaData = valueContext.getCurrentBeanMetaData();// 判断当前bean是否添加了@DefaultGroupSequenceif ( beanMetaData.isDefaultGroupSequenceRedefined() ) {// 先执行beanMetaData.getDefaultGroupSequence(valueContext.getCurrentBean()),此时传入了实体对象。// 如果有动态分组系列程序DefaultGroupSequenceProvider,则会再次执行// DefaultGroupSequenceProvider.getValidationGroups()方法,动态获取分组。// validationOrder.assertDefaultGroupSequenceIsExpandable()默认为空方法validationOrder.assertDefaultGroupSequenceIsExpandable( beanMetaData.getDefaultGroupSequence( valueContext.getCurrentBean() ) );}// 处理第一个单组。对于这些,可以通过在遍历对象之前首先在当前bean上运行所有验证来优化对象遍历Iterator<Group> groupIterator = validationOrder.getGroupIterator();// 遍历分组while ( groupIterator.hasNext() ) {Group group = groupIterator.next();// 设置当前执行的分组valueContext.setCurrentGroup( group.getDefiningClass() );// 执行校验validateConstraintsForCurrentGroup( validationContext, valueContext );if ( shouldFailFast( validationContext ) ) {return validationContext.getFailingConstraints();}}groupIterator = validationOrder.getGroupIterator();// 遍历分组while ( groupIterator.hasNext() ) {Group group = groupIterator.next();// 设置当前执行的分组valueContext.setCurrentGroup( group.getDefiningClass() );// 执行级联校验validateCascadedConstraints( validationContext, valueContext );if ( shouldFailFast( validationContext ) ) {return validationContext.getFailingConstraints();}}// 处理分组序列。对于序列,必须遍历对象图,因为当发生错误时,必须停止处理。// 获取分组序列集合,并遍历SequenceIterator<Sequence> sequenceIterator = validationOrder.getSequenceIterator();while ( sequenceIterator.hasNext() ) {Sequence sequence = sequenceIterator.next();// 遍历sequence中的扩展组,一组系列分组会存放在一个扩展组中。此处感觉有些多余for ( GroupWithInheritance groupOfGroups : sequence ) {int numberOfViolations = validationContext.getFailingConstraints().size();// 遍历组for ( Group group : groupOfGroups ) {// 设置当前分组valueContext.setCurrentGroup( group.getDefiningClass() );// 执行校验validateConstraintsForCurrentGroup( validationContext, valueContext );if ( shouldFailFast( validationContext ) ) {return validationContext.getFailingConstraints();}// 执行级联校验validateCascadedConstraints( validationContext, valueContext );if ( shouldFailFast( validationContext ) ) {return validationContext.getFailingConstraints();}}if ( validationContext.getFailingConstraints().size() > numberOfViolations ) {break;}}}// 校验上下文的错误消息,所有的校验注解之间的上下文ConstraintValidatorContext是完全独立的,无法互相访问通信return validationContext.getFailingConstraints();}private void validateConstraintsForCurrentGroup(BaseBeanValidationContext<?> validationContext, BeanValueContext<?, Object> valueContext) {// 如果不是Default默认组,调用validateConstraintsForNonDefaultGroup(),直接进行验证if ( !valueContext.validatingDefault() ) {validateConstraintsForNonDefaultGroup( validationContext, valueContext );}// 如果是验证默认组序列,需要考虑层次结构中的类可以重新定义默认组序列else {validateConstraintsForDefaultGroup( validationContext, valueContext );}}private <U> void validateConstraintsForDefaultGroup(BaseBeanValidationContext<?> validationContext, BeanValueContext<U, Object> valueContext) {final BeanMetaData<U> beanMetaData = valueContext.getCurrentBeanMetaData();final Map<Class<?>, Class<?>> validatedInterfaces = new HashMap<>();// 评估层次结构中每个类的bean约束,这对于检测潜在的默认组重新定义是必要的for ( Class<? super U> clazz : beanMetaData.getClassHierarchy() ) {// 获取父类的BeanMetaDataBeanMetaData<? super U> hostingBeanMetaData = beanMetaDataManager.getBeanMetaData( clazz );// 获取是否定义了默认组序列。如果通过组序列重新定义或组序列提供程序重新定义了默认组序列,返回trueboolean defaultGroupSequenceIsRedefined = hostingBeanMetaData.isDefaultGroupSequenceRedefined();// 如果当前类重新定义了默认的组序列,则必须将该序列应用于所有类层次结构if ( defaultGroupSequenceIsRedefined ) {// 获取当前beanClass的分组序列。如果定义了DefaultGroupSequenceProvider,则执行getValidationGroups(),获得动态分组序列Iterator<Sequence> defaultGroupSequence = hostingBeanMetaData.getDefaultValidationSequence( valueContext.getCurrentBean() );Set<MetaConstraint<?>> metaConstraints = hostingBeanMetaData.getMetaConstraints();// 遍历分组序列while ( defaultGroupSequence.hasNext() ) {// 过滤每个序列中添加的分组(存在嵌套@GroupSequence)for ( GroupWithInheritance groupOfGroups : defaultGroupSequence.next() ) {boolean validationSuccessful = true;// 遍历每个组for ( Group defaultSequenceMember : groupOfGroups ) {// 执行当前组的校验validationSuccessful = validateConstraintsForSingleDefaultGroupElement( validationContext, valueContext, validatedInterfaces, clazz,metaConstraints, defaultSequenceMember ) && validationSuccessful;}validationContext.markCurrentBeanAsProcessed( valueContext );if ( !validationSuccessful ) {break;}}}}// fast path in case the default group sequence hasn't been redefinedelse {Set<MetaConstraint<?>> metaConstraints = hostingBeanMetaData.getDirectMetaConstraints();validateConstraintsForSingleDefaultGroupElement( validationContext, valueContext, validatedInterfaces, clazz, metaConstraints,Group.DEFAULT_GROUP );validationContext.markCurrentBeanAsProcessed( valueContext );}// all constraints in the hierarchy has been validated, stop validation.if ( defaultGroupSequenceIsRedefined ) {break;}}}private <U> boolean validateConstraintsForSingleDefaultGroupElement(BaseBeanValidationContext<?> validationContext, ValueContext<U, Object> valueContext, final Map<Class<?>, Class<?>> validatedInterfaces,Class<? super U> clazz, Set<MetaConstraint<?>> metaConstraints, Group defaultSequenceMember) {boolean validationSuccessful = true;// 将当前组对应的类名保存到valueContext中valueContext.setCurrentGroup( defaultSequenceMember.getDefiningClass() );for ( MetaConstraint<?> metaConstraint : metaConstraints ) {// 在层次结构中多次实现的接口只需验证一次。一个接口可以定义多个约束,必须检查正在验证的类。final Class<?> declaringClass = metaConstraint.getLocation().getDeclaringClass();if ( declaringClass.isInterface() ) {Class<?> validatedForClass = validatedInterfaces.get( declaringClass );if ( validatedForClass != null && !validatedForClass.equals( clazz ) ) {continue;}validatedInterfaces.put( declaringClass, clazz );}// 执行验证boolean tmp = validateMetaConstraint( validationContext, valueContext, valueContext.getCurrentBean(), metaConstraint );if ( shouldFailFast( validationContext ) ) {return false;}validationSuccessful = validationSuccessful && tmp;}return validationSuccessful;}/*** 非默认组,调用validateMetaConstraints()进行校验*/private void validateConstraintsForNonDefaultGroup(BaseBeanValidationContext<?> validationContext, BeanValueContext<?, Object> valueContext) {// 调用validateMetaConstraints(),逐个遍历约束元数据,执行约束中的isValid()进行校验validateMetaConstraints( validationContext, valueContext, valueContext.getCurrentBean(), valueContext.getCurrentBeanMetaData().getMetaConstraints() );validationContext.markCurrentBeanAsProcessed( valueContext );}
}
在该方法中,如果有序列分组或动态序列分组,会先执行动态序列分组的DefaultGroupSequenceProvider.getValidationGroups()获取分组序列。然后遍历分组序列,执行对应分组的校验。具体的校验方法validateMetaConstraint(),不明白的可以看。
【源码】Spring validation参数校验原理解析之Controller控制器参数校验中@RequestBody参数校验实现原理_simpleconstrainttree-CSDN博客
小结
本篇的源码量比较大,细节也比较多。建议如果本篇不太理解的,可以看看该系列的上一篇或者下一篇源码讲解文章。
关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨,一起学习。