Spring对Bean Validation支持的核心API

spring虽然没有直接实现Bean校验这块JSR规范,但是从spring3.0开始,就提供了对Bean Valication的支持

BeanValidationPostProcessor

能够去校验Spring容器中的Bean,从而决定允不允许它初始化完成,若校验不通过,在违反约束的情况下就会抛出异常,阻止容器的正常启动。

public class BeanValidationPostProcessor implements BeanPostProcessor, InitializingBean {

    @Nullable
    private Validator validator;

    private boolean afterInitialization = false;

    @Override
    public void afterPropertiesSet() throws Exception {
        if (this.validator == null){
            this.validator = Validation.buildDefaultValidatorFactory().getValidator();
        }
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (!this.afterInitialization){
            doValidate(bean);
        }
        return bean;
    }

    protected void doValidate(Object bean) {
        Assert.state(this.validator != null, "No Validator set");
        Object objectToValidate = AopProxyUtils.getSingletonTarget(bean);
        if (objectToValidate == null) {
            objectToValidate = bean;
        }
        Set<ConstraintViolation<Object>> result = this.validator.validate(objectToValidate);

        // 拼接错误消息最终抛出
        if (!result.isEmpty()) {
            StringBuilder sb = new StringBuilder("Bean state is invalid: ");
            for (Iterator<ConstraintViolation<Object>> it = result.iterator(); it.hasNext();) {
                ConstraintViolation<Object> violation = it.next();
                sb.append(violation.getPropertyPath()).append(" - ").append(violation.getMessage());
                if (it.hasNext()) {
                    sb.append("; ");
                }
            }
            throw new BeanInitializationException(sb.toString());
        }
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (this.afterInitialization){
            doValidate(bean);
        }
        return bean;
    }
}

org.springframework.validation.Validator

应用程序特定对象的验证器,这时spring自己抽象的,区别于javax.validation.Validator,这个接口完全脱离任何基础设施或上下文,也就说没有耦合到只验证web层、数据访问层或任何层中的对象,它支持应用于程序内的任何层。

// 注意:它可不是Spring3后才推出的  最初就有
public interface Validator {
	// 此clazz是否可以被validate
	boolean supports(Class<?> clazz);
	// 执行校验,错误消息放在Errors 装着
	// 可以参考ValidationUtils这个工具类,它能帮助你很多
	void validate(Object target, Errors errors);
}

在这里插入图片描述

SmartValidator

这个子接口扩展增加了校验分组:hints

// @since 3.1  这个出现得比较晚
public interface SmartValidator extends Validator {
	
	// 注意:这里的Hints最终都会被转化到JSR的分组里去~~
	// 所以这个可变参数,传接口Class对象即可~
	void validate(Object target, Errors errors, Object... validationHints);

	// @since 5.1  简单的说,这个方法子类请复写 否则不能使用
	default void validateValue(Class<?> targetType, String fieldName, @Nullable Object value, Errors errors, Object... validationHints) {
		throw new IllegalArgumentException("Cannot validate individual value for " + targetType);
	}
}
SpringValidatorAdapter:校验适配器

在这里插入图片描述

这个实现类Class是非常重要的,它是javax.valication.Validator到spring的Validator的适配,通过它就可以对接到JSR的校验器来完成校验工作,同时还公开了原始JSR-303 Validator接口本身。

// @since 3.0
public class SpringValidatorAdapter implements SmartValidator, javax.validation.Validator {

	// 通用的三个约束注解都需要有的属性
	private static final Set<String> internalAnnotationAttributes = new HashSet<>(4);
	static {
		internalAnnotationAttributes.add("message");
		internalAnnotationAttributes.add("groups");
		internalAnnotationAttributes.add("payload");
	}

	// 最终都是委托给它来完成校验的~~~
	@Nullable
	private javax.validation.Validator targetValidator;
	public SpringValidatorAdapter(javax.validation.Validator targetValidator) {
		Assert.notNull(targetValidator, "Target Validator must not be null");
		this.targetValidator = targetValidator;
	}

