spring方法级别数据校验-MethodValidationPostProcessor原理
一、向容器中注入BeanMethodValidationPostProcessor@Beanpublic MethodValidationPostProcessor methodValidationPostProcessor() {return new MethodValidationPostProcessor();}二、MethodValidationPostProcessor 创建adviso
·
一、向容器中注入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)