ValidatorImpl
它是Hibernate Validator
提供的唯一校验器实现(思想准备:非常复杂)
public class ValidatorImpl implements Validator, ExecutableValidator { private static final Collection<Class<?>> DEFAULT_GROUPS = Collections.<Class<?>>singletonList( Default.class ); // 分组Group校验的顺序问题 // 若依赖于校验顺序,可用使用@GroupSequence注解来控制Group顺序 private final transient ValidationOrderGenerator validationOrderGenerator; private final ConstraintValidatorFactory constraintValidatorFactory; ... // 唯一构造函数~ public ValidatorImpl(ConstraintValidatorFactory constraintValidatorFactory, BeanMetaDataManager beanMetaDataManager, ValueExtractorManager valueExtractorManager, ConstraintValidatorManager constraintValidatorManager, ValidationOrderGenerator validationOrderGenerator, ValidatorFactoryScopedContext validatorFactoryScopedContext) { this.constraintValidatorFactory = constraintValidatorFactory; this.beanMetaDataManager = beanMetaDataManager; this.valueExtractorManager = valueExtractorManager; this.constraintValidatorManager = constraintValidatorManager; this.validationOrderGenerator = validationOrderGenerator; this.validatorScopedContext = new ValidatorScopedContext( validatorFactoryScopedContext ); this.traversableResolver = validatorFactoryScopedContext.getTraversableResolver(); this.constraintValidatorInitializationContext = validatorFactoryScopedContext.getConstraintValidatorInitializationContext(); } @Override public final <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) { sanityCheckGroups( groups ); // groups里面的内容不能有null @SuppressWarnings("unchecked") Class<T> rootBeanClass = (Class<T>) object.getClass(); BeanMetaData<T> rootBeanMetaData = beanMetaDataManager.getBeanMetaData( rootBeanClass ); // 若没有约束存在,直接返回~ if ( !rootBeanMetaData.hasConstraints() ) { return Collections.emptySet(); } // ValidationContext这个实体类里面的属性极其多~ 持有各种组件的引用 ValidationContext<T> validationContext = getValidationContextBuilder().forValidate( rootBeanMetaData, object ); // 找到这个分组们的(带有顺序) ValidationOrder validationOrder = determineGroupValidationOrder( groups ); // ValueContext一个实例用于收集所有相关信息,以验证单个类、属性或方法调用。 ValueContext<?, Object> valueContext = ValueContext.getLocalExecutionContext(validatorScopedContext.getParameterNameProvider(), object, validationContext.getRootBeanMetaData(), PathImpl.createRootPath() ); // 此方法传入的信息量非常大~~ 验证上下文、值上下文,验证器 // 返回的是失败的消息对象:ConstraintViolation 它是被存储在ValidationContext里的~~~~ return validateInContext( validationContext, valueContext, validationOrder ); } ... // 省略validateProperty和validateValue // 下面实现`ExecutableValidator`的相关方法 它的四个接口方法无非就是两个方法:validateParameters和validateReturnValue 略 // beanMetaDataManager.getBeanMetaData( clazz )还是相对比较重要的 @Override public final BeanDescriptor getConstraintsForClass(Class<?> clazz) { return beanMetaDataManager.getBeanMetaData( clazz ).getBeanDescriptor(); } @Override public final <T> T unwrap(Class<T> type) { if ( type.isAssignableFrom( Validator.class ) ) { return type.cast( this ); } throw LOG.getTypeNotSupportedForUnwrappingException( type ); } // 返回自己即可。因为它是可以校验方法入参、返回值等等的 @Override public ExecutableValidator forExecutables() { return this; } ... // 省略所有的私有方法们~ }
同样的hibernate实现这套ValidatorImpl校验逻辑不可为不复杂。幸好的是:对于我们web程序员来说,我个人建议只需要掌握到几大主流的组件的使用,就完全够用了(毕竟它有很多能力是给javaFx提供的)。再若不需要关心实现细节,完全面向接口编程我认为也是ok的~~
执行validator.validate(person)方法后,最终拿到的是多个ConstraintViolation,它代表着校验失败的那些讯息,若是Spring框架集成,拿出来做出友好的提示便可达到我们的校验效果~
总结
本文总体还是还是依托实例,再着眼于原理层面的分析,介绍了ValidatorFactory和Validator核心。和上文不一样的是,这两个API应该是我们使用者最应该关注的,所以他们提供的接口方法,希望小伙伴可以稍微留点心,记点忆。
上面也说了,hibernate validation它对数据校验的实现非常非常的复杂,毕竟它提供的能力也是非常强大的(当然弱弱说一句:作者打代码能力也是有待讨论的)。
但是我个人认为,如文章所述掌握到这种程度至少对于web开发者来说是够用了的,甚至我相信大多数小伙伴都感觉内容已经溢出了,所以那就各自领会吧~
Bean Validation核心原理部分到此就先告一段落,像什么扩展它的SPI如:ConstraintMappingContributor、ResourceBundleLocator、DefaultGroupSequenceProvider等虽然功能强大可扩展,但本系列就不再讨论了~~~
接下来开始面向小伙伴最为关心的:使用、集成、高级定制等,当然还包括在Spring环境下的高度整合和扩展使用,请持续关注~
相关阅读
深入了解数据校验:Java Bean Validation 2.0(JSR303、JSR349、JSR380)Hibernate-Validation 6.x使用案例【享学Java】
深入了解数据校验(Bean Validation):基础类打点(ValidationProvider、ConstraintDescriptor、ConstraintValidator)【享学Java】