spring方法级别数据校验-MethodValidationPostProcessor原理

16 篇文章 0 订阅
7 篇文章 0 订阅

一、向容器中注入Bean MethodValidationPostProcessor

@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
    return new MethodValidationPostProcessor();
}

二、MethodValidationPostProcessor 创建advisor,对应的是AnnotationMatchingPointcut,这个切点用来匹配Validated.class。

private Class<? extends Annotation> validatedAnnotationType = Validated.class;

@Override
	public void afterPropertiesSet() {
		Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true);
		this.advisor = new DefaultPointcutAdvisor(pointcut, createMethodValidationAdvice(this.validator));
	}

protected Advice createMethodValidationAdvice(@Nullable Validator validator) {
		return (validator != null ? new MethodValidationInterceptor(validator) : new MethodValidationInterceptor());
	}
<p>Target classes with such annotated methods need to be annotated with Spring's
* {@link Validated} annotation at the type level, for their methods to be searched for
* inline constraint annotations. Validation groups can be specified through {@code @Validated}
* as well. By default, JSR-303 will validate against its default group only.

 需要将Validated 注解 放到到Type level : 类、方法级别上,以便可以搜索目标类的方法,目标方法也是可以用Validated注解,获取分组信息。

三、postProcessAfterInitialization bean后置处理器,添加到advised 中,通过ProxyFactory 返回代理对象。

AbstractAdvisingBeanPostProcessor

@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		if (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 async proxy needed.
		return bean;
	}

四、验证逻辑org.springframework.validation.beanvalidation.MethodValidationInterceptor#invoke

public Object invoke(MethodInvocation invocation) throws Throwable {
		Class<?>[] groups = determineValidationGroups(invocation);

		// Standard Bean Validation 1.1 API
		ExecutableValidator execVal = this.validator.forExecutables();
		Method methodToValidate = invocation.getMethod();
		Set<ConstraintViolation<Object>> result;

		try {
			result = execVal.validateParameters(
					invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
		}
		catch (IllegalArgumentException ex) {
			// Probably a generic type mismatch between interface and impl as reported in SPR-12237 / HV-1011
			// Let's try to find the bridged method on the implementation class...
			methodToValidate = BridgeMethodResolver.findBridgedMethod(
					ClassUtils.getMostSpecificMethod(invocation.getMethod(), invocation.getThis().getClass()));
			result = execVal.validateParameters(
					invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
		}
         验证结果不为空就直接抛出ConstraintViolationExcepion
		if (!result.isEmpty()) {
			throw new ConstraintViolationException(result);
		}

		Object returnValue = invocation.proceed();

		result = execVal.validateReturnValue(invocation.getThis(), methodToValidate, returnValue, groups);
		if (!result.isEmpty()) {
			throw new ConstraintViolationException(result);
		}

		return returnValue;
	}

 

 

 

五、捕获全局异常(dubbo 对外接口,自己根据项目需要定义)模板



@Aspect
public class DubboExceptionAspect {
    private static final Logger log = LoggerFactory.getLogger(DubboExceptionAspect.class);

    public DubboExceptionAspect() {
    }

    @Pointcut("@within(com.lls.framework.rpc.dubbo.annotation.DubboService) || execution(* com..impl.BaseProviderImpl.*(..))")
    public void dubboExceptionPointcut() {
    }

    @Around("dubboExceptionPointcut()")
    public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = null;
        InvokerLog<?> invoker = new InvokerLog();
        long startTime = System.currentTimeMillis();
        boolean err = true;

        try {
            String code;
            try {
                AspectUtils.formatInvokerParams(invoker, joinPoint);
                result = joinPoint.proceed();
                err = false;
            } catch (BaseException var14) {
                invoker.setCode(var14.getErrorCode());
                code = var14.getErrorMessage() == null ? (var14.getMessage() == null ? "" : var14.getMessage()) : var14.getErrorMessage();
                invoker.setMessage(code);
                throw var14;
            } catch (Exception var15) {
                code = ResultCodeEnum.ERROR_CODE_10100.getCode();
                String errorMsg = var15.getMessage() == null ? ResultCodeEnum.ERROR_CODE_10100.getMessage() : var15.getMessage();
                invoker.setCode(code);
                invoker.setMessage(errorMsg);
                throw new BaseException(code, errorMsg, var15, new Object[0]);
            }
        } finally {
            AspectUtils.formatInvokerResultMsg(invoker, startTime, result);
            if (err) {
                log.error(JSONObject.toJSONString(invoker));
            } else {
                log.info(JSONObject.toJSONString(invoker));
            }

        }

        return result;
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
spring-boot-starter-actuator是Spring Boot框架中的一个模块,它提供了一系列用于监控和管理应用程序的端点(endpoints),比如/health、/info、/metrics等。这些端点可以通过HTTP请求访问,返回应用程序的各种指标和状态信息。 spring-boot-starter-actuator的原理主要包括以下几个方面: 1. 自动配置:Spring Boot框架提供了自动配置功能,可以根据应用程序的依赖项和配置文件来自动配置spring-boot-starter-actuator模块。 2. 端点映射:spring-boot-starter-actuator使用Spring MVC框架来处理HTTP请求。它通过端点映射(Endpoint Mapping)将HTTP请求映射到相应的端点处理器(Endpoint Handler)上。 3. 端点处理器:每个端点都有一个对应的处理器,用于处理HTTP请求并返回响应。端点处理器可以是自定义的Java类,也可以是Spring Boot框架提供的默认实现。 4. 数据源:spring-boot-starter-actuator会从应用程序的各种数据源中收集指标和状态信息,比如JVM内存使用情况、数据库连接池状态等。这些数据源可以是应用程序本身、第三方库、操作系统等。 5. 安全性:为了保护应用程序的安全性,spring-boot-starter-actuator提供了一些安全功能,比如基于角色的访问控制、IP地址过滤等。可以通过配置文件来配置这些安全功能。 总之,spring-boot-starter-actuator通过自动配置、端点映射、端点处理器、数据源和安全性等机制,实现了对应用程序的监控和管理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值