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.校验不过打印