dubbo源码阅读-Filter默认实现(十一)之ValidationFilter

API文档

http://dubbo.apache.org/zh-cn/docs/user/demos/parameter-validation.html

ValidationFilter

/**
 * ValidationFilter consumer和Provider使用 含有validation 排序10000
 */
@Activate(group = {Constants.CONSUMER, Constants.PROVIDER}, value = Constants.VALIDATION_KEY, order = 10000)
public class ValidationFilter implements Filter {

    /**
     * SPI扩展
     * 通过 Dubbo SPI 机制,调用 {@link #setValidation(Validation)} 方法,进行注入
     * 注入时机:https://www.cnblogs.com/LQBlog/p/12453900.html#autoid-8-14-0
     */
    private Validation validation;

    public void setValidation(Validation validation) {
        this.validation = validation;
    }

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        //含有validation 参数
        if (validation != null && !invocation.getMethodName().startsWith("$")
                && ConfigUtils.isNotEmpty(invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.VALIDATION_KEY))) {
            try {
                //或缺的Validator
                Validator validator = validation.getValidator(invoker.getUrl());
                if (validator != null) {
                    //执行验证
                    validator.validate(invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments());
                }
            } catch (RpcException e) {
                throw e;//注意都是抛出的PRCException
            } catch (Throwable t) {
                //注意抛出的都是RPCException
                return new RpcResult(t);
            }
        }
        return invoker.invoke(invocation);
    }

}

Validation

接口定义

/**
 * Validation
 */
@SPI("jvalidation")
public interface Validation {

    /**
     * 缺省值为jvalidation
     * @param url
     * @return
     */
    @Adaptive(Constants.VALIDATION_KEY)
    Validator getValidator(URL url);

}

AbstractValidation

/**
 * AbstractValidation
 */
public abstract class AbstractValidation implements Validation {

    private final ConcurrentMap<String, Validator> validators = new ConcurrentHashMap<String, Validator>();

    @Override
    public Validator getValidator(URL url) {
        //从缓存获取Validator
        String key = url.toFullString();
        Validator validator = validators.get(key);
        if (validator == null) {
            validators.put(key, createValidator(url));
            validator = validators.get(key);
        }
        return validator;
    }

    /**
     * 模板方法模式 由子类创建
     * @param url
     * @return
     */
    protected abstract Validator createValidator(URL url);

}

JValidation

/**
 * JValidation
 */
public class JValidation extends AbstractValidation {

    @Override
    protected Validator createValidator(URL url) {
        //返回JValidator
        return new JValidator(url);
    }

}

JValidator

 @Override
    public void validate(String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Exception {
        List<Class<?>> groups = new ArrayList<Class<?>>();
        String methodClassName = clazz.getName() + "$" + toUpperMethoName(methodName);
        Class<?> methodClass = null;
        try {
            // 验证分组集合
            methodClass = Class.forName(methodClassName, false, Thread.currentThread().getContextClassLoader());
            groups.add(methodClass);
        } catch (ClassNotFoundException e) {
        }
        Set<ConstraintViolation<?>> violations = new HashSet<ConstraintViolation<?>>();
        //反射获得对应的方法
        Method method = clazz.getMethod(methodName, parameterTypes);
        Class<?>[] methodClasses = null;
        //是否含有MethodValidated 注解 表示我们可以通过MethodValidated 设置验证的group
        if (method.isAnnotationPresent(MethodValidated.class)){
            methodClasses = method.getAnnotation(MethodValidated.class).value();
            //添加group
            groups.addAll(Arrays.asList(methodClasses));
        }
        // add into default group
        groups.add(0, Default.class);
        groups.add(1, clazz);

        // convert list to array
        Class<?>[] classgroups = groups.toArray(new Class[0]);

        //貌似是自定义校验注解 https://blog.csdn.net/lwg_1540652358/article/details/84193759
        Object parameterBean = getMethodParameterBean(clazz, method, arguments);
        if (parameterBean != null) {
            //进行验证
            violations.addAll(validator.validate(parameterBean, classgroups ));
        }
        //验证参数
        for (Object arg : arguments) {
            validate(violations, arg, classgroups);
        }

        if (!violations.isEmpty()) {
            logger.error("Failed to validate service: " + clazz.getName() + ", method: " + methodName + ", cause: " + violations);
            throw new ConstraintViolationException("Failed to validate service: " + clazz.getName() + ", method: " + methodName + ", cause: " + violations, violations);
        }
    }

使用例子 

我这里采用的是属性配置

1.pom依赖

   <dependencies>
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.1.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.1.1.Final</version>
        </dependency>
        <dependency>
            <groupId>javax.el</groupId>
            <artifactId>javax.el-api</artifactId>
            <version>3.0.0</version>
        </dependency>


        <dependency>
            <groupId>org.glassfish</groupId>
            <artifactId>javax.el</artifactId>
            <version>3.0.0</version>
        </dependency>

    </dependencies>

2.vo配置 更多配置看文档

public class TestVo implements Serializable {
    @NotNull(message = "名字不能为空")
    @Min(value = 6, message = "昵称不能太短")
    public java.lang.String name;

    public java.lang.String password;


}

3.propertis配置

dubbo.application.parameters['validation']=jvalidation

4.校验不过打印

原文地址:https://www.cnblogs.com/LQBlog/p/12504399.html