详述Spring对Bean Validation支持的核心API:Validator、SmartValidator、LocalValidatorFactoryBean...【享学Spring】(中)

简介: 详述Spring对Bean Validation支持的核心API:Validator、SmartValidator、LocalValidatorFactoryBean...【享学Spring】(中)

CustomValidatorBean


可配置(Custom)的Bean类,也同样的实现了双接口。它可以配置ValidatorFactory验证器工厂、MessageInterpolator插值器等…


public class CustomValidatorBean extends SpringValidatorAdapter implements Validator, InitializingBean {
  // javax.validation.ValidatorFactory
  @Nullable
  private ValidatorFactory validatorFactory;
  @Nullable
  private MessageInterpolator messageInterpolator;
  @Nullable
  private TraversableResolver traversableResolver;
  ... // 省略所有set方法(木有get方法)
  // 默认设置~~~~初始化
  @Override
  public void afterPropertiesSet() {
    if (this.validatorFactory == null) {
      this.validatorFactory = Validation.buildDefaultValidatorFactory();
    }
    // 这一句就是new ValidatorContextImpl( this )
    ValidatorContext validatorContext = this.validatorFactory.usingContext();
    // 插值器
    MessageInterpolator targetInterpolator = this.messageInterpolator;
    if (targetInterpolator == null) {
      targetInterpolator = this.validatorFactory.getMessageInterpolator();
    }
    validatorContext.messageInterpolator(new LocaleContextMessageInterpolator(targetInterpolator));
    if (this.traversableResolver != null) {
      validatorContext.traversableResolver(this.traversableResolver);
    }
    // 把已经配置好的这个Validator设置进去~
    setTargetValidator(validatorContext.getValidator());
  }
}


命名中就能可以看出,它是一个Bean,所以可以配合Spring容器一起使用。Spring内部虽然没有直接使用到它,但我们自己有需求的话自己可以使用它(其实更多的还是使用更强的子类)~


LocalValidatorFactoryBean


它和CustomValidatorBean平级,都是继承自SpringValidatorAdapter,但是它提供的能力更加的强大,比如Spring处理校验这块最重要的处理器MethodValidationPostProcessor就是依赖于它来给提供验证器~


它是Spring上下文中javax.validation的中心配置类。

// @since 3.0  这个类非常的丰富  实现了接口javax.validation.ValidatorFactory
// 实现了ApplicationContextAware拿到Spring上下文...
// 但其实,它的实际工作都是委托式,自己只提供了各式各样的配置~~~(主要是配置JSR)
public class LocalValidatorFactoryBean extends SpringValidatorAdapter implements ValidatorFactory, ApplicationContextAware, InitializingBean, DisposableBean {
  ... // 省略所有的配置属性
  ... // 省略所有的get/set
  ... // 省略afterPropertiesSet()进行的默认配置初始化  最终调用setTargetValidator(this.validatorFactory.getValidator());
  // 备注:还记得上文吗?上文的validator校验器是从上下文拿的,这里是从工厂拿的
  // 省略所有对ValidatorFactory接口的方法实现~
}


这个类是非常重要的,虽然它也不被Spring直接使用,但是它是基石。


备注:虽然命名后缀是FactoryBean,但它并不是org.springframework.beans.factory.FactoryBean这个接口的子类。

其实这是断句问题,正确断句方式是:Local ValidatorFactory Bean~


OptionalValidatorFactoryBean


@since 4.0.1提供的,它做的唯一一件事:让org.springframework.validation.Validator成为可选(即使没有初始化成功,也不会报错,相当于把异常吃了嘛~)


// @since 4.0.1
public class OptionalValidatorFactoryBean extends LocalValidatorFactoryBean {
  @Override
  public void afterPropertiesSet() {
    try {
      super.afterPropertiesSet();
    } catch (ValidationException ex) {
      LogFactory.getLog(getClass()).debug("Failed to set up a Bean Validation provider", ex);
    }
  }
}


综上,若你想使用org.springframework.validation.SmartValidator来完成对Bean的校验,那就手动定义一个这样的Bean,然后自行调用API校验完成校验~

若你想这一切能面向注解编程,自动完成校验,那就听下文分解吧(也是最为关心,最为重要的内容)~


SpringConstraintValidatorFactory

ConstraintValidatorFactory整个API前问有讲过,本类就是Spring对它的扩展,从而和Spring容器整合了~

public class SpringConstraintValidatorFactory implements ConstraintValidatorFactory {
  private final AutowireCapableBeanFactory beanFactory;
  public SpringConstraintValidatorFactory(AutowireCapableBeanFactory beanFactory) {
    Assert.notNull(beanFactory, "BeanFactory must not be null");
    this.beanFactory = beanFactory;
  }
  // 注意:此处是直接调用了create方法,放进容器
  @Override
  public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) {
    return this.beanFactory.createBean(key);
  }
  // Bean Validation 1.1 releaseInstance method
  public void releaseInstance(ConstraintValidator<?, ?> instance) {
    this.beanFactory.destroyBean(instance);
  }
}


