也许去年,还是什么时候,当时注意到校验时的无序问题时,只觉得是内部有个用于校验的线程池(想复杂了)。一直没有“档期”去细看,其实蛮简单的
比较简单的框架,直接就从调用堆栈开始吧
// ConstraintValidator
isValid:22, NotNullValidator (org.hibernate.validator.internal.constraintvalidators.bv)
validateSingleConstraint:180, ConstraintTree (org.hibernate.validator.internal.engine.constraintvalidation)
validateConstraints:62, SimpleConstraintTree (org.hibernate.validator.internal.engine.constraintvalidation)
validateConstraints:75, ConstraintTree (org.hibernate.validator.internal.engine.constraintvalidation)
doValidateConstraint:130, MetaConstraint (org.hibernate.validator.internal.metadata.core)
validateConstraint:123, MetaConstraint (org.hibernate.validator.internal.metadata.core)
validateMetaConstraint:555, ValidatorImpl (org.hibernate.validator.internal.engine)
// step into ...
// 这里 所有的ConstraintValidators 循环校验
// 说明并非并发校验所致
// 我们可以看下这个集合是怎么来的
validateConstraintsForSingleDefaultGroupElement:518, ValidatorImpl (org.hibernate.validator.internal.engine)
validateConstraintsForDefaultGroup:488, ValidatorImpl (org.hibernate.validator.internal.engine)
validateConstraintsForCurrentGroup:450, ValidatorImpl (org.hibernate.validator.internal.engine)
validateInContext:400, ValidatorImpl (org.hibernate.validator.internal.engine)
validate:172, ValidatorImpl (org.hibernate.validator.internal.engine)
validate:358, SpringValidatorAdapter (org.springframework.validation.beanvalidation)
// test-class
t0:29, ValidationTest (cn.angel.boot.demo.validation)
附上test-class
package cn.angel.boot.demo.validation;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.stereotype.Component;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @author weng
* @since 2023/6/12
*/
@AllArgsConstructor
@Data
public class ValidationBean {
@NotBlank(message = "name不能为空串")
String name;
@NotNull(message = "id不能为空")
Long id;
}
// org.hibernate.validator.internal.engine.ValidatorImpl#validateConstraintsForSingleDefaultGroupElement
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.setCurrentGroup( defaultSequenceMember.getDefiningClass() );
// 普通的循环而已
// 说明这个集合已经乱了(这是个set类型)
for ( MetaConstraint<?> metaConstraint : metaConstraints ) {
// HV-466, an interface implemented more than one time in the hierarchy has to be validated only one
// time. An interface can define more than one constraint, we have to check the class we are validating.
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;
}
// org.hibernate.validator.internal.engine.ValidatorImpl#validateConstraintsForDefaultGroup
private <U> void validateConstraintsForDefaultGroup(BaseBeanValidationContext<?> validationContext, BeanValueContext<U, Object> valueContext) {
final BeanMetaData<U> beanMetaData = valueContext.getCurrentBeanMetaData();
final Map<Class<?>, Class<?>> validatedInterfaces = new HashMap<>();
// evaluating the constraints of a bean per class in hierarchy, this is necessary to detect potential default group re-definitions
for ( Class<? super U> clazz : beanMetaData.getClassHierarchy() ) {
BeanMetaData<? super U> hostingBeanMetaData = beanMetaDataManager.getBeanMetaData( clazz );
boolean defaultGroupSequenceIsRedefined = hostingBeanMetaData.isDefaultGroupSequenceRedefined();
// if the current class redefined the default group sequence, this sequence has to be applied to all the class hierarchy.
if ( defaultGroupSequenceIsRedefined ) {
Iterator<Sequence> defaultGroupSequence = hostingBeanMetaData.getDefaultValidationSequence( valueContext.getCurrentBean() );
Set<MetaConstraint<?>> metaConstraints = hostingBeanMetaData.getMetaConstraints();
while ( defaultGroupSequence.hasNext() ) {
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 {
// 有方向了
// org.hibernate.validator.internal.metadata.aggregated.BeanMetaDataImpl#getDirectMetaConstraints
// return directMetaConstraints;
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;
}
}
}
被校验bean的校验元信息解析的地方
// 看来只有这里可以赋值这个集合了
// org.hibernate.validator.internal.metadata.aggregated.BeanMetaDataImpl#BeanMetaDataImpl
/**
* Creates a new {@link BeanMetaDataImpl}
*
* @param beanClass The Java type represented by this meta data object.
* @param defaultGroupSequence The default group sequence.
* @param defaultGroupSequenceProvider The default group sequence provider if set.
* @param constraintMetaDataSet All constraint meta data relating to the represented type.
*/
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;
// 最后又回到了这列
// 所以说乱序的根因不是并发所致,而是hash分布
Set<MetaConstraint<?>> allMetaConstraints = newHashSet();
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;
// step into ...
// 这里
this.directMetaConstraints = getDirectConstraints();
this.executableMetaDataMap = CollectionHelper.toImmutableMap( bySignature( executableMetaDataSet ) );
this.unconstrainedExecutables = CollectionHelper.toImmutableSet( tmpUnconstrainedExecutables );
// We initialize those elements eagerly so that any eventual error is thrown when bootstrapping the bean metadata
this.defaultGroupSequenceRedefined = this.defaultGroupSequence.size() > 1 || hasDefaultGroupSequenceProvider();
this.resolvedDefaultGroupSequence = getDefaultGroupSequence( null );
}
private Set<MetaConstraint<?>> getDirectConstraints() {
Set<MetaConstraint<?>> constraints = newHashSet();
Set<Class<?>> classAndInterfaces = newHashSet();
classAndInterfaces.add( beanClass );
classAndInterfaces.addAll( ClassHierarchyHelper.getDirectlyImplementedInterfaces( beanClass ) );
for ( Class<?> clazz : classAndInterfaces ) {
// 搜索一下哪里赋值了这个 allMetaConstraints
for ( MetaConstraint<?> metaConstraint : allMetaConstraints ) {
if ( metaConstraint.getLocation().getDeclaringClass().equals( clazz ) ) {
constraints.add( metaConstraint );
}
}
}
return CollectionHelper.toImmutableSet( constraints );
}