内容简介:本文主要研究一下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
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Flash PHP实用开发技术
Steve Webster著、王黎译 / 王黎 / 清华大学出版社 / 2002-3 / 39.00元
本书将介绍服务器端脚本所提供的各种可能的操作方案,帮助读者掌握设计数据库集成程序和高端应用程序的知识。一起来看看 《Flash PHP实用开发技术》 这本书的介绍吧!