MessageSourceResourceBundleLocator


这个类也非常有意思,它扩展了Hibernate包的ResourceBundleLocator国际化,而使用

Spring自己的国际化资源:org.springframework.context.MessageSource


说明:ResourceBundleLocator是它Hibernate的一个SPI,Hibernate内部自己对它可是也有实现的哦~(Bean Validation内部大量的用到了SPI技术,有兴趣的可以了解)


public class MessageSourceResourceBundleLocator implements ResourceBundleLocator {
  private final MessageSource messageSource;
  public MessageSourceResourceBundleLocator(MessageSource messageSource) {
    Assert.notNull(messageSource, "MessageSource must not be null");
    this.messageSource = messageSource;
  }
  @Override
  public ResourceBundle getResourceBundle(Locale locale) {
    return new MessageSourceResourceBundle(this.messageSource, locale);
  }
}


关于MessageSourceResourceBundle它,就相对比较熟悉点了,它不是校验专用的,是Spring整体上用来处理国际化资源:MessageSource,java.util.ResourceBundl的帮助类~


//@since 27.02.2003 java.util.ResourceBundle  它是JDK提供来读取国际化的属性配置文件的  是个抽象类
public class MessageSourceResourceBundle extends ResourceBundle {
  private final MessageSource messageSource;
  private final Locale locale;
  public MessageSourceResourceBundle(MessageSource source, Locale locale) {
    Assert.notNull(source, "MessageSource must not be null");
    this.messageSource = source;
    this.locale = locale;
  }
  public MessageSourceResourceBundle(MessageSource source, Locale locale, ResourceBundle parent) {
    this(source, locale);
    setParent(parent);
  }
  @Override
  @Nullable
  protected Object handleGetObject(String key) {
    try {
      return this.messageSource.getMessage(key, null, this.locale);
    } catch (NoSuchMessageException ex) {
      return null;
    }
  }
  // @since 1.6
  @Override
  public boolean containsKey(String key) {
    try {
      this.messageSource.getMessage(key, null, this.locale);
      return true;
    }
    catch (NoSuchMessageException ex) {
      return false;
    }
  }
  @Override
  public Enumeration<String> getKeys() {
    throw new UnsupportedOperationException("MessageSourceResourceBundle does not support enumerating its keys");
  }
  @Override
  public Locale getLocale() {
    return this.locale;
  }
}


Spring环境下不仅可以使用Hibernate的国际化文件,也可以借助MessageSourceResourceBundleLocator搞自己的。

相关文章
|
1月前
|
XML 安全 Java
|
13天前
|
存储 Java Spring
【Spring】获取Bean对象需要哪些注解
@Conntroller,@Service,@Repository,@Component,@Configuration,关于Bean对象的五个常用注解
|
13天前
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
|
20天前
|
存储 安全 Java
Spring Boot 编写 API 的 10条最佳实践
本文总结了 10 个编写 Spring Boot API 的最佳实践,包括 RESTful API 设计原则、注解使用、依赖注入、异常处理、数据传输对象(DTO)建模、安全措施、版本控制、文档生成、测试策略以及监控和日志记录。每个实践都配有详细的编码示例和解释,帮助开发者像专业人士一样构建高质量的 API。
|
19天前
|
XML Java 数据格式
Spring容器Bean之XML配置方式
通过对以上内容的掌握,开发人员可以灵活地使用Spring的XML配置方式来管理应用程序的Bean,提高代码的模块化和可维护性。
56 6
|
21天前
|
XML Java 数据格式
🌱 深入Spring的心脏:Bean配置的艺术与实践 🌟
本文深入探讨了Spring框架中Bean配置的奥秘,从基本概念到XML配置文件的使用,再到静态工厂方式实例化Bean的详细步骤,通过实际代码示例帮助读者更好地理解和应用Spring的Bean配置。希望对你的Spring开发之旅有所助益。
85 3
|
1月前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
35 1
|
2月前
|
Java 测试技术 API
详解Swagger:Spring Boot中的API文档生成与测试工具
详解Swagger:Spring Boot中的API文档生成与测试工具
56 4
|
JSON 前端开发 Java
Spring Validation参数效验各种使用姿势
在日常的项目开发中,为了防止非法参数对业务造成的影响,需要对接口的参数做合法性校验,例如在创建用户时,需要效验用户的账号名称不能输入中文与特殊字符,手机号、邮箱格式是否准确。
5074 7
|
3月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
265 2