详述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搞自己的。

相关文章
|
5天前
|
Java uml Spring
手写spring第四章-完善bean实例化,自动填充成员属性
手写spring第四章-完善bean实例化,自动填充成员属性
14 0
|
12天前
|
安全 Java API
第7章 Spring Security 的 REST API 与微服务安全(2024 最新版)(上)
第7章 Spring Security 的 REST API 与微服务安全(2024 最新版)
33 0
第7章 Spring Security 的 REST API 与微服务安全(2024 最新版)(上)
|
1天前
|
消息中间件 安全 Java
在Spring Bean中,如何通过Java配置类定义Bean?
【4月更文挑战第30天】在Spring Bean中,如何通过Java配置类定义Bean?
8 1
|
4天前
|
前端开发 Java 数据格式
【Spring系列笔记】定义Bean的方式
在Spring Boot应用程序中,定义Bean是非常常见的操作,它是构建应用程序的基础。Spring Boot提供了多种方式来定义Bean,每种方式都有其适用的场景和优势。
18 2
|
5天前
|
XML Java 数据格式
手写spring第七章-完成便捷实现bean对象初始化和销毁方法
手写spring第七章-完成便捷实现bean对象初始化和销毁方法
6 0
|
5天前
|
XML Java 数据格式
手写spring第六章-实现应用上下文,完成bean的扩展机制
手写spring第六章-实现应用上下文,完成bean的扩展机制
11 0
|
5天前
|
设计模式 搜索推荐 Java
手写spring第三章-重构,使用依赖关系完善实例化bean操作
手写spring第三章-重构,使用依赖关系完善实例化bean操作
12 0
|
6天前
|
XML 人工智能 Java
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
|
7天前
|
安全 Java API
Spring工厂API与原理
Spring工厂API与原理
29 10
|
12天前
|
安全 Java API
第7章 Spring Security 的 REST API 与微服务安全(2024 最新版)(下)
第7章 Spring Security 的 REST API 与微服务安全(2024 最新版)
21 0