【源码】Spring validation参数校验之分组序列校验@GroupSequenceProvider、@GroupSequence的实现原理

 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的实现原理

10、【源码】Spring validation参数校验实现原理总结

前言

本篇继续从源码的角度分析一下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对象,来源为Annotation
        return 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为true
		this.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为true
				if ( 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()方法获取分组,否则返回分组系列
	 */
	@Override
	public List<Class<?>> getDefaultGroupSequence(T beanState) {
		if ( hasDefaultGroupSequenceProvider() ) {
			List<Class<?>> providerDefaultGroupSequence = defaultGroupSequenceProvider.getValidationGroups( beanState );
			return getValidDefaultGroupSequence( beanClass, providerDefaultGroupSequence );
		}

		return defaultGroupSequence;
	}
	
    /**
	 * 获取当前beanClass的分组序列。如果定义了DefaultGroupSequenceProvider,则执行getValidationGroups(),获得动态分组序列Sequence集合
	 */
	@Override
	public 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()代码如下:

    @Override
	public 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-621
				validationOrder.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是否添加了@DefaultGroupSequence
		if ( 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();
			}
		}

		// 处理分组序列。对于序列,必须遍历对象图,因为当发生错误时,必须停止处理。
		// 获取分组序列集合,并遍历Sequence
		Iterator<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() ) {
			// 获取父类的BeanMetaData
			BeanMetaData<? super U> hostingBeanMetaData = beanMetaDataManager.getBeanMetaData( clazz );
			// 获取是否定义了默认组序列。如果通过组序列重新定义或组序列提供程序重新定义了默认组序列,返回true
			boolean 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 redefined
			else {
				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博客

小结

本篇的源码量比较大,细节也比较多。建议如果本篇不太理解的,可以看看该系列的上一篇或者下一篇源码讲解文章。

关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨,一起学习。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/567763.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

区块链钱包开发——专业区块链开发

随着区块链技术的发展&#xff0c;钱包开发成为了一项至关重要的任务。本文将探讨区块链钱包开发的重要性&#xff0c;分析当前面临的挑战&#xff0c;并展望未来的发展趋势。 一、区块链钱包概述 区块链钱包是一种用于存储和管理数字货币的软件工具。它为用户提供了一个安全的…

05_FreeRTOS信号量

信号量 信号量信号量简介常用信号量API函数 信号量 信号量简介 信号量&#xff08;Semaphore&#xff09;是一种实现任务间通信的机制&#xff0c;可以实现任务之间同步或临界资源的互斥访问&#xff0c;常用于协助一组相互竞争的任务来访问临界资源。在多任务系统中&#xf…

【C语言__指针02__复习篇12】

目录 前言 一、数组名的理解 二、使用指针访问数组 三、一维数组传参的本质 四、冒泡排序 五、二级指针 六、指针数组 七、指针数组模拟二维数组 前言 本篇主要讨论以下问题&#xff1a; 1. 数组名通常表示什么&#xff0c;有哪两种例外情况&#xff0c;在例外情况中…

Electron+Vue3+ElectronForge整合 - 打包时整合 -分步打包

说明 本文介绍一下 Electron Vue3 的打包整合的基本操作。实现的效果是 &#xff1a; 1、一个正常的Vue3项目&#xff1b; 2、整合加入 Electron 框架 &#xff1a;开发时 Electron 加载的是开发的vue项目&#xff1b; 3、完成打包时整合&#xff1a;3.1 先完成vue3项目的正常…

加州理工华人用AI颠覆数学证明!提速5倍震惊陶哲轩,80%数学步骤全自动化

加州理工团队解决了形式化研究神器Lean运行LLM推理时的核心技术挑战&#xff0c;可以让LLM在Lean中提出证明策略&#xff0c;允许人类以无缝的方式干预和修改。 Lean Copilot&#xff0c;让陶哲轩等众多数学家赞不绝口的这个形式化数学工具&#xff0c;又有超强进化了&#xf…

pytest教程-29-重复执行用例插件-pytest-repeat

领取资料&#xff0c;咨询答疑&#xff0c;请➕wei: June__Go 上一小节我们学习了设置用例超时时间插件pytest-timeout&#xff0c;本小节我们讲解一下pytest重复执行用例插件pytest-repeat。 前言 做功能测试的时候&#xff0c;经常会遇到某个模块不稳定&#xff0c;偶然会…

五款最受欢迎的上网行为管理软件

五款最受欢迎的上网行为管理软件 员工上网看视频怎么办&#xff1f;员工偷偷刷抖音怎么办&#xff1f;员工天天上招聘网&#xff0c;是不是有离职打算&#xff1f; 解决上述困扰的最好办法是使用监控软件了解员工一言一行。以下是几款推荐的上网行为管理和监控软件&#xff1a;…

【Linux】开关机命令和服务管理类命令

一般Linux是不会经常进行关机的,关机的正确流程是: sync->shutdown->reboot->poweroff sync: 将内存中的数据同步到硬盘中poweroff: 关闭系统,等同于shutdown -h nowreboot: 重启系统,等同于 shutdown -r nowshutdown[选项] [时间] shutdown命令常见用法: shutdown:…

二叉树的先序、中序和后序遍历,以及二叉树的高度

1、二叉树的三种遍历方式 前序遍历&#xff1a; 访问根节点前序遍历左子树前序遍历右子树示例&#xff1a;对于节点 A&#xff08;左子树为 B&#xff0c;右子树为 C&#xff09;&#xff0c;遍历顺序为 A -> B -> C。 中序遍历&#xff1a; 中序遍历左子树访问根节点中…

如何在Windows服务做性能测试(CPU、磁盘、内存)

目录 前言1. 基本知识2. 参数说明 前言 由于需要做一些接口测试&#xff0c;测试是否有真的优化 1. 基本知识 该基本知识主要用来用到Performance Monitor&#xff0c;以下着重介绍下这方面的知识 性能监视器&#xff08;Performance Monitor&#xff09;&#xff1a;Windo…

本地部署Docker容器可视化图形管理工具DockerUI并实现无公网IP远程访问——“cpolar内网穿透”

文章目录 前言1. 安装部署DockerUI2. 安装cpolar内网穿透3. 配置DockerUI公网访问地址4. 公网远程访问DockerUI5. 固定DockerUI公网地址 前言 DockerUI是一个docker容器镜像的可视化图形化管理工具。DockerUI可以用来轻松构建、管理和维护docker环境。它是完全开源且免费的。基…

Unity的旋转实现一些方法总结(案例:通过输入,玩家进行旋转移动)

目录 1. Transform.Rotate 方法 使用 2. Transform.rotation 或 Transform.localRotation 属性与四元数 使用方式&#xff1a; 小案例 &#xff1a;目标旋转角度计算&#xff1a;targetRotation&#xff08;Quaternion类型&#xff09; 玩家发现敌人位置&#xff0c;玩家…

八股中的记录

1. protected修饰符&#xff1a;同包或子类&#xff08;不同包&#xff09; 区分普通人和专业人调用的一些方法 2. 抽象&#xff1a;abstract修饰类和方法 抽象类不可实例化&#xff0c;避免错误的new对象 抽象方法是用abstract修饰的方法声明&#xff0c;没有方法体&#xff…

半导体存储器整理

半导体存储器用来存储大量的二值数据&#xff0c;它是计算机等大型数字系统中不可缺少的组成部分。按照集成度划分&#xff0c;半导体存储器属于大规模集成电路。 目前半导体存储器可以分为两大类&#xff1a; 只读存储器&#xff08;ROM&#xff0c;Read Only Memory&#xff…

MySQL连接失败

最近接手了公司的一个软件项目&#xff0c;通过打印日志&#xff0c;发现该软件会偶发出现连接MySQL数据库失败的问题。 首先排查是否是网络问题导致的连接失败。对该软件和MySQL的3306端口进行抓包&#xff0c;发现连接数据库失败时并没有出现tcp三次握手失败的情况。并且该软…

semaphore信号量使用+原理分析

1.概述 Semaphore 信号量&#xff0c;相当于一个计数器&#xff0c;通常用来限制线程的数量。 每个线程操作前会先获取一个许可证&#xff0c;逻辑处理完成之后就归还这个许可证。 通俗的解释&#xff1a;相当于一个停车场&#xff0c;有10个停车位&#xff0c;进来一个车&am…

按照以下步骤使用Transformer模型

“Transformer”是一种深度学习模型架构&#xff0c;用于处理序列数据&#xff0c;特别是在自然语言处理&#xff08;NLP&#xff09;领域中表现出色。它由Google Brain团队于2017年提出&#xff0c;并在机器翻译任务中取得了突破性的成果。Transformer的核心思想是完全基于自注…

指挥中心实战指挥平台-通信指挥类装备多链路聚合设备解决方案实例

一、建设目标及要求 坚持“一切为了实战、一切围绕实战、一切服务实战”的总要求&#xff0c;紧紧围绕大数据应用和自动化、智能化、智慧化这一主题主线&#xff0c;建设升级改造支队指挥中心&#xff0c;集成语音、视频、即时消息、短信、对讲、会议等多媒体通信能力&#xf…

基于SpringBoot的智慧物业管理设计与实现论文

摘  要 随着我国发展和城市开发&#xff0c;物业管理已形成规模&#xff0c;其效益也越来越明显。在经济效益对地方政府而言&#xff0c;主要体现为&#xff1a;减少了大量的财政补贴&#xff0c;对住宅区开发企业而言&#xff0c;能提高物业市场竞争力&#xff0c;使开发企…

场景 - 分库分表

分什么 数据量大分表&#xff0c;并发大分库 分表字段如何选择 如果对交易订单进行分表&#xff0c;可以选择的东西很多&#xff0c;比如说商户id&#xff0c;用户id&#xff0c;地区等等 分表的时候要考虑到数据倾斜问题 数据倾斜 比如说按商户号进行分表&#xff0c;一共…
最新文章