亲爱的小伙伴们我来填坑啦,java中优雅的参数校验方法中的校验的实现原理。
1.前言
验证数据是发生在所有应用程序层(从表示层到持久层)的常见任务。通常在每一层中实现相同的验证逻辑,这既耗时又容易出错。为了避免重复这些验证,开发人员经常将验证逻辑直接捆绑到域模型中,将域类与验证代码混淆,验证代码实际上是关于类本身的元数据。

JSR 380 - Bean Validation 2.0 - 定义了用于实体和方法验证的元数据模型和 API。默认元数据源是注释,能够通过使用 XML 覆盖和扩展元数据。API 不依赖于特定的应用程序层或编程模型。它特别不依赖于 Web 或持久层,并且可用于服务器端应用程序编程以及富客户端 Swing 应用程序开发人员。

Hibernate Validator 是这个 JSR 380 的参考实现。实现本身以及 Bean Validation API 和 TCK 都是在Apache Software License 2.0下提供和分发的 。
Hibernate Validator 6 和 Bean Validation 2.0 需要 Java 8 或更高版本。
2.Hibernate Validator
2.1手动对参数进行校验
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import java.util.Iterator;
import java.util.Set;
/**
* @Author: wangxia
* @Date: 2021/10/20 16:30
*/
public class TestPerson {
public static void main(String[] args) {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
TestPerson testPerson = new TestPerson();
testPerson.setAge(-5);
Set<ConstraintViolation<TestPerson>> validate = validator.validate(testPerson);
Iterator<ConstraintViolation<TestPerson>> iterator = validate.iterator();
while (iterator.hasNext()) {
ConstraintViolation<TestPerson> e=iterator.next();
System.out.println(e.getMessage());
}
}
@NotEmpty(message = "用户名不能为空")
private String username;
@Min(value = 0,message = "年龄不能小于0岁")
@Max(value =150,message = "年龄不能大于150岁")
private int age;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}校验结果:
虽然这样能够手动的获取校验结果但是每次想要校验都添加这段校验的代码还是很麻烦的,由此就衍生出里 @Validated,下面就讲下 @Validated是如何实现校验功能的。
3.@Validated生效原理
@Validated生效之所以能生效主要依赖于Spring的Aop和拦截器,在MethodValidationPostProcessor类中通过Aop和拦截器实现@Validated调用参数校验的目的。Aop的主要目的是每次遇到@Validated注解时都执行拦截器中的方法。
public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor implements InitializingBean {
private Class<? extends Annotation> validatedAnnotationType = Validated.class;
@Nullable
private Validator validator;
public MethodValidationPostProcessor() {
}
public void setValidatedAnnotationType(Class<? extends Annotation> validatedAnnotationType) {
Assert.notNull(validatedAnnotationType, "'validatedAnnotationType' must not be null");
this.validatedAnnotationType = validatedAnnotationType;
}
public void setValidator(Validator validator) {
if (validator instanceof LocalValidatorFactoryBean) {
this.validator = ((LocalValidatorFactoryBean)validator).getValidator();
} else if (validator instanceof SpringValidatorAdapter) {
this.validator = (Validator)validator.unwrap(Validator.class);
} else {
this.validator = validator;
}
}
public void setValidatorFactory(ValidatorFactory validatorFactory) {
this.validator = validatorFactory.getValidator();
}
//InitializingBean接口的方法,在类初始化时调用afterPropertiesSet方法
public void afterPropertiesSet() {
//针对@Validated注解创建切点
Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true);
//整合切点到切面中,每次遇到@Validated切点就执行this.createMethodValidationAdvice(this.validator)方法
this.advisor = new DefaultPointcutAdvisor(pointcut, this.createMethodValidationAdvice(this.validator));
}
protected Advice createMethodValidationAdvice(@Nullable Validator validator) {
//创建拦截器
return validator != null ? new MethodValidationInterceptor(validator) : new MethodValidationInterceptor();
}
}拦截器简介

参考文档:hibernate-validator
其实目前这个还不是太完善,会尽快把坑填上的。