内容简介:本文主要研究一下dubbo的ValidationFilterdubbo-2.7.2/dubbo-filter/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/filter/ValidationFilter.javadubbo-2.7.2/dubbo-filter/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/Validation.java
序
本文主要研究一下dubbo的ValidationFilter
ValidationFilter
dubbo-2.7.2/dubbo-filter/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/filter/ValidationFilter.java
@Activate(group = {CONSUMER, PROVIDER}, value = VALIDATION_KEY, order = 10000) public class ValidationFilter implements Filter { private Validation validation; /** * Sets the validation instance for ValidationFilter * @param validation Validation instance injected by dubbo framework based on "validation" attribute value. */ public void setValidation(Validation validation) { this.validation = validation; } /** * Perform the validation of before invoking the actual method based on <b>validation</b> attribute value. * @param invoker service * @param invocation invocation. * @return Method invocation result * @throws RpcException Throws RpcException if validation failed or any other runtime exception occurred. */ @Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { if (validation != null && !invocation.getMethodName().startsWith("$") && ConfigUtils.isNotEmpty(invoker.getUrl().getMethodParameter(invocation.getMethodName(), VALIDATION_KEY))) { try { Validator validator = validation.getValidator(invoker.getUrl()); if (validator != null) { validator.validate(invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()); } } catch (RpcException e) { throw e; } catch (Throwable t) { return AsyncRpcResult.newDefaultAsyncResult(t, invocation); } } return invoker.invoke(invocation); } }
-
ValidationFilter实现了Filter接口,其invoke方法在validation不为null且invoker的URL中的method参数中包含有validation,且方法名不是
$
开头的,那么就会从validation获取validator,然后进行校验
Validation
dubbo-2.7.2/dubbo-filter/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/Validation.java
@SPI("jvalidation") public interface Validation { /** * Return the instance of {@link Validator} for a given url. * @param url Invocation url * @return Instance of {@link Validator} */ @Adaptive(VALIDATION_KEY) Validator getValidator(URL url); }
- Validation接口定义了getValidator方法
AbstractValidation
dubbo-2.7.2/dubbo-filter/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/support/AbstractValidation.java
public abstract class AbstractValidation implements Validation { private final ConcurrentMap<String, Validator> validators = new ConcurrentHashMap<>(); @Override public Validator getValidator(URL url) { String key = url.toFullString(); Validator validator = validators.get(key); if (validator == null) { validators.put(key, createValidator(url)); validator = validators.get(key); } return validator; } protected abstract Validator createValidator(URL url); }
- AbstractValidation实现了Validation接口,它定义了一个ConcurrentHashMap类型的validators,并且实现了getValidator方法,同时定义了createValidator抽象方法供子类实现
JValidation
dubbo-2.7.2/dubbo-filter/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/support/jvalidation/JValidation.java
public class JValidation extends AbstractValidation { /** * Return new instance of {@link JValidator} * @param url Valid URL instance * @return Instance of JValidator */ @Override protected Validator createValidator(URL url) { return new JValidator(url); } }
- JValidation继承了AbstractValidation,它的createValidator创建的是JValidator
Validator
dubbo-2.7.2/dubbo-filter/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/Validator.java
public interface Validator { void validate(String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Exception; }
- Validator接口定义了validate方法
JValidator
dubbo-2.7.2/dubbo-filter/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/support/jvalidation/JValidator.java
public class JValidator implements Validator { private static final Logger logger = LoggerFactory.getLogger(JValidator.class); private final Class<?> clazz; private final Map<String, Class> methodClassMap; private final javax.validation.Validator validator; @SuppressWarnings({"unchecked", "rawtypes"}) public JValidator(URL url) { this.clazz = ReflectUtils.forName(url.getServiceInterface()); String jvalidation = url.getParameter("jvalidation"); ValidatorFactory factory; if (jvalidation != null && jvalidation.length() > 0) { factory = Validation.byProvider((Class) ReflectUtils.forName(jvalidation)).configure().buildValidatorFactory(); } else { factory = Validation.buildDefaultValidatorFactory(); } this.validator = factory.getValidator(); this.methodClassMap = new ConcurrentHashMap<>(); } //...... @Override public void validate(String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Exception { List<Class<?>> groups = new ArrayList<>(); Class<?> methodClass = methodClass(methodName); if (methodClass != null) { groups.add(methodClass); } Set<ConstraintViolation<?>> violations = new HashSet<>(); Method method = clazz.getMethod(methodName, parameterTypes); Class<?>[] methodClasses; if (method.isAnnotationPresent(MethodValidated.class)){ methodClasses = method.getAnnotation(MethodValidated.class).value(); 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[groups.size()]); 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); } } //...... }
- JValidator实现了Validator接口,其validate方法内部使用的是javax.validation.ValidatorFactory创建的javax.validation.Validator
实例
dubbo-2.7.2/dubbo-filter/dubbo-filter-validation/src/test/java/org/apache/dubbo/validation/filter/ValidationFilterTest.java
public class ValidationFilterTest { private Invoker<?> invoker = mock(Invoker.class); private Validation validation = mock(Validation.class); private Validator validator = mock(Validator.class); private RpcInvocation invocation = mock(RpcInvocation.class); private ValidationFilter validationFilter; @BeforeEach public void setUp() throws Exception { this.validationFilter = new ValidationFilter(); } @Test public void testItWithNotExistClass() throws Exception { URL url = URL.valueOf("test://test:11/test?default.validation=true"); given(validation.getValidator(url)).willThrow(new IllegalStateException("Not found class test, cause: test")); given(invoker.invoke(invocation)).willReturn(new AppResponse("success")); given(invoker.getUrl()).willReturn(url); given(invocation.getMethodName()).willReturn("echo1"); given(invocation.getParameterTypes()).willReturn(new Class<?>[]{String.class}); given(invocation.getArguments()).willReturn(new Object[]{"arg1"}); validationFilter.setValidation(validation); Result result = validationFilter.invoke(invoker, invocation); assertThat(result.getException().getMessage(), is("Not found class test, cause: test")); } @Test public void testItWithExistClass() throws Exception { URL url = URL.valueOf("test://test:11/test?default.validation=true"); given(validation.getValidator(url)).willReturn(validator); given(invoker.invoke(invocation)).willReturn(new AppResponse("success")); given(invoker.getUrl()).willReturn(url); given(invocation.getMethodName()).willReturn("echo1"); given(invocation.getParameterTypes()).willReturn(new Class<?>[]{String.class}); given(invocation.getArguments()).willReturn(new Object[]{"arg1"}); validationFilter.setValidation(validation); Result result = validationFilter.invoke(invoker, invocation); assertThat(String.valueOf(result.getValue()), is("success")); } @Test public void testItWithoutUrlParameters() throws Exception { URL url = URL.valueOf("test://test:11/test"); given(validation.getValidator(url)).willReturn(validator); given(invoker.invoke(invocation)).willReturn(new AppResponse("success")); given(invoker.getUrl()).willReturn(url); given(invocation.getMethodName()).willReturn("echo1"); given(invocation.getParameterTypes()).willReturn(new Class<?>[]{String.class}); given(invocation.getArguments()).willReturn(new Object[]{"arg1"}); validationFilter.setValidation(validation); Result result = validationFilter.invoke(invoker, invocation); assertThat(String.valueOf(result.getValue()), is("success")); } @Test public void testItWhileMethodNameStartWithDollar() throws Exception { URL url = URL.valueOf("test://test:11/test"); given(validation.getValidator(url)).willReturn(validator); given(invoker.invoke(invocation)).willReturn(new AppResponse("success")); given(invoker.getUrl()).willReturn(url); given(invocation.getMethodName()).willReturn("$echo1"); given(invocation.getParameterTypes()).willReturn(new Class<?>[]{String.class}); given(invocation.getArguments()).willReturn(new Object[]{"arg1"}); validationFilter.setValidation(validation); Result result = validationFilter.invoke(invoker, invocation); assertThat(String.valueOf(result.getValue()), is("success")); } @Test public void testItWhileThrowoutRpcException() throws Exception { Assertions.assertThrows(RpcException.class, () -> { URL url = URL.valueOf("test://test:11/test?default.validation=true"); given(validation.getValidator(url)).willThrow(new RpcException("rpc exception")); given(invoker.invoke(invocation)).willReturn(new AppResponse("success")); given(invoker.getUrl()).willReturn(url); given(invocation.getMethodName()).willReturn("echo1"); given(invocation.getParameterTypes()).willReturn(new Class<?>[]{String.class}); given(invocation.getArguments()).willReturn(new Object[]{"arg1"}); validationFilter.setValidation(validation); validationFilter.invoke(invoker, invocation); }); } }
- 这里分别验证了withNotExistClass、withExistClass、withoutUrlParameters、methodNameStartWithDollar、throwoutRpcException这几个场景
小结
$
doc
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Out of their Minds
Dennis Shasha、Cathy Lazere / Springer / 1998-07-02 / USD 16.00
This best-selling book is now available in an inexpensive softcover format. Imagine living during the Renaissance and being able to interview that eras greatest scientists about their inspirations, di......一起来看看 《Out of their Minds》 这本书的介绍吧!
JS 压缩/解压工具
在线压缩/解压 JS 代码
Markdown 在线编辑器
Markdown 在线编辑器