概述
MethodValidationPostProcessor
处理bean
中的JSR-303
方法验证注解。比如某个bean
方法使用了JSR-303
注解如下 :
public @NotNull Object myValidMethod(@NotNull String arg1, @Max(10) int arg2)
当该bean
的类上再使用了Spring
的注解@Validated
时,上面的这些方法就会是MethodValidationPostProcessor
的关注点。
MethodValidationPostProcessor
对这些验证方法的处理流程简单总结是这样的 :
MethodValidationPostProcessor
实现了接口InitializingBean
,该bean
自身的初始化逻辑会创建一个DefaultPointcutAdvisor
用于向符合条件的对象添加进行方法验证的AOP advise
。MethodValidationPostProcessor
实现了接口BeanPostProcessor
定义的方法postProcessAfterInitialization
,该方法会检查每个bean
的创建(在该bean
初始化之后),如果检测到该bean
符合条件,会向其增加MethodValidationPostProcessor
自身初始化时所创建的DefaultPointcutAdvisor
中的AOP advise
。- 上面例子中提到的
bean
方法myValidMethod
被调用时,上面所提到的用于方法验证的AOP advise
就会执行方法验证逻辑。
关于
MethodValidationPostProcessor
的使用,可以参考Spring Boot的自动配置ValidationAutoConfiguration。
源代码解析
源代码版本 : Spring Context 5.1.5.RELEASE
package org.springframework.validation.beanvalidation;
// 省略 import 行
@SuppressWarnings("serial")
public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor
implements InitializingBean {
// 缺省支持的表示类需要进行验证的注解:Spring 的注解 @Validated
private Class<? extends Annotation> validatedAnnotationType = Validated.class;
// 所要使用的验证器
@Nullable
private Validator validator;
/**
* Set the 'validated' annotation type.
* The default validated annotation type is the Validated annotation.
* <p>This setter property exists so that developers can provide their own
* (non-Spring-specific) annotation type to indicate that a class is supposed
* to be validated in the sense of applying method validation.
* 设置要支持的表示类需要进行验证的注解,缺省支持Spring提供的@Validated,
* 开发人员可以通过该方法提供自己要支持的注解类型而不一定要是Spring相关的注解
* @param validatedAnnotationType the desired annotation type
*/
public void setValidatedAnnotationType(Class<? extends Annotation> validatedAnnotationType) {
Assert.notNull(validatedAnnotationType, "'validatedAnnotationType' must not be null");
this.validatedAnnotationType = validatedAnnotationType;
}
/**
* Set the JSR-303 Validator to delegate to for validating methods.
* Default is the default ValidatorFactory's default Validator.
* 设置JSR-303验证器,最终的方法验证任务代理给该JSR-303验证器完成
*/
public void setValidator(Validator validator) {
// Unwrap to the native Validator with forExecutables support
if (validator instanceof LocalValidatorFactoryBean) {
this.validator = ((LocalValidatorFactoryBean) validator).getValidator();
}
else if (validator instanceof SpringValidatorAdapter) {
this.validator = validator.unwrap(Validator.class);
}
else {
this.validator = validator;
}
}
/**
* Set the JSR-303 ValidatorFactory to delegate to for validating methods,
* using its default Validator.
* Default is the default ValidatorFactory's default Validator.
* 设置JSR-303验证器工厂,最终的方法验证任务代理给由该JSR-303验证器工厂生成的
* 验证器完成。如果使用了该方法,所使用的验证器是工厂的缺省验证器。
* 该方法和setValidator()二者用一个即可
* @see javax.validation.ValidatorFactory#getValidator()
*/
public void setValidatorFactory(ValidatorFactory validatorFactory) {
this.validator = validatorFactory.getValidator();
}
// InitializingBean 接口定义的方法,在该 BeanPostProcessor bean实例创建过程中
// 初始化阶段执行,构造一个 DefaultPointcutAdvisor (pointcut + advise) 记录到 this.advisor
// 用于对符合条件的方法进行验证
@Override
public void afterPropertiesSet() {
Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true);
this.advisor = new DefaultPointcutAdvisor(pointcut,
createMethodValidationAdvice(this.validator));
}
/**
* Create AOP advice for method validation purposes, to be applied
* with a pointcut for the specified 'validated' annotation.
* @param validator the JSR-303 Validator to delegate to
* @return the interceptor to use (typically, but not necessarily,
* a {@link MethodValidationInterceptor} or subclass thereof)
* @since 4.2
*/
protected Advice createMethodValidationAdvice(@Nullable Validator validator) {
return (validator != null ? new MethodValidationInterceptor(validator) :
new MethodValidationInterceptor());
}
}
从上面的代码可以看出,MethodValidationPostProcessor
继承自AbstractBeanFactoryAwareAdvisingPostProcessor
,进而继承自AbstractAdvisingBeanPostProcessor
。而BeanPostProcessor
定义的方法实现逻辑就在该类中,它会在每个bean
创建过程中初始化之后,检查该bean
是否符合条件,符合条件的话,把上面所创建的方法验证advisor
绑定到该bean
,代码如下所示 :
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (this.advisor == null || bean instanceof AopInfrastructureBean) {
// Ignore AOP infrastructure such as scoped proxies.
return bean;
}
if (bean instanceof Advised) {
Advised advised = (Advised) bean;
if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
// Add our local Advisor to the existing proxy's Advisor chain...
// 如果当前 bean 实现了接口 Advised,
// 并且当前 bean 没有被冻结 ,
// 并且当前bean 符合该 MethodValidationPostProcessor 的处理条件,
// 则将 this.advisor 添加到当前 bean,这样的它的方法被调用时,
// this.advisor 中的方法验证逻辑就会被应用
if (this.beforeExistingAdvisors) {
advised.addAdvisor(0, this.advisor);
}
else {
advised.addAdvisor(this.advisor);
}
return bean;
}
}
// bean 没有实现 Advised 接口, 但是也符合 MethodValidationPostProcessor
// 处理条件的情况,跟上面 bean 实现了 Advised 接口的处理流程类似,只是这里
// 是把 this.advisor 添加到当前 bean 的代理工厂类上然后生成并返回该 bean
// 相应的代理对象,而不再是原来的 bean 本身
if (isEligible(bean, beanName)) {
ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
if (!proxyFactory.isProxyTargetClass()) {
evaluateProxyInterfaces(bean.getClass(), proxyFactory);
}
proxyFactory.addAdvisor(this.advisor);
customizeProxyFactory(proxyFactory);
return proxyFactory.getProxy(getProxyClassLoader());
}
// No proxy needed.
return bean;
}