Java bean validation 规范与原理

JSR 303 – Bean Validation

JSR 303是JAVA EE 6中的一项子规范,Bean Validation 为 JavaBean 验证定义了相应的元数据模型和 API。缺省的元数据是 Java Annotations,通过使用 XML 可以对Java注解信息进行覆盖和扩展;
例如: @NotNull, @Max, @ZipCode, 就可以确保数据模型(JavaBean)的正确性;

Constraint

constraint在JSR的规范上是这样说的:A constraint on a JavaBean is expressed through one or more annotations. An annotation is considered a constraint definition if its retention policy contains RUNTIMEand if the annotation itself is annotated withjavax.validation.Constraint
大概含义是:使用Constraint来使一个或更多个annotaion起作用
其定义如下:

@Documented
@Target({ ANNOTATION_TYPE })
@Retention(RUNTIME)
public @interface Constraint {

 /**
  * {@link ConstraintValidator} classes must reference distinct target types
  * for a given {@link ValidationTarget}
  * If two {@code ConstraintValidator}s refer to the same type,
  * an exception will occur.
  * 

* At most one {@code ConstraintValidator} targeting the array of parameters of * methods or constructors (aka cross-parameter) is accepted. If two or more * are present, an exception will occur. * * @return array of (@code ConstraintValidator} classes implementing the constraint */ Class>[] validatedBy(); }

使用方法:
通过validatedBy指定校验器的class,Validation API的实现会自动加载你所指定的校验器,如下:
@Constraint(validatedBy = OrderNumberValidator.class)

package com.acme.constraint;

/**
 * Mark a String as representing a well formed order number
 */
@Documented
*@Constraint(validatedBy = OrderNumberValidator.class)*
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface OrderNumber {
    String message() default "{com.acme.constraint.OrderNumber.message}";
    Class[] groups() default {};
    Class[] payload() default {};
}

估计有人会有疑问,为什么自带的API都没有指定Validator,这个是因为如果是有官方定义的Api,在相应的Api实现上已经把指定的Validator加进去,例如:
Hibernate-validator是Validator Api实现,在ConstraintHelper的有如下代码:

public ConstraintHelper() {
  Map, List>> tmpConstraints = newHashMap();
  putConstraint( tmpConstraints, AssertFalse.class, AssertFalseValidator.class );
  putConstraint( tmpConstraints, AssertTrue.class, AssertTrueValidator.class );
  putConstraint( tmpConstraints, CNPJ.class, CNPJValidator.class );
  ....省略部分代码
  putConstraint( tmpConstraints, URL.class, URLValidator.class );
  this.builtinConstraints = Collections.unmodifiableMap( tmpConstraints );
 }

目前已有的Validator

Java bean validation 规范与原理_第1张图片
Paste_Image.png

Validator的官方实现Hibernate新增的Validator

Java bean validation 规范与原理_第2张图片
Paste_Image.png

如何使用:

写代码引入校验
Validator validator = Validation.byProvider( HibernateValidator.class )
.configure()
.failFast( true )
.buildValidatorFactory()
.getValidator();
Set> constraintViolations = validator.validate( anInstance );

在Spring中可以配置如下:



Validatior Api和Hibernate-Validator的关系

用过SPI来扩展实现,在Validator中

private static class GetValidationProviderListAction implements PrivilegedAction>> {
  private static final WeakHashMap>>> providersPerClassloader =
    new WeakHashMap>>>();

  public static List> getValidationProviderList() {
   final GetValidationProviderListAction action = new GetValidationProviderListAction();
   if ( System.getSecurityManager() != null ) {
    return AccessController.doPrivileged( action );
   }
   else {
    return action.run();
   }
  }

  public List> run() {
   ClassLoader classloader = Thread.currentThread().getContextClassLoader();
   List> validationProviderList = loadProviders( classloader );
   return validationProviderList;
  }

  private List> loadProviders(ClassLoader classloader) {
   ServiceLoader loader = ServiceLoader.load( ValidationProvider.class, classloader );
   Iterator providerIterator = loader.iterator();
   List> validationProviderList = new ArrayList>();
   while ( providerIterator.hasNext() ) {
    try {
     validationProviderList.add( providerIterator.next() );
    }
    catch ( ServiceConfigurationError e ) {
    }
   }
   return validationProviderList;
  }
 }

下一章将对如何使用Annotation和Xml两种方式来实现对Java Bean的校验

你可能感兴趣的:(Java bean validation 规范与原理)