一、向容器中注入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;
    }
}

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