首页 > 其他分享 >Spring BeanPostProcessor : MethodValidationPostProcessor

Spring BeanPostProcessor : MethodValidationPostProcessor

时间:2023-08-23 13:31:35浏览次数:54  
标签:BeanPostProcessor 验证 Spring MethodValidationPostProcessor bean validator Validat

概述

MethodValidationPostProcessor处理bean中的JSR-303方法验证注解。比如某个bean方法使用了JSR-303注解如下 :

public @NotNull Object myValidMethod(@NotNull String arg1, @Max(10) int arg2)

当该bean的类上再使用了Spring的注解@Validated时,上面的这些方法就会是MethodValidationPostProcessor的关注点。

MethodValidationPostProcessor对这些验证方法的处理流程简单总结是这样的 :

  1. MethodValidationPostProcessor实现了接口InitializingBean,该bean自身的初始化逻辑会创建一个DefaultPointcutAdvisor用于向符合条件的对象添加进行方法验证的AOP advise
  2. MethodValidationPostProcessor实现了接口BeanPostProcessor定义的方法postProcessAfterInitialization,该方法会检查每个bean的创建(在该bean初始化之后),如果检测到该bean符合条件,会向其增加MethodValidationPostProcessor自身初始化时所创建的DefaultPointcutAdvisor中的AOP advise
  3. 上面例子中提到的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;
	}

参考文章

标签:BeanPostProcessor,验证,Spring,MethodValidationPostProcessor,bean,validator,Validat
From: https://blog.51cto.com/u_15668812/7202137

相关文章

  • springboot整合资源文件
    1:什么是SpringBoot?SpringBoot基于Spring4.0设计,不仅继承了Spring框架原有的优秀特性,而且还通过==简化配置==来进一步简化Spring应用的整个搭建和开发过程。另外SpringBoot还通过继承大量框架使依赖包的版本冲突,以及引用不稳定性等问题的到了很好的解决。2:SpringBoot的优点(1)可以......
  • 基于Springboot的个人网站的设计与实现-计算机毕业设计源码+LW文档
    一、设计(论文)选题的依据1.研究背景与意义现在越来越多的人关注网站的自动化设计与开发,什么是个人网站呢?它的出现和运营究竟承载这怎样的信息?这并不是每个人都清楚的很多人无法准确的理解个人网站的优势和作用,我对网站的认识还处于相当低的程度中所以在正文开始前我想先阐述自己对......
  • SpringMVC执行流程流程版
    1.用户向服务器发送请求,请求被SpringMVC前端控制器DispatcherServlet捕获。2.DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI),判断请求URI对应的映射:a.不存在i.再次判断是否配置mvc:default-servlet-handlerii:如果开启default-servlet-:会先交给DispatherServl......
  • 从头到尾说一次 Spring 事务管理(器) | 京东云技术团队
    事务管理,一个被说烂的也被看烂的话题,还是八股文中的基础股之一。本文会从设计角度,一步步的剖析Spring事务管理的设计思路(都会设计事务管理器了,还能玩不转?)为什么需要事务管理?先看看如果没有事务管理器的话,如果想让多个操作(方法/类)处在一个事务里应该怎么做://MethodA:publicvoid......
  • Vue+SpringBoot项目分离部署踩坑记录
    昨天花了一晚上终于成功部署了个人网站,在这个过程中踩了很多坑,现在回顾总结记录一下,以免今后继续犯错误前端:Vue后端:SpringBoot数据库:Mysql一、前端1、前端项目采用Nginx进行部署,其中Nginx配置文件部分内容如下nginx.conf部分内容1server{2listen443ssl......
  • SpringMVC执行流程注解版
    下面是SpringMVC执行流程的注解版:存在的问题:·1.web.xml文件需要存在(不然Tomcat(log->GBK编码)的War包构建不成功,部署会失败).2.spring和springmvc需要加载bean会有冲突的问题,可以统一管理Bean等WebInit(代替web.xml)//代替web.xmlpublicclassWebInitextends......
  • 从头到尾说一次 Spring 事务管理(器)
    事务管理,一个被说烂的也被看烂的话题,还是八股文中的基础股之一。​本文会从设计角度,一步步的剖析Spring事务管理的设计思路(都会设计事务管理器了,还能玩不转?)为什么需要事务管理?先看看如果没有事务管理器的话,如果想让多个操作(方法/类)处在一个事务里应该怎么做://MethodA:publ......
  • 告别混乱代码:这份 Spring Boot 后端接口规范来得太及时了!
    一、前言一个后端接口大致分为四个部分组成:接口地址(url)、接口请求方式(get、post等)、请求数据(request)、响应数据(response)。虽然说后端接口的编写并没有统一规范要求,而且如何构建这几个部分每个公司要求都不同,没有什么“一定是最好的”标准,但其中最重要的关键点就是看是否规范。二......
  • idea无法构建springboot工程
    1、出现的问题Initializationfailedfor'http://start.aliyun.com'PleasecheckURL,networkandproxysettings.Errormessage:ErrorparsingJSONresponse 2.解决方案   ......
  • SpringMVC 中中文乱码解决
    请求中文乱码在web.xml中配置spring自带的过滤器org.springframework.web.filter.CharacterEncodingFilter,只可以解决请求<!--spring自带的解决中文乱码的filter--><filter><filter-name>encoding</filter-name><filter-class>org.springframework.web.fil......