SpringBoot 中 Spring Validation 工作方式

validation 是javax中定義的一套驗證接口, 目前我們大家熟悉的實現是hibernate的validation 實現 ;

問題1 , 在springboot中 validation是如何引入的?

問題2,  spring中validation的驗證如何實現?

// 自動配置驗證器bean到上下文中
@Configuration
@ConditionalOnClass(ExecutableValidator.class)
@ConditionalOnResource(resources = "classpath:META-INF/services/javax.validation.spi.ValidationProvider")
@Import(PrimaryDefaultValidatorPostProcessor.class)
public class ValidationAutoConfiguration {

 // 驗證器bean的初始化,主要是通過ServiceLoader加載 jar包中的實現類 classpath:META-INF/services/javax.validation.spi.ValidationProvider, 
//例如hibernate的validation實現,
//可以通過messageInterpolatorFactory源碼獲取,詳細瞭解請看源碼
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	@ConditionalOnMissingBean(Validator.class)
	public static LocalValidatorFactoryBean defaultValidator() {
		LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
		MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();
		factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
		return factoryBean;
	}


// 方法級別的驗證後置處理器,
//是通過BeanPostProcessor#postProcessAfterInitialization
//方法實現通過對bean中類級別的annotation標籤(@Validated)的掃描,
//進行AOP方法攔截,進而實現啓用驗證的目的
	@Bean
	@ConditionalOnMissingBean
	public static MethodValidationPostProcessor methodValidationPostProcessor(Environment environment,
			@Lazy Validator validator) {
		MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
		boolean proxyTargetClass = environment.getProperty("spring.aop.proxy-target-class", Boolean.class, true);
		processor.setProxyTargetClass(proxyTargetClass);
		processor.setValidator(validator);
		return processor;
	}

}

問題2 , 我們具體來看MethodValidationPostProcessor這個bean的關鍵源碼

MethodValidationPostProcessor 實現InitializingBean接口

	@Override
	public void afterPropertiesSet() {
/** 創建一個Aop切點,切點的Annotation是 org.springframework.validation.annotation.Validated
*
*切點的兩個特性:
 *   1》 this.classFilter = new AnnotationClassFilter(classAnnotationType, checkInherited); *@Validated標籤類匹配
*	2》	this.methodMatcher = MethodMatcher.TRUE; 全部方法匹配
**/
		Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true);
/**
    切面實現  創建 MethodValidationInterceptor方法驗證攔截器實現
**/
		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());
	}

同時其父類AbstractAdvisingBeanPostProcessor 又實現了 BeanPostProcessor接口 ,因此我們看下具體的實現方法:

@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		return 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...
				if (this.beforeExistingAdvisors) {
					advised.addAdvisor(0, this.advisor);
				}
				else {
					advised.addAdvisor(this.advisor);
				}
				return 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;
	}

該方法將會生成代理類(對容器中構建好的bean進行掃描 , 生成代理類)

好了 就寫到這裏了 , 如有紕漏,請留言指正, 希望能對你有所幫助!

發佈了18 篇原創文章 · 獲贊 4 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章