深入了解数据校验(Bean Validation):ValidatorFactory和Validator等核心API【享学Java】(下)

简介: 深入了解数据校验(Bean Validation):ValidatorFactory和Validator等核心API【享学Java】(下)

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】

相关文章
|
4天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
16 2
|
3月前
|
安全 Java API
告别繁琐编码,拥抱Java 8新特性:Stream API与Optional类助你高效编程,成就卓越开发者!
【8月更文挑战第29天】Java 8为开发者引入了多项新特性,其中Stream API和Optional类尤其值得关注。Stream API对集合操作进行了高级抽象,支持声明式的数据处理,避免了显式循环代码的编写;而Optional类则作为非空值的容器,有效减少了空指针异常的风险。通过几个实战示例,我们展示了如何利用Stream API进行过滤与转换操作,以及如何借助Optional类安全地处理可能为null的数据,从而使代码更加简洁和健壮。
108 0
|
19天前
|
Java API 数据处理
探索Java中的Lambda表达式与Stream API
【10月更文挑战第22天】 在Java编程中,Lambda表达式和Stream API是两个强大的功能,它们极大地简化了代码的编写和提高了开发效率。本文将深入探讨这两个概念的基本用法、优势以及在实际项目中的应用案例,帮助读者更好地理解和运用这些现代Java特性。
|
1月前
|
分布式计算 Java 大数据
大数据-147 Apache Kudu 常用 Java API 增删改查
大数据-147 Apache Kudu 常用 Java API 增删改查
28 1
|
2月前
|
安全 Java API
时间日期API(Date,SimpleDateFormat,Calendar)+java8新增日期API (LocalTime,LocalDate,LocalDateTime)
这篇文章介绍了Java中处理日期和时间的API,包括旧的日期API(Date、SimpleDateFormat、Calendar)和Java 8引入的新日期API(LocalTime、LocalDate、LocalDateTime)。文章详细解释了这些类/接口的方法和用途,并通过代码示例展示了如何使用它们。此外,还讨论了新旧API的区别,新API的不可变性和线程安全性,以及它们提供的操作日期时间的灵活性和简洁性。
|
2月前
|
Java 程序员 API
Java 8新特性之Lambda表达式与Stream API的探索
【9月更文挑战第24天】本文将深入浅出地介绍Java 8中的重要新特性——Lambda表达式和Stream API,通过实例解析其语法、用法及背后的设计哲学。我们将一探究竟,看看这些新特性如何让Java代码变得更加简洁、易读且富有表现力,同时提升程序的性能和开发效率。
|
2月前
|
Java
flyway报错Caused by: java.lang.NoSuchMethodError: org.flywaydb.core.api.configuration.FluentConfigurat
flyway报错Caused by: java.lang.NoSuchMethodError: org.flywaydb.core.api.configuration.FluentConfigurat
39 2
|
1月前
|
缓存 前端开发 Java
Java中的RESTful API原则
总结而言,遵循RESTful原则不仅能够提升API的互操作性,还便于维护和扩展,是构建现代Web服务的重要实践。通过精心设计的URI、利用HTTP协议特性以及采用成熟框架如Spring Boot,Java开发者能够高效地创建出既强大又易于使用的RESTful API。
50 0
|
2月前
|
安全 Java API
【性能与安全的双重飞跃】JDK 22外部函数与内存API:JNI的继任者,引领Java新潮流!
【9月更文挑战第7天】JDK 22外部函数与内存API的发布,标志着Java在性能与安全性方面实现了双重飞跃。作为JNI的继任者,这一新特性不仅简化了Java与本地代码的交互过程,还提升了程序的性能和安全性。我们有理由相信,在外部函数与内存API的引领下,Java将开启一个全新的编程时代,为开发者们带来更加高效、更加安全的编程体验。让我们共同期待Java在未来的辉煌成就!
65 11
|
3月前
|
Java API
Java 8新特性:Lambda表达式与Stream API的深度解析
【7月更文挑战第61天】本文将深入探讨Java 8中的两个重要特性:Lambda表达式和Stream API。我们将首先介绍Lambda表达式的基本概念和语法,然后详细解析Stream API的使用和优势。最后,我们将通过实例代码演示如何结合使用Lambda表达式和Stream API,以提高Java编程的效率和可读性。