美文网首页SSM+shiro等
Java bean validation 规范与原理

Java bean validation 规范与原理

作者: linking12 | 来源:发表于2016-04-14 11:39 被阅读1664次

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.
  * <p/>
  * 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<? extends ConstraintValidator<?, ?>>[] 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<? extends Payload>[] payload() default {};
}

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

public ConstraintHelper() {
  Map<Class<? extends Annotation>, List<? extends Class<?>>> 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

Paste_Image.png

Validator的官方实现Hibernate新增的Validator

Paste_Image.png

如何使用:

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

在Spring中可以配置如下:
<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="providerClass"
value="org.hibernate.validator.HibernateValidator" />
</bean>

Validatior Api和Hibernate-Validator的关系

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

private static class GetValidationProviderListAction implements PrivilegedAction<List<ValidationProvider<?>>> {
  private static final WeakHashMap<ClassLoader, SoftReference<List<ValidationProvider<?>>>> providersPerClassloader =
    new WeakHashMap<ClassLoader, SoftReference<List<ValidationProvider<?>>>>();

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

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

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

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

相关文章

网友评论

    本文标题:Java bean validation 规范与原理

    本文链接:https://www.haomeiwen.com/subject/qvzwlttx.html