	// 简单的说:默认支持校验所有的Bean类型~~~
	@Override
	public boolean supports(Class<?> clazz) {
		return (this.targetValidator != null);
	}
	// processConstraintViolations做的事一句话解释:
	// 把ConstraintViolations错误消息,全都适配放在Errors(BindingResult)里面存储着
	@Override
	public void validate(Object target, Errors errors) {
		if (this.targetValidator != null) {
			processConstraintViolations(this.targetValidator.validate(target), errors);
		}
	}

	@Override
	public void validate(Object target, Errors errors, Object... validationHints) {
		if (this.targetValidator != null) {
			processConstraintViolations(this.targetValidator.validate(target,  asValidationGroups(validationHints)), errors);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public void validateValue(Class<?> targetType, String fieldName, @Nullable Object value, Errors errors, Object... validationHints) {
		if (this.targetValidator != null) {
			processConstraintViolations(this.targetValidator.validateValue(
					(Class) targetType, fieldName, value, asValidationGroups(validationHints)), errors);
		}
	}

	// 把validationHints都转换为group (支识别Class类型哦)
	private Class<?>[] asValidationGroups(Object... validationHints) {
		Set<Class<?>> groups = new LinkedHashSet<>(4);
		for (Object hint : validationHints) {
			if (hint instanceof Class) {
				groups.add((Class<?>) hint);
			}
		}
		return ClassUtils.toClassArray(groups);
	}

	// 关于Implementation of JSR-303 Validator interface  省略...
}

CustomValidatorBean

可配置的Bean

在这里插入图片描述

public class CustomValidatorBean extends SpringValidatorAdapter implements Validator, InitializingBean {

	@Nullable
	private ValidatorFactory validatorFactory;

	@Nullable
	private MessageInterpolator messageInterpolator;

	@Nullable
	private TraversableResolver traversableResolver;


	/**
	 * 提供配置校验器工厂的set方法
	 * 
	 */
	public void setValidatorFactory(ValidatorFactory validatorFactory) {
		this.validatorFactory = validatorFactory;
	}

	/**
	 * 指定用于此验证器的自定义MessageInterpolator。
	 */
	public void setMessageInterpolator(MessageInterpolator messageInterpolator) {
		this.messageInterpolator = messageInterpolator;
	}

	/**
	 * 指定用于此验证器的自定义TraversableResolver
	 */
	public void setTraversableResolver(TraversableResolver traversableResolver) {
		this.traversableResolver = traversableResolver;
	}


	/**
	* 通过`javax.valication.Validator`获取实例
	*/
	@Override
	public void afterPropertiesSet() {
		if (this.validatorFactory == null) {
			this.validatorFactory = Validation.buildDefaultValidatorFactory();
		}

		// 获取校验器上下文对象
		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());
	}

}

LocalValidatorFactoryBean

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

// @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接口的方法实现~
}

OptionalValidatorFactoryBean

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

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);
		}
	}

}
SpringConstraintValidatorFactory

将ConstraintValidator放入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

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);
	}

}

LocaleContextMessageInterpolator

它是个javax.validation.MessageInterpolator插值器,Spring把它和自己的LocaleContext结合起来了。

// @since 3.0
// org.springframework.context.i18n.LocaleContextHolder#getLocale()
public class LocaleContextMessageInterpolator implements MessageInterpolator {

	private final MessageInterpolator targetInterpolator;
	public LocaleContextMessageInterpolator(MessageInterpolator targetInterpolator) {
		Assert.notNull(targetInterpolator, "Target MessageInterpolator must not be null");
		this.targetInterpolator = targetInterpolator;
	}

	@Override
	public String interpolate(String message, Context context) {
		return this.targetInterpolator.interpolate(message, context, LocaleContextHolder.getLocale());
	}
	@Override
	public String interpolate(String message, Context context, Locale locale) {
		return this.targetInterpolator.interpolate(message, context, locale);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值